之前的一篇博客简单介绍了平台设备驱动模型(http://www.cnblogs.com/ape-ming/p/5107641.html),现在就根据那篇博客所列出来的模板把上一篇博客(http://www.cnblogs.com/ape-ming/p/5110996.html)的例程改成平台设备驱动模型。
一、平台设备
根据模板首先要写一个平台设备加载函数:
1 /*
2 * 函数名 : button_device_init
3 * 函数功能: 设备加载
4 */
5
6 static int __init button_device_init(void)
7 {
8 int ret = 0;
9
10 /* 注册平台设备 */
11 platform_device_register(&button_platform_device);
12 return ret;
13 }
在这个函数里面调用platform_device_register()对设备进行注册。这个时候就需要给定一个平台设备结构体button_platform_device:
1 static struct platform_device button_platform_device =
2 {
3 .name = 'button_dev',
4 .id = 0,
5 .num_resources = ARRAY_SIZE(button_resource),
6 .resource = button_resource,
7 };
根据模型在这个结构体里面需指定了设备资源button_resource:
1 static struct resource button_resource[] =
2 {
3 [0] =
4 {
5 .start = IRQ_EINT(0),
6 .end = IRQ_EINT(3),
7 .flags = IORESOURCE_IRQ,
8 },
9 [1] =
10 {
11 .start = (resource_size_t)S3C64XX_GPNDAT,
12 .end = (resource_size_t)S3C64XX_GPNDAT,
13 .flags = IORESOURCE_MEM,
14 },
15 };
数组第一个元素指定了设备的中断号为IRQ_EINT(0)到IRQ_EINT(3),第二个元素指定了设备的IO资源。
二、平台驱动
平台驱动也要先写一个平台驱动加载函数:
1 /*
2 * 函数名 : button_driver_init
3 * 函数功能: 驱动加载
4 */
5
6 static int __init button_driver_init(void)
7 {
8 int ret = 0;
9 ret = platform_driver_register(&button_platform_driver);
10 return ret;
11 }
在这里面完成了平台驱动的注册,接下来就要有一个平台驱动的结构体button_platform_driver:
1 static struct platform_driver button_platform_driver =
2 {
3 .probe = button_platform_probe,
4 .remove = button_platform_remove,
5 .driver =
6 {
7 .owner = THIS_MODULE,
8 .name = 'button_dev',
9 },
10 };
probe成员所指定的函数就是平台设备与驱动配置之后要执行的第一个函数,匹配的条件就是driver里面的name成员是不是和上面平台设备结构体里面的name成员一致。
1 /*
2 * 函数名 : button_platform_probe
3 * 函数功能: 匹配驱动与设备
4 */
5
6 static int button_platform_probe(struct platform_device *button_device)
7 {
8 int ret = 0;
9 int i = 0;
10 int num = 0;
11 struct resource* irq_resource;
12
13 /* 注册混杂设备驱动 */
14 ret = misc_register(&misc);
15 if(ret)
16 {
17 printk('can't register miscdevn');
18 return ret;
19 }
20
21 /* 填充数组 */
22 irq_resource = platform_get_resource(button_device,IORESOURCE_IRQ,0);
23 for(num = 0,i = irq_resource->start;i <= irq_resource->end;i++,num++)
24 {
25 button_irq[num].irq = i;
26 }
27 mem_resource = platform_get_resource(button_device,IORESOURCE_MEM,0);
28
29 /* 申请外部中断 */
30 for(i = 0;i < sizeof(button_irq)/sizeof(button_irq[0]);i++)
31 {
32 ret = request_irq(button_irq[i].irq,button_interrupt,IRQF_TRIGGER_FALLING,button_irq[i].name,(void*)&button_irq[i]);
33 if(ret != 0)
34 {
35 printk('request_irq failuren');
36 }
37 }
38
39 /* 初始化工作队列 */
40 INIT_WORK(&button_work,do_buttons);
41
42 /* 初始化内核定时器 */
43 init_timer(&button_time);
44 button_time.expires = jiffies + HZ/10; //100ms
45 button_time.function = button_do_time;
46 add_timer(&button_time);
47
48 return ret;
49 }
在button_platform_probe()函数中完成混杂设备驱动的注册、用platform_get_resource()获取设备的资源、申请外部中断、初始化工作队列、初始化内核定时器。其实就是把混杂设备驱动模型里面的设备注册函数和open函数所做的工作全部放到button_platform_probe()函数里面完成。之后的操作就跟混杂设备模型编写的按键驱动例程基本一样了。
这里总结一下:平台设备驱动只是一个框架,其归根到底还是采用混杂设备驱动模型(或字符设备等)的方式进行驱动程序的编写。但是采用平台设备驱动的方式使得板级代码和驱动代码分离开来,在同一类型的驱动中只需要通过相应的函数获取设备资源和数据而不必要去修改驱动代码。
完整代码:
1 /*
2 * 文件名 : button_device.c
3 * 功能描述: 通过外部中断实现按键驱动程序,平台设备驱动方式
4 * 驱动模型: platform
5 * 设备节点: /dev/buttons6410
6 * MCU : S3C6410
7 * 端口连接: KEY0-GPN0 KEY1-GPN1 KEY2-GPN2 KEY3-GPN3
8 */
9
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17
18 #include
19 #include
20 #include
21 #include
22 #include
23
24
25
26 static struct resource button_resource[] =
27 {
28 [0] =
29 {
30 .start = IRQ_EINT(0),
31 .end = IRQ_EINT(3),
32 .flags = IORESOURCE_IRQ,
33 },
34 [1] =
35 {
36 .start = (resource_size_t)S3C64XX_GPNDAT,
37 .end = (resource_size_t)S3C64XX_GPNDAT,
38 .flags = IORESOURCE_MEM,
39 },
40 };
41
42 static struct platform_device button_platform_device =
43 {
44 .name = 'button_dev',
45 .id = 0,
46 .num_resources = ARRAY_SIZE(button_resource),
47 .resource = button_resource,
48 };
49
50 /*
51 * 函数名 : button_device_init
52 * 函数功能: 设备加载
53 */
54
55 static int __init button_device_init(void)
56 {
57 int ret = 0;
58
59 /* 注册平台设备 */
60 platform_device_register(&button_platform_device);
61 return ret;
62 }
63
64 /*
65 * 函数名 : button_device_exit
66 * 函数功能: 设备卸载
67 */
68
69 static void __exit button_device_exit(void)
70 {
71 /* 注销平台设备*/
72 platform_device_unregister(&button_platform_device);
73 }
74
75 module_init(button_device_init);
76 module_exit(button_device_exit);
77 MODULE_LICENSE('GPL');
1 /*
2 * 文件名 : button_driver.c
3 * 功能描述: 通过外部中断实现按键驱动程序,平台设备驱动方式
4 * 驱动模型: platform
5 * 设备节点: /dev/buttons6410
6 * MCU : S3C6410
7 * 端口连接: KEY0-GPN0 KEY1-GPN1 KEY2-GPN2 KEY3-GPN3
8 */
9
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 #include
18 #include
19 #include
20 #include
21 #include
22 #include
23 #include
24 #include
25
26 #include
27 #include
28 #include
29
30 #include
31 #include
32 #include
33
34
35 volatile int isKey_Pressed = 0; // 按键按下标志
36 struct work_struct button_work; //定义工作队列
37 struct timer_list button_time;
38 struct resource* mem_resource;
39 struct button_irqs
40 {
41 unsigned int irq;
42 int id;
43 char* name;
44 };
45
46 static struct button_irqs button_irq[] =
47 {
48 {0,0,'KEY0'},
49 {0,1,'KEY1'},
50 {0,2,'KEY2'},
51 {0,3,'KEY3'},
52 };
53
54 /* 初始化等待队列 */
55 DECLARE_WAIT_QUEUE_HEAD(q_buttons);
56
57 static volatile int button_press[4] = {0};
58
59 /*
60 * 函数名 : do_buttons
61 * 函数功能: 工作队列处理函数,处理按键工作
62 */
63 static void do_buttons(struct work_struct *work)
64 {
65 mod_timer(&button_time,jiffies + HZ/10);