现在的位置: 首页 > 综合 > 正文

专题一、Linux设备驱动模型

2018年03月16日 ⁄ 综合 ⁄ 共 6059字 ⁄ 字号 评论关闭

Linux2.6内核以后引入新的设备驱动模型,设备驱动模型的基础数据结构主要有KObject和KSet,Kset顾名思义应该是一个集合(比如说总线集、设备驱动集合、设备集合),KObject顾名思义应该是具体的一个事物(比如说总线、驱动、设备),KSet就是KObject的集合,通过这两个结构体来表征总线、设备、设备驱动之间的层次关系。而完成设备驱动具体功能主要由总线、设备驱动、设备三个结构体以及其中的功能函数。

         在实际的驱动编写中,主要是针对总线、设备驱动、设备这个部件进行编程,通过这三个标准部件,完成Linux下驱动编写的标准化。

         我们编写一个设备驱动,首先需要考虑的这个设备驱动是属于那个总线的,是USB总线、PCI总线还是I2C总线或者是其他设备总线。一个设备不管是手动或者自动安装到系统时,会首先向系统注册,系统会根据设备驱动的总线类型(设备驱动结构体中已经定义好)找到对应的设备总线,然后将设备驱动加到对应总线的驱动KSet中去,即将当前设备驱动KObject加入到对应总线的KSet中去,当新的设备插入系统时,系统也会根据硬件连接判断设备属于那个总线,然后遍历总线下驱动KSet,通过驱动探测函数匹配设备驱动(匹配条件如设备的ID),如果找到设备驱动程序,就将该设备加入总线的设备KSet中,并修改设备结构体中设备驱动程序指针,将设备和设备驱动程序关联起来,如果没有找到匹配设备驱动,就仅仅将设备加入到总线的设备KSet中,没有关联的设备驱动程序。由此可见总线KObject包含设备KSet和设备驱动KSet。

         综上所述每个设备或者设备驱动程序都是属于总线,不管是新的设备插入还是新的设备驱动注册安装,都会通过遍历总线下设备KSet和设备驱动KSet来完成设备和驱动的匹配,实现设备与驱动的关联。

         那么,总线、设备、设备驱动在Linux中是如何具体关联的呢?

         在Linux设备驱动模型中,总线有bus_type结构体描述,定义在<linux/device.h>文件中

总线驱动也属于内核模块,因此在编写具体总线驱动时,也需要完成module_init和module_exit接口。在Linux驱动模型中,总线也被看做设备,因此在编写总线的驱动时,需要同时实现总线接口和设备接口。

         下面是总线bus_type的接口

struct bus_type {
 const char  *name;       --总线名
 struct bus_attribute *bus_attrs;    --总线属性
 struct device_attribute *dev_attrs;  --总线设备属性
 struct driver_attribute *drv_attrs;  --总线驱动属性
  以下的函数会在设备注册或驱动注册的时候调用。
 int (*match)(struct device *dev, struct device_driver*drv);      --实现设备与驱动的匹配。不同的总线实现匹配的方法不同,如platform总线采用name匹配,而usb_bus采用id匹配
 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
 int (*probe)(struct device*dev);                          --在2.6的内核中实现一个设备与驱动的探测。主要是因为热插拔的设备的增多。
 int (*remove)(struct device*dev);                         --移除设备
 void (*shutdown)(struct device*dev);                      --关闭设备

 int (*suspend)(struct device *dev,pm_message_t state);      
 int (*suspend_late)(struct device *dev, pm_message_t state);  
 int (*resume_early)(struct device*dev);                      
 int (*resume)(struct device *dev);
 
 struct dev_pm_ops*pm;                                  --电源管理

 struct bus_type_private *p;                           --bus_type私有成员,这个结构体中主要包括了kset以及klist,用于管理其挂载其总线下的设备和驱动
}; 

总线中有一个匹配接口,实现挂载在总线上设备与设备驱动的匹配。在模块初始化过程中,注册总线和注册设备。(比较重要的是match接口)

bus_attrs:总线默认属性

struct bus_attribute {

        struct attribute        attr;<br>        ssize_t (*show)(struct bus_type *bus, char *buf);

        ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);

};

@dev_attrs:所有挂载设备默认属性?

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);

};

@drv_attrs:所有挂载驱动默认属性?

struct driver_attribute {

        struct attribute attr;

        ssize_t (*show)(struct device_driver *driver, char *buf);

        ssize_t (*store)(struct device_driver *driver, const char *buf,

                         size_t count);

};

struct subsys_private {

        structkset subsys;

        structkset *devices_kset;

 

        structkset *drivers_kset;

        structklist klist_devices;

        structklist klist_drivers;

        structblocking_notifier_head bus_notifier;

        unsignedint drivers_autoprobe:1;

        structbus_type *bus;

 

        structlist_head class_interfaces;

        structkset glue_dirs;

        structmutex class_mutex;

        structclass *class;

};

下面是设备驱动和设备的接口

struct device_driver {

        constchar             *name;

        structbus_type         *bus;

 

        structmodule           *owner;

        constchar             *mod_name;      /* used for built-in modules */

 

        boolsuppress_bind_attrs;       /* disablesbind/unbind via sysfs */

 

        conststruct of_device_id       *of_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);

        conststruct attribute_group **groups;

 

        conststruct dev_pm_ops *pm;

 

        structdriver_private *p;

};

设备?

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

        struct dev_pm_info      power;

        struct dev_power_domain *pwr_domain;

 

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

 

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

        /* arch specific additions */

        struct dev_archdata     archdata;

 

        struct device_node      *of_node; /* associated device tree node */

 

        dev_t                   devt;   /* dev_t, creates the sysfs "dev" */

        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);

};

设备和设备驱动是如何联系起来的呢?前面已经介绍过了,每个设备和设备驱动都是属于某个总线的,设备和设备驱动都是挂载在总线上,当新设备插入时或者新的设备驱动向系统注册时,系统会遍历相应总线上的设备和设备驱动,并通过bus_type结构体中的match函数实现设备与设备驱动的匹配,那么匹配函数时如何匹配设备设备驱动呢?在设备结构体有个init_name 的成员,在设备驱动结构体中有一个name的成员。

抱歉!评论已关闭.