以led驱动程序为例,介绍字符设备驱动程序的传统写法。
驱动程序:
程序代码来源于韦老大视频代码
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/fs.h>
4 #include <linux/init.h>
5 #include <linux/delay.h>
6 #include <linux/uaccess.h>
7 #include <asm/irq.h>
8 #include <asm/io.h>
9 #include <linux/of.h>
10 #include <linux/of_device.h>
11 #include <linux/of_platform.h>
12
13 #define S3C2440_GPA(n) (0<<16 | n)
14 #define S3C2440_GPB(n) (1<<16 | n)
15 #define S3C2440_GPC(n) (2<<16 | n)
16 #define S3C2440_GPD(n) (3<<16 | n)
17 #define S3C2440_GPE(n) (4<<16 | n)
18 #define S3C2440_GPF(n) (5<<16 | n)
19 #define S3C2440_GPG(n) (6<<16 | n)
20 #define S3C2440_GPH(n) (7<<16 | n)
21 #define S3C2440_GPI(n) (8<<16 | n)
22 #define S3C2440_GPJ(n) (9<<16 | n)
23
24 static int led_pin = S3C2440_GPF(5);
25 static volatile unsigned int *gpio_con;
26 static volatile unsigned int *gpio_dat;
27
28 /* 123. 分配/设置/注册file_operations
29 * 4. 入口
30 * 5. 出口
31 */
32
33 static int major;
34 static struct class *led_class;
35
36 static unsigned int gpio_base[] = {
37 0x56000000, /* GPACON */
38 0x56000010, /* GPBCON */
39 0x56000020, /* GPCCON */
40 0x56000030, /* GPDCON */
41 0x56000040, /* GPECON */
42 0x56000050, /* GPFCON */
43 0x56000060, /* GPGCON */
44 0x56000070, /* GPHCON */
45 0, /* GPICON */
46 0x560000D0, /* GPJCON */
47 };
48
49 static int led_open (struct inode *node, struct file *filp)
50 {
51 /* 把LED引脚配置为输出引脚 */
52 /* GPF5 - 0x56000050 */
53 int bank = led_pin >> 16;
54 int base = gpio_base[bank];
55
56 int pin = led_pin & 0xffff;
57 gpio_con = ioremap(base, 8);
58 if (gpio_con) {
59 printk("ioremap(0x%x) = 0x%x
", base, gpio_con);
60 }
61 else {
62 return -EINVAL;
63 }
64
65 gpio_dat = gpio_con + 1;
66
67 *gpio_con &= ~(3<<(pin * 2));
68 *gpio_con |= (1<<(pin * 2));
69
70 return 0;
71 }
72
73 static ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
74 {
75 /* 根据APP传入的值来设置LED引脚 */
76 unsigned char val;
77 int pin = led_pin & 0xffff;
78
79 copy_from_user(&val, buf, 1);
80
81 if (val)
82 {
83 /* 点灯 */
84 *gpio_dat &= ~(1<<pin);
85 }
86 else
87 {
88 /* 灭灯 */
89 *gpio_dat |= (1<<pin);
90 }
91
92 return 1; /* 已写入1个数据 */
93 }
94
95 static int led_release (struct inode *node, struct file *filp)
96 {
97 printk("iounmap(0x%x)
", gpio_con);
98 iounmap(gpio_con);
99 return 0;
100 }
101
102
103 static struct file_operations myled_oprs = {
104 .owner = THIS_MODULE,
105 .open = led_open,
106 .write = led_write,
107 .release = led_release,
108 };
109
110
111 static int myled_init(void)
112 {
113 major = register_chrdev(0, "myled", &myled_oprs);
114
115 led_class = class_create(THIS_MODULE, "myled");
116 device_create(led_class, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
117
118 return 0;
119 }
120
121 static void myled_exit(void)
122 {
123 unregister_chrdev(major, "myled");
124 device_destroy(led_class, MKDEV(major, 0));
125 class_destroy(led_class);
126 }
127
128 module_init(myled_init);
129 module_exit(myled_exit);
130
131
132 MODULE_LICENSE("GPL");
2、测试程序
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5
6 /* ledtest on
7 * ledtest off
8 */
9 int main(int argc, char **argv)
10 {
11 int fd;
12 unsigned char val = 1;
13 fd = open("/dev/led", O_RDWR);
14 if (fd < 0)
15 {
16 printf("can't open!
");
17 }
18 if (argc != 2)
19 {
20 printf("Usage :
");
21 printf("%s <on|off>
", argv[0]);
22 return 0;
23 }
24
25 if (strcmp(argv[1], "on") == 0)
26 {
27 val = 1;
28 }
29 else
30 {
31 val = 0;
32 }
33
34 write(fd, &val, 1);
35 return 0;
36 }