一、前言:
面向对象的思想就是一切事物皆对象,Linux
的设备驱动管理将运用这一思想对各式各样的设备、总线以及驱动进行管理。在此可以感受到老子说的:一生二,二生三,三生万物。
二、对象的“一生二”
内核对象(kernel object
)是将一个数据结构 Struct kobject
作为一种公共连接部件定义到更高层的其他数据结构中去,而各个高层数据结构之间的关系通过 kobject
结构以不同的链表方式表示,从而形成结构紧密的上下层次关联。通过这种 kobject
结构,可以清晰地描述总线、设备、设备上的接口等相互间的关系,使之变得更有层次,也便于系统管理者了解系统状况。
1、内核对象机制主要数据结构
Kobject
是内核对象机制中最基本的数据结构,在最初的设计构思中,仅仅是想将其作为一个引用计数器。
随着时间的推移,kobjects
的作用越来越大。该结构一般不独立存在,它总是被包含在上层数据结构中,包含 kobject
的上层数据结构通过内核对象来描述与其他数据结构之间的关系。看看 kobject
的处理函数,就会发现他们其实是为其他对象提供服务的,从另一个角度来说,kobject
跟自身利益没什么关系,它仅仅为高层对象与设备模型提供纽带,用面向对象的方法,kobjects
可以看作是顶层,其他类都由该抽象类派生的。
struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
struct kobj_type *ktype;
struct kernfs_node *sd; /* sysfs directory entry */
struct kref kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
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;
};
- 其中
parent
表示父对象,诸如总线和设备就是父子关系。 - 而
sd
则与sysfs
的目录项进行关联,简而言之就是每一个kobject
都对应着一个sysfs
下面的目录。 - 至于
kref
主要是对该对象的引用进行计数管理。 - 对
ktype
的类型kobj_type
进行展开
struct kobj_type {
void (*release)(struct kobject * kobj);
const struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs; /* use default_groups instead */
const struct attribute_group **default_groups;
const struct kobj_ns_type_operations *(*child_ns_type) (struct kobject * kobj);
const void *(*namespace)(struct kobject * kobj);
void (*get_ownership)(struct kobject * kobj, kuid_t * uid, kgid_t * gid);
};
sysfs_ops
这是打开sysfs文件对象后的操作接口集合default_groups
表示对象的属性信息
struct attribute_group {
const char *name;
umode_t(*is_visible) (struct kobject *, struct attribute *, int);
umode_t(*is_bin_visible) (struct kobject *, struct bin_attribute *, int);
struct attribute **attrs;
struct bin_attribute **bin_attrs;
};
三、对象的“二生三”
管理的基础对象kobject
和kset
定义好了,那么就需要开始贴合实际,延伸出一些通用的管理类型结构。于是就有了:设备、驱动和总线,它们都将视为对象而存在。
1、device
struct device {
/*父设备 */
struct device *parent;
/*该device的私有变量 */
struct device_private *p;
/*该设备对应的kobject */
struct kobject kobj;
const char *init_name; /* initial name of the device */
const struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to
* its driver.
*/
/*该device所需要注册的总线 */
struct bus_type *bus; /* type of bus device is on */
/*该设备所绑定的驱动 */
struct device_driver *driver; /* which driver has allocated this
device */
/*platform模块相关的参数,device-bus-driver模型不关心该变量 */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
/*电源管理相关的内容 */
struct dev_pm_info power;
struct dev_pm_domain *pm_domain;
/*引脚配置相关的内容,可实现对该设备关联的引脚进行初始化与设置操作 */
#ifdef CONFIG_PINCTRL
struct dev_pin_info *pins;
#endif
/*numa相关的内容,本次不涉及 */
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
/*以下为dma 相关的内容 */
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 */
#ifdef CONFIG_CMA
struct cma *cma_area; /* contiguous memory area for dma
allocations */
#endif
/* arch specific additions */
struct dev_archdata archdata;
/*该变量主要用于设备树模块使用,该device_node表示dts中的节点信息,当开启OF宏时,driver会根据该device_node
中的节点名称以及driver中of相关的节点名称,进行device-driver的匹配检测操作,从而支持设备树 */
struct device_node *of_node; /* associated device tree node */
struct acpi_dev_node acpi_node; /* associated ACPI device node */
/*设备号,当为block/char设备时,需要设置该值,通过该值会实现该设备对应kobject与/sysfs/dev/char 、/sysfs/dev/block
对应的kobject的链接关联 */
dev_t devt; /* dev_t, creates the sysfs "dev" */
u32 id; /* device instance */
spinlock_t devres_lock;
struct list_head devres_head;
/*链接至系统class模块的kset的链表中 */
struct klist_node knode_class;
/*该设备所属的类 */
struct class *class;
/*该设备的默认属性组 */
const struct attribute_group **groups; /* optional groups */
/*release接口,当对该设备进行释放其kobject时,会通过dev_kobj_type的release接口进行device的释放(
该接口会调用device->release进行device的释放操作)。 */
void (*release)(struct device * dev);
struct iommu_group *iommu_group;
};
2、device_driver
struct device_driver {
const char *name;/*驱动名称*/
struct bus_type *bus;/*该驱动所依附的总线*/
/*该驱动所属module*/
struct module *owner;
/*模块的名称*/
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
/*设备树使用的设备id*/
const struct of_device_id *of_match_table;
const struct acpi_device_id *acpi_match_table;
/*该驱动的探测接口*/
int (*probe) (struct device *dev);
/*该驱动的移除接口*/
int (*remove) (struct device *dev);
/*shutdown 、suspend、resume主要是对应电源管理方面的接口*/
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
/*该驱动所相关的属性接口,主要用于与sysfs模块管理*/
const struct attribute_group **groups;
/*性能管理相关的内容*/
const struct dev_pm_ops *pm;
/*该驱动模块相关的私有变量,主要包括驱动对应的kobject、所属模块的kobject等*/
struct driver_private *p;
};
struct driver_private {
/*该驱动对应的kobject*/
struct kobject kobj;
/*用于汇聚该驱动所绑定的所有设备*/
struct klist klist_devices;
/*用于链接至xxx_bus_type的klist_drivers链表上*/
struct klist_node knode_bus;
/*该驱动所属模块的kobject*/
struct module_kobject *mkobj;
/*指向本driver_private类型变量所属的driver变量*/
struct device_driver *driver;
};
3、bus_type
struct bus_type {
/*总线名称*/
const char *name;
/*总线对应设备名称*/
const char *dev_name;
/*该总线对应的device*/
struct device *dev_root;
struct bus_attribute *bus_attrs;/*总线属性*/
struct device_attribute *dev_attrs;/*设备属性*/
struct driver_attribute *drv_attrs;/*驱动属性*/
/*match接口,用于进行device与driver的匹配*/
int (*match)(struct device *dev, struct device_driver *drv);
/*uevent接口,用于发送kobject event,供应用层mdev/udev使用*/
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
/*总线的probe接口,该接口会调用具体驱动的probe接口*/
int (*probe)(struct device *dev);
/*总线的remove接口,一般该接口主要是调用具体驱动的remove接口*/
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;/*pm相关*/
struct iommu_ops *iommu_ops;
/*该接口包含了该bus对应kobject、device对应的kset、driver对应的kset、
链接所有设备的链表、链接所有驱动的链表等*/
struct subsys_private *p;
struct lock_class_key lock_key;
};
4、class
struct class {
const char *name;
struct module *owner;
/*该变量定义了该类别默认的属性*/
struct class_attribute *class_attrs;
/*该变量定义了所有属性该类别的设备所定义的默认的属性*/
struct device_attribute *dev_attrs;
struct bin_attribute *dev_bin_attrs;
struct kobject *dev_kobj;
/*事件接口(用于向应用层发送事件如class设备的添加与移除等)*/
int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
char *(*devnode)(struct device *dev, umode_t *mode);
/*释放接口*/
void (*class_release)(struct class *class);
void (*dev_release)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
const struct kobj_ns_type_operations *ns_type;
const void *(*namespace)(struct device *dev);
const struct dev_pm_ops *pm;
struct subsys_private *p;
}
四、对象的“三生万物”
到现在已经定义好了设备、驱动、总线和类。如何衍生系统中的设备万物呢?
1、继承device特性进行扩展
设备种类纷繁复杂,我们必须挑个典型来看,否则就有可能迷失其中,那就从PCI
开始,以PCI
进行展开,然后举一反三进行类比思考。
首先还是设备相关的,PCI
总线上的设备都会有一个设备类型,它就是pci_dev
,它的结构体比较庞大。
struct pci_dev {
struct list_head bus_list; /* Node in per-bus list */
struct pci_bus *bus; /* Bus this device is on */
struct pci_bus *subordinate; /* Bus this device bridges to */
...
struct device dev; /* Generic device interface */
...
}
我们可以看到有这么一个数据成员:struct device dev
。对的,它就是继承了device
特性扩展而来的,在Linux
的设备驱动管理框架中则可以看到这么一个宏定义to_pci_dev
,通过device
找到pci_dev
结构。同样的,类似的usb_device
,定义usb
设备类型的,它里面同样也嵌入了一个device
结构成员,它也有一个to_usb_device
的宏定义。继续推进i2c_device
也是嵌入了device
结构成员,只是它通过了i2c_adapter
间接嵌入的,但是它同样有一个偏移定位结构位置的宏定义to_i2c_adapter
,虽然只是定位到i2c_adapter
而已。
2、device_driver衍生
它也是从device_driver
衍生出来的数据类型,同样,它也类似于设备一样,有一个偏移定位结构位置的宏定义to_pci_driver
。类似的USB
设备驱动有usb_driver
,I2C
设备驱动有i2c_driver
。
struct pci_driver {
struct list_head node;
const char *name;
const struct pci_device_id *id_table; /* Must be non-NULL for probe to be called */
int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */
void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */
int (*suspend)(struct pci_dev *dev, pm_message_t state); /* Device suspended */
int (*suspend_late)(struct pci_dev *dev, pm_message_t state);
int (*resume_early)(struct pci_dev *dev);
int (*resume)(struct pci_dev *dev); /* Device woken up */
void (*shutdown)(struct pci_dev *dev);
int (*sriov_configure)(struct pci_dev *dev, int num_vfs); /* On PF */
const struct pci_error_handlers *err_handler;
const struct attribute_group **groups;
struct device_driver driver;
struct pci_dynids dynids;
};