主要参考:http://blog.chinaunix.net/uid-26285146-id-3307147.html
http://blog.chinaunix.net/uid-26285146-id-3307147.html
重要的结构体
<1>struct device <linux/device.h>
//用于描述设备相关的信息设备之间的层次关系,以及设备与总线、驱动的关系
http://blog.csdn.net/abo8888882006/article/details/5424363
重要成员:
void *platform_data; /* Platform specific data, device core doesn‘t touch it */
struct device_driver *driver;
//指向被分配到该设备的设备驱动
//在really_probe(struct device *dev, struct device_driver *drv)函数中dev->driver = drv;将设备和驱动绑定
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
struct bus_type *bus;
//在platform_device_add()中pdev->dev.bus = &platform_bus_type;
struct device *parent; //指向其父设备在platform_device_add中被赋值为&platform_bus;
void (*release)(struct device * dev); //释放设备描述符的回调函数
<2>struct resource <linux/ioport.h>
//这个结构表示设备所拥有的资源,即I/O端口、I/O映射内存、中断及DMA等。这里的地址指的是物理地址。
成员:
resource_size_t start; //定义资源的起始地址
resource_size_t end; //定义资源的结束地址
const char *name; //定义资源的名称
unsigned long flags; //定义资源的类型,比如MEM,IO,IRQ,DMA类型
struct resource *parent, *sibling, *child;
<3>struct device_driver <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 driver_private *p;
device_driver提供了一些操作接口,但其并没有实现,相当于一些虚函数,由派生类platform_driver进行重载,无论何种类型的driver都是基于device_driver派生而来的,具体的各种操作都是基于统一的基类接口的,这样就实现了面向对象的设计。
device_driver结构中name变量和platform_device中name变量一致。内核正是通过这个一致性来为驱动程序找到资源,即 platform_device中的resource。
<4>struct platform_device <linux/platform_device.h>
成员:
const char * name; //定义平台设备的名称,此处设备的命名应和相应驱动程序命名一致
int id;
struct device dev; //描述了设备的情况,platform_device由device派生而来,是一种特殊的device
u32 num_resources;
struct resource * resource; //定义平台设备的资源
<4>struct platform_driver <linux/platform_device.h>
//该结构中需要实现 shutdown,suspend,resume这三个函数,若不支持,将他们设为null。
成员:
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 device_driver driver;
重要函数
<1>
platform_device_register(srtuct platform_device *pdev) // drivers/base/platform.c
//调用platform_device_add(pdev)注册到platform总线上
//platform_device_add调用device_add()
platform_device_unregister()
device_register(struct device *dev) // linux/drivers/base/core.c
//调用device_add(dev)
//将该device对象dev插入设备模型中
device_unregister()
device_register()和 platform_device_register()都会首先初始化设备,区别在于第二步:其实platform_device_add()包括 device_add(),不过要先注册resources,然后将设备挂接到特定的platform总线。
<2>
platform_driver_register(struct platform_driver *drv) // drivers/base/platform.c
//调用driver_register(&drv->driver)
platform_driver_unregister()
platform_device_alloc() //动态申请一个platform_device设备
然后通过platform_device_add_resources及platform_device_add_data等添加相关资源和属性。
//最终通过platform_device_add注册到platform总线上
<3>platform_add_devices()
系统中的设备资源可以通过指针数组列举在一起
static struct platform_device *smdk6410_devices[] __initdata = {
......
&s3c_device_usbgadget,
&s3c_device_usb, //jeff add.
......
}
然后在初始化函数中执行
platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));将所有的device添加进系统。platform_add_devices的好处在于它是一次性的执行多个platform_device_register。
device和driver的绑定的实现
<1>虚拟总线 "platform"的属性和操作的定义: // drivers/base/platform.c
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
//总线bus是联系driver和device的中间枢纽。Device通过所属的bus找到driver,由match操作方法进行匹配。
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
...
return (strcmp(pdev->name, drv->name) == 0);
}
<2>设备注册platform_device_register()->platform_device_add()->(pdev->dev.bus = &platform_bus_type)把设备挂在虚拟的platform bus下;
<3>驱动注册platform_driver_register(struct platform_driver *drv)
->driver_register(struct device_driver *drv)
->bus_add_driver(struct device_driver *drv)
->driver_attach(struct device_driver *drv) //return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
->bus_for_each_dev(),对每个挂在虚拟的platform bus的设备作__driver_attach(struct device *dev, void *data)
->driver_probe_device(struct device_driver *drv, struct device *dev),
判断drv->bus->match()是否存在并且是否执行成功,此时通过指针执行platform_match,比较strncmp(pdev->name, drv->name, BUS_ID_SIZE),
如果相符就调用really_probe(struct device *dev, struct device_driver *drv)//driver_sysfs_add()
在该函数中有drv->probe(dev):调用device_driver的probe(dev),实际就是执行的相应设备的platform_driver->probe(platform_device)
probe函数一般完成硬件设备使能,struct resource的获取以及虚拟地址的动态映射和具体类型设备的注册(因为平台设备只是一种虚拟的设备类型);remove函数完成硬件设备的关闭,struct resource以及虚拟地址的动态映射的释放和具体类型设备的注销
注意:platform_drv_probe的_dev参数是由bus_for_each_dev的next_device获得)开始真正的探测加载,如果probe成功则绑定该设备到该驱动。
int bus_for_each_dev(struct bus_type * bus,
struct device * start,
void * data,
int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device * dev;
int error = 0;
if (!bus)
return -EINVAL;
klist_iter_init_node(&bus->klist_devices, &i,
(start ? &start->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}
<4>init/main.c中:
start_kernel 》 rest_init 》 kernel_init 》 do_basic_setup》driver_init 》platform_bus_init初始化platform_bus(虚拟总线);(先)
start_kernel 》 rest_init 》 kernel_init 》 do_basic_setup》do_initcalls platform driver和platform device的初始化(后)
创建了platform_bus设备,后续platform的设备都会以此为parent。在sysfs中表示为:所有platform类型的设备都会添加在 platform_bus所代表的目录下,即 /sys/devices/platform下面