#导入Word文档图片# Linux平台设备驱动模型
Posted DS小龙哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#导入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 平台总线驱动模型特点
- 平台模型采用了分层结构,把一个设备驱动程序分成了两个部分:
平台设备(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函数。
- 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);导出给其他模块使用) |
这个函数内部调用的还是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; struct module#导入Word文档图片# Linux下I2C驱动架构全面分析 |