首页 > 代码库 > platform驱动模型一

platform驱动模型一

主要参考: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 = http://www.mamicode.com/{

......

 &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下面

 

platform驱动模型一