通过自己的语言描述linux设备模型思想,Linux设备模型(总结)

本文详细解析了Linux内核设备模型的注册过程,展示了如何使用C语言实现面向对象编程思想。从设备和驱动的注册、kobject和kset的管理,到sysfs接口的创建,以及设备和驱动的匹配与绑定,揭示了内核中的封装、继承和多态特性。通过pci_driver和platform_driver等示例,阐述了如何在内核中实现类的继承和方法重写,强调了面向对象在内核设计中的重要性。
摘要由CSDN通过智能技术生成

int device_add(struct device *dev) //主要流程{dev = get_device(dev);parent = get_device(dev->parent);kobject_set_name(&dev->kobj, "%s", dev->bus_id);dev->kobj.parent = &parent->kobj;kobject_add(&dev->kobj);//将自身kobject加入到层次结构中,并且建立sysfs entry.

//设置uevent_attr:

dev->uevent_attr.attr.name = "uevent";dev->uevent_attr.attr.mode = S_IWUSR;

if (dev->driver)dev->uevent_attr.attr.owner = dev->driver->owner;dev->uevent_attr.store = store_uevent;device_create_file(dev, &dev->uevent_attr);

//建立显示设备号的sysfs入口,即当前设备入口下的"dev"文件显示设备主从设备号。

if (MAJOR(dev->devt)) {attr->attr.name = "dev";attr->attr.mode = S_IRUGO;if (dev->driver)attr->attr.owner = dev->driver->owner;attr->show = show_dev;error = device_create_file(dev, attr);}

//建立类的sysfs符号连接if (dev->class) {sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj,"subsystem");sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,dev->bus_id);}sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");class_name = make_class_name(dev->class->name, &dev->kobj);sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);}

error = bus_add_device(dev);//添加一些bus相关的sysfs符号连接

/*设置环境变量,然后调用call_usermodehelper (argv[0], argv, envp, 0); 引起热拔插事件用户空间脚本执行。*/

kobject_uevent(&dev->kobj, KOBJ_ADD);

bus_attach_device(dev); /*如

果dev->driver已经存在,调用device_bind_driver(dev);进行绑定,否则遍历dev->bus上

drivers列表,调用dev->bus.match(dev,drv)来看是否有一个驱动与该dev匹配。如果匹配则绑定。*/

} OK,上述是主要流程。。

下面是register_driver(drv)函数:

int driver_register(struct device_driver * drv)

{

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);

}

klist_init(&drv->klist_devices, klist_devices_get, klist_devices_put);

init_completion(&drv->unloaded);

return bus_add_driver(drv);

}

driver_register(drv);-->bus_add_driver(drv);

int bus_add_driver(struct device_driver * drv)

{

struct bus_type * bus = get_bus(drv->bus);error = kobject_set_name(&drv->kobj, "%s", drv->name);drv->kobj.kset = &bus->drivers; //驱动隶属于总线的驱动集合

error = kobject_register(&drv->kobj);//注册自身kobject

driver_attach(drv);//添加驱动到总线 klist_add_tail(&drv->knode_bus, &bus->klist_drivers);

module_add_driver(drv->owner, drv);

driver_add_attrs(bus, drv);

add_bind_files(drv);

}

driver_register(drv);-->bus_add_driver(drv);-->driver_attach(drv);

void driver_attach(struct device_driver * drv)

{

bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

}

对总线上的每个设备dev,调用__driver_attach(dev,drv);最终调用

driver_probe_device(drv, dev);

driver_register(drv);-->bus_add_driver(drv);-->driver_attach(drv);

-->__driver_attach(dev,drv);-->driver_probe_device(drv, dev);

int driver_probe_device(struct device_driver * drv, struct device * dev)

{if (drv->bus->match && !drv->bus->match(dev, drv))

goto Done;//优先调用总线提供匹配方法dev->driver = drv;

if (dev->bus->probe) {

ret = dev->bus->probe(dev);//总线的探测方法

}

else if (drv->probe)

{

ret = drv->probe(dev); //用dev->driver的探测方法

}

device_bind_driver(dev); /*探测成功则绑定设备到驱动,添加dev到drv的设备列表并且建立驱动与设备在sys/入口中相互关联的符号连接*/

goto Done;

Done:

return ret;

}

乱七八糟的。主线还是模型的层次关系。对kobject,kset细节中关于属性,热拔插,sys入口的部分没有深入。或许,理解总体和设计思想是更重要的。人的精力真的有限。

四、面向对象的思想在linux设备模型中的应用分析.

过设备模型,看到了面向对象编程思想用C语言的实现。内核中常见到封装了数据和方法的结构体,这是面向对象封装特性的实现。而这里展现的更多的是继承方面

的实现。比如说pci_driver,它的父类是device_driver,而更上一层是一个kobject。在C++中,继承一个父类则子类中相应的

包含父类的一个实例。内核中也是通过包含一个父类的实体来实现这种派生关系。因此,一个pci_driver内部必然包含一个

device_driver,同样,device_driver内部必然包含一个kobject。

上面提到过,注册一个模型的过程类似于面向对象中构造函数的调用。子类需要调用父类构造函数来完成自身的构造。再来看看注册一个pci_driver的过程:

pci_register_driver(struct pci_driver *driver)

-->driver_register(&drv->driver);

-->kobject_register(&drv->kobj);

这不是OO中的继承么?

备模型源码中还能找到多态(虚函数)的思想。看到pci_driver和device_driver中提供了差不多同名的方法不觉得奇怪吗??它们不同的

地方在于参数。pci_driver中方法的参数是pci_device * dev ,而device_driver方法的参数则是 device *

dev 。这么安排是有意的!最典型的例子莫过于platform_driver和device_driver。struct platform_driver {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 (*resume)(struct platform_device *);struct device_driver driver;};

这显然比pci_driver来得简洁。platform_driver除了包含一个device_driver,其它就是5个与device_driver同名的方法。

注册一个platform_driver的过程:

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;

return driver_register(&drv->driver);

}

这里设置了platform_driver包含的device_driver的函数指针。看看这些函数中的platform_drv_probe。

static int platform_drv_probe(struct device *_dev)

{

struct platform_driver *drv = to_platform_driver(_dev->driver);

struct platform_device *dev = to_platform_device(_dev);

return drv->probe(dev);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值