版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、总线设备驱动模型主要包含总线、设备、驱动三个部分,总线可以是一条真实存在的总线,例如USB I2C等典型的设备。但是对于一些设备 (内部的设备)可能没有现成的总线。Linux 2.6内核中引入了总线设备驱动模型。总线设备驱动模型与之前的三类驱动(字符、块 设备、网络设备)没有必然的联系。设备只是搭载到了总线中。在linux内核中假设存在一条虚拟总线,称之为 platform总线。platform总线相比与常规的总线模型其优势主要是platform总线是由内核实现的,而不用自己定义总线类型,总线设备来加载总线。platform总线是内核已经实现好的。只需要添加相应的platform device
2、和platform driver。具体的实现过程主要包括如下的过程:两者 的工作 顺序是 先定义 platform_device -> 注册 platform_device-> ,再定义 platform_driver-> 注册 platform_driver 。整体而言只需要完成两个步骤,也就是设备的实现和驱动的实现,每一个实现都包括相关结构体的定义和注册。platform_device 注册platform_device 结构体这些设备资源就能实需要注意的是platform_device实质上是经过处理过的设备,在 中存在一个设备结构体, 与之前的设备存在差别的是引入了设
3、备资源。现对设备寄存器,中断等资源的访问。平台设备的基本结构体如下:struct platform_device /*设备名*/const char * n ame;/*设备ID号*/intid;/*结构体包含一个具体的device结构体*/struct device dev;/*资源的数量*/u32nu m_resources;/*资源结构体,用来保存硬件的资源*/struct resource * resource;/*平台设备的ID*/struct platform_deviced*id_e ntry;其中struct device和struct resource 是重要的结构体。str
4、uct device 在总线设备驱动模型中 已经提到了。这次讨论一下 struct resource 。struct resource /*资源的起始值,如果是地址,那么是物理地址,不是虚拟地址*/resource_size_t start;/*资源的结束值,如果是地址,那么是物理地址,不是虚拟地址*/resource_size_t end;/*资源名*/const char *n ame;/*资源的标示,用来识别不同的资源*/un sig ned long flags;/*资源指针,可以构成链表*/struct resource *pare nt, *sibli ng, *child; pl
5、atform_device 的注册很简单,只需要在设备的初始化函数中首先定义相应的设备,通常 采用函数 platform_device *platform_device_alloc(const char *name, int id) 动态申请,通常 name 就是需要申请的设备名,而 id 为 -1。然后采用 int platform_device_add(struct platform_device *pdev) 或者int platform_device_register(struct platform_device *pdev) 注册定义好的设备即可。同样在退出函数中释放注册好的设备即可
6、,可以采用函数:void platform_device_unregister(struct platform_device *pdev) 。 然后一个平台设备就完成了,不需要像自己实现模型时定义相关的文件属性等。 设备资源可以通过相关函数得到: struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)中断资源也可以通过:int platform_get_irq(struct platform_device *dev, unsigned int
7、 num) 资源的使用主要是驱动实现过程中需要使用到的,但是后期的使用一般需要在驱动的 probe 函数中实现申请中断或者 IO 内存才能使用,而不能直接使用。特别是资源中的地址通常是 物理地址,需要通过申请 IO 内存和映射完成物理到虚拟地址的转换,便于进程的访问。 platform_driver 注册平台驱动结构体 platform_driver 实现如下:struct platform_driver /* 平台驱动需要实现的相关函数操作,其中的前 4 个函数与最后一个函数与 device_driver 中的函数是相同的 本质是实现对 device_driver 中相关函数的赋值。*/in
8、t (*probe)(struct platform_device *);int (*remove)(struct platform_device *);void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*suspend_late)(struct platform_device *, pm_message_t state);int (*resume_early)(struct platform_device *);int (*r
9、esume)(struct platform_device *);/* 内嵌了一个设备驱动结构体 */struct device_driver driver;/* 平台设备 ID ,这与 platform_device 中的 struct platform_device_id *id_entry 是相同的 主要是完成总线的匹配操作, platform 总线的匹配操作第一匹配要素就是该元素。而 不再是简单的 name 选项。*/struct platform_device_id *id_table;通常驱动的入口函数 :int (*probe)(struct platform_device *)
10、; 当总线完成了设备的 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);/* match against the id table first */*
11、从定义上分析, id_table 是首先匹配的对象,然后才是 name 的匹配,当 ID 匹配完成 时就说明匹配好了 */if (pdrv->id_table)return platform_match_id(pdrv->id_table, pdev) != NULL;/* fall-back to driver name match */return (strcmp(pdev->name, drv->name) = 0);从上面的定义可以知道 platform 总线的匹配函数手下是比较 id_table 是匹配的首选项。 probe 函数称之为探针函数,用于检测总线上
12、有该驱动能够处理的设备,而 remove 函数则 是为了说明总线上该驱动能够处理的设备被移除。因此这两个函数是在平台设备中一定要被实现的函数。 其他的函数则不一样要求实现。平台驱动的设计主要是完成平台驱动结构体的填充和注册。 通常的平台驱动结构体实现如下:static struct platform_driver my_driver =/* 平台驱动的 probe 函数实现 */.probe = my_probe,/* 平台驱动的 remove 函数实现 */.remove = my_remove,/* 实现设备驱动的 name 和 owner 变量 */.driver =/* 该参数主要实现
13、总线中的匹配函数调用 */.name = "my_dev",/* 该函数表示模块的拥有者 */.owner = THIS_MODULE,;其中的 my_probe 和 my_remove 是自己定义的 probe 和 remove 函数。 最主要的是内嵌设备驱动结构体的填充, 主要的填充包括 name 和 owner 两个, 当然也可以 包括其他的。由于没有填充 id_table,那么name就是总线匹配操作的第一选择。因此如果没 有填充好 id_table, 那么 name 元素是一定要实现的, 不然不能完成相应的设备驱动匹配操作。 完成 platform_driver
14、结构体的填充过后就是完成驱动的在初始化阶段的注册以及退出阶段 的释放操作,基本的实现函数为:注册函数,通常在驱动初始化函数中调用:int platform_driver_register(struct platform_driver *drv) 释放函数,通常在驱动退出函数调用: void platform_driver_unregister(struct platform_driver *drv) 完成相关的注册以后总线、设备、驱动的大概框架就完成啦。 但是这只是常用的框架,还不能在应用程序中使用。基于平台驱动的设备驱动都是基于总线架构的, 基本的实现过程与之前的简单字符设备存在 较大的差别
15、, 主要的区别在驱动的初始化不在是平台设备驱动的初始化函数中实现, 而是在 probe 函数中实现。 而驱动的卸载函数则是在 remove 函数中实现。 probe 函数是平台总线实 现匹配以后首先被调用的函数, 因此在其中实现字符设备、 块设备、 网络设备驱动的初始化 是有意义的,这样的设备驱动就是基于平台总线的设备驱动,便于维护。平台总线驱动的注册过程分析:int platform_driver_register(struct platform_driver *drv)/* 第一步,仍然是完成结构体的填充操作 */* 驱动的总线类型 */drv->driver.bus = &
16、platform_bus_type;/* 将自己定义的 probe 函数赋值给平台驱动中设备驱动的probe 函数 ,其他函数类似 */if (drv->probe)drv->be = platform_drv_probe;if (drv->remove)drv->driver.remove = platform_drv_remove;if (drv->shutdown)drv->driver.shutdown = platform_drv_shutdown;if (drv->suspend)drv->driver.suspe
17、nd = platform_drv_suspend;if (drv->resume)drv->driver.resume = platform_drv_resume;/* 第二步,仍然是完成一般设备驱动的注册操作 */* 然手就是一般驱动的注册,这样就完成了设备的注册 */return driver_register(&drv->driver);/* 设备驱动的 probe 函数的赋值过程 */static int platform_drv_probe(struct device *_dev)/* 得到设备对应的平台驱动 */struct platform_drive
18、r *drv = to_platform_driver(_dev->driver);/* 得到设备的平台设备 */struct platform_device *dev = to_platform_device(_dev);/* 下面的 probe 是自己实现的 probe 函数。具体的实现思路: 根据一般设备找对应的平台设备,同时根据设备的驱动找到平台驱动。然后返回平台驱动的 probe 函数 (自己实现通常是初始化操作 )地址。*/return drv->probe(dev); 实现的总线平台驱动模型的最简单源码 : 平台设备的实现: device.c #include<
19、linux/device.h> #include<linux/module.h> #include<linux/kernel.h> #include<linux/init.h> #include<linux/string.h> #include<linux/platform_device.h> /* 平台模型驱动的平台设备对象 */ static struct platform_device *my_device; /* 初始化函数 */ static int _init my_device_init(void) int ret
20、 = 0;/* 采用 platform_device_alloc 分配一个 platform_device 对象 参数分别为 platform_device 的 name, 和 id 。*/my_device = platform_device_alloc("my_dev",-1);/* 注册设备 ,注意不是 platform_device_register ,将平台设备注册到内核中 */ ret = platform_device_add(my_device);/* 如果出错释放相关的内存单元 */if(ret) platform_device_put(my_device
21、);return ret;/* 卸载处理函数 */static void _exit my_device_exit(void) platform_device_unregister(my_device);module_init(my_device_init); module_exit(my_device_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("GP-<gp19861112>");平台驱动的实现: driver.c#include<linux/module.h>#include<l
22、inux/init.h>#include<linux/kernel.h>#include<linux/platform_device.h>#include<linux/string.h>/* 平台驱动中的 probe 和 remove 函数是必须实现的函数 */* 设备驱动的探测函数,主要实现检测总线上是否有该驱动对应的设备 */ static my_probe(struct device *dev)/* 如果添加实际的设备到该平台总线设备驱动模型中,则可以在该函数 中实现具体的设备驱动函数的初始化操作,包括设备号的申请,设备 的初始化,添加。自动设备
23、文件创建函数的添加等操作。 或者是混杂字符设备的相关初始化操作。当然结构体的相关处理仍 然采取全局变量的形式。*/printk("Driver found devices which this driver can be handlen");return 0;/* 设备驱动的移除函数,主要检测该驱动支持设备的移除活动检测 */static my_remove(struct device *dev)/* 如果添加实际的设备到该平台总线设备驱动模型中,则可以在该函数 中实现具体的设备的释放,包括设备的删除,设备号的注销等操作。*/printk("Driver foun
24、d device unpludedn");return 0;static struct platform_driver my_driver =/* 平台驱动的 probe 函数实现 */.probe = my_probe,/* 平台驱动的 remove 函数实现 */.remove = my_remove,/* 实现设备驱动的 name 和 owner 变量 */.driver =/* 该参数主要实现总线中的匹配函数调用 */.name = "my_dev",/* 该函数表示模块的拥有者 */.owner = THIS_MODULE,;/* 初始化函数 */sta
25、tic int _init my_driver_init(void)/* 注册平台驱动 */return platform_driver_register(&my_driver);/* 退出函数 */static void _exit my_driver_exit(void)/* 注销平台驱动 */return platform_driver_unregister(&my_driver);/* 加载和卸载 */ module_init(my_driver_init); module_exit(my_driver_exit); MODULE_LICENSE("GPL&q
26、uot;);MODULE_AUTHOR("GP-<gp19861112>");将一般设备驱动加入到总线设备模型中的相关操作是后期总结和学习的内容。 设备驱动实现 的实现原理还是之前的那些操作,但是初始化和推出函数发生了改变。总结: platform 总线的驱动模型只是在一般总线模型的基础上做了相关的延伸,实质上只要 弄清除总线模型的一般原理,学习 platform 总线也就简单不少。但是毕竟还是学习阶段。一. 概述platform 设备和驱动与linux设备模型密切相关。platform 在linux设备模型中,其实就是一种虚拟总线没有对应的硬件结构。它的主要作
27、用就是管理系统的外设资源,比如io内存冲断信号线。现在大多数处理器芯片都是soc,如s3c2440,它包括处理器内核(arm920t)和系统的外设(led接口,nandflash接口等)。linux在引入了 platform机制之后,内核假 设所有的这些外设都挂载在platform虚拟总线上,以便进行统一管理。二. platform 总线1. 在系统中platform 对应的文件drivers/base/platform.c ,它不是作为一个模块注册到内二| 核的,关键的注册总线的函数由系统初始化部分,对应/init/main.c中的do_basic_setup 函数间接调用。这里可以看出 p
28、latform非常重要,要在系统其他驱动加载之前注册。下面分 析platform总线注册函数cpp view pla in copyvoid )1. int _init platform_bus_init(2. 3. int error;4. early_platform_cleanup();5. error = device_register(&platform_bus);6. /总线也是设备,所以也要进行设备的注册7. if (error)8. return error;9. error = bus_register(&platform_bus_type);10. / 注册
29、 platform_bus_type总线到内核11. if (error)12. device_unregister(&platform_bus);13. return error;14. 这个函数向内核注册了一种总线。 他首先由/drivers/base/init.c 中的driver_init函数调用, driver_init 函数由 /init/main.c 中的 do_basic_setup 函数调用,do_basic_setup 这个函数由 kernel_init调用,所以platform总线是在内核初始化的时候就注册进了内核。2. platform_bus_type总线结构
30、与设备结构(1) platform总线 设备结构cpp view pla in copy1.structdevice platform_bus = 2.init_name ="platform" ,3.;platform总线也是一种设备,这里初始化一个device结构,设备名称platform,因为没有指定父设备,所以注册后将会在/sys/device/下出现platform目录。(2) platform总线总线结构cppview pla in copy1. struct bus_type platform_bus_type = 2. .name="platfor
31、m"3. .dev_attrs =platform_dev_attrs,4. .match=platform_match,5. .uevent=platform_uevent,6. .pm = & platform_dev_pm_ops,7. ;platform_dev_attrs设备属性platform_matchmatch函数,这个函数在当属于 platform的设备或者驱动注册到内核时就会调用,完成设备与驱动的匹配工作。platform ueve nt热插拔操作函数三.platform 设备1. platform device结构cpp view pla in copy
32、1. struct platform_device 2. const char * name;3. int id;4. struct device dev;5. u32 num_resources;6. structresource * resource;7. structplatform_device_id *id_entry;8. /* arch specific additions */9. structpdev_archdata archdata;10. ;(1) platform_device结构体中有一个 struct resource结构,是设备占用系统的资源,|定义在iopor
33、t.h中,如下cpp view pla in copy1.struct resource 2.resource_size_t start;3.resource_size_t end;4.constchar *name;5.unsignedlong flags;6.structresource *parent, *sibling, *child;7.;(2) num_resources占用系统资源的数目,一般设备都占用两种资源,io内存和中断信号线。这个为两种资源的总和。2.设备注册函数platform device registercpp view pla in copy1. int plat
34、form_device_register(2. struct platform_device *pdev)3.device_initialize(&pdev->dev);4. return platform_device_add(pdev);5. 这个函数首先初始化了platform device 的device结构,然后调用platform device add,这个是注册函数的关键,下面分析platform_device_add :cpp view pla in copy1. int platform_device_add( struct platform_device *p
35、dev)2. 3. int i, ret = 0;4.4. if (!pdev)5. return -EINVAL;7.6. if (!pdev->dev.parent)7. pdev->dev.parent = &platform_bus;8. /可以看出,platform设备的父设备一般都是platform_bus ,所以注册后的platform设备都出现在 /sys/devices/platform_bus下11.12.pdev->dev.bus = &platform_bus_type;/挂到platform 总线上13.if (pdev->id
36、 != -1)14.dev_set_name(&pdev->dev,"%s.%d" , pdev->name, pdev->id);15.else16.dev_set_name(&pdev->dev,"%s" , pdev->name);17./设置设备名字,这个名字与18.for(i = 0; i < pdev->num_resources; i+) /sys/devices/platform_bus/下面操作设备所占用的系统资下的名字对应3.device_initialize(&pde
37、v->dev);3.device_initialize(&pdev->dev);4.35.struct resource *p, *r = &pdev->resourcei;if (r->name = NULL)r->name = dev_name(&pdev->dev);p = r->parent;if (!p) if (resource_type(r) = IORESOURCE_MEM)p = &iomem_resource;
38、else if (resource_type(r) = IORESOURCE_IO) p = &ioport_resource;if (p && insert_resource(p, r) printk(KERN_ERR"%s: failed to claim resource %dn"dev_name(&pdev->dev), i);36.ret = -EBUSY;37.goto failed;38.39.40./上面主要是遍历设备所占用的资源,找到对应的父资源,如果没有定义,那么根据资源的类型,分另U赋予 iomem_resourc
39、e 和 ioport_resource,然后调用 insert_resource插入资源。41./这样系统的资源就形成了一个树形的数据结构,便于系统的管理42.pr_debug("Registering platform device '%s'. Parent at %sn",43.dev_name(&pdev->dev), dev_name(pdev->dev.parent);44.45.ret = device_add(&pdev->dev);46./注册到设备模型中47.if (ret = 0)48.return re
40、t;49.failed:50.while (-i >= 0) 51.struct resource *r = &pdev->resourcei;52.unsignedlong type = resource_type(r);53.if (type = IORESOURCE_MEM | type = IORESOURCE_IO)54.release_resource(r);55.56.return ret;57.3.mini2440 内核注册platform设备过程因为种soc确疋之后,其外设模块就已经确疋了,所以注册platform设备就由板级初始化代码来元成,在mini2
41、440 中是 mach-mini2440.C 的mini2440_machine_init函数中调用 platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices)来元成注nn 丿册。这个函数完成 mini2440的所有platform设备的注册:(1)platform_add_devices 函数是 platform_device_register的简单圭寸装,它向内核注册一组platform设备(2)mini2440 devices 是一个 platform device 指针数组,疋义如下:cppview pla i
42、n copy1.static structplatform_device *mini2440_devices _initdata = 2.&s3c_device_usb,3.&s3c_device_rtc,4.&s3c_device_lcd,5.&s3c_device_wdt,6.&s3c_device_i2c0.7.&s3c_device_iis,8.& mini2440_device_eth.9.& s3c24xx_uda134x.10.&s3c_device_nand,9. & s3c_device_sdi,
43、10. &s3c_device_usbgadget,11. ;这个就是mini2440的所有外设资源了,每个外设的具体定义在/arch/arm/plat-s3c24xx/devs.c ,下面以 s3c_device_lcd 为例说明,其他的类似。s3c device lcd 在 devs.c 中它定义为:cppview pla in copy1.struct platform_device s3c_device_lcd = 2.name="s3c2410-lcd",3.id= -1,4.num_resources = ARRAY_SIZE(s3c_lcd_resou
44、rce),5.resource = s3c_lcd_resource,6.dev= 7.dma_mask= &s3c_device_lcd_dmamask.8.coherent_dma_mask = OxffffffffUL9.10.;可以看出,它占用的资源s3c lcd resource ,疋义如下:cppview pla in copy1.static struct resource s3c_lcd_resource = 2.0 = 3.start = S3C24XX_PA_LCD,4.end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,5.flag
45、s = IORESOURCE_MEM,6.,7.1 = 8.start = IRQ_LCD,9.end = IRQ_LCD,10.flags = IORESOURCERQ,11.12.;这是-个数组,有两个兀素,说明led占用了系统两个资源,一个资源类型是IORESOURCE_MEM 代表 io 内存,起使地址 S3C24XX_PA_LCD ,这个是LCDCON1寄存器的地址。另外一个资源是中断信号线。四.platform设备驱动如果要将所写的驱动程序注册成platform驱动,那么所做的工作就是初始化一个platform_driver ,然后调用 platform_driver_regist
46、er进行注册。基本数据机构 platform drivercpp view pla in copy1. struct platform_driver 2. int (*probe)( struct platform_device *);3. int (*remove)( struct platform_device *);4. void (*shutdown)( struct platform_device *);5. int (*suspend)( struct platform_device *, pm_message_t state);6. int (*resume)( struct p
47、latform_device*);7. struct device_driver driver;8. struct platform_device_id *id_table;9. ;这是platform驱动基本的数据结构,在驱动程序中我们要做的就是声明一个这样的结构 并初始化。下面是led驱动程序对它的初始化:cpp view pla in copy1. static struct platform_driver s3c2412fb_driver = 2. .probe = s3c2412fb_probe,3. .remove= s3c2410fb_remove,4. .suspend = s3c2410fb_suspend,5. .resume= s3c2410fb_resume,6. .driver = 7. .name ="s3c2412-lcd",8. .owner = THIS_MODULE,9. ,10. ;上面几个函数是我们要实现的,它将赋值给device_driver中的相关成员,probe函数是用来查询特定设备是够真正存在的函数。当设备从系统删除的时候调用remove函数。1. 注册函数 platform driver registercpp view pla in copy1. int platfo
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 金融行业网络交易安全管理制度
- 石油储存温度监控方案
- 金融行业安全设备采购实施方案
- 桥梁工程独立基础施工方案研究
- 地下天然气管道检测与修复方案
- 2023年激光精密加工和蚀刻成套设备项目综合评估报告
- 2023年残疾人用车及其零件项目综合评估报告
- 2023年公路旅客运输服务项目评价分析报告
- 2024至2030年结构用管项目投资价值分析报告
- 2024至2030年真皮公事包项目投资价值分析报告
- 公务员(国考)之行政职业能力测验模拟考试试卷A卷含答案
- CH-T 1026-2012 数字高程模型质量检验技术规程
- 创新创业基础-理论、案例与训练(大学生创新创业教育课程)全套教学课件
- 展厅设计施工合同
- 2024年江苏省高中学业水平合格性考试数学试卷试题(答案详解1)
- 2024年中国邮政集团有限公司校园招聘考试试题及参考答案
- 认识城市轨道交通安全管理讲解
- 场内运输机械检查验收表
- 不锈钢加工检验标准
- 泰国投资指导手册
- 2024年新华社招聘笔试参考题库附带答案详解
评论
0/150
提交评论