从platform驱动看驱动模型

从platform_driver看驱动模型,

一. device kset 和 bus kset

根据sys的结构图,我们知道,在sysfs中,首先注册的是bus,devices

而buses_init

       bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);

该函数调用

Kset_create(name,uevent_ops,parent_kobj)

Kset_register(kset)

 

Kset_create(name,uevent_ops,parent_kobj)

简单的就是生成一个kset结构,

而Kset_register(kset)

就是将此kset注册(对于kset->kobj->kset为空的则,自己创建为kset头,否则将此kset添加入kset->kobj->kset所指向的kset链表)

 

Bus 总 kset

static struct kset_uevent_ops bus_uevent_ops = {

       .filter = bus_uevent_filter,

};

 

Device   总 kset

static struct kset_uevent_ops device_uevent_ops = {

       .filter =  dev_uevent_filter,

       .name =        dev_uevent_name,

       .uevent =      dev_uevent,

};

 

具体生成的bus_kset如下,

我们知道由kobject 决定了层次目录,以此为基础进行分析

      

二.platform bus 和device 已经目录下driver和device

       Platform_bus

Platform_bus_init

---------àdevice_register(&platform_bus); 注册到device目录下

struct device platform_bus = {

       .bus_id         = "platform",

};

               ---------------àdevice_initialize(dev)                

              ----------------àdevice_add(dev)

kobject的层次决定目录,我们可以知道

Platform_bus这一device,其platform_bus->kobj->parent=device_kset->kobj

同时,能通过device_kset->kobj->list遍历整个所有的kobj,实际上与遍历文件一样

 

同时,根据kset容器的定义,可以知道kset目录下放置的全是device,而实际上这些device->kset=device_kset,                                 

 

所以可以想象,device目录下的结构图为,

从platform驱动看驱动模型_第1张图片

 

 

---------àbus_register(&platform_bus_type);注册到bus目录下

 

 

 

由于 bus总线下总是绑定着设备和驱动,这样就有了

bus_type_priveate->klist_devicesbus_type_private->klist_drivers

通过将总线上的device(实际只是链接关系,真正的device在device_kset下)通通添加到bus_type_private->klist_devices上,将总线上的驱动通通添加到bus_type_private->klist_drivers上

 

其中bus_type_priveate->device_kset对应的bus下的device目录

bus_type_private->driver_kset对应的bus下的driver目录

 

而显然,由目录关系我们知道

Bus_type_private->subsys->kobj->parent=bus_kset->kobj;

Bus_type_private->subsys->kobj->kset=bus_kset;

 

同时,能通过bus_kset->kobj->list遍历bus整个所有的kobj,实际上与遍历文件一样

 

而bus下的device目录(kset->parent=bus_type_private->subsys->kobj)

Driver目录(kset->parent=bus_type_private->kobj)

 

三.platform_driver_register,platform_device_register

以上两步之后,就等着设备和驱动来注册了

 

分别调用platform_driver_register,platform_device_register

 

Platform_device_register

 

static struct platform_device test_device={

       .name="test_ts",

       .id=-1;

}

 

If(!pdev->id!=-1)

       Id=-1,表明设备只有一个,用设备名为bus_id,

就是将pdev->name赋值给pdev->dev.bus_id

 

而ID不为1,表明设备有多个,需要用序号来表明bus_id

pdev->dev.bus_id=pdev->name +‘.’+pdev->id

 

补充platform中资源的应用

简单的就是将对应资源添加到对应的资源树中

比如,

如果platform的资源r是IORESOUCE_MEM,则其parent resource p则为

Iomem_resouce

如果资源为IORESOUCE_IO,则为ioprot_resource

然后调用insert_resource(p,r)将资源添加到资源树中

struct resource iomem_resource = {

       .name     = "PCI mem",

       .start      = 0,

       .end       = -1,

       .flags     = IORESOURCE_MEM,

};

struct resource ioport_resource = {

       .name     = "PCI IO",

       .start      = 0,

       .end       = IO_SPACE_LIMIT,

       .flags     = IORESOURCE_IO,

};

 

在bus_attach_device中,先是检查属性文件drivers_autoprobe是否为1,

为1,则调用device_attach,

如果返回为大于等于0的值(未匹配成功),则将设备挂在bus的klist_device下,当驱动请求匹配的时候,platform bus总线就会遍历devices链表为驱动查找合适的设备。具体代码就是

Klist_add_tail(&dev->knode_bus,&bus->p->klist_devices)

 

对于device_attach,就是对所有的driver调用driver_probe_device,查找是否有匹配的driver

一般是先检测drv->bus->match是否存在,存在则调用(platform match 存在),match主要是检查driverDevicename是否一样,如果一样则调用probe,否则继续查找

接着是检测drv->bus->probe是否存在,存在则调用(platform bus不存在),否则调用drv->probe,而drv->probe又会转而调用具体的platform_driver->probe

 

 

platform_driver_register

static struct platform_driver test_driver={

       .probe = test_probe,

       .remove =test_remove,

       .driver={

       .name="test_ts",

       .owner=THIS_MODULE,

       },

}

在platform_driver_register中,如果platform_driver定义了.Probe,

.remove,

则其内嵌的driver的probe和remove也会相应的设置platform对应的函数,从而能够调用platform_driver的probe和remove。

具体就是

       if (drv->probe)

              drv->driver.probe = platform_drv_probe;

       if (drv->remove)

              drv->driver.remove = platform_drv_remove;

 

    driver_register(&drv->driver)

然后通过内嵌的driver调用driver_register进行注册

Driver_register的调用流程如下:

(1)         检测总线的操作函数和驱动的操作函数是否同时存在,同时存在,则使用总线提供的操作函数

(2)         检测是否已经注册过

(3)         添加驱动到总线上 bus_add_drv(drv)

(4)         添加驱动到组driver_add_groups(drv,drv->groups)

 

Bus_add_drv中,

主要在如果driver_autoprobe设置为1,则调用driver_attach(和device_attach类似),并且将驱动添加到klist_drivers中,

Klist_add_tail(&priv->knode_bus,&bus->p->klist_drivers)

Module_add_driver(drv->owner,drv)// 与/sys/modules */ module_kset有关

 

经过这样之后,platform驱动模型就建立好了

 

四.文件的操作和ktype

       上面说到的autoprobe的属性文件就是ktype提供的一种修改内核参数的方法。

       建立属性文件autoprobe的方法不提,一般使用的sysfs_create_file

而通过系统的调用,文件的操作会调用sysfs_file_operation

       const struct file_operations sysfs_file_operations = {


        .read                = sysfs_read_file,


        .write                = sysfs_write_file,


        .llseek                = generic_file_llseek,


        .open                = sysfs_open_file,


        .release        = sysfs_release,


        .poll                = sysfs_poll,


};

 

在sysfs_open_file中,我们通过file找到sysfs_dirent,再由sysfs_dirent找到对应的kobj结构,(文件对应的kobj)

Struct sysfs_buffer *buffer;

Struct sysfs_ops *ops;

在该函数中,

       这种重定向ops的方法,在讲ALSA驱动框架时,说到打开/dev/dsp也提到过。

       Ktype作用正在于此

       If(kobj->ktype&&kobj->ktype->sysfs_ops)

              Ops=kobj->ktype->sysfs_ops;

       …

然后将设置好的ops挂在在buffer上,

       Buffer->ops=ops;

       File->private_data=buffer;

 

而在sysfs_read_file和sysfs_write_file中,通过这种方式,一路跟踪,最后

分别调用了(对于bus的autoprobe文件而言)

       Bus_attr->show(bus_priv->bus,buf)

       Bus_attr->store(bus_priv->bus,buf)

这里就是在定义属性文件时提到的.show和.Store

 

总的来说基本上,驱动模型大致是这样,不过其中的class,uevent等没有细说

你可能感兴趣的:(从platform驱动看驱动模型)