linux内核学习之总线驱动设备ksetkobject
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux内核学习之总线驱动设备ksetkobject相关的知识,希望对你有一定的参考价值。
最近在研究总线的注册、设备与驱动在总线上的注册、驱动如何找到总线上的设备进行匹配、设备又如何找到总线上的设备进行匹配,在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为例子,因为是比较特殊的。不贴代码,详细看内核源码。
(1)总线注册函数bus_register,kobject是bus_type->p->sysbus->kobj
注册platform_bus时:
初始化platform_bus->p私有数据。
platform_bus的kobject->kset指向bus_kset,。
platform_bus的kobject->parent指向bus_kset->kobj,。
platform_bus的kobject->entry节点加入到bus_kset->list链表中。
初始化platform_bus->p->drivers_kset(用来管理总线下的驱动的集合)。
初始化platform_bus->p->devices_kset(总线下的设备的kobject不会加入这个集合, 但是利用软连接链入这个集合)。
(2)设备注册函数device_register, kobject是device->kobj
我先贴个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);
...
...
}
以上是关于linux内核学习之总线驱动设备ksetkobject的主要内容,如果未能解决你的问题,请参考以下文章
面向对象地分析Linux内核设备驱动——Linux内核设备模型与总线