ImageVerifierCode 换一换
格式:DOCX , 页数:21 ,大小:82.97KB ,
资源ID:15924865      下载积分:5 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-15924865.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(如何设计平台设备和驱动.docx)为本站会员(b****7)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

如何设计平台设备和驱动.docx

1、如何设计平台设备和驱动如何设计平台设备和驱动 2.6内核引入了platform机制,能够实现对设备所占用的资源进行统一管理。Platform机制抽象出了platform_device和platform_driver两个核心概念,与此相关的还有一个重要概念就是资源resource。1.1.1 资源1 描述和类型 资源resource是对设备所占用的硬件信息的抽象,目前包括I/O、内存、IRQ、DMA、BUS这5类。在内核中,用resource结构来对资源进行描述。resource结构在文件中定义,如程序清单2.35所示。程序清单2.35 resource数据结构struct resource r

2、esource_size_t start; /* 资源在CPU上的物理起始地址 */ resource_size_t end; /* 资源在CPU上的物理结束地址 */ const char *name; /* 资源名称 */ unsigned long flags; /* 资源的标志 */ struct resource *parent, *sibling, *child; /* 资源的父亲、兄弟和子资源 */; flags通常被用来表示资源的类型,可用的资源类型有IO、MEM、IRQ等,在中定义,各资源类型和定义如下:#define IORESOURCE_TYPE_BITS 0x00001

3、f00 /*资源类型 */#define IORESOURCE_IO 0x00000100#define IORESOURCE_MEM 0x00000200#define IORESOURCE_IRQ 0x00000400#define IORESOURCE_DMA 0x00000800#define IORESOURCE_BUS 0x000010002 资源定义 一个设备的资源定义可以同时包含所占用的多种资源。例如,对于一个既占用内存资源,又占用IRQ中断资源的设备,其资源定义可以如程序清单2.36所示。程序清单2.36资源定义实例#define EMC_CS2_BASE 0x1100000

4、0 /* 总线片选地址 */static struct resource ecm_ax88796b_resource = 0 = /* 内存资源 */ .start = EMC_CS2_BASE, /* 起始地址 */ .end = EMC_CS2_BASE + 0xFFF, /* 结束地址 */ .flags = IORESOURCE_MEM, /* 资源类型:IORESOURCE_MEM */ , 1 = /* IRQ资源 */ .start = IRQ_GPIO_04, .end = IRQ_GPIO_04, .flags = IORESOURCE_IRQ, /* 资源类型:IORESO

5、URCE_IRQ */ ;3 资源获取 定义了一个设备的资源后,需通过特定函数获取才能使用,这些函数在文件中定义,一共有3个函数,分别是:platform_get_resource()、platform_get_resource_byname()、platform_get_irq()和platform_get_irq_byname()。 platform_get_resource()函数用于获取指定类型的资源,函数原型如下:extern struct resource *platform_get_resource(struct platform_device *, unsigned int,

6、unsigned int); dev指向包含资源定义的platform_device结构;type表示将要获取的资源类型;num表示获取资源的数量。返回值为0表示获取失败,成功返回申请的资源地址。 platform_get_resource_byname()则是根据平台设备的设备名称获取指定类型的资源,函数原型如下:extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, const char *); 另外,内核还单独提供了获取IRQ的接口函数platform_get

7、_irq(),实际上就是platform_get_resource()获取IORESOURCE_IRQ的封装,方便用户使用。原型如下:int platform_get_irq(struct platform_device *dev, unsigned int num); 获取设备的私有数据,可通过宏platform_get_drvdata实现:#define platform_get_drvdata(_dev) dev_get_drvdata(&(_dev)-dev)实际上是获取_dev-dev-p-driver_data,可参考程序清单2.29 device结构的定义。 platform_g

8、et_irq_byname()则可根据平台设备名称获取设备的IRQ资源,函数原型如下:extern int platform_get_irq_byname(struct platform_device *, const char *); 在驱动编写中如何实际使用这些函数,下面给出一个代码片段,如程序清单2.37所示。程序清单2.37平台资源获取和使用范例 if (!mem) res = platform_get_resource (pdev, IORESOURCE_MEM, 0); /* 获取内存资源 */ if (!res) printk(%s: get no resource !n, DR

9、V_NAME); return -ENODEV; mem = res-start; if(!irq) irq = platform_get_irq(pdev, 0); /* 获取IRQ资源 */ if (!request_mem_region (mem, AX88796B_IO_EXTENT, ax88796b) /* 申请IO内存 */ PRINTK (ERROR_MSG, PFX request_mem_region fail !); return -EBUSY; addr = ioremap_nocache(mem, AX88796B_IO_EXTENT); /* 内存映射ioremap

10、 */ if (!addr) ret = -EBUSY; goto release_region; 该范例演示了内存资源和IRQ资源的获取和使用。特别说明一下内存资源,在定义内存资源的时候,通常使用内存的物理地址,而在驱动中须转换为虚拟地址使用,所以需要进行ioremap操作,而在ioremap之前又需要先申请IO内存,所以在代码中看到的是先使用request_mem_region()函数申请IO内存,然后再通过ioremap_nocache()函数完成内存映射。1.1.2 平台设备 并不是任何设备都可以抽象成为platform_device。platform_device是在系统中以独立实体

11、出现的设备,包括传统的基于端口的设备、主机到外设的总线以及大部分片内集成的控制器等。这些设备的一个共同点是CPU都可以通过总线直接对它们进行访问。在极少数情况下,一个platform_device可能会经过一小段其它总线,但是它的寄存器依然可以被CPU直接访问。1 platform_device 用于描述平台设备的数据结构是platform_device,在文件中定义,如程序清单2.38所示。程序清单2.38 platform_device数据结构struct platform_device const char * name; /* 设备名称 */ int id; /* 设备ID */ st

12、ruct device dev; /* 设备的device数据结构 */ u32 num_resources; /* 资源的个数 */ struct resource * resource; /* 设备的资源 */ const struct platform_device_id *id_entry; /* 设备ID入口 */ /*体系结构相关的附加项*/ struct pdev_archdata archdata; /* 体系结构相关的数据 */; name是设备的名称,用于与platform_driver进行匹配绑定,resourse用于描述设备的资源如地址、IRQ等。2 分配platfor

13、m_device结构 注册一个platform_device之前,必须先定义或者通过platform_device_alloc()函数为设备分配一个platform_device结构,platform_device_alloc()函数原型如下:struct platform_device *platform_device_alloc(const char *name, int id);3 添加资源 通过platform_device_alloc()申请得到的platform_device结构,必须添加相关资源和私有数据才能进行注册。添加资源的函数是platform_device_add_res

14、ources:int platform_device_add_resources(struct platform_device *pdev, const struct resource *res, unsigned int num); 添加私有数据的函数是platform_device_add_data:int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size);4 注册和注销platform_device 申请到platform_device结构后,可以通过platform

15、_device_register()往系统注册,platform_device_register()函数原型如下:int platform_device_register(struct platform_device *pdev); platform_device_register()只能往系统注册一个platform_device,如果有多个platform_device,可以用platform_add_devices()一次性完成注册,platform_add_devices()函数原型如下:int platform_add_devices(struct platform_device *

16、devs, int num); 通过platform_device_unregister()可以注销系统的platform_device,platform_device_unregister()函数原型如下:void platform_device_unregister(struct platform_device *pdev); 如果已经定义了设备的资源和私有数据,可以用platform_device_register_resndata()一次性完成数据结构申请、资源和私有数据添加以及设备注册:struct platform_device *_init_or_module platform_

17、device_register_resndata( struct device *parent, const char *name, int id, const struct resource *res, unsigned int num, const void *data, size_t size); platform_device_register_simple()函数是platform_device_register_resndata()函数的简化版,可以一步实现分配和注册设备操作,platform_device_register_simple()函数原型如下:static inline

18、 struct platform_device *platform_device_register_simple( const char *name, int id, const struct resource *res, unsigned int num);实际上就是:platform_device_register_resndata(NULL, name, id, res, num, NULL, 0)。 在文件还提供了更多的platform_device相关的操作接口函数,在有必要的时候可以查看并使用。5 向系统添加平台设备的流程 向系统添加一个平台设备,可以通过两种方式完成: 方式1:定

19、义资源,然后定义platform_device结构并初始化;最后注册; 方式2:定义资源,然后动态分配一个platform_device结构,接着往结构添加资源信息,最后注册。 两种方式归纳如图2.7所示。图2.7添加平台设备的方式1.1.3 平台驱动1 platform_driver platform_driver是device_driver的封装,提供了驱动的probe和remove方法,也提供了与电源管理相关的shutdown和suspend等方法,如程序清单2.39所示。程序清单2.39platform_driver数据结构struct platform_driver int (*pr

20、obe)(struct platform_device *); /* probe方法 */ int (*remove)(struct platform_device *); /* remove方法 */ void (*shutdown)(struct platform_device *); /* shutdown方法 */ int (*suspend)(struct platform_device *, pm_message_t state); /* suspend方法 */ int (*resume)(struct platform_device *); /* resume方法 */ str

21、uct device_driver driver; /* 设备驱动 */ const struct platform_device_id *id_table; /* 设备的ID表 */; Platform_driver有5个方法: probe成员指向驱动的探测代码,在probe方法中获取设备的资源信息并进行处理,如进行物理地址到虚拟地址的remap,或者申请中断等操作,与模块的初始化代码不同; remove成员指向驱动的移除代码,进行一些资源释放和清理工作,如取消物理地址与虚拟地址的映射关系,或者释放中断号等,与模块的退出代码不同; shutdown成员指向设备被关闭时的实现代码; suspe

22、nd成员执行设备挂起时候的处理代码; resume成员执行设备从挂起中恢复的处理代码。 2 注册和注销platform_driver 注册和注销platform_driver的函数分别是platform_driver_register()和platform_driver_unregister(),函数原型分别如下:int platform_driver_register(struct platform_driver *drv);void platform_driver_unregister(struct platform_driver *drv); 另外,platform_driver_pro

23、be()函数也能完成设备注册,原型如下: int platform_driver_probe(struct platform_driver *driver, int (*probe)(struct platform_device *); 如果已经明确知道一个设备不支持热插拔,可以在_init断代码中调用platform_driver_probe()函数,以减少运行时对内存的消耗。如程序清单2.40所示代码是中的范例,可以参考。程序清单2.40使用platform_driver_probe的范例int _init init_module(void) int retval; ne_add_devi

24、ces(); retval = platform_driver_probe(&ne_driver, ne_drv_probe); if (retval) if (io0 = 0) printk(KERN_NOTICE ne.c: You must supply io=0xNNN value(s) for ISA cards.n); ne_loop_rm_unreg(1); return retval; /* Unregister unused platform_devices. */ ne_loop_rm_unreg(0); return retval;注意:在设备驱动模型中已经提到,bus根

25、据驱动和设备的名称寻找匹配的设备和驱动,因此注册驱动必须保证platform_driver的driver.name字段必须和platform_device的name相同,否则无法将驱动和设备进行绑定而注册失败。1.1.4 平台驱动与普通驱动的差异 基于platform机制编写的驱动与普通字符驱动,只是在框架上有差别,驱动的实际内容是差不多相同的,如果有必要的话,一个普通驱动很容易就可被改写为platform驱动。图2.8是普通字符驱动与平台驱动的框架对照。图2.8普通驱动与平台驱动对比 可以看到,将一个普通字符驱动改写为平台驱动,驱动各方法方法的实现以及fops定义都是一样的,不同之处是框架结

26、构发生了变化,资源的申请和释放等代码的位置发生了变化: 资源申请、设备注册等从普通字符驱动的模块初始化部分移到了平台驱动的probe方法,对于特殊情况,也可以继续放在模块初始化代码中; 设备注销、资源释放等从普通字符驱动的模块退出代码移到了平台驱动的remove方法。 平台驱动还增加了资源定义和初始化、平台设备和驱动的定义和初始化,以及驱动必要方法的实现等。 平台驱动的模块初始化代码可以很简单,几乎只需简单的调用平台设备注册和注销的接口函数。1.1.5 平台驱动范例 前面已经提到过,采用platform方式编程,能够很好的将资源与驱动分开,便于程序移植和驱动复用。本节继续以LED为例,用pla

27、tform方式重新实现LED驱动,实现与第2.5.4小节驱动相同的功能。 为了演示资源和驱动分离,本例将驱动分为如下两个模块: led_platform模块:实现资源定义和platform设备注册; led_drv模块:通过platform方式实现LED驱动。 在使用的时候,须依次插入led_platform和led_drv,才能生成设备节点。1 led_platform模块 led_platform模块只有led_platform.c一个文件。该文件实现了LED资源定义,并向系统注册了一个led platform设备,代码如程序清单2.41所示。程序清单2.41led_platform.c参

28、考代码 1 #include 2 #include 3 #include 4 #include 5 6 #define GPIO_LED_PIN_NUM 55 /* gpio 1_23 */ 7 8 /* 定义LED资源 */ 9 static struct resource led_resources = 10 0 = 11 .start = GPIO_LED_PIN_NUM, 12 .end = GPIO_LED_PIN_NUM, 13 .flags = IORESOURCE_IO, 14 , 15 ; 16 17 static void led_platform_release(stru

29、ct device *dev) 18 19 return; 20 21 22 /* 定义平台设备 */ 23 static struct platform_device led_platform_device = 24 .name = led, /* platform_driver中,.name必须与该名字相同 */ 25 .id = -1, 26 .num_resources = ARRAY_SIZE(led_resources), 27 .resource = led_resources, 28 .dev = 29 /* Device led does not have a release

30、() function, it is broken and must be fixed. */ 30 .release = led_platform_release, 31 .platform_data = NULL, 32 , 33 ; 34 35 static int _init led_platform_init(void) 36 37 int ret; 38 39 ret = platform_device_register(&led_platform_device); 40 if (ret 0) 41 platform_device_put(&led_platform_device);

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2