之前的一篇博客简单介绍了平台设备驱动模型(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);
上一篇:Linux设备驱动开发 - LCD设备驱动分析
下一篇:Linux混杂设备驱动 - 按键设备驱动
推荐阅读最新更新时间:2024-11-05 06:42
设计资源 培训 开发板 精华推荐
- 螺线管驱动电路 —— TB67S158FTG
- 使用 NXP Semiconductors 的 MCIMX6S 的参考设计
- LT6656AIS6-4.096、4.096V 低功率精密高压电源监视器的典型应用
- LT3091IR 12V 至 ±3.3V 低噪声电源的典型应用
- STEVAL-ILL065V1,基于 LED5000 3A LED 驱动器的 BB+ 拓扑评估板
- 使用 Analog Devices 的 LTC1479IG 的参考设计
- ADA4891-2ARM-EBZ,采用 8 引脚 SOIC 封装的双通道高速运算放大器评估板
- 32W、32V 交流转直流单输出打印机电源
- LM2595ATPBCKGEVB:降压开关稳压器评估板
- LT3990IMSE-5 5V 降压转换器的典型应用