Chinaunix首页 | 论坛 | 博客
  • 博客访问: 458659
  • 博文数量: 113
  • 博客积分: 446
  • 博客等级: 下士
  • 技术积分: 1229
  • 用 户 组: 普通用户
  • 注册时间: 2012-12-09 16:01
个人简介

Let's go!!!!!

文章分类

全部博文(113)

文章存档

2019年(5)

2018年(4)

2017年(9)

2016年(5)

2015年(39)

2014年(6)

2013年(28)

2012年(17)

分类: LINUX

2018-11-30 14:19:09

一 platform总线
一个现实的linux设备驱动通常需要挂接在一种总线上,对于本身依附于PCI,USB,IIC,SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,SOC系统中集成的独立的外设控制器,挂接在SOC内存空间的外设等确不依附于此类总线。基于这一背景,linux发明了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动成为platform_driver.Platform总线是linux2.6内核加的一种虚拟总线。 
Linux platform driver机制和传统的device driver 机制(通过driver_register函数进行注册)相比,一个十分明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性(这些标准接口是安全的)。


二 平台设备的驱动软件设计流程




三 平台设备
3.1 用于描述平台设备的数据结构是platform_device, 在”linux/platform_device.h”文件中定义,程序清单如下所示:
struct platform_device{
const char      *name;           //设备名字
int             id;             //设备ID
struct device   dev;            //设备的device数据结构
u32             num_resources;  //资源的个数
struct resource *resource;      //设备的资源
const struct platform_device_id  *id_entry;//设备ID入口
struct pdev_archdata archdata;   //体系结构相关的数据
};

3.2 分配platform_device结构 
注册一个platform_device之前,必须先定义或者通过platform_device_alloc()函数为设备分配一个platform_device结构。原型如下:
struct platform_device *platform_device_alloc(const char *name,int id);

3.3添加资源 
通过platform_device_alloc()申请得到的platform_device结构,必须添加相关资源和私有数据才能注册。添加资源的函数是platform_device_add_resources:
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)

3.4 注册和注销platform_device 
申请到platform_device结构后,可以通过platform_device_register()往系统进行注册。原型如下:
int platform_device_register(struct platform_device *pdev);

上述函数只能注册一个platform_device,如果有多个platform_device,则可以用platform_add_devcies()一次性完成注册,原型如下:
int platform_add_devices(struct platform_device  *devs,int num);

通过platform_device_unregister()可以注销系统的plat_device.原型如下:
void platform_unresigner(struct platform_device *pdev);
如果已经定义了设备的资源和私有数据,可以用 platform_device_register_resndata()一次 
性完成数据结构申请、资源和私有数据添加以及设备注册:
struct platform_device *__init_or_module platform_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 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)。在\Linux/platform_device.h/文件还提供了更多的 platform_device 相关的操作接口函数, 
在有必要的时候可以查看并使用。 
3.5向系统添加平台设备的流程 
向系统添加一个平台设备,可以通过两种方式完成: 
? 方式 1:定义资源,然后定义 platform_device 结构并初始化;最后注册; 
? 方式 2:定义资源,然后动态分配一个 platform_device 结构,接着往结构添加资源 
信息,最后注册。 
如下图所示: 



四 平台驱动
4.1platform_driver 
platform_driver 是 device_driver 的封装,提供了驱动的 probe 和 remove 方法,也提供了 
与电源管理相关的 shutdown 和 suspend 等方法
struct platform_driver {
int (*probe)(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 方法 */
struct device_driver driver;                 /* 设备驱动 */
const struct platform_device_id *id_table;  /* 设备的 ID 表 */
};

Platform_driver 有 5 个方法: 
? probe成员指向驱动的探测代码,在 probe方法中获取设备的资源信息并进行处理, 
如进行物理地址到虚拟地址的 remap,或者申请中断等操作,与模块的初始化代码 
不同; 
? remove 成员指向驱动的移除代码,进行一些资源释放和清理工作,如取消物理地 
址与虚拟地址的映射关系,或者释放中断号等,与模块的退出代码不同; 
? shutdown 成员指向设备被关闭时的实现代码; 
? suspend 成员执行设备挂起时候的处理代码; 
? resume 成员执行设备从挂起中恢复的处理代码 
4.2注册和注销平台设备 
注册和注销 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_probe()函数也能完成设备注册, 原型如下:
int platform_driver_probe(struct platform_driver *driver, int (*probe)(struct platform_device *));

如果已经明确知道一个设备不支持热插拔,可以在__init 断代码中调用 platform_driver 
_probe()函数,以减少运行时对内存的消耗。如下程序清单所示代码是


int __init init_module(void)
{
int retval;
ne_add_devices();
retval = platform_driver_probe(&ne_driver, ne_drv_probe);
if (retval) {
if (io[0] == 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 根据驱动和设备的名称寻找匹配的设备和驱动, 
因此注册驱动必须保证 platform_driver 的 driver.name 字段必须和 platform_device 的 name 相 
同, 否则无法将驱动和设备进行绑定而注册失败。

阅读(2786) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~