鸟的迁徙纪录片中文版:Linux驱动下的platform总线架构详解
来源:百度文库 编辑:偶看新闻 时间:2024/05/15 09:51:44
从 Linux 2.6 内核起,引入一套新的驱动管理和注册机制:platform_device 和 platform_driver 。
Linux 中大部分的设备驱动,都可以使用这套机制,设备用 platform_device 表示;驱动用 platform_driver 进行注册。
Linux platform driver 机制和传统的 device driver 机制(即:通过 driver_register函数进行注册)相比,一个十分明显的优势在于 platform 机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中用使用这些资源时,通过platform device 提供的标准接口进行申请并使用。
platform 是一个虚拟的地址总线,相比PCI、USB,它主要用于描述 SOC 上的片上资源。比如 S3C2410 上集成的控制器(LCD、Watchdog、RTC等),platform 所描述的资源有一个共同点:在 CPU 的总线上直接取址。
平台设备会分到一个名称(用在驱动绑定中)以及一系列诸如地址和中断请求号(IRQ)之类的资源。
struct platform_device { // include/linux/platform_device.h
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
};
***************************************************************************
/*
* 主要用于定义具体设备占用的硬件资源(如:地址空间、中断号等)。
*/
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
***************************************************************************
platform 总线下驱动的开发步骤是:
1、设备
设备注册中,需要实现的机构体是:platform_device 。
1)初始化 resource 结构变量
2)初始化 platform_device 结构变量
3)向系统注册设备:platform_device_register。(以上三步,必须在 设备驱动加载前完成,所以,AT91RM9200 的内核下,该三步是放在 arch/arm/mach-at91/board-dk.c 中)
2、驱动
驱动注册中,需要实现的结构体是:platform_driver 。
struct platform_driver { // include/linux/platform_device.h
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 (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct pm_ext_ops *pm;
struct device_driver driver;
};
在驱动程序的初始化函数中,调用了 platform_driver_register() 注册 platform_driver 。
需要注意的是:platform_driver 和 platform_device 中的 name 变量的值必须是相同的 。这样在
platform_driver_register()注册时,会将当前注册的 platform_driver 中的 name 变量的值和已注册的所有 platform_device 中的 name变量的值进行比较,只有找到具有相同名称的 platform_device 才能注册成功。当注册成功时,会调用 platform_driver结构元素 probe 函数指针。
rtc-ds1302.c 中,驱动首先执行:
********************************************************************
static int __init ds1302_rtc_init(void)
{
return platform_driver_register(&ds1302_platform_driver);
}
********************************************************************
然后,进入:drivers/base/platform.c:platform_driver_register()
********************************************************************
/**
* platform_driver_register
* @drv: platform driver structure
*/
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
if (drv->suspend)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
if (drv->pm)
drv->driver.pm = &drv->pm->base;
return driver_register(&drv->driver);
}
此处,对drv->driver 结构体中的几个函数指针进行初始化设置。最后,调用 driver_register 注册 driver 成员。
drv->driver 的类型是:
struct platform_driver { // include/linux/platform_device.h
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 (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct pm_ext_ops *pm;
struct device_driver driver; // drv->driver
};
struct device_driver { // include/linux/device.h
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
struct attribute_group **groups;
struct pm_ops *pm;
struct driver_private *p;
};
********************************************************************
然后,进入:drivers/base/driver.c:driver_register
********************************************************************
/**
* driver_register - register driver with bus
* @drv: driver to register
*
* We pass off most of the work to the bus_add_driver() call,
* since most of the things we have to do deal with the bus
* structures.
*/
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus);
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n
Linux 中大部分的设备驱动,都可以使用这套机制,设备用 platform_device 表示;驱动用 platform_driver 进行注册。
Linux platform driver 机制和传统的 device driver 机制(即:通过 driver_register函数进行注册)相比,一个十分明显的优势在于 platform 机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中用使用这些资源时,通过platform device 提供的标准接口进行申请并使用。
platform 是一个虚拟的地址总线,相比PCI、USB,它主要用于描述 SOC 上的片上资源。比如 S3C2410 上集成的控制器(LCD、Watchdog、RTC等),platform 所描述的资源有一个共同点:在 CPU 的总线上直接取址。
平台设备会分到一个名称(用在驱动绑定中)以及一系列诸如地址和中断请求号(IRQ)之类的资源。
struct platform_device { // include/linux/platform_device.h
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
};
***************************************************************************
/*
* 主要用于定义具体设备占用的硬件资源(如:地址空间、中断号等)。
*/
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
***************************************************************************
platform 总线下驱动的开发步骤是:
1、设备
设备注册中,需要实现的机构体是:platform_device 。
1)初始化 resource 结构变量
2)初始化 platform_device 结构变量
3)向系统注册设备:platform_device_register。(以上三步,必须在 设备驱动加载前完成,所以,AT91RM9200 的内核下,该三步是放在 arch/arm/mach-at91/board-dk.c 中)
2、驱动
驱动注册中,需要实现的结构体是:platform_driver 。
struct platform_driver { // include/linux/platform_device.h
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 (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct pm_ext_ops *pm;
struct device_driver driver;
};
在驱动程序的初始化函数中,调用了 platform_driver_register() 注册 platform_driver 。
需要注意的是:platform_driver 和 platform_device 中的 name 变量的值必须是相同的 。这样在
platform_driver_register()注册时,会将当前注册的 platform_driver 中的 name 变量的值和已注册的所有 platform_device 中的 name变量的值进行比较,只有找到具有相同名称的 platform_device 才能注册成功。当注册成功时,会调用 platform_driver结构元素 probe 函数指针。
rtc-ds1302.c 中,驱动首先执行:
********************************************************************
static int __init ds1302_rtc_init(void)
{
return platform_driver_register(&ds1302_platform_driver);
}
********************************************************************
然后,进入:drivers/base/platform.c:platform_driver_register()
********************************************************************
/**
* platform_driver_register
* @drv: platform driver structure
*/
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
if (drv->suspend)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
if (drv->pm)
drv->driver.pm = &drv->pm->base;
return driver_register(&drv->driver);
}
此处,对drv->driver 结构体中的几个函数指针进行初始化设置。最后,调用 driver_register 注册 driver 成员。
drv->driver 的类型是:
struct platform_driver { // include/linux/platform_device.h
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 (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct pm_ext_ops *pm;
struct device_driver driver; // drv->driver
};
struct device_driver { // include/linux/device.h
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
struct attribute_group **groups;
struct pm_ops *pm;
struct driver_private *p;
};
********************************************************************
然后,进入:drivers/base/driver.c:driver_register
********************************************************************
/**
* driver_register - register driver with bus
* @drv: driver to register
*
* We pass off most of the work to the bus_add_driver() call,
* since most of the things we have to do deal with the bus
* structures.
*/
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus);
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n
linux下的硬件驱动
linux下的数据采集驱动
linux 下的网卡驱动问题
linux下网卡驱动
SM总线控制的驱动
SM总线控制器驱动那里下?
如何可以得到Linux Fedora下的网卡驱动源码
在linux系统下怎么安装X550XT显卡的驱动?
linux kernel 2.6的网卡驱动下栽和设置?
求教:关于linux下D-link驱动的问题!
我的网卡在linux下找不到驱动,咋办?
linux 的网卡驱动
linux下串口驱动如何实现?
LINUX下如何安装网卡驱动,谢谢
linux下ati显卡怎么驱动?
linux下如何装载声卡驱动
SM总线控制的驱动是不是就是主板的驱动
platform technology 指的什么?
Linux下的几个问题
linux下的光盘启动
LINUX下的问题!!!
在linux下的
AGP 总线驱动?
ubs总线怎么样驱动