总线设备驱动模型---platform篇
来源:互联网 发布:小说阅读网软件 编辑:程序博客网 时间:2024/09/21 09:28
linux从2.6起就加入了一套新的驱动管理和注册的机制platform平台总线,是一条虚拟的总线,设备用platform_device表示,驱动用platform_driver进行注册。于传统的bus/device/driver机制相比,platform由内核进行统一管理,在驱动中使用资源,提高了代码的安全性和可移植性。其过程和总线的注册过程差不多,驱动和设备匹配后,调用platform的match函数。由传统的机制,也不难总结出platform的开发流程为在struct resource结构中我们通常只关心start、end和flags这3个字段,分别表示资源的开始值、结束值和类型,flags可以用内存资源,IO资源,中断资源等。其上最后也是调用device_add的,其主要是将device加入到bus总线中,并由device_attach完成设备与驱动之间的匹配,这个过程在设备一篇中已经有详细的分析过程中,再看看驱动的注册过程。可见,它包含了设备操作的功能函数,同时包含了device_driver结构。内核提供的platform_driver结构的注册为其注册函数中比较重要的还是调用了driver_register,添加到platform总线链表,完成设备与驱动之间的匹配过程,其主要的过程在总线设备驱动模型的驱动篇已经有过分析。由上面可以看出,只需要比较dev的名字和drv的名字,如果是相同的话就匹配成功。在platform的设备驱动的编写有两种方法:如果我们要实现一个设备的添加,那么只需要加入一个struct platform_device的数组,然后只需要编写对应的platform_driver驱动程序就可以了。从这种方法可以看出,存在一个很明显的缺点,如果要改写驱动,就要重新的编译内核。drv文件:platform_drv.c
下面来看看内核时怎么注册platform总线的过程
点击(此处)折叠或打开
- int __init platform_bus_init(void)
- {
- int error;
- early_platform_cleanup();
- error = device_register(&platform_bus);//注册了platform的设备
- if (error)
- return error;
- error = bus_register(&platform_bus_type);//注册了platform总线
- if (error)
- device_unregister(&platform_bus);
- return error;
- }
点击(此处)折叠或打开
- struct device platform_bus = {
- .init_name ="platform",
- };
点击(此处)折叠或打开
- struct bus_type platform_bus_type = {
- .name ="platform",
- .dev_attrs = platform_dev_attrs,
- .match = platform_match,
- .uevent = platform_uevent,
- .pm =&platform_dev_pm_ops,
- };
1、定义一个platform_device,并注册
2、定义一个platform_driver,并注册
定义platform_device过程
点击(此处)折叠或打开
- struct platform_device *platform_device_alloc(const char*name, int id)
- {
- struct platform_object *pa;
- pa = kzalloc(sizeof(struct platform_object)+ strlen(name), GFP_KERNEL);
- if (pa){
- strcpy(pa->name, name);
- pa->pdev.name= pa->name;
- pa->pdev.id= id;
- device_initialize(&pa->pdev.dev);
- pa->pdev.dev.release= platform_device_release;
- arch_setup_pdev_archdata(&pa->pdev);
- }
- return pa ? &pa->pdev: NULL;
- }
下面首先来看看platform_device的注册过程
点击(此处)折叠或打开
- struct platform_device {
- const char * name; //设备名
- int id; //设备ID
- struct device dev;
- u32 num_resources; //设备使用的资源的数目
- struct resource * resource; //设备使用的资源
- const struct platform_device_id *id_entry;
- /* MFD cell pointer*/
- struct mfd_cell *mfd_cell;
- /* arch specific additions*/
- struct pdev_archdata archdata;
- };
点击(此处)折叠或打开
- struct resource {
- resource_size_t start;
- resource_size_t end;
- const char *name;
- unsigned long flags;
- struct resource *parent,*sibling, *child;
- };
点击(此处)折叠或打开
- int platform_device_register(struct platform_device*pdev)
- {
- device_initialize(&pdev->dev);//dev初始化
- arch_setup_pdev_archdata(pdev);
- return platform_device_add(pdev);//加入到dev链表
- }
点击(此处)折叠或打开
- int platform_device_add(struct platform_device*pdev)
- {
- int i, ret= 0;
- if (!pdev)
- return -EINVAL;
- if (!pdev->dev.parent)
- pdev->dev.parent= &platform_bus;//父设备设置为platform_bus
- pdev->dev.bus= &platform_bus_type;//设备挂载在platforrm总线上
- if (pdev->id!= -1)
- dev_set_name(&pdev->dev,"%s.%d", pdev->name, pdev->id);
- else
- dev_set_name(&pdev->dev,"%s", pdev->name);
- for (i= 0; i < pdev->num_resources; i++){ //完成资源的初始化
- struct resource *p,*r = &pdev->resource[i];
- if (r->name== NULL)
- r->name= dev_name(&pdev->dev);
- p = r->parent;
- if (!p){
- if (resource_type(r)== IORESOURCE_MEM)
- p = &iomem_resource;
- else if (resource_type(r)== IORESOURCE_IO)
- p = &ioport_resource;
- }
- if (p&& insert_resource(p, r)){
- printk(KERN_ERR
- "%s: failed to claim resource %d\n",
- dev_name(&pdev->dev), i);
- ret = -EBUSY;
- goto failed;
- }
- }
- pr_debug("Registering platform device '%s'. Parent at %s\n",
- dev_name(&pdev->dev), dev_name(pdev->dev.parent));
- ret = device_add(&pdev->dev);
- if (ret== 0)
- return ret;
- failed:
- while (--i>= 0){
- struct resource *r = &pdev->resource[i];
- unsigned long type = resource_type(r);
- if (type== IORESOURCE_MEM|| type == IORESOURCE_IO)
- release_resource(r);
- }
- return ret;
- }
点击(此处)折叠或打开
- struct platform_driver {
- int (*probe)(struct platform_device*);
- int (*remove)(struct platform_device*);
- void (*shutdown)(struct platform_device*);
- int (*suspend)(struct platform_device*, pm_message_t state);
- int (*resume)(struct platform_device*);
- struct device_driver driver;
- const struct platform_device_id *id_table;
- };
点击(此处)折叠或打开
- int platform_driver_register(struct platform_driver*drv)
- {
- drv->driver.bus= &platform_bus_type;//注册到总线上,drv与dev匹配通过platform_bus_type注册的platform_match完成
- if (drv->probe)
- drv->driver.probe= platform_drv_probe;
- if (drv->remove)
- drv->driver.remove= platform_drv_remove;
- if (drv->shutdown)
- drv->driver.shutdown= platform_drv_shutdown;
- return driver_register(&drv->driver);
- }
点击(此处)折叠或打开
- int driver_register(struct device_driver*drv)
- {
- int ret;
- struct device_driver *other;
- BUG_ON(!drv->bus->p);
- if ((drv->bus->probe&& drv->probe)||
- (drv->bus->remove&& drv->remove)||
- (drv->bus->shutdown&& drv->shutdown))
- printk(KERN_WARNING "Driver '%s' needs updating - please use "
- "bus_type methods\n", drv->name);
- other = driver_find(drv->name, drv->bus);
- if (other){
- put_driver(other);
- printk(KERN_ERR "Error: Driver '%s' is already registered, "
- "aborting...\n", drv->name);
- return -EBUSY;
- }
- ret = bus_add_driver(drv);
- if (ret)
- return ret;
- ret = driver_add_groups(drv, drv->groups);
- if (ret)
- bus_remove_driver(drv);
- return ret;
- }
下面看看看驱动和设备的匹配过程,由以前可以看出,主要是调用bus的match函数来完成匹配。
点击(此处)折叠或打开
- static int platform_match(struct device*dev, struct device_driver*drv)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct platform_driver *pdrv = to_platform_driver(drv);
- /* Attempt an OF style match first*/
- if (of_driver_match_device(dev, drv))
- return 1;
- /* Then try to match against the id table */
- if (pdrv->id_table)
- return platform_match_id(pdrv->id_table, pdev)!= NULL;
- /* fall-backto driver name match */
- return (strcmp(pdev->name, drv->name)== 0);
- }
1、在bsp版文件中实现定义,在文件中将platform_device被化为一个数组,最后通过platform_add_devices函数注册。对于2440来说位于arch\arm\mach-s3c2440\mach-smdk2440.c中定义
点击(此处)折叠或打开
- static struct platform_device *smdk2440_devices[] __initdata= {
- &s3c_device_usb,
- &s3c_device_lcd,
- &s3c_device_wdt,
- &s3c_device_i2c,
- &s3c_device_iis,
- };
2、第二种方法只需要单独编写一个内核模块加载到内核中。
例子:
device文件:platform_dev.c
点击(此处)折叠或打开
- struct platform_device *my_led_dev;
-
- static int __init platform_dev_init(void)
- {
- int ret;
-
- //分配一个 platform_device结构体
- my_led_dev = platform_device_alloc("platform_led",-1);
-
- ret = platform_device_add(my_led_dev);//将自定义的设备添加到内核设备架构中
-
- if(ret)
- platform_device_put(my_led_dev);//销毁platform设备结构
-
- return ret;
- }
-
- static void __exit platform_dev_exit(void)
- {
- platform_device_unregister(my_led_dev);//注销platform_device
- }
-
- module_init(platform_dev_init);
- module_exit(platform_dev_exit);
-
- MODULE_AUTHOR("Sola");
- MODULE_LICENSE("GPL");
点击(此处)折叠或打开
- static int s3c6410_led_open(struct inode*inode, struct file*file)
- {
- unsigned tmp;
- tmp = readl(S3C64XX_GPMCON);
- tmp = (tmp& ~(0xFFFF))|(0x1111U);
- writel(tmp, S3C64XX_GPMCON);
-
- return 0;
- }
-
-
- static int s3c6410_led_close(struct inode*inode, struct file*file)
- {
- return 0;
- }
-
-
- static int s3c6410_led_read(struct file*filp, char __user*buff, size_t count, loff_t*offp)
- {
- printk("#########read######\n");
- return count;
- }
- static int s3c6410_led_write (struct file *filp,const char __user *buf, size_t count,loff_t*f_pos)
- {
- char wbuf[10];
- unsigned tmp;
- copy_from_user(wbuf,buf,count);
- if(wbuf[0]==1)//1号灯亮
- switch(wbuf[1])
- {
- case 0://off
- tmp = readl(S3C64XX_GPMDAT);
- tmp |=(0x1U);
- writel(tmp, S3C64XX_GPMDAT);
- break;
- case 1://on
- tmp = readl(S3C64XX_GPMDAT);
- tmp &=~(0x1U);
- writel(tmp, S3C64XX_GPMDAT);
- break;
- default :
- break;
- }
-
- if(wbuf[0]==2)//2号灯亮
- switch(wbuf[1])
- {
- case 0://off
- tmp = readl(S3C64XX_GPMDAT);
- tmp |=(0x2U);
- writel(tmp, S3C64XX_GPMDAT);
- break;
- case 1://on
- tmp = readl(S3C64XX_GPMDAT);
- tmp &=~(0x2U);
- writel(tmp, S3C64XX_GPMDAT);
- break;
- default :
- break;
- }
-
- if(wbuf[0]==3)//3号灯亮
- switch(wbuf[1])
- {
- case 0://off
- tmp = readl(S3C64XX_GPMDAT);
- tmp |=(0x4U);
- writel(tmp, S3C64XX_GPMDAT);
- break;
- case 1://on
- tmp = readl(S3C64XX_GPMDAT);
- tmp &=~(0x4U);
- writel(tmp, S3C64XX_GPMDAT);
- break;
- default :
- break;
- }
-
- if(wbuf[0]==4)//4号灯亮
- switch(wbuf[1])
- {
- case 0://off
- tmp = readl(S3C64XX_GPMDAT);
- tmp |=(0x8U);
- writel(tmp, S3C64XX_GPMDAT);
- break;
- case 1://on
- tmp = readl(S3C64XX_GPMDAT);
- tmp &=~(0x8U);
- writel(tmp, S3C64XX_GPMDAT);
- break;
- default :
- break;
- }
- return count;
- }
-
-
- static struct file_operations led_fops = {
- .owner = THIS_MODULE,
- .open = s3c6410_led_open,
- .release = s3c6410_led_close,
- .read = s3c6410_led_read,
- .write = s3c6410_led_write,
- };
-
-
- static int my_plat_probe(struct platform_device*dev)
- {
- int rc;
- printk("Test platform_led dev\n");
- //注册设备
- rc = register_chrdev(LED_MAJOR,"platform_led",&led_fops);
- if (rc<0)
- {
- printk ("register %s char dev error\n","led");
- return -1;
- }
- printk ("ok!\n");
- return 0;
- }
-
- static int my_plat_remove(struct platform_device*dev)
- {
- printk("my platfrom device has removed.\n");
- return 0;
- }
-
- struct platform_driver my_led_drv = {
- .probe = my_plat_probe,
- .remove = my_plat_remove,
- .driver ={
- .owner = THIS_MODULE,
- .name = "platform_led",
- },
- };
-
- static int __init platform_drv_init(void)
- {
- int ret;
-
- ret = platform_driver_register(&my_led_drv);
-
- return ret;
- }
-
- static void __exit platform_drv_exit(void)
- {
- platform_driver_unregister(&my_led_drv);
- }
-
- module_init(platform_drv_init);
- module_exit(platform_drv_exit);
- MODULE_LICENSE("GPL");
0 0
- 总线设备驱动模型---platform篇
- 总线设备驱动模型---platform篇
- 总线设备驱动模型---platform篇
- 总线设备驱动模型---platform篇
- 总线设备驱动模型---platform篇
- 总线设备驱动模型---platform篇
- 总线设备驱动模型---platform篇
- 总线设备驱动模型---platform篇
- 总线设备驱动模型---platform
- 总线设备驱动模型——platform篇
- Linux设备驱动模型之platform总线
- Linux设备驱动模型之platform总线
- Linux设备驱动模型之platform总线
- 总线设备驱动模型(bus/platform)
- linux设备总线驱动模型 之 platform总线驱动
- linux设备总线驱动模型 之 platform总线驱动
- linux设备总线驱动模型 之 platform总线驱动
- platform总线、设备、驱动模型之led驱动实例
- 静态导入
- 设计模式之开篇---面向对象的六大原则
- 使用python进行汉字与二进制之间的转换
- Python Challenge 0-9
- JSTL表达式与EL表达式用法*更新版*
- 总线设备驱动模型---platform篇
- 【C语言】递归 - 汉诺塔
- C#练习--实现超市购物结算
- 集合与数组之间的相互转换
- 【CJOJ P1957】【NOIP2010冲刺十模拟赛】数字积木
- android 应用对内存是如何限制的?我们应该如何合理使用内存?如何限制的?
- apache服务器安装虚拟机
- 序列合并(codevs1245 最小的N个和)
- 文字排版--字体