最近在研究总线的注册、设备与驱动在总线上的注册、驱动如何找到总线上的设备进行匹配、设备又如何找到总线上的设备进行匹配,在linux2.6以后,这些过程都离不开设备驱动模型,所以也与kset、kobjcet有关。
kobject就是一个对象,kset就是所有相同对象的集合,linux的设备驱动模型是用C语言实现面向对象。用linux时使用ls命令查看的文件和目录就是对应每一个kobject。
一.设备device、驱动device_driver、总线bus_type、kobject、kset结构如下:
(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 mutex mutex; /* mutex 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; #ifdef CONFIG_OF struct device_node *of_node; #endif 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 device_private
struct device_private { struct klist klist_children; struct klist_node knode_parent; struct klist_node knode_driver; /* knode_bus: * 1.注册设备时会将knode_bus成员加入到设备所在总线bus->p->klist_devices链,表示已注册到总线 * 2.同理,注销设备时会在设备所在总线bus->p->klist_devices链寻找设备->p->knode_bus节点并移除 */
struct klist_node knode_bus; void *driver_data; /* device: * 常指向设备自己,这样就可以通过device_private找到device */
struct device *device; };
(2)struct device_driver
struct device_driver { const char *name; struct bus_type *bus; struct module *owner; const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
#if defined(CONFIG_OF)
const struct of_device_id *of_match_table; #endif
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 attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; };
struct driver_private
struct driver_private { struct kobject kobj; struct klist klist_devices; /* knode_bus: * 1.注册设备时会将knode_bus成员加入到设备所在总线bus->p->klist_devices链,表示已注册到总线 * 2.同理,注销设备时会在设备所在总线bus->p->klist_devices链寻找设备->p->knode_bus节点并移除 */
struct klist_node knode_bus; struct module_kobject *mkobj; /* driver: * 常指向驱动自己, 这样就可以通过driver_private找到device_driver */
struct device_driver *driver; };
(3)struct bus_type
struct bus_type { const char *name; struct bus_attribute *bus_attrs; struct device_attribute *dev_attrs; struct driver_attribute *drv_attrs; int (*match)(struct device *dev, struct device_driver *drv); int (*uevent)(struct device *dev, struct kobj_uevent_env *env); 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 subsys_private *p; };
struct subsys_private
struct subsys_private { struct kset subsys; struct kset *devices_kset; struct kset *drivers_kset; struct klist klist_devices; /*用于遍历总线下的设备成员*/
struct klist klist_drivers; /* 用于遍历总线下的驱动成员 */
struct blocking_notifier_head bus_notifier; /* 进程上下文通知链 */ unsigned int drivers_autoprobe:1; struct bus_type *bus; struct list_head class_interfaces; struct kset glue_dirs; struct mutex class_mutex; struct class *class; };
(4)struct kobject
struct kobject { const char *name; struct list_head entry; struct kobject *parent; struct kset *kset; struct kobj_type *ktype; struct sysfs_dirent *sd; struct kref kref; unsigned int state_initialized:1; unsigned int state_in_sysfs:1; unsigned int state_add_uevent_sent:1; unsigned int state_remove_uevent_sent:1; unsigned int uevent_suppress:1; };
(5)struct kset
struct kset { struct list_head list; spinlock_t list_lock; struct kobject kobj; const struct kset_uevent_ops *uevent_ops; };
设备、驱动、总线结构都含有1个kobject结构。(device->kobj, device_driver->driver_private->kobj, bus_type->p->subsys->kobj).
在说注册之前,先说一下二个结构bus_kset、devices_kset。这二个结构是在启动内核时调用driver_init中,调用devices_init和buses_init函数初始化的。bus_kset管理所有总线的,devices管理所有物理设备的。其中有一个例外,就是platform_bus结构,平台总线本来就是不存在的,是虚拟出来的一条总线,是一个设备。这里不详说这个。
二.设备、总线、驱动注册
这里我简单的说一下它们在注册时在干什么,以注册platform_bus、platform_dev、platform_driver为例子,其中platform_dev包含device结构,platform_driver包含device_driver结构。不贴代码,详细看内核源码。
(1)总线注册device_register(&platform_bus)与bus_register(&platform_bus_type)。
注册platform_bus时:
初始化platform_bus->p私有数据。
platform_bus的kobject->kset指向devices_kset。
platform_bus的kobject->parent指向devices_kset->kobj。
platform_bus的kobject->entry节点加入到devices_kset->list链表中。
注册platform_bus_type时:
初始化platform_bus_type->p私有数据。
platform_bus_type的kobject->kset指向bus_kset。
platform_bus_type的kobject->parent指向bus_kset->kobj,。
platform_bus_type的kobject->entry节点加入到bus_kset->list链表中。
初始化platform_bus_type->p->drivers_kset(用来管理总线下的驱动的集合)。
初始化platform_bus_type->p->devices_kset(总线下的设备的kobject不会加入这个集合, 但是利用软连接链入这个集合)。
(2)设备注册到总线platform_device_register
我先贴个device_register函数源码出来:
int device_register(struct device *dev) { device_initialize(dev); return device_add(dev); }
而注册platform_device是用platform_device_register函数的:
int platform_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev); return platform_device_add(pdev); } int platform_device_add(struct platform_device *pdev) { int i, ret = 0; if (!pdev) return -EINVAL; if (!pdev->dev.parent) pdev->dev.parent = &platform_bus; pdev->dev.bus = &platform_bus_type; ... ... ret = device_add(&pdev->dev); ... ... }
两者相差指定父设备与总线。device_register只是简单的注册一个设备,然后kobject交给device_kset管理。platform_device_register是注册一个platform_device到platform_bus_type总线下,kobject加入到device_kset但由platform_bus_type总线管理。
所以注册一个platform_device时:
初始化platform_device->dev->p私有数据。
platform_device的kobject->kset指向devices_kset。
platform_device->dev->parent指向platform_bus。
platform_device->dev->bus指向platform_bus_type。
因为platform_device->dev->parent指向platform_bus, 所以platform_device的kobject->parent指向platform_bus->kobj。
platform_device的kobject->entry节点加入到device_kset->list链表中。
platform_device->dev->kobj软连接到platform_bus->p->devices_kset中。
platform_device->dev->p->knode_parent节点加入到platform_bus->p->klist_children链表(klist)中。
platform_device->dev->p->knode_bus节点加入到platform_bus_type->p->klist_devices链表(klist)中。
注册platform_device会遍历platform_bus_type下的所有驱动进行匹配操作。
(3)注册驱动到总线platform_driver_register
贴个platform_driver_register出来,指定总线并最后调用的driver_register
int platform_driver_register(struct platform_driver *drv) { drv->driver.bus = &platform_bus_type; if (drv->probe) drv->driver.probe = platform_drv_probe; if (drv->remove) drv->driver.remove = platform_drv_remove; if (drv->shutdown) drv->driver.shutdown = platform_drv_shutdown; return driver_register(&drv->driver); }
所以注册platform_driver时:
初始化platform_driver->driver->私有数据。
platform_driver->driver->bus指向platform_bus_type。
platform_driver的kobject->kset指向platform_bus_type->p->drivers_kset
platform_driver的kobject->entry节点加入到platform_bus_type->p->drivers_kset->list链表中。
platform_driver->driver->p->knode_bus节点加入到platform_bus_type->p->klist_drivers链表(klist)中。
注册platform_driver会遍历platform_bus_type下的所有设备进行匹配操作。
三、平台总线、驱动、设备注册后的图如下。