深入浅出Linux内核模块篇 15.1Linux的设备驱动管理之内核对象(Kernel object)机制

Posted 内核笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入浅出Linux内核模块篇 15.1Linux的设备驱动管理之内核对象(Kernel object)机制相关的知识,希望对你有一定的参考价值。

在这里插入图片描述

平台内核版本安卓版本
RK3399Linux4.4android7.1

前言:

面向对象的思想就是一切事物皆对象,Linux的设备驱动管理将运用这一思想对各式各样的设备、总线以及驱动进行管理。在此可以感受到老子说的:一生二,二生三,三生万物。


1、对象的“一生二”

内核对象(kernel object)是将一个数据结构 Struct kobject 作为一种公共连接部件定义到更高层的其他数据结构中去,而各个高层数据结构之间的关系通过 kobject结构以不同的链表方式表示,从而形成结构紧密的上下层次关联。通过这种 kobject 结构,可以清晰地描述总线、设备、设备上的接口等相互间的关系,使之变得更有层次,也便于系统管理者了解系统状况。

1.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;
};

2、对象的“二生三”

管理的基础对象kobjectkset定义好了,那么就需要开始贴合实际,延伸出一些通用的管理类型结构。于是就有了:设备、驱动和总线,它们都将视为对象而存在。

2.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.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;
};

2.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;
};

2.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;
}

3、对象的“三生万物”

到现在已经定义好了设备、驱动、总线和类。如何衍生系统中的设备万物呢?

3.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而已。

3.2、device_driver衍生

它也是从device_driver衍生出来的数据类型,同样,它也类似于设备一样,有一个偏移定位结构位置的宏定义to_pci_driver。类似的USB设备驱动有usb_driverI2C设备驱动有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;
};

以上是关于深入浅出Linux内核模块篇 15.1Linux的设备驱动管理之内核对象(Kernel object)机制的主要内容,如果未能解决你的问题,请参考以下文章

深入浅出Linux内核模块篇 15.2Linux 设备驱动模型的初始化

Linux疑难杂症解决方案100篇(十五)-万字长文带你深入Linux 内核学习:环境搭建和内核编译

Linux疑难杂症解决方案100篇(十五)-万字长文带你深入Linux 内核学习:环境搭建和内核编译

深入浅出分析Linux内核slab性能优化的核心思想

如何编译一个linux下的驱动模块

linux内核模块编译makefile