单片机
返回首页

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

2024-09-20 来源:cnblogs

之前的一篇博客简单介绍了平台设备驱动模型(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);

 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 failuren');

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 miscdevn');

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 failuren');

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');


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

最新器件
精选电路图
  • CCD图像传感器在微光电视系统中的应用

  • 光控音效发生器电路

  • 非常简单的150W功放电路图

  • 分享一个电网倾角计电路

  • 电谐波图形均衡器示意图

  • 一种构建12V和230V双直流电源的简单方法

    相关电子头条文章