在一般情况下,2.6内核中已经初始化并挂载了一条platform总线在sysfs文件系统中。那么我们编写platform模型驱动时,需要完成两个工作:1:实现platform驱动 2:实现platform设备,然而在实现这两个工作的过程中还需要实现其他的很多小工作,在后面介绍。platform模型驱动的实现过程核心架构就很简单,如下所示。
简单介绍下platform驱动的工作过程:设备(或驱动)注册的时候,都会引发总线调用自己的match函数来寻找目前platform总线是否挂载有与该设备(或驱动)名字匹配的驱动(或设备)( http://blog.csdn.net/xy010902100449/article/details/45700523 前面我们讲了platform设备驱动的match自动匹配过程), 如果存在则将双方绑定;如果先注册设备,驱动还没有注册,那么设备在被注册到总线上时,将不会匹配到与自己同名的驱动,然后在驱动注册到总线上时,因为设备已注册,那么总线会立即匹配与绑定这时的同名的设备与驱动,再调用驱动中的probe函数等;如果是驱动先注册,同设备驱动一样先会匹配失败,匹配失败将导致它的probe函数暂不调用,而是要等到设备注册成功并与自己匹配绑定后才会调用。
/** * @Author: ZP1015 * * @Copyright:SCUT. * * @Function:Platform device driver for led * * @Creat:2015-06-10 * * @Modify:2015-12-22 **/ #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/device.h> #include <linux/cdev.h> #include <linux/platform_device.h> static void Myled_platform_device_release(struct device * dev) { return ; } static struct resource Myled_resource[] = { [0] = { .start = 0xe0200280, .end = 0xe0200280 + 12, .flags = IORESOURCE_MEM }, }; static struct platform_device Myledplatform_device_led = { .name = "Myled_platform_device_driver", .id = -1, .num_resources = ARRAY_SIZE(Myled_resource), .resource = Myled_resource, .dev = { .release = Myled_platform_device_release, }, }; static int __init Myled_platform_device_init(void) { printk("Myled_platform_device add ok!\n"); return platform_device_register(&Myledplatform_device_led); } static void __exit Myled_platform_device_exit(void) { printk("Myled_platform_device remove ok!\n"); platform_device_unregister(&Myledplatform_device_led); } MODULE_AUTHOR("ZP1015"); MODULE_LICENSE("GPL"); module_init(Myled_platform_device_init); module_exit(Myled_platform_device_exit); //////////////////////////////
/** * @Author: ZP1015 * * @Copyright:SCUT. * * @Function:Platform driver for led * * @Creat:2015-06-10 * * @Modify:2015-12-22 **/ #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/device.h> #include <linux/cdev.h> #include <linux/platform_device.h> #define GLOBAL_LED_MAJOR 250 static unsigned int global_led_major = GLOBAL_LED_MAJOR; static struct cdev *led_cdev = NULL; static struct class *led_class = NULL; volatile unsigned long *gpbcon = NULL; volatile unsigned long *gpbdat = NULL; volatile unsigned long *gpbup = NULL; static int Myled_open(struct inode * inode,struct file * file) { return 0; } static ssize_t Myled_read(struct file * file,char __user * in,size_t size,loff_t * off) { return 0; } static ssize_t Myled_write(struct file * file,const char __user * in,size_t size,loff_t * off) { return 0; } static void myled_configure(void) { *gpbcon &= ~((0x3<<(0*4)) | (0x3<<(1*4)) | (0x3<<(2*4)) | (0x3<<(3*4))); *gpbcon |= ((0x1<<(0*4)) | (0x1<<(1*4)) | (0x1<<(2*4)) | (0x1<<(3*4))); } static void myled_on(void) { *gpbdat &= ~((1<<0) | (1<<1) | (1<<2) | (1<<3));// 点灯 } static void myled_off(void) { *gpbdat |= (1 << 0)|(1 << 1)|(1 << 2)|(1 << 3);// 灭灯 } struct file_operations led_fops = { .owner = THIS_MODULE, .open = Myled_open, .read = Myled_read, .write = Myled_write, }; static int __devinit Myled_probe(struct platform_device *pdev) { int ret; int err; dev_t devno; struct resource *pIORESOURCE_MEM = NULL; printk(KERN_ALERT"Myled_probe!\n"); /*1.初始化cdev*/ led_cdev = cdev_alloc();//分配cdev cdev_init(led_cdev,&led_fops);//初始化cdev led_cdev->owner = THIS_MODULE; /*2.获取字符设备号*/ devno = MKDEV(global_led_major,0);//将主设备号和次设备号转换成dev_t类型 if (devno) { ret = register_chrdev_region(devno,1,"Myled_platfor_driver");//注册一系列设备号 } else { ret = alloc_chrdev_region(&devno,0,1,"Myled_platfor_driver");//未知主设备号注册设备号 global_led_major = MAJOR(devno); } if (ret < 0) { return ret; } /*3.注册字符设备*/ err = cdev_add(led_cdev,devno,1);//注册cdev if (err) { printk(KERN_NOTICE"Error %d adding led_cdev",err); return -1; } else { printk(KERN_NOTICE"Myled_platfor_driver init ok!\n"); } /*4.注册platform机制,在/sys/class/下创建类目录*/ led_class = class_create(THIS_MODULE,"Myled_platfor_driver");//自动创建设备节点 device_create(led_class,NULL,devno,NULL,"platfor_driver_for_Myled"); pIORESOURCE_MEM = platform_get_resource(pdev,IORESOURCE_MEM,0); gpbcon = ioremap(pIORESOURCE_MEM->start,pIORESOURCE_MEM->end - pIORESOURCE_MEM->start); gpbdat = gpbcon + 1; gpbup = gpbcon + 2; myled_configure(); myled_on(); printk(KERN_NOTICE"platfor_driver_for_Myled init ok!\n"); return 0; } static int __devexit Myled_remove(struct platform_device *pdev) { dev_t devno; devno = MKDEV(global_led_major,0);//将主设备号和次设备号转换成dev_t类型 printk("Myled_remove!\n"); myled_off(); cdev_del(led_cdev); iounmap(gpbcon); unregister_chrdev_region(devno,1); device_destroy(led_class,devno); class_destroy(led_class); return 0; } static struct platform_driver Myled_platform_driver = { .probe = Myled_probe, .remove = __devexit_p(Myled_remove), .driver = { .name = "Myled_platform_device_driver", .owner = THIS_MODULE, } }; static int __init Myled_platform_driver_init(void) { printk("platform_driver_for_Myled init\n"); return platform_driver_register(&Myled_platform_driver); } static void __exit Myled_platform_driver_exit(void) { printk("platform_driver_for_Myled exit\n"); platform_driver_unregister(&Myled_platform_driver); } MODULE_AUTHOR("ZP1015"); MODULE_LICENSE("GPL"); module_param(global_led_major,int,S_IRUGO); module_init(Myled_platform_driver_init); module_exit(Myled_platform_driver_exit); ///////////////////////
insmod 一下灯全亮,rmmod 一下等全灭。
/** * @Author: ZP1015 * * @Copyright:SCUT. * * @Function:Platform driver for led * * @Creat:2015-06-10 * * @Modify:2015-12-22 **/ #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/device.h> #include <linux/cdev.h> #include <linux/platform_device.h> #define GLOBAL_LED_MAJOR 250 #define DEVICE_NAME "Myled_platfor_driver" static unsigned int global_led_major = GLOBAL_LED_MAJOR; static struct cdev *led_cdev = NULL; static struct class *led_class = NULL; volatile unsigned long *gpbcon = NULL; volatile unsigned long *gpbdat = NULL; volatile unsigned long *gpbup = NULL; static void myled_configure(void) { *gpbcon &= ~((0x3<<(0*4)) | (0x3<<(1*4)) | (0x3<<(2*4)) | (0x3<<(3*4))); *gpbcon |= ((0x1<<(0*4)) | (0x1<<(1*4)) | (0x1<<(2*4)) | (0x1<<(3*4))); } static void myled_on(void) { *gpbdat &= ~((1<<0) | (1<<1) | (1<<2) | (1<<3));// 点灯 } static void myled_off(void) { *gpbdat |= (1 << 0)|(1 << 1)|(1 << 2)|(1 << 3);// 灭灯 } static int Myled_open(struct inode * inode,struct file * file) { myled_configure(); return 0; } static ssize_t Myled_read(struct file * file,char __user * in,size_t size,loff_t * off) { return 0; } static ssize_t Myled_write(struct file * file,const char __user * in,size_t size,loff_t * off) { char val[1]; if(copy_from_user(val, in, size)) {//用户到内核空间 return -EFAULT; } printk("[%s,%d]val:%c %d\n",__func__,__LINE__,val[0],val[0]); switch(val[0]) { case '0': myled_on(); break; case '1': myled_off(); break; } return 0; } struct file_operations led_fops = { .owner = THIS_MODULE, .open = Myled_open, .read = Myled_read, .write = Myled_write, }; static int __devinit Myled_probe(struct platform_device *pdev) { int ret; int err; dev_t devno; struct resource *pIORESOURCE_MEM = NULL; printk(KERN_ALERT"Myled_probe!\n"); /*1.初始化cdev*/ led_cdev = cdev_alloc();//分配cdev cdev_init(led_cdev,&led_fops);//初始化cdev led_cdev->owner = THIS_MODULE; /*2.获取字符设备号*/ devno = MKDEV(global_led_major,0);//将主设备号和次设备号转换成dev_t类型 if (devno) { ret = register_chrdev_region(devno,1,DEVICE_NAME);//注册一系列设备号 } else { ret = alloc_chrdev_region(&devno,0,1,DEVICE_NAME);//未知主设备号注册设备号 global_led_major = MAJOR(devno); } if (ret < 0) { return ret; } /*3.注册字符设备*/ err = cdev_add(led_cdev,devno,1);//注册cdev if (err) { printk(KERN_NOTICE"Error %d adding led_cdev",err); return -1; } else { printk(KERN_NOTICE"Myled_platfor_driver init ok!\n"); } /*4.自动创建设备节点,在/sys/class/下创建类目录*/ led_class = class_create(THIS_MODULE,"myled_class");//自动创建设备节点 device_create(led_class,NULL,devno,NULL,"myled"); pIORESOURCE_MEM = platform_get_resource(pdev,IORESOURCE_MEM,0); gpbcon = ioremap(pIORESOURCE_MEM->start,pIORESOURCE_MEM->end - pIORESOURCE_MEM->start); gpbdat = gpbcon + 1; gpbup = gpbcon + 2; printk(KERN_NOTICE"Myled_platfor_driver init ok!\n"); return 0; } static int __devexit Myled_remove(struct platform_device *pdev) { dev_t devno; devno = MKDEV(global_led_major,0);//将主设备号和次设备号转换成dev_t类型 printk("Myled_remove!\n"); myled_off(); cdev_del(led_cdev); iounmap(gpbcon); unregister_chrdev_region(devno,1); device_destroy(led_class,devno); class_destroy(led_class); return 0; } static struct platform_driver Myled_platform_driver = { .probe = Myled_probe, .remove = __devexit_p(Myled_remove), .driver = { .name = "Myled_platform_device_driver", .owner = THIS_MODULE, } }; static int __init Myled_platform_driver_init(void) { printk("platform_driver_for_Myled init\n"); return platform_driver_register(&Myled_platform_driver); } static void __exit Myled_platform_driver_exit(void) { printk("platform_driver_for_Myled exit\n"); platform_driver_unregister(&Myled_platform_driver); } MODULE_AUTHOR("ZP1015"); MODULE_LICENSE("GPL"); module_param(global_led_major,int,S_IRUGO); module_init(Myled_platform_driver_init); module_exit(Myled_platform_driver_exit); ///////////////////////测试程序:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> // open() close() #include <unistd.h> // read() write() int main(void) { int fd; fd = open("/dev/myled", O_RDWR|O_NDELAY); if (fd < 0) { printf("open device /lib/module/2.6.32.2/myled error!\n"); } else { while(1) { printf("led is on!\n"); write(fd,"1",1); sleep(1);//等待1秒再做下一步操作 printf("led is off!\n"); write(fd,"0",1); sleep(1); } close(fd); } return 0; }