Linux 驱动模型初探2——device_driver
1,思考
device_driver也是一个kobject?,但你注意没有,在sys/目录下有bus/,有device/就是没有device_driver/,Y?为什么这么设计?
先看struct devic_driver;
struct device_driver {
const char *name;
struct bus_type *bus;
...
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);
...
const struct dev_pm_ops *pm;
struct driver_private *p;
};
虽然 device_driver中没有kobject,但他的driver_private成员中有kobject,
struct driver_private {
struct kobject kobj;
...
};
但如何证明,他使用这个private数据的kobj来与其它kojb来交互呢,看driver_register()中,bus_add_driver(struct device_driver *drv)是通过kobject/kset与bus来进行“连接”的。
kobject_init_and_add(&priv->kobj,
&driver_ktype, NULL, "%s", drv->name);kobject的add也是通过priv->kobj。建议把bus_add_driver记住,后续还有使用。
好,第一个问题回答了,那么第二个问题?其实跟第一个的回答一样,在bus_add_driver的函数中。先看一下调用关系:
int driver_register(struct device_driver *drv)
->
bus_add_driver(struct device_driver *drv)
->
priv->kobj.kset = bus->p->drivers_kset;
kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,"%s", drv->name);
->
kobject_add_varg(kobj, parent, fmt, args);
->
kobject_add_internal(kobj);
->
/* join kset if set, use it as parent if we do not already have one */
if (kobj->kset) {
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
kobj_kset_join(kobj);
kobj->parent = parent;
}
答案应这段code。因为kobj->kset已经赋值,所以此时的kobj->parent就是bus->p->drivers_kset。所以,新加的driver都会在bus中的driver文件件中,而不是/sys/下的一个drivers文件夹。
第三个问题,为什么这样设计?
暂时没想通,架构层面的东西,可以上升到了哲学观了。我期待有哲人指点,或者周公托梦。
2,driver_register(struct device_driver *drv)走读
读register函数之前,先看一上struct device_driver的类图(只列出关键成员)
再看一下,driver_register(),我把几个关键的函数Highlight出来
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
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);
other = driver_find(drv->name, drv->bus);
if (other) {
printk(KERN_ERR "Error: Driver ‘%s‘ is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret) {
bus_remove_driver(drv);
return ret;
}
kobject_uevent(&drv->p->kobj, KOBJ_ADD);
return ret;
}
该函数的核心函数是bus_add_driver,在前面基本上已经分析了,他就是在指定bus(busy_type类型)的drivers文件夹中添加自己,内部的逻辑就是添加到bus->p->klist_drivers的链表中。
顺便讲一下,开关的if判断
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
如果drv和drv->bus都实现了probe/remove/shutdown方法,就会有个警告打印。看上面的类图也可以看到有两个Probe,从Warning的信息来看,如果bus实现了probe函数,就使用bus的。但我们知道,bus上可以挂很多driver,实操中应该是不实现bus的probe,而且是留给相应的driver去实现。那么两个probe有啥关系?看一张关系图(来处网友tynew)
如果都实现了,会打印这种错误
再看driver_add_groups函数,是把driver结构体中**groups添加到sys文件系统中(看上面类图)
再看kobject_uevent(&drv->p->kobj, KOBJ_ADD);函数是处理KOBJ_ADD的事件,里面会调用call_usermodehelper(argv[0],
argv, env->envp, UMH_WAIT_EXEC);启动一个用户程序。这就是uevent的功能
3,kf_driver的实现
code:(完整版见github项目)
static int kf_device_driver_probe(struct device *dev){
printk("enter drive probe\n");
return 0;
}
static struct device_driver kf_device_driver={
.name = "kf-device-driver",
.probe = kf_device_driver_probe,
};
static int kf_device_dirver_register(void){
int ret = -1;
kf_device_driver.bus = &kf_bus_type;//指定挂在哪条bus(bus_type)上
ret = driver_register(&kf_device_driver);
printk("kf_device_driver reister ok!\n");
return ret;
}
static void kf_device_dirver_unregister(void){
driver_unregister(&kf_device_driver);
}
编译成ko,在平台上,insod上去,我们来看看sys文件系统。
在/sys/bus/kf-bus/driver中增加了一些文件
kf-device-driver就是我们新加的dirver的name
driver_register()->bus_add_driver()->kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, "%s", drv->name);
->...->kobject_add_internal(kobj);生成kf-device-dirver
那bind uevent unbind呢?
uevent:
driver_register()->bus_add_driver()->driver_create_file(drv, &driver_attr_uevent);
bind,unbind
driver_register()->bus_add_driver()->add_bind_files(drv);
->driver_create_file(drv, &driver_attr_unbind); driver_create_file(drv, &driver_attr_bind);
driver还有一个很重要的函数__driver_attach。他跟bus的__device_attach殊途同归,看它们是怎么走在一起的?看上面的关系图。