驱动框架
通过使用platform设备驱动框架,实现led驱动与设备操作的分离。
我们关注led_drv里面的 struct platform_driver led_drv里面的.probe函数,当有同名的device注册到内核,将运行这个driver的probe函数(同名的:led_dev里面的struct platform_device led_dev里面的.name与 struct platform_driver led_drv里面的.name一一对应)。
led_dev.c
1 /* 分配/设置/注册一个platform_device */
2 #include <linux/module.h>
3 #include <linux/version.h>
4
5 #include <linux/init.h>
6 #include <linux/fs.h>
7 #include <linux/interrupt.h>
8 #include <linux/irq.h>
9 #include <linux/sched.h>
10 #include <linux/pm.h>
11 #include <linux/sysctl.h>
12 #include <linux/proc_fs.h>
13 #include <linux/delay.h>
14 #include <linux/platform_device.h>
15 #include <linux/input.h>
16 #include <linux/irq.h>
17 #include <asm/uaccess.h>
18 #include <asm/io.h>
19
20
21 static struct resource led_resource[] = {
22 [0] = {
23 .start = 0x56000050,
24 .end = 0x56000050 + 8 - 1,
25 .flags = IORESOURCE_MEM, //标记资源类型
26 },
27
28 [1] = {
29 .start = 4,
30 .end = 4,
31 .flags = IORESOURCE_IRQ,
32 }
33 };
34
35 static void led_release(struct device *dev)
36 {
37
38 }
39
40 static struct platform_device led_dev = {
41 .name = "myled", //与drv保持一致
42 .id = -1,
43 .num_resources = ARRAY_SIZE(led_resource),
44 .resource = led_resource,
45 .dev = {
46 .release = led_release,
47 }
48 };
49
50
51 static int led_dev_init(void)
52 {
53 platform_device_register(&led_dev);
54 return 0;
55 }
56
57
58 static void led_dev_exit(void)
59 {
60 platform_device_unregister(&led_dev);
61 return;
62 }
63
64 module_init(led_dev_init);
65 module_exit(led_dev_exit);
66 MODULE_LICENSE("GPL");
led_drv.c
1 /* 分配/设置/注册一个platform_driver */
2 #include <linux/module.h>
3 #include <linux/version.h>
4
5 #include <linux/init.h>
6 #include <linux/fs.h>
7 #include <linux/interrupt.h>
8 #include <linux/irq.h>
9 #include <linux/sched.h>
10 #include <linux/pm.h>
11 #include <linux/sysctl.h>
12 #include <linux/proc_fs.h>
13 #include <linux/delay.h>
14 #include <linux/platform_device.h>
15 #include <linux/input.h>
16 #include <linux/irq.h>
17 #include <asm/uaccess.h>
18 #include <asm/io.h>
19
20
21
22 static int major;
23
24 static struct class *led_class;
25 static struct class_device *led_class_dev;
26
27 static unsigned long *gpioctl;
28 static unsigned long *gpiodat;
29
30 static int led_pin;
31
32
33 static int led_open(struct inode *inode, struct file *file)
34 {
35 /* 初始化LED硬件 ―― GPF4、GPF5、GPF6设置为输出 */
36 *gpioctl &= ~(0x3<<(led_pin*2));
37 *gpioctl |= (0x1<<(led_pin*2));
38 return 0;
39 }
40
41 static ssize_t led_write(struct file *file, const char __user *buf,
42
size_t count, loff_t *ppos)
43 {
44 int val;
45
46 copy_from_user(&val, buf, count);
47 if (1 == val)
48 {
49 *gpiodat &= ~(1<<led_pin);
50 }
51 else {
52 *gpiodat |= 1<<led_pin;
53 }
54 return 0;
55 }
56
57 static struct file_operations led_fops = {
58 .owner = THIS_MODULE,
59 .open = led_open,
60 .write = led_write,
61 };
62
63 static int led_probe(struct platform_device *pdev)
64 {
65 struct resource *res;
66
67 printk("led_probe, found led\n");
68
69 /* 根据platform_device(led_dev)里面的资源,进行ioremap */
70 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
71 gpioctl = ioremap(res->start, res->end - res->start + 1);
72 gpiodat = gpioctl + 1;
73
74 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
75 led_pin = res->start;
76
77 /* 注册字符设备驱动 */
78 major = register_chrdev(0, "myled", &led_fops);
79
80 led_class = class_create(THIS_MODULE, "myled");
81
82 /* 创建有主设备号和次设备号的设备节点系统信息 */
83 led_class_dev = class_device_create(led_class, NULL, MKDEV(major, 0), NULL, "led");
84
85 return 0;
86 }
87
88 static int led_remove(struct platform_device *pdev)
89 {
90 printk("led_remove\n");
91 /* 根据platform_device(led_dev)里面的资源,进行iounmap */
92
93 /* 卸载字符设备驱动 */
94 unregister_chrdev(major, "myled");
95 class_device_unregister(led_class_dev);
96 class_destroy(led_class);
97
98 /* 释放虚拟地址映射 */
99 iounmap(gpioctl);
100
101 return 0;
102 }
103
104 struct platform_driver led_drv = {
105 .probe = led_probe,
106 .remove = led_remove,
107 .driver = {
108 .name = "myled",//与dev保持一致
109 }
110 };
111
112 static int led_drv_init(void)
113 {
114 platform_driver_register(&led_drv);
115 return 0;
116 }
117
118 static void led_drv_exit(void)
119 {
120 platform_driver_unregister(&led_drv);
121 return;
122 }
123
124 module_init(led_drv_init);
125 module_exit(led_drv_exit);
126 MODULE_LICENSE("GPL");
app.c
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5
6 int main (int argc, char **argv)
7 {
8 int fd;
9 int val = 1;
10 char *filename;
11
12 printf("test app!\n");
13 if (argc != 3)
14 {
15 printf("Usage: led<on|off>\n");
16 return -1;
17 }
18
19 filename = argv[1];
20
21 printf("filename: %s\n", filename);
22
23 fd = open(filename, O_RDWR);
24 if(fd < 0)
25 {
26 printf("open failed!---%d---\n", fd);
27 return -1;
28 }
29
30 //if (argv[2] == "on")
31 if (!strcmp("on", argv[2]))
32 {
33 val = 1;
34 write(fd, &val, 4);
35 }
36 //else if(argv[2] == "off")
37 else if(!strcmp("off", argv[2]))
38 {
39 val = 0;
40 write(fd, &val, 4);
41 }
42 return 0;
43 }
Makefile
1 KERN_DIR = /work/system/linux-2.6.22.6
2
3 all:
4 make -C $(KERN_DIR) M=`pwd` modules
5
6 clean:
7 make -C $(KERN_DIR) M=`pwd` modules clean
8 rm -rf modules.order
9
10 obj-m += led_drv.o
11 obj-m +=
led_dev.o