Linux 驱动模型初探3——device
讲device之前,我要引入一个比喻,这个比喻来自一个学长(z2007b)。driver是帅哥,device是美女,bus是红娘,bus是提供device和driver配对的场所(方法?)。好吧,暂时先这样定,现在要讲的就是美女。
1,老规则,先看看struce device这个美女有哪些特性(成员)和方法
struct device {
struct device *parent;
struct device_private*p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
...
struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
...
}
看一下类图(类图被我整得错综复杂,还不知道怎么组织好,先截一小段)
2,device_register()方法
int device_register(struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}
先分析device_initialize(dev);大体上知道它的功能:初始化device结构体,包括list/mutex/pm/...
->
dev->kobj.kset = devices_kset;
kobject_init(&dev->kobj, &device_ktype);//前面两句,是到/sys/目录下新建一个devices目录。
INIT_LIST_HEAD(&dev->dma_pools);
mutex_init(&dev->mutex);
lockdep_set_novalidate_class(&dev->mutex);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
device_pm_init(dev);
set_dev_node(dev, -1);
再分析device_add(dev);大致功能是把初始化好的device回到系统的device层级中
device_private_init(dev);//如果private成员没初始化,在这里init。
|
dev_set_name(dev, "%s", dev->init_name);
->kobject_set_name_vargs(&dev->kobj, fmt, vargs);
//如果指定了device的init_name;通过kobject_set_name_vargs,实际是把init_name赋给了dev->kobject->name
|
if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
//如果没指定init_name;那么就把其所在的bus->dev_name + dev->id组合成一个dev-kobject->name的名字
|
kobject_add(&dev->kobj, dev->kobj.parent, NULL);//回到kobject系统中,这样就管理他的uevent,kref等。已经指定了名字,为什么传一个NULL值呢?
|
device_create_file(dev, &uevent_attr);//创建uevent属性
|
device_create_file(dev, &devt_attr);//如果dev->devt已经实例化了,那么就建立相关dev节点。其中devt是MKDEV函数的返回值
|
device_add_class_symlinks(dev);//如果实例化了class,那么建立class的symlink
|
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);//通过uevent机制,通知用户层,比如有设备插入,可以挂载了。
|
->
if (bus->p->drivers_autoprobe) { //在device_init中已经把这个置1了。
}
3,kf_device的实现
code片断:
static void kf_device_release(struct device *dev){
printk("%s\n",__func__);
}
static struct device kf_device={
.init_name = "kf-device0",
.devt = MKDEV(KFMAJOR,1),
.release = kf_device_release,
};
static int kf_device_register(void){
int ret = -1;
//Do not point this class
//kf_device.class = &kf_class;
kf_device.bus = &kf_bus_type;
kf_device.parent = &kf_bus;
ret = device_register(&kf_device);
if(ret < 0){
printk("kf device reister error!\n");
}
printk("kf device reister ok!\n");
return ret;
}
static void kf_device_unregister(void){
device_unregister(&kf_device);
}
编译成ko,在平台上,insod上去,我们来看看sys文件系统。
uevent:
1,device_register(struct device *dev)->device_add(dev)->device_create_file(dev, &uevent_attr);
2,如果指定了class,就会在class目录里面建相关目录,通过函数
device_add_class_symlinks(dev);
device_add_attrs(dev);
3,如果指定了相关bus,就会在/sys/bus/里面建相关节点
bus_add_device(dev);
power:
1,device_register(struct device *dev)->device_add(dev)->dpm_sysfs_add(dev);->ysfs_merge_group(&dev->kobj, &pm_runtime_attr_group);
->pm_runtime_attr_group就是power目录,同时这个目录里面的几个文件
static struct attribute *runtime_attrs[] = {
#ifdef CONFIG_PM_RUNTIME
#ifndef CONFIG_PM_ADVANCED_DEBUG
&dev_attr_runtime_status.attr,
#endif
&dev_attr_control.attr,
&dev_attr_runtime_suspended_time.attr,
&dev_attr_runtime_active_time.attr,
&dev_attr_autosuspend_delay_ms.attr,
#endif /* CONFIG_PM_RUNTIME */
NULL,
};
2,struct device中device_driver成员,而struct device_driver中没有device成员,
也可以说明device(美女)很专一,她只能有指定的驱动。
而device_driver(帅哥)很花心,他很有很多device,所以他不能指定某个设备在他的成员中。