简述struct device相关的东西。
类似于bus_type,kobject是嵌入在struct device中的。
而且device也有device_attribute。
用struct device声明一个设备,然后用device_register函数来注册,完后用device_unregister注销设备。
用struct device_attribute定义设备属性,或用DEVICE_ATTR宏来定义,对属性文件的处理使用
device_create_file函数和device_remove_file函数。
这里以platform_bus_init()函数来为例来介绍设备注册的过程。
platform_bus_init是在设备初始化过程中调用的函数,对应于目录/sys/devices/platform。
1:struct device
这个结构体比较复杂。
- struct device {
- struct device *parent;
- struct device_private *p;
- struct kobject kobj;
- const char *init_name; /* initial name of the device */
- struct device_type *type;
- struct semaphore sem; /* semaphore to synchronize calls to its driver. */
- struct bus_type *bus; /* type of bus device is on */
- struct device_driver *driver; /* which driver has allocated this device */
- void *platform_data; /* Platform specific data, device core doesn't touch it */
- struct dev_pm_info power;
- #ifdef CONFIG_NUMA
- int numa_node; /* NUMA node this device is close to */
- #endif
- u64 *dma_mask; /* dma mask (if dma'able device) */
- u64 coherent_dma_mask;/* Like dma_mask, but for
- alloc_coherent mappings as
- not all hardware supports
- 64 bit addresses for consistent
- allocations such descriptors. */
- struct device_dma_parameters *dma_parms;
- struct list_head dma_pools; /* dma pools (if dma'ble) */
- struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */
- /* arch specific additions */
- struct dev_archdata archdata;
- dev_t devt; /* dev_t, creates the sysfs "dev" */
- spinlock_t devres_lock;
- struct list_head devres_head;
- struct klist_node knode_class;
- struct class *class;
- const struct attribute_group **groups; /* optional groups */
- void (*release)(struct device *dev);
- };
- struct driver_private {
- struct kobject kobj;
- struct klist klist_devices;
- struct klist_node knode_bus;
- struct module_kobject *mkobj;
- struct device_driver *driver;
- };
platform_bus的定义如下:
- struct device platform_bus = {
- .init_name = "platform",
- };
在platform_bus_init(void)中调用了“error = device_register(&platform_bus);”下面主要分析device_register函数
2:device_register(struct device *)
- int device_register(struct device *dev)
- {
- device_initialize(dev);
- return device_add(dev);
- }
意外的只有两句,先初始化设备,然后add设备。
3:device_initialize(struct device *)
- void device_initialize(struct device *dev)
- {
- /* 先初始化dev->kobj */
- dev->kobj.kset = devices_kset;
- kobject_init(&dev->kobj, &device_ktype);
-
- /* 初始化其他部分 */
- INIT_LIST_HEAD(&dev->dma_pools);
- init_MUTEX(&dev->sem);
- spin_lock_init(&dev->devres_lock);
- INIT_LIST_HEAD(&dev->devres_head);
- device_init_wakeup(dev, 0);
- device_pm_init(dev);
- set_dev_node(dev, -1);
- }
那么前两句将dev->kobj的kset初始化为devices_kset, ktype初始化为device_ktype。
devices_kset是在函数devices_init中初始化的,
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
device_ktype的定义如下:
- static struct kobj_type device_ktype = {
- .release = device_release,
- .sysfs_ops = &dev_sysfs_ops,
- };
-
- /* 先尝试dev->release,在尝试dev->type->release,最后尝试dev->class->dev_release */
- static void device_release(struct kobject *kobj)
- static struct sysfs_ops dev_sysfs_ops = {
- .show = dev_attr_show,
- .store = dev_attr_store,
- };
- static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
- {
- struct device_attribute *dev_attr = to_dev_attr(attr);
- struct device *dev = to_dev(kobj);
- ssize_t ret = -EIO;
- if (dev_attr->show)
- ret = dev_attr->show(dev, dev_attr, buf);
- ...
- }
- static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
- {
- struct device_attribute *dev_attr = to_dev_attr(attr);
- struct device *dev = to_dev(kobj);
- ssize_t ret = -EIO;
- if (dev_attr->store)
- ret = dev_attr->store(dev, dev_attr, buf, count);
- return ret;
- }
可见device_ktype与bus_ktype类似。对show和store函数的调用最终还是要调用device_attribute中指定的show与store函数。
4:device_add(struct *dev)
核心函数,该函数比较复杂。
- int device_add(struct device *dev)
- {
- struct device *parent = NULL;
- struct class_interface *class_intf;
- int error = -EINVAL;
-
- /* 调用了kobject_get(&dev->kobj) */
- dev = get_device(dev);
- if (!dev)
- goto done;
- if (!dev->p) {
- /* 分配了一个device_private对象,并初始化dev->p->klist_children */
- error = device_private_init(dev);
- if (error)
- goto done;
- }
- /* 对platform_bus变量来说,这里将dev->kobj.name设成"platform" */
- if (dev->init_name) {
- dev_set_name(dev, "%s", dev->init_name);
- dev->init_name = NULL;
- }
- if (!dev_name(dev))
- goto name_error;
- pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
- /* platform_bus->parent为NULL, setup_parent函数用于设定dev->kobj.parent的值*/
- parent = get_device(dev->parent);
- setup_parent(dev, parent);
- /* use parent numa_node */
- if (parent)
- set_dev_node(dev, dev_to_node(parent));
- /* first, register with generic layer. */
- /* we require the name to be set before, and pass NULL */
- /* 调用kobject_add将dev->kobj加入设备模型,这里parent为NULL,因此此处将
- dev->kobj加入了devices_kset, 并将dev->kobj.parent = devices_kset->kobj */
- error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
- if (error)
- goto Error;
- /* notify platform of device entry */
- if (platform_notify)
- platform_notify(dev);
-
- /* 创建属性文件,即uevent文件 (在注册pci_bus_type时也有它)*/
- error = device_create_file(dev, &uevent_attr);
- if (error)
- goto attrError;
- if (MAJOR(dev->devt)) {
- error = device_create_file(dev, &devt_attr);
- if (error)
- goto ueventattrError;
- error = device_create_sys_dev_entry(dev);
- if (error)
- goto devtattrError;
- devtmpfs_create_node(dev);
- }
- /* 对于platform_bus变量来说,下面的函数均无作用(是我选的device不好,有点特殊)*/
- error = device_add_class_symlinks(dev);
- if (error)
- goto SymlinkError;
- error = device_add_attrs(dev);
- if (error)
- goto AttrsError;
- error = bus_add_device(dev);
- if (error)
- goto BusError;
- error = dpm_sysfs_add(dev);
- if (error)
- goto DPMError;
- device_pm_add(dev);
- /* Notify clients of device addition. This call must come
- * after dpm_sysf_add() and before kobject_uevent().
- */
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_ADD_DEVICE, dev);
- kobject_uevent(&dev->kobj, KOBJ_ADD);
- bus_probe_device(dev);
- if (parent)
- klist_add_tail(&dev->p->knode_parent,
- &parent->p->klist_children);
- if (dev->class) {
- mutex_lock(&dev->class->p->class_mutex);
- /* tie the class to the device */
- klist_add_tail(&dev->knode_class,
- &dev->class->p->class_devices);
- /* notify any interfaces that the device is here */
- list_for_each_entry(class_intf,
- &dev->class->p->class_interfaces, node)
- if (class_intf->add_dev)
- class_intf->add_dev(dev, class_intf);
- mutex_unlock(&dev->class->p->class_mutex);
- }
- done:
- put_device(dev);
- return error;
- /* 下面都是错误处理相关的代码,已省略 */
- .........
- }
好吧,这个platform_bus的例子不太好,该变量太特殊,并没有具体的设备,因此device_add函数里很多函数没有用到。
通常在device_register之前需要设置好device对象的parent, bus_id, bus和release成员,但platform_bus仅设定了init_name,
可见对platform_bus的注册主要就是调用kobject_add函数在/sys/devices目录下创建个platform目录。
!!!需补充例子...
待续...
阅读(282) | 评论(0) | 转发(0) |