platform模型驱动编程,需要实现platform_device(设备)与platform_driver(驱动)在platform(虚拟总线)上的注册、匹配,相互绑定,然后再做为一个普通的字符设备进行相应的应用,总之如果编写的是基于字符设备的platform驱动,在遵循并实现platform总线上驱动与设备的特定接口的情况下,最核心的还是字符设备的核心结构:cdev、 file_operations(包含它的操作函数接口)、dev_t(设备号)、设备文件(/dev)等,因为用platform机制编写的字符驱动,它的本质是字符驱动。 在一般情况下,2.6内核中已经初始化并挂载了一条platform总线在sysfs文件系统中。那么我们编写platform模型驱动时,需要完成两个工作: 1:实现platform驱动 2:实现platform设备 然而在实现这两个工作的过程中还需要实现其他的很多小工作,在后面介绍。platform模型驱动的实现过程核心架构就很简单,如下所示,注意先后顺序。 platform驱动模型三个对象:platform总线、platform设备、platform驱动。 platform总线对应的内核结构:struct bus_type-->它包含的最关键的函数:match() platform设备对应的内核结构:struct platform_device-->注册:platform_device_register(unregiste) platform驱动对应的内核结构:struct platform_driver-->注册:platform_driver_register(unregiste) 简单介绍下platform驱动的工作过程:设备(或驱动)注册的时候,都会引发总线调用自己的match函数来寻找目前platform总线是否挂载有与该设备(或驱动)名字匹配的驱动(或设备),如果存在则将双方绑定;如果先注册设备,驱动还没有注册,那么设备在被注册到总线上时,将不会匹配到与自己同名的驱动,然后在驱动注册到总线上时,因为设备已注册,那么总线会立即匹配与绑定这时同名的设备与驱动,再调用驱动中的probe函数等;如果是驱动先注册,同设备驱动一样先会匹配失败,匹配失败将导致它的probe函数暂不调用,而是要等到设备注册成功并与自己匹配绑定后才会调用。接下来讲解如下实现platform驱动与设备的详细过程。1:定义驱动实例 gitLedDriver static struct platform_driver gitLedDriver = { .probe = PlatLedProbe, .remove = __devexit_p(PlatLedRemove), .driver = { .name= LED_DEV_DRIVER_NAME, .owner= THIS_MODULE, }};2:实现驱动实例成员函数:probe PlatLedProbe probe函数中要实现的功能包括:注册LED设备为混杂设备,绑定file_operations。3:platform模型驱动写字符设备仍要实现字符设备的核心结构file_operations,第一步的cdev要用到 将file_operations结构体中open、write、read等要用到的接口函数实现。4:实现驱动实例成员函数:remove mini2440_led_remove remove函数中要实现的功能与probe中的相反,进行相关设备与资源的注销。probe与remove函数其实对应前面用非platform机制写驱动的时候所实现的模块加载与卸载函数,而在platform机制中,模块的加载与卸载函数调用的是设备或驱动的注册函数。5:实现驱动的加载与卸载函数: 在加载函数中,调用驱动的注册函数,platform_driver_register(...); 在卸载函数中,调用驱动的卸载函数,platform_driver_unregister(...);实现platform设备的详细过程platform设备的实现有两种方法: 1:最笨的一种:直接在内核源代码里面添加相关的资源代码,\arch\arm\mach-s3c2440\mach-mini2440.c 2:编写设备模块,用insmod命令加载该设备模块到platform总线上。 当然用第二种了,不过这两种方法的原理与要写的代码都是一样的,但是第一种不用自己注册,因为系统初始化的时候会将mach-mini2440.c中struct platform_device *mini2440_devices[] __initdata 设备数组中包含的所有设备注册到总线上。而第二种手动注册。1:定义设备与资源实例static struct resource gitLedResource[] = { [0] = { .start= 0x56000010, .end= 0x56000010 + 12, .flags= IORESOURCE_MEM },};static struct platform_device gitLedDev = { .name= LED_DEV_DRIVER_NAME, .id= -1, .num_resources= ARRAY_SIZE(gitLedResource), .resource= gitLedResource, .dev= { .release= LedDevRelease, },};2:实现设备的成员函数release static void mini2440_led_platform_device_release(struct device * dev){ return ;}3:实现设备的加载与卸载函数: 在加载函数中,调用设备的注册函数,platform_device_register(...); 在卸载函数中,调用设备的卸载函数,platform_device_unregister(...); 多个设备同时注册:platform_add_devices(struct platform_devices **devs, int num); struct platform_devices **devs设备数组,num包含的设备数目 驱动与设备是否成功注册,我们都可以在/sys/bus/platform/devices(drivers)/下查看 本实验实现了通过write或者Ioctl来控制LED,实现了可以单独开启或者关闭其中某个灯,或者一起开启或者关闭。下面是代码清单:#include#include#include#include#include#include#include#include#include#include "plat-led.h"static volatile unsigned long *gpfcon = NULL;static volatile unsigned long *gpfdat = NULL; static volatile unsigned long *gpfup = NULL;static void LedDevRelease(struct device * dev){ /* do nothing */}static struct resource gitLedResource[] = { [0] = { .start= 0x56000010, .end= 0x56000010 + 12, .flags= IORESOURCE_MEM },};static struct platform_device gitLedDev = { .name= LED_DEV_DRIVER_NAME, .id= -1, .num_resources= ARRAY_SIZE(gitLedResource), .resource= gitLedResource, .dev= { .release= LedDevRelease, },};static int LedOpen(struct inode * inode, struct file * file){ DPRINTK("led open[kernel_space]\n"); *gpfcon &= ~((0x3 *gpfcon |= ((0x1 return 0;}static ssize_t LedRead(struct file *file, const char __user *in, size_t size, loff_t *off){ DPRINTK("led read[kernel_space]\n"); return 0;}static ssize_t LedWrite(struct file *file, const char __user *in, size_t size, loff_t *off){ int ret = 0; uint8_t iaBuf[2] = {0}, i = 0; DPRINTK("led write[kernel_space]\n"); ret = copy_from_user(iaBuf, in, size); for(i = 0; i { DPRINTK("iaBuf[%d] = %d\n", i, iaBuf[i]); } if(iaBuf[0] == 1) { //*gpfdat &= ~((0x1 *gpfdat &= ~(0x1 } else { //*gpfdat |= (0x1 *gpfdat |= 0x1 } return 0;}int LedIoctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int err = 0, ret = 0, iLedNum = 0; //检测命令的有效性 if(_IOC_TYPE(cmd) != LED_IOC_MAGIC) { return -EINVAL; } if(_IOC_NR(cmd) > LED_IOC_MAXNR) { return -EINVAL; } //根据命令类型,检测参数空间是否可以访问 if(_IOC_DIR(cmd) & _IOC_READ) { err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); } else if(_IOC_DIR(cmd) & _IOC_WRITE) { err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); } if(err != 0) { return -EFAULT; } DPRINTK("led ioctl[kernel_space]\n"); //根据命令,执行相应的操作 switch(cmd) { case LED_IOC_ON: { ret = __get_user(iLedNum, (int *)arg); *gpfdat &= ~(0x1 } break; case LED_IOC_OFF: { ret = __get_user(iLedNum, (int *)arg); *gpfdat |= 0x1 } break; case LED_IOC_ALL_ON: { *gpfdat &= ~((0x1 } break; case LED_IOC_ALL_OFF: { *gpfdat |= (0x1 } break; default: { return -EINVAL; } break; }/* end switch(cmd) */ return ret;}struct file_operations gitLedFops = { .owner= THIS_MODULE, .open= LedOpen, .read= LedRead, .write= LedWrite, .ioctl= LedIoctl,};static struct miscdevice gitLedMiscDev = { .minor= MISC_DYNAMIC_MINOR, .name= DEVICE_NAME, .fops= &gitLedFops,};static int __devinit PlatLedProbe(struct platform_device *pdev){ int ret = 0; struct resource *pIORESOURCE_MEM; pIORESOURCE_MEM = platform_get_resource(pdev, IORESOURCE_MEM, 0); gpfcon = ioremap(pIORESOURCE_MEM->start, pIORESOURCE_MEM->end - pIORESOURCE_MEM->start); DPRINTK("start is %x\n", pIORESOURCE_MEM->start); gpfdat = gpfcon + 1; gpfup = gpfcon + 2; ret = misc_register(&gitLedMiscDev); return ret;}static int __devexit PlatLedRemove(struct platform_device *pdev){ DPRINTK("mini2440_led_remove!\n"); iounmap(gpfcon); misc_deregister(&gitLedMiscDev); return 0;}static struct platform_driver gitLedDriver = { .probe = PlatLedProbe, .remove = __devexit_p(PlatLedRemove), .driver = { .name= LED_DEV_DRIVER_NAME, .owner= THIS_MODULE, }};static int __init PlatLedInit(void){ DPRINTK("mini2440_led_platform_device add ok!\n"); platform_device_register(&gitLedDev); DPRINTK("platform_driver_for_mini2440_led init\n"); platform_driver_register(&gitLedDriver);}static void __exit PlatLedExit(void){ DPRINTK("platform_driver_for_mini2440_led exit\n"); platform_driver_unregister(&gitLedDriver); DPRINTK("mini2440_led_platform_device remove ok!\n"); platform_device_unregister(&gitLedDev);}MODULE_AUTHOR("apple_guet");MODULE_LICENSE("GPL");module_init(PlatLedInit);module_exit(PlatLedExit);头文件为:#ifndef _PLAT_LED_H_#define _PLAT_LED_H_#define LED_DEV_DRIVER_NAME"plat-led"#define DEVICE_NAME"platform-leds"//定义幻数#define LED_IOC_MAGIC'k'//定义命令#define LED_IOC_MAXNR4#define LED_IOC_ON_IOW(LED_IOC_MAGIC, 0, int)#define LED_IOC_OFF_IOW(LED_IOC_MAGIC, 1, int)#define LED_IOC_ALL_ON_IOW(LED_IOC_MAGIC, 2, int)#define LED_IOC_ALL_OFF_IOW(LED_IOC_MAGIC, 3, int)#undef DEBUG#define DEBUG#ifdef DEBUG#define DPRINTK printk#else#define DPRINTK /\/DEBUGP#endif#endif测试文件:#include#include#include#include#include "ledApp.h"int main(int argc, char **argv){ unsigned char iaBuf[2] = {0}; int index = 0, fd = 0, iCmd = 0; //检测输入的参数合法性 if((argc != 3) || (sscanf(argv[2], "%d", &index) != 1) || (index 6)) { printf("Usage: leds_test on|off 1|2|3|4\n"); exit(1); } iaBuf[1] = (unsigned char)index - 1; if(strcmp(argv[1], "on") == 0) { iaBuf[0] = 1; iCmd = LED_IOC_ON; } else if(strcmp(argv[1], "off") == 0) { iaBuf[0] = 0; iCmd = LED_IOC_OFF; } else { printf("Usage: leds_test on|off 1|2|3|4\n"); exit(1); } if(iaBuf[1] == 4) { iCmd = LED_IOC_ALL_ON; } else if(iaBuf[1] == 5) { iCmd = LED_IOC_ALL_OFF; } fd = open("/dev/platform-leds", O_RDWR); //打开LED设备 if(fd { printf("Open Led Device Faild!\n"); exit(1); } if(ioctl(fd, iCmd, &iaBuf[1]) { printf("ioctl err!\n"); exit(1); } //write(fd, iaBuf, sizeof(iaBuf)); close(fd); //关闭LED设备 return 0;}测试头文件:#ifndef _LED_APP_H_#define _LED_APP_H_#include//定义幻数#define LED_IOC_MAGIC'k'//定义命令#define LED_IOC_MAXNR4#define LED_IOC_ON_IOW(LED_IOC_MAGIC, 0, int)#define LED_IOC_OFF_IOW(LED_IOC_MAGIC, 1, int)#define LED_IOC_ALL_ON_IOW(LED_IOC_MAGIC, 2, int)#define LED_IOC_ALL_OFF_IOW(LED_IOC_MAGIC, 3, int)#endif 11-17 01:12