#导入Word文档图片# Linux平台设备驱动模型

吾生也有涯,而知也无涯。这篇文章主要讲述#导入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 平台总线驱动模型特点?

  1. 平台模型采用了分层结构,把一个设备驱动程序分成了两个部分:?
平台设备(platform_device)和平台驱动(platform_driver)。?
(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函数。?
  1. 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); 导出给其他模块使用)?
  1. 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); 导出给其他模块使用)?
在设备层编程中,这两个函数所做的工作是相反的,一个用于添加设备到内核,另一个用于从内核中把设备删除。?
  1. 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); 导出给其他模块使用)?
这个函数内部调用的还是platform_device_register(struct platform_device *pdev),不同在于platform_device_register(struct platform_device *pdev)只注册单个平台设备,platform_add_devices(struct platform_device **devs, int num)注册多个平台设备结构。?


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

    推荐阅读