Linux平台设备驱动 - 按键设备驱动

之前的一篇博客简单介绍了平台设备驱动模型(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 miscdev\n");
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 failure\n");
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 <linux/init.h>
11 #include <linux/module.h>
12 #include <linux/fs.h>
13 #include <linux/device.h>
14 #include <linux/kernel.h>
15 #include <linux/irq.h>
16 #include <linux/platform_device.h>
17 
18 #include <mach/gpio-bank-n.h>
19 #include <mach/regs-gpio.h>
20 #include <mach/map.h>
21 #include <mach/regs-clock.h>
22 #include <plat/gpio-cfg.h>
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 <linux/module.h>
 11 #include <linux/kernel.h>
 12 #include <linux/fs.h>
 13 #include <linux/init.h>
 14 #include <linux/delay.h>
 15 #include <linux/poll.h>
 16 #include <linux/irq.h>
 17 #include <asm/irq.h>
 18 #include <asm/io.h>
 19 #include <linux/interrupt.h>
 20 #include <asm/uaccess.h>
 21 #include <mach/hardware.h>
 22 #include <linux/platform_device.h>
 23 #include <linux/cdev.h>
 24 #include <linux/miscdevice.h>
 25 
 26 #include <mach/map.h>
 27 #include <mach/regs-clock.h>
 28 #include <mach/regs-gpio.h>
 29 
 30 #include <plat/gpio-cfg.h>
 31 #include <mach/gpio-bank-n.h>
 32 #include <mach/gpio-bank-l.h>
 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);
 66 }
 67 
 68 /*
 69  *    函数名     : button_interrupt
 70  *    函数功能: 外部中断服务程序
 71  */
 72 static irqreturn_t button_interrupt(int irq, void *dev_id)
 73 {
 74     struct button_irqs *button_id = (struct button_irqs*)dev_id;
 75     switch(button_id->id)
 76     {
 77         case 0:
 78         case 1:
 79         case 2:
 80         case 3:
 81         schedule_work(&button_work);
 82         break;
 83         default: break;
 84     }
 85     return IRQ_HANDLED;
 86 }
 87 
 88 /*
 89  *    函数名     : button_do_time
 90  *    函数功能: 内核定时器服务程序
 91  */
 92 
 93 static void button_do_time(unsigned long arg)
 94 {
 95     int i = 0;
 96     unsigned short tmp = 0;
 97     tmp = readw(mem_resource->start) & 0x000F;
 98     switch(tmp)
 99     {
100         case 0x0E:
101             button_press[0] = 1;
102         break;
103         case 0x0D:
104             button_press[1] = 1;
105         break;
106         case 0x0B:
107             button_press[2] = 1;
108         break;
109         case 0x07:
110             button_press[3] = 1;
111         break;
112     }
113     for(i = 0;i < sizeof(button_press)/sizeof(button_press[0]);i++)
114     {
115         if(button_press[i] == 0)
116             continue;
117             
118         isKey_Pressed = 1;
119 
120         /* 唤醒等待队列 */
121         wake_up_interruptible(&q_buttons);
122         break;
123     }
124     
125 }
126 
127 
128 /*
129  *    函数名     : button_open
130  *    函数功能: 文件打开
131  */
132 static int button_open(struct inode *node, struct file *filp)
133 {
134     return 0;
135 }
136 
137 /*
138  *    函数名     : button_read
139  *    函数功能: 文件读
140  */
141 static ssize_t button_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
142 {
143     ssize_t ret = 0;
144     size_t size = min(count,sizeof(button_press));
145 
146     /* 等待队列唤醒 */
147     wait_event_interruptible(q_buttons,isKey_Pressed);
148     isKey_Pressed = 0;
149     
150     if(copy_to_user((void*)buffer,(const void*)&button_press,size))
151     {
152         ret = -1;
153         printk("copy to user failure\n");
154     }
155     else
156     {
157         memset((void*)&button_press,0,sizeof(button_press));
158         ret = size;
159     }
160     return ret;
161 }
162 
163 
164 static struct file_operations fops = 
165 {
166     .owner = THIS_MODULE,
167     .open = button_open,
168     .read = button_read,
169 };
170 
171 static struct miscdevice misc = 
172 {
173     .minor = MISC_DYNAMIC_MINOR,
174     .name = "buttons6410",
175     .fops = &fops,
176 };
177 
178 /*
179  *    函数名     : button_platform_probe
180  *    函数功能: 匹配驱动与设备
181  */
182 
183 static int button_platform_probe(struct platform_device *button_device)
184 {
185     int ret = 0;
186     int i = 0;
187     int num = 0;
188     struct resource* irq_resource;
189     
190     /* 注册混杂设备驱动 */
191     ret = misc_register(&misc);
192     if(ret)
193     {
194         printk("can't register miscdev\n");
195         return ret;
196     }
197 
198     /* 填充数组 */
199     irq_resource = platform_get_resource(button_device,IORESOURCE_IRQ,0);
200     for(num = 0,i = irq_resource->start;i <= irq_resource->end;i++,num++)
201     {
202         button_irq[num].irq = i;
203     }
204     mem_resource = platform_get_resource(button_device,IORESOURCE_MEM,0);
205     
206     /* 申请外部中断 */
207     for(i = 0;i < sizeof(button_irq)/sizeof(button_irq[0]);i++)
208     {
209         ret = request_irq(button_irq[i].irq,button_interrupt,IRQF_TRIGGER_FALLING,button_irq[i].name,(void*)&button_irq[i]);
210         if(ret != 0)
211         {
212             printk("request_irq failure\n");
213         }
214     }
215 
216     /* 初始化工作队列 */
217     INIT_WORK(&button_work,do_buttons);
218 
219     /* 初始化内核定时器 */
220     init_timer(&button_time);
221     button_time.expires = jiffies + HZ/10;    //100ms
222     button_time.function = button_do_time;
223     add_timer(&button_time);
224 
225     return ret;
226 }
227 
228 /*
229  *    函数名     : button_platform_remove
230  *    函数功能: 删除设备
231  */
232 
233 static int button_platform_remove(struct platform_device *button_device)
234 {
235     int ret = 0;
236     int i = 0;
237 
238     /* 释放中断 */
239     for(i = 0;i < sizeof(button_irq)/sizeof(button_irq[0]);i++)
240     {
241         free_irq(button_irq[i].irq,(void*)&button_irq[i]);
242     }
243 
244     /* 释放内核定时器 */
245     del_timer(&button_time);
246 
247     /* 卸载混杂设备驱动 */
248     misc_deregister(&misc);
249 
250     return ret;
251 }
252 
253 static struct platform_driver button_platform_driver = 
254 {
255     .probe = button_platform_probe,
256     .remove = button_platform_remove,
257     .driver = 
258     {
259         .owner = THIS_MODULE,
260         .name = "button_dev",
261     },
262 };
263 
264 /*
265  *    函数名     : button_driver_init
266  *    函数功能: 驱动加载
267  */
268 
269 static int __init button_driver_init(void)
270 {
271     int ret = 0;
272     ret = platform_driver_register(&button_platform_driver);
273     return ret;
274 }
275 
276 /*
277  *    函数名     : button_driver_exit
278  *    函数功能: 驱动卸载
279  */
280 
281 static void __exit button_driver_exit(void)
282 {
283     platform_driver_unregister(&button_platform_driver);
284 }
285 
286 module_init(button_driver_init);
287 module_exit(button_driver_exit);
288 MODULE_LICENSE("GPL");

 

你可能感兴趣的:(Linux平台设备驱动 - 按键设备驱动)