您的位置:首页 > 其它

从platform驱动看驱动模型

2013-09-05 10:53 239 查看
从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目录下的结构图为,







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









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

bus_type_priveate->klist_devices和bus_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主要是检查driver和Device的name是否一样,如果一样则调用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等没有细说

Copyright © 1999-2012, CSDN.NET, All Rights Reserved



查看所有通知

暂没有新通知

返回通知列表
下一条
上一条

您有0条新通知

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: