原文地址:http://blog.chinaunix.net/uid-24631445-id-3420457.html
简述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目录。
!!!需补充例子...
待续...
阅读(1804) | 评论(0) | 转发(0) |