linux设备驱动(1)基本知识

 

1. 前言

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

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

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

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

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

硬件拓扑描述Linux设备模型中四个重要概念中三个:Bus,Class、Device和Device Driver。

基于Linux 3.10.73,结构体定义位于include\linux\device.h,如下:

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

 1 /**
 2  * struct bus_type - The bus type of the device
 3  *
 4  * @name:    The name of the bus.
 5  * @dev_name:    Used for subsystems to enumerate devices like ("foo%u", dev->id).
 6  * @dev_root:    Default device to use as the parent.
 7  * @bus_attrs:    Default attributes of the bus.
 8  * @dev_attrs:    Default attributes of the devices on the bus.
 9  * @drv_attrs:    Default attributes of the device drivers on the bus.
10  * @match:    Called, perhaps multiple times, whenever a new device or driver
11  *        is added for this bus. It should return a nonzero value if the
12  *        given device can be handled by the given driver.
13  * @uevent:    Called when a device is added, removed, or a few other things
14  *        that generate uevents to add the environment variables.
15  * @probe:    Called when a new device or driver add to this bus, and callback
16  *        the specific driver's probe to initial the matched device.
17  * @remove:    Called when a device removed from this bus.
18  * @shutdown:    Called at shut-down time to quiesce the device.
19  * @suspend:    Called when a device on this bus wants to go to sleep mode.
20  * @resume:    Called to bring a device on this bus out of sleep mode.
21  * @pm:        Power management operations of this bus, callback the specific
22  *        device driver's pm-ops.
23  * @iommu_ops:  IOMMU specific operations for this bus, used to attach IOMMU
24  *              driver implementations to a bus and allow the driver to do
25  *              bus-specific setup
26  * @p:        The private data of the driver core, only the driver core can
27  *        touch this.
28  *
29  * A bus is a channel between the processor and one or more devices. For the
30  * purposes of the device model, all devices are connected via a bus, even if
31  * it is an internal, virtual, "platform" bus. Buses can plug into each other.
32  * A USB controller is usually a PCI device, for example. The device model
33  * represents the actual connections between buses and the devices they control.
34  * A bus is represented by the bus_type structure. It contains the name, the
35  * default attributes, the bus' methods, PM operations, and the driver core's
36  * private data.
37  */
38 struct bus_type {
39     const char        *name; 总线名字
40     const char        *dev_name;用于子系统枚举设备
41     struct device        *dev_root;作为父设备使用的默认设备
42     struct bus_attribute    *bus_attrs;总线的默认属性
43     struct device_attribute    *dev_attrs;总线上设备的默认属性
44     struct driver_attribute    *drv_attrs;总线上设备驱动的默认属性
45 
46     int (*match)(struct device *dev, struct device_driver *drv);当为该总线添加新设备或驱动程序时,可能会调用多次。如果给定的驱动程序可以处理给定的设备,那么它应该返回一个非零值。
47     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);当设备被添加、删除或其他一些操作时调用,生成uevent来添加环境变量
48     int (*probe)(struct device *dev);新设备或驱动程序添加到此总线时调用,并回调特定驱动程序的探测(probe)以初始化匹配的设备。
49     int (*remove)(struct device *dev)设备从总线移除时调用。
50     void (*shutdown)(struct device *dev);关机的时候调用
51 
52     int (*suspend)(struct device *dev, pm_message_t state);设备进入睡眠模式的时候调用
53     int (*resume)(struct device *dev);设备退出睡眠模式时调用
54 
55     const struct dev_pm_ops *pm;总线的电源管理操作,回调特定设备驱动程序的pm-ops。
56 
57     struct iommu_ops *iommu_ops;此总线的IOMMU特定操作,用于将IOMMU驱动程序实现附加到总线,并允许驱动程序做特定的总线的设置
58 
59     struct subsys_private *p;驱动内核的私有数据,只有驱动内核可以访问它。
60     struct lock_class_key lock_key;
61 };

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

 1 /**
 2  * struct class - device classes
 3  * @name:    Name of the class.
 4  * @owner:    The module owner.
 5  * @class_attrs: Default attributes of this class.
 6  * @dev_attrs:    Default attributes of the devices belong to the class.
 7  * @dev_bin_attrs: Default binary attributes of the devices belong to the class.
 8  * @dev_kobj:    The kobject that represents this class and links it into the hierarchy.
 9  * @dev_uevent:    Called when a device is added, removed from this class, or a
10  *        few other things that generate uevents to add the environment
11  *        variables.
12  * @devnode:    Callback to provide the devtmpfs.
13  * @class_release: Called to release this class.
14  * @dev_release: Called to release the device.
15  * @suspend:    Used to put the device to sleep mode, usually to a low power
16  *        state.
17  * @resume:    Used to bring the device from the sleep mode.
18  * @ns_type:    Callbacks so sysfs can detemine namespaces.
19  * @namespace:    Namespace of the device belongs to this class.
20  * @pm:        The default device power management operations of this class.
21  * @p:        The private data of the driver core, no one other than the
22  *        driver core can touch this.
23  *
24  * A class is a higher-level view of a device that abstracts out low-level
25  * implementation details. Drivers may see a SCSI disk or an ATA disk, but,
26  * at the class level, they are all simply disks. Classes allow user space
27  * to work with devices based on what they do, rather than how they are
28  * connected or how they work.
29  */
30 struct class {
31     const char        *name;类名字
32     struct module        *owner;累的所有者
33 
34     struct class_attribute        *class_attrs;类的默认属性
35     struct device_attribute        *dev_attrs;类中设备的默认属性
36     struct bin_attribute        *dev_bin_attrs;类中设备的binary的默认属性
37     struct kobject            *dev_kobj;代表这个类并将其链接到分层结构kobject中。
38 
39     int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);当一个设备被添加,从这个类中删除,或者其他事情要生成uevent添加环境变量时调用。
40     char *(*devnode)(struct device *dev, umode_t *mode);提供devtmps回调
41 
42     void (*class_release)(struct class *class);类释放时调用
43     void (*dev_release)(struct device *dev);设备释放时调用
44 
45     int (*suspend)(struct device *dev, pm_message_t state);用于将设备设置为休眠模式,通常为低功耗状态。
46     int (*resume)(struct device *dev);退出睡眠模式
47 
48     const struct kobj_ns_type_operations *ns_type;sys回调,使其知道命名空间
49     const void *(*namespace)(struct device *dev);类中设备的命名空间
50 
51     const struct dev_pm_ops *pm;类的默认设备电源管理操作
52 
53     struct subsys_private *p;驱动程序内核的私有数据,除了驱动程序内核之外,其他不可访问
54 };

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

  1 /**
  2  * struct device - The basic device structure
  3  * @parent:    The device's "parent" device, the device to which it is attached.
  4  *         In most cases, a parent device is some sort of bus or host
  5  *         controller. If parent is NULL, the device, is a top-level device,
  6  *         which is not usually what you want.
  7  * @p:        Holds the private data of the driver core portions of the device.
  8  *         See the comment of the struct device_private for detail.
  9  * @kobj:    A top-level, abstract class from which other classes are derived.
 10  * @init_name:    Initial name of the device.
 11  * @type:    The type of device.
 12  *         This identifies the device type and carries type-specific
 13  *         information.
 14  * @mutex:    Mutex to synchronize calls to its driver.
 15  * @bus:    Type of bus device is on.
 16  * @driver:    Which driver has allocated this
 17  * @platform_data: Platform data specific to the device.
 18  *         Example: For devices on custom boards, as typical of embedded
 19  *         and SOC based hardware, Linux often uses platform_data to point
 20  *         to board-specific structures describing devices and how they
 21  *         are wired.  That can include what ports are available, chip
 22  *         variants, which GPIO pins act in what additional roles, and so
 23  *         on.  This shrinks the "Board Support Packages" (BSPs) and
 24  *         minimizes board-specific #ifdefs in drivers.
 25  * @power:    For device power management.
 26  *         See Documentation/power/devices.txt for details.
 27  * @pm_domain:    Provide callbacks that are executed during system suspend,
 28  *         hibernation, system resume and during runtime PM transitions
 29  *         along with subsystem-level and driver-level callbacks.
 30  * @pins:    For device pin management.
 31  *        See Documentation/pinctrl.txt for details.
 32  * @numa_node:    NUMA node this device is close to.
 33  * @dma_mask:    Dma mask (if dma'ble device).
 34  * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all
 35  *         hardware supports 64-bit addresses for consistent allocations
 36  *         such descriptors.
 37  * @dma_parms:    A low level driver may set these to teach IOMMU code about
 38  *         segment limitations.
 39  * @dma_pools:    Dma pools (if dma'ble device).
 40  * @dma_mem:    Internal for coherent mem override.
 41  * @archdata:    For arch-specific additions.
 42  * @of_node:    Associated device tree node.
 43  * @acpi_node:    Associated ACPI device node.
 44  * @devt:    For creating the sysfs "dev".
 45  * @id:        device instance
 46  * @devres_lock: Spinlock to protect the resource of the device.
 47  * @devres_head: The resources list of the device.
 48  * @knode_class: The node used to add the device to the class list.
 49  * @class:    The class of the device.
 50  * @groups:    Optional attribute groups.
 51  * @release:    Callback to free the device after all references have
 52  *         gone away. This should be set by the allocator of the
 53  *         device (i.e. the bus driver that discovered the device).
 54  *
 55  * At the lowest level, every device in a Linux system is represented by an
 56  * instance of struct device. The device structure contains the information
 57  * that the device model core needs to model the system. Most subsystems,
 58  * however, track additional information about the devices they host. As a
 59  * result, it is rare for devices to be represented by bare device structures;
 60  * instead, that structure, like kobject structures, is usually embedded within
 61  * a higher-level representation of the device.
 62  */
 63 struct device {
 64     struct device        *parent;设备的“父”设备,它所连接的设备。在大多数情况下,父设备是某种总线或主机控制器。如果父设备为空,则该设备是一个顶级设备,不过一般不会。
 65 
 66     struct device_private    *p;保存设备驱动核心部分的私有数据。有关详细信息,参考struct device_private
 67 
 68     struct kobject kobj;其他类派生的顶级抽象类
 69     const char        *init_name; /* initial name of the device */设备初始化名字
 70     const struct device_type *type;设备类型,表示设备类型和特定类型信息
 71 
 72     struct mutex        mutex;    /* mutex to synchronize calls to
 73                      * its driver.
 74                      */互斥同步锁,driver程序调用
 75 
 76     struct bus_type    *bus;        /* type of bus device is on */总线设备类型
 77     struct device_driver *driver;    /* which driver has allocated this驱动对应的驱动
 78                        device */
 79     void        *platform_data;    /* Platform specific data, device core doesn't touch it */设备的特定平台数据。例如:对于custom板上的设备,作为典型的嵌入式和基于SOC的硬件,
80 Linux经常使用platform_data来指向custom板的结构,这些结构描述设备及其连接方式。这可以包括可用的端口、芯片变体、GPIO引脚等等。这减少了“板支持包”(bsp).
81 struct dev_pm_info power;设备电源管理信息,详见Documentation/power/devices.txt  82 struct dev_pm_domain *pm_domain;提供在系统挂起、休眠、系统恢复和运行时PM转换期间执行的回调,以及子系统级和驱动程序级回调。 83 84 #ifdef CONFIG_PINCTRL 85 struct dev_pin_info *pins;用于设备pin管理。有关详细信息,详见Documentation/pinctrl.txt。 86 #endif 87 88 #ifdef CONFIG_NUMA 89 int numa_node; /* NUMA node this device is close to */设备的NUMA节点 90 #endif 91 u64 *dma_mask; /* dma mask (if dma'able device) */dma掩码 92 u64 coherent_dma_mask;/* Like dma_mask, but for 93 alloc_coherent mappings as 94 not all hardware supports 95 64 bit addresses for consistent 96 allocations such descriptors. */ 97 98 struct device_dma_parameters *dma_parms; 99 100 struct list_head dma_pools; /* dma pools (if dma'ble) */ 101 102 struct dma_coherent_mem *dma_mem; /* internal for coherent mem 103 override */ 104 #ifdef CONFIG_CMA 105 struct cma *cma_area; /* contiguous memory area for dma 106 allocations */ 107 #endif 108 /* arch specific additions */ 109 struct dev_archdata archdata; 110 111 struct device_node *of_node; /* associated device tree node */ 112 struct acpi_dev_node acpi_node; /* associated ACPI device node */ 113 114 dev_t devt; /* dev_t, creates the sysfs "dev" */设备号 115 u32 id; /* device instance */ 116 117 spinlock_t devres_lock;保护设备资源的自旋锁 118 struct list_head devres_head;设备的资源列表 119 120 struct klist_node knode_class;用于将设备添加到类列表的节点。 121 struct class *class;设备的类 122 const struct attribute_group **groups; /* optional groups */可选的组属性 123 124 void (*release)(struct device *dev);回调函数,所有引用都释放掉之后。由bus设置。 125 struct iommu_group *iommu_group; 126 };

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

 1 /**
 2  * struct device_driver - The basic device driver structure
 3  * @name:    Name of the device driver.
 4  * @bus:    The bus which the device of this driver belongs to.
 5  * @owner:    The module owner.
 6  * @mod_name:    Used for built-in modules.
 7  * @suppress_bind_attrs: Disables bind/unbind via sysfs.
 8  * @of_match_table: The open firmware table.
 9  * @acpi_match_table: The ACPI match table.
10  * @probe:    Called to query the existence of a specific device,
11  *        whether this driver can work with it, and bind the driver
12  *        to a specific device.
13  * @remove:    Called when the device is removed from the system to
14  *        unbind a device from this driver.
15  * @shutdown:    Called at shut-down time to quiesce the device.
16  * @suspend:    Called to put the device to sleep mode. Usually to a
17  *        low power state.
18  * @resume:    Called to bring a device from sleep mode.
19  * @groups:    Default attributes that get created by the driver core
20  *        automatically.
21  * @pm:        Power management operations of the device which matched
22  *        this driver.
23  * @p:        Driver core's private data, no one other than the driver
24  *        core can touch this.
25  *
26  * The device driver-model tracks all of the drivers known to the system.
27  * The main reason for this tracking is to enable the driver core to match
28  * up drivers with new devices. Once drivers are known objects within the
29  * system, however, a number of other things become possible. Device drivers
30  * can export information and configuration variables that are independent
31  * of any specific device.
32  */
33 struct device_driver {
34     const char        *name;驱动名字
35     struct bus_type        *bus;驱动的所属总线
36 
37     struct module        *owner;驱动的所有者
38     const char        *mod_name;    /* used for built-in modules */用作内置模块
39 
40     bool suppress_bind_attrs;    /* disables bind/unbind via sysfs */通过sysfs disable bind/unbind
41 
42     const struct of_device_id    *of_match_table;
43     const struct acpi_device_id    *acpi_match_table;
44 
45     int (*probe) (struct device *dev);
46     int (*remove) (struct device *dev);
47     void (*shutdown) (struct device *dev);
48     int (*suspend) (struct device *dev, pm_message_t state);
49     int (*resume) (struct device *dev);
50     const struct attribute_group **groups;
51 
52     const struct dev_pm_ops *pm;
53 
54     struct driver_private *p;
55 };

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

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

感谢博友分享,参考博文:https://blog.csdn.net/qq_16777851/java/article/details/81367246

posted @ 2020-05-10 18:24  Action_er  阅读(1477)  评论(0编辑  收藏  举报