[linux]linux设备模型 LDM数据结构

LDM linux设备模型

Linux设备驱动开发》读书笔记

LDM数据结构

LDM上层依赖项

  • 总线 struct bus_type
  • 设备驱动程序 struct device_driver
  • 设备 struct device
  • attribute 属性

总线

  • 设备和处理器之间的通道,是所有该类设备的父设备
    • I2C总线,I2C设备挂载到I2C总线上,I2C总线提供协议和一些通用性内容
struct bus_type {
    const char        *name;       /*总线名称*/
    const char        *dev_name;
    struct device        *dev_root;
    struct device_attribute    *dev_attrs;    /* use dev_groups instead */
    const struct attribute_group **bus_groups;   /*总线属性*/
    const struct attribute_group **dev_groups;   /*设备属性*/
    const struct attribute_group **drv_groups;   /*驱动属性*/
 
    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 (*online)(struct device *dev);
    int (*offline)(struct device *dev);
 
    int (*suspend)(struct device *dev, pm_message_t state);
    int (*resume)(struct device *dev);
 
    const struct dev_pm_ops *pm;
 
    const struct iommu_ops *iommu_ops;
 
    struct subsys_private *p;
    struct lock_class_key lock_key;
}
  • 参数
    match 让总线确定某个设备能否匹配指定的驱动
    例如设备树中 table添加 “I2C”
    probe 匹配完成 调用该函数
    dev_groups 总线上的设备的默认属性
    bus_group 保存一套默认属性

  • 总线除了定义bud_type之外,还需要定义总线特有的驱动程序和设备

    • 分别拓展通用struct device_driver和struct device
    • 例如:
      struct mybus_device;
      struct mybus_driver;
      
  • 总线驱动程序

    • 总线本身是驱动,所以也需要自己的register接口
      • 为探测匹配的物理设备分配特定的设备结构
      • 依据通用的struct device和struct driver获取总线设备和总线设备驱动程序
      • 初始化设备的bus和parent
      • 向LDM内核注册设备
  • 总线管理的列表

    • 添加到总线的设备列表
    • 添加到总线的驱动程序列表
    • 总线提供给device的核心接口函数: device注册和device_driver注册(allocregister
    mybus_device_alloc
    mybus_device_register
    
  • NOTE

    • I2C设备需要挂载到I2C总线上,因为所有的I2C设备底层通讯的逻辑一样,但是不同的I2C设备会有不同功能,比如sensorled;所以会有自己的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 */
    	enum probe_type probe_type;
     
    	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);
    	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;
    }
    
  • 核心函数

    • driver_register 用来向总线注册设备驱动的底层函数,将驱动添加到总线的驱动列表中

设备

struct device {
	struct device		*parent;

	struct device_private	*p;

	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.
					 */

	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 */
	void		*driver_data;	/* Driver data, set and get with
					   dev_set/get_drvdata */
	struct dev_pm_info	power;
	struct dev_pm_domain	*pm_domain;

#ifdef CONFIG_PINCTRL
	struct dev_pin_info	*pins;
#endif

#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. */
	unsigned long	dma_pfn_offset;

	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_DMA_CMA
	struct cma *cma_area;		/* contiguous memory area for dma
					   allocations */
#endif
	/* arch specific additions */
	struct dev_archdata	archdata;

	struct device_node	*of_node; /* associated device tree node */
	struct fwnode_handle	*fwnode; /* firmware device node */

	dev_t			devt;	/* dev_t, creates the sysfs "dev" */
	u32			id;	/* device instance */

	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 iommu_group	*iommu_group;

	bool			offline_disabled:1;
	bool			offline:1;
};
  • 核心函数

    • device_register 函数功能为遍历驱动程序的总线列表,查找支持改设备的驱动程序,然后把设备添加到总线的设备列表中
  • 整个流程

    • 会先调用总线驱动程序的匹配方法(bus_type->match),如果匹配是该总线类型设备就会调用总线驱动的probe方法(bus_type->probe),给出设备和驱动程序作为参数
    • 然后由总线驱动程序调用设备驱动程序的probe方法(driver->probe)
    • mybus为例: mybus_device_register(struct mybus_device *dev)
      • 设备驱动程序自己内部会调用device_registe,参数来自mybus_device_alloc

LDM实现

依赖

  • kobject
  • kobj_type
  • kset

kobject

设备模型的核心
  • 主要用于计数以及提供设备层次和他们之间的关系
  • 每个内核设备直接或者间接嵌入kobject属性
  • kobject作用:
    • kobject代表了sysfs文件系统的目录name就是目录名
    • parent指定了在sysfs文件系统中的位置
      • kobject的父项为NULL,那么kobject_add将其父项设置为kset;若二者都是NULL,那么该对象将成为顶级sys目录的一级子目录
    • ktypekobject的属性,属性就用文件表示,放在kobject对应的目录下

kobj_type

主要用于描述kobject行为
  • 嵌入kobject的每个结构都需要相应的kobj_type
    struct kobj_type {
    void (*release)(struct kobject *kobj); 释放kobject和其占用资源的函数
    const struct sysfs_ops *sysfs_ops;      操作下一个属性数组的方法
    struct attribute **default_attrs;        属性数组
    
    };
    
  • 参数
    default_attrs定义kobject的默认属性
    sysfs_ops定义如何操作这些属性

kset

将相关的内核对象组合在一起(集合)

属性

  • 属性将内核数据映射到sysfs中的文件中

  • 可以通过属性定义kobjectsysfs系统下的读写权限(o644)

  • 所谓的attibute,就是内核空间和用户空间进行交互的一种方式

    • 例如某个driver定义了一个变量,却希望用户空间程序可以修改该变量,以控制driver的运行行为,那么就可以将该变量以sysfs attribute的形式开放出来
  • 属性类型

    • 普通的attribute
    struct attribute {
        const char        *name;
        umode_t            mode;
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
        bool            ignore_lockdep:1;
        struct lock_class_key    *key;
        struct lock_class_key    skey;
    #endif
    }
    
    • 二进制attribute
    struct bin_attribute {
       struct attribute    attr;
       size_t            size;
       void            *private;
       ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *,
               char *, loff_t, size_t);
       ssize_t (*write)(struct file *,struct kobject *, struct bin_attribute *,
                char *, loff_t, size_t);
       int (*mmap)(struct file *, struct kobject *, struct bin_attribute *attr,
               struct vm_area_struct *vma);
    };
    
    • struct attribute为普通的attribute,使用该attribute生成的sysfs文件,只能用字符串的形式读写
      • struct bin_attributestruct attribute的基础上,增加了read/write等函数,因此它所生成的sysfs文件可以用任何方式读写

设备模型和sysfs

linux存在一个虚拟文件系统sysfs,内核使用它实现与用户空间直接的简单交互,内核启动后会将sysfs自动挂载到/sys

  • 上述功能通过kobject,kobj_type,kset实现
    • kobject 某个设备/某类设备
    • kobj_type 设备的默认属性(包括sysfs_ops)
    • kset kobject的集合
  • 用户空间操作内核的设备方法
    • 设备虚拟化为/dev/下的节点,read/write/ioctl操作
    • /proc
    • /sysfs
  • sysfs是非持久性虚拟文件,通过kobject显示内核对象的层次结构
    • 设备和驱动程序的功能通过sysfs进行公开(给用户)
    • kobject显示为目录;目录下的文件称为属性,可以读写
    build:/sys$ tree -L 1 .
    .
    ├── block
    ├── bus
    ├── class
    ├── dev          //以无层次方式包含已注册的设备节点,每个节点都是/sys/device目录中真实设备的符号链接
    ├── devices
    ├── firmware
    ├── fs
    ├── hypervisor
    ├── kernel
    ├── module
    └── power
    
    • kobject被添加到sysfs(kobject_add),添加位置取决于kobject父项
      • 若父指针已设置,则它被添加到父目录内的子目录
      • 若父指针为NULL,将其添加到kset->kobj的子目录
      • 若二者都未设备,映射到/sysfs根目录
    • 操作kobject对象时可以使用sysfs_{create|remove}_link操作对象的符号链接,允许对象存在于多个位置
      • 对象被删除时要删除相应的符号链接

sysfs文件和属性

sysfs文件的默认设置是通过kobjectkset中的ktypekobj_typedefault_attrs设置
除此之外可以使用除了创建自己的ktypekobject来添加属性外,还可以使用当前存在的设备驱动程序总线属性

设备属性(DEVICE_ATTR)

使用例子

  • 除了嵌入到设备中的kobject的默认属性外,还可以自定义属性

    struct device_attribute {
    	struct attribute    attr;
    	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
    			char *buf);
    	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
    			 const char *buf, size_t count);
    }
  • 使用DEVICE_ATTR宏来声明

    #define DEVICE_ATTR(_name, _mode, _show, _store) \
    	struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
    
    • 设备属性可以在该设备驱动初始化时使用sysfs_create_file接口将属性添加到dev->kob中,退出时使用sysfs_remove_file接口删除

除设备属性外,总线属性(BUS_ATTR),设备驱动程序属性(DRIVER_ATTR),类属性(CLASS_ATTR)使用流程和设备属性相同

  • NOTE
    • 之前对所有相同的kobject/ktype的所有属性定义一套相同的store/show回调函数,而现在针对每个属性使用自定义回调
      • 参考C++类的使用,kobject在继承kobject的基础上可以定义自己属性结构
      • 设备真实使用的回调函数实际上也是每个属性自己定义的回调函数(fix me)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值