之前的一篇博客簡單介紹了平台設備驅動模型(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");