吾生也有涯,而知也无涯。这篇文章主要讲述#导入Word文档图片# Linux平台设备驱动模型相关的知识,希望能为你提供帮助。
?
16.1 平台设备和驱动初识?16.1.1 总线驱动模型简介?
在Linux 2.6的设备驱动模型中,关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。?
一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB、I2 C、SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,SOC系统中集成的独立的外设控制器、挂接在SOC内存空间的外设等却不依附于此类总线。?
基于这一背景,Linux发明了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动成为platform_driver。?
16.1.2 平台总线驱动模型特点?
- 平台模型采用了分层结构,把一个设备驱动程序分成了两个部分:?
(2)平台设备将设备本身的资源注册进内核,可以由内核统一管理。?
(3)统一了设备驱动模型,使智能电源管理更容易实现(设计设计之初就是为了管理电源的)。?
(4)从代码的维护角度看,平台模型的可移植性,通用性更好。?
16.2 平台设备驱动模型分层?下面分别来介绍设备和驱动层的结构及内核提供编写的API函数。?
16.2.1 平台设备层核心数据结构?
在Linux 2.6内核中将每个设备的资源用结构struct platform_device来描述,该结构体定义在kernel\\include\\linux\\platform_device.h中,struct platform_device结构如下:?
struct platform_device ? const char * name; //设备名,要求和驱动层中的.name相同。? int id; //设备ID,一般为-1? struct devicedev; //内嵌标准device,一般可以用来传递平台数据? u32 num_resources; //设备占用资源个数? struct resource* resource; //设备占用资源的首地址。? struct platform_device_id*id_entry; //设备id入口,一般驱动不用? /* arch specific additions */? struct pdev_archdataarchdata; ? ; ? |
该结构一个重要的元素是resource,该元素存入了最为重要的设备资源信息,定义在kernel\\include\\linux\\ioport.h中,结构如下:?
struct resource ? resource_size_t start; //资源起始物理地址? resource_size_t end; //资源结束物理地址? const char *name; //资源名称,可以随便写,一般要有意义。? unsigned long flags; //资源类型,IO,内存,中断,DMA。? struct resource *parent, *sibling, *child; ? ; ? |
struct resource 结构中flags成员是指资源的类型,目前可用资源类型定义在include\\linux\\ioport.h文件 中。如下:?
#define IORESOURCE_IO0x00000100 空间,一般在X86框架中存在,ARM一般没有? #define IORESOURCE_MEM0x00000200 内存空间,占用的是CPU 4G统一编址空间? #define IORESOURCE_IRQ0x00000400 中断资源,实际上就是中断号? #define IORESOURCE_DMA0x00000800 内存空间,占用的是CPU 4G统一编址空间,? 但是这个空间是用来做dma模型使用的缓冲空间。? |
另外一个很重要的成员是struct device,这个成员是用来实现设备模型的,其中的void 成员用途很大,一般称为平台数据指针,可以给平台驱动层传递任何信息需要的信息,因这个成员指针类型是void类型的,在平台设备驱动模型中,随处可以看到这个成员的踪迹,在例子中会看到如何使用。?
以下struct device的结构信息:?
struct device ? struct device*parent; /* 父设备指针 */? struct device_private*p; ? struct kobject kobj; ? const char*init_name; /*逻辑设备的名字*/? struct device_type*type; /* 设备类型 */? struct semaphoresem; /* semaphore to synchronize calls toits driver. */? struct bus_type*bus; /* 设备所属的总线类型 */? struct device_driver *driver; /* 指向开辟struct device结构driver指针*/? void*platform_data; /* 平台设备的私有数据指针,要以传递任何结构*/? struct dev_pm_infopower; ? #ifdef CONFIG_NUMA? intnuma_node; /* NUMA node this device is close to */? #endif? u64*dma_mask; /* dma mask (if dmaable device) */? /*Like dma_mask, but foralloc_coherent mappings as? not all hardware supports 64 bit addresses for consistent? allocations such descriptors. */? u64coherent_dma_mask; ? struct device_dma_parameters *dma_parms; ? /* dma pools (if dmable) */? struct list_headdma_pools; ? /* internal for coherent mem override */? struct dma_coherent_mem*dma_mem; /* arch specific additions */? struct dev_archdataarchdata; ? dev_tdevt; /* 存放设备号dev_t,creates the sysfs"dev" */? spinlock_tdevres_lock; ? struct list_headdevres_head; ? struct klist_nodeknode_class; ? struct class*class; /* 设备所属类*/? const struct attribute_group **groups; /* optional groups */? void(*release)(struct device *dev); ? ; ? |
以上结构中对驱动开发者比较重要的成员已经使用粗体标注出来。?
16.2.2 platform设备层API?
在学习平台驱动设备层代码如何编写前,先介绍一下和设备层代码相关的内核API函数。?
- int platform_device_register(struct platform_device *pdev)
函数原型? | int platform_device_register(struct platform_device *pdev)? |
函数功能? | 向内核注册一平台设备? |
函数参数? | pdev: 要注册的struct platform_device结构指针? |
函数返回值? | 0:注册成功;? 负数:注册失败? |
函数头文件? | include\\linux\\platform_device.h? |
函数定义文件? | drivers\\base\\platform.c? (用EXPORT_SYMBOL_GPL(platform_device_register); 导出给其他模块使用)? |
- void platform_device_unregister(struct platform_device *pdev)
函数原型? | void platform_device_unregister(struct platform_device *pdev)? |
函数功能? | 把指定的平台设备struct platform_device从内核中删除? |
函数参数? | pdev: 要删除的struct platform_device结构指针? |
函数返回值? | 无? |
函数头文件? | include\\linux\\platform_device.h? |
函数定义文件? | drivers\\base\\platform.c ? (用EXPORT_SYMBOL_GPL(platform_device_unregister); 导出给其他模块使用)? |
- int platform_add_devices(struct platform_device **devs, int num)?
函数原型? | int platform_add_devices(struct platform_device **devs, int num)? |
函数功能? | 把devs数组中的num个平台设备struct platform_device结构注册到内核中。? |
函数参数? | pdev: struct platform_device结构指针数组? num:pdev数组元素中的个数。? |
函数返回值? | 0:注册成功;? 负数:注册失败? |
函数头文件? | include\\linux\\platform_device.h? |
函数定义文件? | drivers\\base\\platform.c ? (用EXPORT_SYMBOL_GPL(platform_add_devices); 导出给其他模块使用)? |
16.2.3 platform 设备层编程?
需要实现的结构体是:struct platform_device。? 1)初始化 struct resource 结构变量。? 2)初始化 struct platform_device 结构变量。? 3)向系统注册设备,使用platform_device_register()函数。? |
16.2.4 平台驱动层核心数据结构?
在内核中平台驱动模型的驱动层使用struct platform_driver结构来描述一个设备的驱动信息,定义在include\\linux\\platform_device.h文件中,结构如下:?
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; //里边的name很重要,用来匹配? struct platform_device_id *id_table; ? ; ? |
这个结构中probe,remove是必须的要实现的函数成员,其他函数成员根据需要自行决定是否要实现。?
struct device_driver driver成员中的name成员很重要,它的内容必须要和设备层核心结构struct platform_device的name成员相同,才能实现驱动层和设备层的绑定。?
struct device_driver结构如下:?
struct device_driver ? const char*name; 驱动层的名字,用来和设备层匹配的*/ ? struct bus_type*bus; ? 【#导入Word文档图片# Linux平台设备驱动模型】struct module 推荐阅读
|