SDIO驱动(7)sdio总线结尾

来源:互联网 发布:java报表技术实例 编辑:程序博客网 时间:2024/05/22 02:16

Linux 2.6.38

SDIO总线:

static struct bus_type sdio_bus_type = {
    .name        = "sdio",
    .dev_attrs    = sdio_dev_attrs,
    .match        = sdio_bus_match,

    .uevent        = sdio_bus_uevent,
    .probe        = sdio_bus_probe,
    .remove        = sdio_bus_remove,
    .pm        = SDIO_PM_OPS_PTR,
};

remove,模块卸载时调用,结合之前的介绍,sdio_bus_remove函数一看就明白。

pm,电源管理(Power Manager)相关,这些年来kernel的PM可谓风云变幻,有志研究的TZ参见“电源管理子系统”系列文章。

uevent,这个可以单独拿出来,所以这里就带着sdio_bus_uevent回调简单说下:
1、uevent是什么?user event的缩写,用于kernel和user之间热插拔事件通信的机制。
2、通信如何实现?内核中的netlink模块(netlink man page),即socket通信。

3、典型例子:udev,Android等。

看下sdio_bus_uevent的实现:

static int sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env){struct sdio_func *func = dev_to_sdio_func(dev);if (add_uevent_var(env,"SDIO_CLASS=%02X", func->class))return -ENOMEM;if (add_uevent_var(env, "SDIO_ID=%04X:%04X", func->vendor, func->device))return -ENOMEM;if (add_uevent_var(env,"MODALIAS=sdio:c%02Xv%04Xd%04X",func->class, func->vendor, func->device))return -ENOMEM;return 0;}
这个函数关键点就一个:add_uevent_var,用来设置环境变量,这样发送数据格式:

SDIO_CLASS=0x7890
用户空间收到这个uevent事件后进行解析,进而获取了关心的内容。

sdio_bus_uevent的调用流程:

static int dev_uevent(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env){if (dev->bus && dev->bus->uevent) {retval = dev->bus->uevent(dev, env);}}static const struct kset_uevent_ops device_uevent_ops = {.filter =dev_uevent_filter,.name =dev_uevent_name,.uevent =dev_uevent,};/** * kobject_uevent_env - send an uevent with environmental data * * @action: action that is happening * @kobj: struct kobject that the action is happening to * @envp_ext: pointer to environmental data * * Returns 0 if kobject_uevent_env() is completed with success or the * corresponding error when it fails. */int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp_ext[]){const struct kset_uevent_ops *uevent_ops;struct kobject *top_kobj;struct kset *kset;/* search the kset we belong to */top_kobj = kobj;while (!top_kobj->kset && top_kobj->parent)top_kobj = top_kobj->parent;kset = top_kobj->kset;uevent_ops = kset->uevent_ops;/* skip the event, if the filter returns zero. */if (uevent_ops && uevent_ops->filter)if (!uevent_ops->filter(kset, kobj)) {pr_debug("kobject: '%s' (%p): %s: filter function " "caused the event to drop!\n", kobject_name(kobj), kobj, __func__);return 0;}/* originating subsystem */if (uevent_ops && uevent_ops->name)subsystem = uevent_ops->name(kset, kobj);elsesubsystem = kobject_name(&kset->kobj);/* let the kset specific function add its stuff */if (uevent_ops && uevent_ops->uevent) {retval = uevent_ops->uevent(kset, kobj, env);}}
kobject是device的一个成员,kset是同一类设备的集合,如果设置了device->kobject->kset就是说我们为这个设备指定了类别,那32行的while循环不会执行。如果没有指定,就得沿着device的parent一级一级向上查找。

37行,获取上面的dev_uevent回调,之后的代码流程就水到渠成了。事件产生,调用各个设备的通用的event,bus对应某个总线特定的event信息。


至此我们知道了sdio总线的种种,那么对于i2c、usb、spi等等总线(虚拟总线plateform),亦是如此。

0 0