1、概述
在一般情况下,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总线是否挂载有与该设备(或驱动)名字匹配的驱动(或设备)( http://blog.csdn.net/xy010902100449/article/details/45700523 前面我们讲了platform设备驱动的match自动匹配过程), 如果存在则将双方绑定;如果先注册设备,驱动还没有注册,那么设备在被注册到总线上时,将不会匹配到与自己同名的驱动,然后在驱动注册到总线上时,因为设备已注册,那么总线会立即匹配与绑定这时的同名的设备与驱动,再调用驱动中的probe函数等;如果是驱动先注册,同设备驱动一样先会匹配失败,匹配失败将导致它的probe函数暂不调用,而是要等到设备注册成功并与自己匹配绑定后才会调用,device注册和driver注册顺序没关系,随便哪个先注册。
2、代码
- /*
- * Author: ZP1015
- *
- * Copyright 2015 SCUT.
- *
- * platform device for led
- */
- #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 2015 SCUT.
- *
- * platform driver for led
- */
- #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,const 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;
- devno = MKDEV(global_led_major,0);
- printk(KERN_ALERT"Myled_probe!\n");
- 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;
- }
- led_cdev = cdev_alloc();
- cdev_init(led_cdev,&led_fops);
- led_cdev->owner = THIS_MODULE;
- err = cdev_add(led_cdev,devno,1);
- led_class = class_create(THIS_MODULE,"Myled_platfor_driver");
- device_create(led_class,NULL,MKDEV(global_led_major,0),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();
- if (err) {
- printk(KERN_NOTICE"Error %d adding led_cdev",err);
- return -1;
- } else {
- printk(KERN_NOTICE"platform_driver_for_Myled init ok!\n");
- return 0;
- }
- }
- static int __devexit Myled_remove(struct platform_device *pdev)
- {
- printk("Myled_remove!\n");
- cdev_del(led_cdev);
- iounmap(gpbcon);
- unregister_chrdev_region(MKDEV(global_led_major,0),1);
- device_destroy(led_class, MKDEV(global_led_major,0));
- class_destroy(led_class);
- myled_off();
- 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);
3、 实现结果
先注册设备,然后注册设备驱动insmod 一下灯全亮,rmmod 一下等全灭。