1. 前言

在上一节中,蜗蜗大神有提到,由于Linux支持世界上几乎所有的、不同功能的硬件设备(这是Linux的优点),导致Linux内核中有一半的代码是设备驱动,而且随着硬件的快速升级换代,设备驱动的代码量也在快速增长。个人意见,这种现象打破了“简洁就是美”的理念,是丑陋的。它导致Linux内核看上去非常臃肿、杂乱、不易维护。但蜗蜗也知道,这不是Linux的错,Linux是一个宏内核,它必须面对设备的多样性,并实现对应的驱动。

为了降低设备多样性带来的Linux驱动开发的复杂度,以及设备热拔插处理、电源管理等,Linux内核提出了设备模型(也称作Driver Model)的概念。设备模型将硬件设备归纳、分类,然后抽象出一套标准的数据结构和接口。驱动的开发,就简化为对内核所规定的数据结构的填充和实现。

本文将会从设备模型的基本概念开始,通过分析内核相应的代码,一步一步解析Linux设备模型的实现及使用方法。

2. Linux设备模型的基本概念

2.1 Bus, Class, Device和Device Driver的概念

下图是嵌入式系统常见的硬件拓扑的一个示例

device_toplogy

硬件拓扑描述Linux设备模型中四个重要概念中三个:Bus,Class和Device(第四个为Device Driver,后面会说)。

Bus(总线):Linux认为(可以参考include/linux/device.h中struct bus_type的注释),总线是CPU和一个或多个设备之间信息交互的通道。而为了方便设备模型的抽象,所有的设备都应连接到总线上(无论是CPU内部总线、还是虚拟的总线“platform Bus”)。


/*** struct bus_type - The bus type of the device** @name:  The name of the bus.* @dev_name:    Used for subsystems to enumerate devices like ("foo%u", dev->id).* @dev_root:    Default device to use as the parent.* @dev_attrs:   Default attributes of the devices on the bus.* @bus_groups: Default attributes of the bus.* @dev_groups:    Default attributes of the devices on the bus.* @drv_groups: Default attributes of the device drivers on the bus.* @match:   Called, perhaps multiple times, whenever a new device or driver*        is added for this bus. It should return a positive value if the*        given device can be handled by the given driver and zero*       otherwise. It may also return error code if determining that*       the driver supports the device is not possible. In case of*     -EPROBE_DEFER it will queue the device for deferred probing.* @uevent:  Called when a device is added, removed, or a few other things*      that generate uevents to add the environment variables.* @probe:    Called when a new device or driver add to this bus, and callback*       the specific driver's probe to initial the matched device.* @remove:    Called when a device removed from this bus.* @shutdown: Called at shut-down time to quiesce the device.** @online:  Called to put the device back online (after offlining it).* @offline:   Called to put the device offline for hot-removal. May fail.** @suspend: Called when a device on this bus wants to go to sleep mode.* @resume:   Called to bring a device on this bus out of sleep mode.* @pm:       Power management operations of this bus, callback the specific*     device driver's pm-ops.* @iommu_ops:  IOMMU specific operations for this bus, used to attach IOMMU*              driver implementations to a bus and allow the driver to do*              bus-specific setup* @p:       The private data of the driver core, only the driver core can*      touch this.* @lock_key: Lock class key for use by the lock validator** A bus is a channel between the processor and one or more devices. For the* purposes of the device model, all devices are connected via a bus, even if* it is an internal, virtual, "platform" bus. Buses can plug into each other.* A USB controller is usually a PCI device, for example. The device model* represents the actual connections between buses and the devices they control.* A bus is represented by the bus_type structure. It contains the name, the* default attributes, the bus' methods, PM operations, and the driver core's* private data.*/
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;
};

Class(分类):在Linux设备模型中,Class的概念非常类似面向对象程序设计中的Class(类),它主要是集合具有相似功能或属性的设备,这样就可以抽象出一套可以在多个设备之间共用的数据结构和接口函数。因而从属于相同Class的设备的驱动程序,就不再需要重复定义这些公共资源,直接从Class中继承即可。

/*** struct class - device classes* @name:  Name of the class.* @owner: The module owner.* @class_attrs: Default attributes of this class.* @dev_groups:    Default attributes of the devices that belong to the class.* @dev_kobj: The kobject that represents this class and links it into the hierarchy.* @dev_uevent:   Called when a device is added, removed from this class, or a*       few other things that generate uevents to add the environment*      variables.* @devnode:   Callback to provide the devtmpfs.* @class_release: Called to release this class.* @dev_release: Called to release the device.* @suspend:    Used to put the device to sleep mode, usually to a low power*       state.* @resume:    Used to bring the device from the sleep mode.* @shutdown:   Called at shut-down time to quiesce the device.* @ns_type:  Callbacks so sysfs can detemine namespaces.* @namespace:    Namespace of the device belongs to this class.* @pm:        The default device power management operations of this class.* @p:      The private data of the driver core, no one other than the*     driver core can touch this.** A class is a higher-level view of a device that abstracts out low-level* implementation details. Drivers may see a SCSI disk or an ATA disk, but,* at the class level, they are all simply disks. Classes allow user space* to work with devices based on what they do, rather than how they are* connected or how they work.*/
struct class {const char        *name;struct module     *owner;struct class_attribute       *class_attrs;const struct attribute_group   **dev_groups;struct kobject         *dev_kobj;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);int (*shutdown)(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;
};

Device(设备):抽象系统中所有的硬件设备,描述它的名字、属性、从属的Bus、从属的Class等信息。

/*** struct device - The basic device structure* @parent:   The device's "parent" device, the device to which it is attached.*      In most cases, a parent device is some sort of bus or host*         controller. If parent is NULL, the device, is a top-level device,*      which is not usually what you want.* @p:        Holds the private data of the driver core portions of the device.*      See the comment of the struct device_private for detail.* @kobj:    A top-level, abstract class from which other classes are derived.* @init_name:  Initial name of the device.* @type: The type of device.*        This identifies the device type and carries type-specific*      information.* @mutex:   Mutex to synchronize calls to its driver.* @bus:    Type of bus device is on.* @driver: Which driver has allocated this* @platform_data: Platform data specific to the device.*         Example: For devices on custom boards, as typical of embedded*      and SOC based hardware, Linux often uses platform_data to point*        to board-specific structures describing devices and how they*       are wired.  That can include what ports are available, chip*        variants, which GPIO pins act in what additional roles, and so*         on.  This shrinks the "Board Support Packages" (BSPs) and*      minimizes board-specific #ifdefs in drivers.* @driver_data: Private pointer for driver specific info.* @power:  For device power management.*       See Documentation/power/devices.txt for details.* @pm_domain:   Provide callbacks that are executed during system suspend,*         hibernation, system resume and during runtime PM transitions*       along with subsystem-level and driver-level callbacks.* @pins:  For device pin management.*     See Documentation/pinctrl.txt for details.* @msi_list:  Hosts MSI descriptors* @msi_domain: The generic MSI domain this device is using.* @numa_node:   NUMA node this device is close to.* @dma_mask:  Dma mask (if dma'ble device).* @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all*        hardware supports 64-bit addresses for consistent allocations*      such descriptors.* @dma_pfn_offset: offset of DMA memory range relatively of RAM* @dma_parms:   A low level driver may set these to teach IOMMU code about*         segment limitations.* @dma_pools:   Dma pools (if dma'ble device).* @dma_mem:   Internal for coherent mem override.* @cma_area: Contiguous memory area for dma allocations* @archdata:  For arch-specific additions.* @of_node: Associated device tree node.* @fwnode:  Associated device node supplied by platform firmware.* @devt:   For creating the sysfs "dev".* @id:     device instance* @devres_lock: Spinlock to protect the resource of the device.* @devres_head: The resources list of the device.* @knode_class: The node used to add the device to the class list.* @class:  The class of the device.* @groups:  Optional attribute groups.* @release:   Callback to free the device after all references have*      gone away. This should be set by the allocator of the*      device (i.e. the bus driver that discovered the device).* @iommu_group: IOMMU group the device belongs to.* @iommu_fwspec: IOMMU-specific properties supplied by firmware.** @offline_disabled: If set, the device is permanently online.* @offline:    Set after successful invocation of bus type's .offline().** At the lowest level, every device in a Linux system is represented by an* instance of struct device. The device structure contains the information* that the device model core needs to model the system. Most subsystems,* however, track additional information about the devices they host. As a* result, it is rare for devices to be represented by bare device structures;* instead, that structure, like kobject structures, is usually embedded within* a higher-level representation of the device.*/
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 thisdevice */void     *platform_data; /* Platform specific data, devicecore doesn't touch it */void       *driver_data;   /* Driver data, set and get withdev_set/get_drvdata */struct dev_pm_info    power;struct dev_pm_domain  *pm_domain;#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAINstruct irq_domain    *msi_domain;
#endif
#ifdef CONFIG_PINCTRLstruct dev_pin_info    *pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQstruct list_head   msi_list;
#endif#ifdef CONFIG_NUMAint     numa_node;  /* NUMA node this device is close to */
#endifu64       *dma_mask;  /* dma mask (if dma'able device) */u64      coherent_dma_mask;/* Like dma_mask, but foralloc_coherent mappings asnot all hardware supports64 bit addresses for consistentallocations 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 memoverride */
#ifdef CONFIG_DMA_CMAstruct cma *cma_area;      /* contiguous memory area for dmaallocations */
#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;struct iommu_fwspec    *iommu_fwspec;bool          offline_disabled:1;bool         offline:1;
};

Device Driver(驱动):Linux设备模型用Driver抽象硬件设备的驱动程序,它包含设备初始化、电源管理相关的接口实现。而Linux内核中的驱动开发,基本都围绕该抽象进行(实现所规定的接口函数)。


/*** struct device_driver - The basic device driver structure* @name:   Name of the device driver.* @bus:   The bus which the device of this driver belongs to.* @owner:    The module owner.* @mod_name:   Used for built-in modules.* @suppress_bind_attrs: Disables bind/unbind via sysfs.* @probe_type: Type of the probe (synchronous or asynchronous) to use.* @of_match_table: The open firmware table.* @acpi_match_table: The ACPI match table.* @probe:   Called to query the existence of a specific device,*        whether this driver can work with it, and bind the driver*      to a specific device.* @remove: Called when the device is removed from the system to*       unbind a device from this driver.* @shutdown:   Called at shut-down time to quiesce the device.* @suspend:  Called to put the device to sleep mode. Usually to a*       low power state.* @resume:  Called to bring a device from sleep mode.* @groups: Default attributes that get created by the driver core*     automatically.* @pm:        Power management operations of the device which matched*        this driver.* @p:       Driver core's private data, no one other than the driver*       core can touch this.** The device driver-model tracks all of the drivers known to the system.* The main reason for this tracking is to enable the driver core to match* up drivers with new devices. Once drivers are known objects within the* system, however, a number of other things become possible. Device drivers* can export information and configuration variables that are independent* of any specific device.*/
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;
};

注:什么是Platform Bus? 
在计算机中有这样一类设备,它们通过各自的设备控制器,直接和CPU连接,CPU可以通过常规的寻址操作访问它们(或者说访问它们的控制器【寄存器】)。这种连接方式,并不属于传统意义上的总线连接。但设备模型应该具备普适性,因此Linux就虚构了一条Platform Bus,供这些设备挂靠。

2.2 设备模型的核心思想

Linux设备模型的核心思想是(通过xxx手段,实现xxx目的):

1. 用Device(struct device)和Device Driver(struct device_driver)两个数据结构,分别从“有什么用”和“怎么用”两个角度描述硬件设备。这样就统一了编写设备驱动的格式,使驱动开发从论述题变为填空体,从而简化了设备驱动的开发。

2. 同样使用Device和Device Driver两个数据结构,实现硬件设备的即插即用(热拔插)。 
在Linux内核中,只要任何Device和Device Driver具有相同的名字,内核就会执行Device Driver结构中的初始化函数(probe),该函数会初始化设备,使其为可用状态。 
而对大多数热拔插设备而言,它们的Device Driver一直存在内核中。当设备没有插入时,其Device结构不存在,因而其Driver也就不执行初始化操作。当设备插入时,内核会创建一个Device结构(名称和Driver相同),此时就会触发Driver的执行。这就是即插即用的概念。

3. 通过"Bus-->Device”类型的树状结构(见2.1章节的图例)解决设备之间的依赖,而这种依赖在开关机、电源管理等过程中尤为重要。 
试想,一个设备挂载在一条总线上,要启动这个设备,必须先启动它所挂载的总线。很显然,如果系统中设备非常多、依赖关系非常复杂的时候,无论是内核还是驱动的开发人员,都无力维护这种关系。 
而设备模型中的这种树状结构,可以自动处理这种依赖关系。启动某一个设备前,内核会检查该设备是否依赖其它设备或者总线,如果依赖,则检查所依赖的对象是否已经启动,如果没有,则会先启动它们,直到启动该设备的条件具备为止。而驱动开发人员需要做的,就是在编写设备驱动时,告知内核该设备的依赖关系即可。

4. 使用Class结构,在设备模型中引入面向对象的概念,这样可以最大限度地抽象共性,减少驱动开发过程中的重复劳动,降低工作量。

参考博客http://www.wowotech.net/device_model/13.html

linux设备模型一(基础知识)相关推荐

  1. Linux 设备模型之 (kobject、kset 和 Subsystem)(二)

    1.kobject 结构 在Linux内核里,kobject是组成Linux设备模型的基础,一个kobject对应sysfs里的一个目录.从面向对象的角度来说,kobject可以看作是所有设备对象的基 ...

  2. Linux设备模型(2)——Kobject

    转载:http://www.wowotech.net/device_model/kobject.html 1. 前言 Kobject是Linux设备模型的基础,也是设备模型中最难理解的一部分(可参考D ...

  3. Linux设备模型 kobject kset

    http://www.wowotech.net/device_model/13.html 1. 前言 在"Linux内核的整体架构"中,蜗蜗有提到,由于Linux支持世界上几乎所有 ...

  4. Linux设备模型_导航篇

    Linux设备模型_导航篇 1. Linux设备模型系列文章说明 2. Linux设备模型系列文章目录 2.0 [Linux内核的整体架构](https://zhuanlan.zhihu.com/p/ ...

  5. 《linux设备驱动程序》——Linux设备模型

    一.概论 1.2.6版内核对系统结构的一般性抽象描述.现在内核使用了该抽象支持了多种不同的任务,其中包括: 1).电源管理和系统关机. 2).与用户控件通信. 3).热插拔设备. 4).设备类型. 5 ...

  6. Linux设备模型、平台设备驱动、设备树(device tree)、GPIO子系统以及pinctrl子系统介绍

    文章目录 一.Linux设备模型介绍 (1)设备驱动模型总体介绍 (2)设备驱动模型文件表现 (3)设备驱动模型工作原理 [1]总线 [2]设备 [3]驱动 [4]注册流程 二.平台设备驱动介绍 (1 ...

  7. Linux系统编程——进程基础知识

    Linux系统编程--进程基础知识 1.程序和进程 程序,是指编译好的二进制文件,在磁盘上,不占用系统资源(cpu.内存.打开的文件.设备.锁-) 进程,是一个抽象的概念,与操作系统原理联系紧密.进程 ...

  8. Linux通常把设备对象抽象为,linux 设备模型(1)

    设备模型(一) 一.概述 从2.6内核引入了sysfs文件系统,与proc, devfs, devpty同类别,属于虚拟的文件系统.目的是展示设备驱动模型中各组件的层次关系,第一层目录:block, ...

  9. Linux设备模型(总结)

    转:http://www.360doc.com/content/11/1219/16/1299815_173418267.shtml 看了一段时间的驱动编程,从LDD3的hello wrod到后来的字 ...

最新文章

  1. powershell连接数据库_PowerShell 连接SQL Server 数据库
  2. 世界软件出现十个拐点 中国软件几乎按兵不动
  3. wien2k 2009 编译方法
  4. docker 全部杀掉
  5. android wifi 静态地址设置_手机“wifi”越来越慢,3个优化小技巧,网速提升好几倍...
  6. L2-010 排座位 (25 分)
  7. FFmpeg 和 MP4Box 几个命令
  8. SpringBoot使用Ehcache
  9. # Logistic regression中的threshold
  10. 杭电通信841考研考研经验交流及资料分享
  11. php.ini配置文件中文详细解释
  12. Mini LED,显示技术的春天?!
  13. 湖北省制造业高质量发展专项资金政策!2022年各大类申报条件以及奖励补贴标准汇总
  14. lintcdoe: Number of Airplanes in the Sky
  15. WPF中的3D Wireframe
  16. C#编程:用Substring获取年份生肖-4
  17. SWF格式的视频如何快速无损地转换成MP4格式
  18. 亿万富豪欠债消失 10多名员工集体讨薪
  19. PR导出错误怎么办?解决PR导出视频提示“编译影片时出错“ GPU渲染错误 错误代码:-1609629695
  20. java毕业设计超市购物系统mybatis+源码+调试部署+系统+数据库+lw

热门文章

  1. 前端更新需要清空浏览器缓存_浏览器缓存机制分析及前端缓存清理
  2. LightningChart JS Crack,2D 和 3D JavaScript 图表
  3. plt.xticks()
  4. vue读取excel表格数据_vue 利用 js-xslx 读取 excel 表格文件
  5. vb ajax提交post,使用jQuery AJAX将JS数组传递给VB.Net post
  6. 剑~~~~~~~~~~
  7. vivado xilinx IOB = true的使用
  8. 网络安全如何做?提防黑客来“敲门”
  9. @18. 自幂数、水仙花数、四叶玫瑰数等等是什么?
  10. 开发8年的老Android才知道,赶紧收藏备战金三银四!