设备驱动程序模型建立在几个基本数据结构上,这些结构描述了总线、设备、设备驱动、属性以及他们之间的关系。我们首先认识一下这些数据结构。
一、数据结构
设备表述符
struct device {
struct device *parent;/*指向父设备的指针*/
/*该字段用于管理device和其他device结构,一起device
与其他结构之间的关系*/
struct device_private *p;
struct kobject kobj;/*内嵌的kobject结构*/
const char *init_name; /* initial name of the device */
struct device_type *type;
struct semaphore sem; /* semaphore 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;
#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缓冲池链表的首部*//* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem;/*指向设备所使用的一致性DMA存储器描述符的指针*//* internal for coherent mem
override */
/* arch specific additions */
struct dev_archdata archdata;
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描述符
struct bus_type {
const char *name;/*总线类型名称*/
/*指向对象的指针,该对象包含总线属性和用于导出此属性到sysfs文件系统的方法*/
struct bus_attribute *bus_attrs;
/*指向对象的指针,该对象包含设备属性和用于导出此属性sysfs文件系统的方法*/
struct device_attribute *dev_attrs;
/*指向对象的指针,该对象包含设备驱动程序属性和用于导出此属性到sysfs文件
的方法*/
struct driver_attribute *drv_attrs;
/*检验给定的设备驱动程序是否支持特定设备的方法*/
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 (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
const struct dev_pm_ops *pm;
struct bus_type_private *p;
};
设备驱动
/*设备驱动程序模型中的每个驱动程序*/
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 */
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;
};
类描述符
/*
* device classes
*/
struct class {
const char *name;
struct module *owner;
struct class_attribute *class_attrs;
struct device_attribute *dev_attrs;
struct kobject *dev_kobj;
int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
char *(*devnode)(struct device *dev, mode_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 dev_pm_ops *pm;
struct class_private *p;
};
下面数据结构用以描述结构间关系的
/**
* struct device_private - structure to hold the private to the driver core portions of the device structure.
*
* @klist_children - klist containing all children of this device
* @knode_parent - node in sibling list
* @knode_driver - node in driver list
* @knode_bus - node in bus list
* @driver_data - private pointer for driver specific info. Will turn into a
* list soon.
* @device - pointer back to the struct class that this structure is
* associated with.
*
* Nothing outside of the driver core should ever touch these fields.
*/
struct device_private {
struct klist klist_children;
struct klist_node knode_parent;
struct klist_node knode_driver;
struct klist_node knode_bus;
void *driver_data;
struct device *device;
};
struct class_private {
struct kset class_subsys;
struct klist class_devices;
struct list_head class_interfaces;
struct kset class_dirs;
struct mutex class_mutex;
struct class *class;
};
/**
* struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
*
* @subsys - the struct kset that defines this bus. This is the main kobject
* @drivers_kset - the list of drivers associated with this bus
* @devices_kset - the list of devices associated with this bus
* @klist_devices - the klist to iterate over the @devices_kset
* @klist_drivers - the klist to iterate over the @drivers_kset
* @bus_notifier - the bus notifier list for anything that cares about things
* on this bus.
* @bus - pointer back to the struct bus_type that this structure is associated
* with.
*
* This structure is the one that is the actual kobject allowing struct
* bus_type to be statically allocated safely. Nothing outside of the driver
* core should ever touch these fields.
*/
struct bus_type_private {
struct kset subsys;
struct kset *drivers_kset;
struct kset *devices_kset;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;
};
struct driver_private {
struct kobject kobj;
struct klist klist_devices;
struct klist_node knode_bus;
struct module_kobject *mkobj;
struct device_driver *driver;
};
描述属性文件的结构
/* FIXME
* The *owner field is no longer used.
* x86 tree has been cleaned up. The owner
* attribute is still left for other arches.
*/
struct attribute {
const char *name;
struct module *owner;
mode_t mode;
};
后面有时间我会补上上面数据结构之间的关系图,便于理解。
二、原理与源码解析
解决问题我还是习惯追根溯源,我们从内核启动对设备驱动模型初始化开始看起,设备驱动中sys/文件系统的初始化工作为start_kernel()->rest_init()->
static noinline void __init_refok rest_init(void)
__releases(kernel_lock)
{
……
/*创建并启动内核线程kernel_init用于初始化一些
内核部件工作*/
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
……
}
内核线程kernel_init()用于驱动的初始化
kernel_init()->do_basic_setup()->driver_init()
/**
* driver_init - initialize driver model.
*
* Call the driver model init functions to initialize their
* subsystems. Called early from init/main.c.
*/
/*在内核初始化时的线程中调用*/
void __init driver_init(void)
{
/* These are the core pieces */
/*devtmpfs 的功用是在 Linux 核心 启动早期建立一个初步的 /dev,
令一般启动程序不用等待 udev,缩短 GNU/Linux 的开机时间。
devtmpfs 在 2009 年初被提出,并在同年年尾进出的 Linux 2.6.32 正式收录
*/
devtmpfs_init();
/*设备相关初始化*/
devices_init();
/*bus初始化*/
buses_init();
/*class初始化*/
classes_init();
/*firmware初始化*/
firmware_init();
/*虚拟化平台hypervisor初始化。虚拟化 就是通过某种方式隐藏底层物理硬件
的过程,从而让多个操作系统可以透明地使用和共享它。这种
架构的另一个更常见的名称是平台虚拟化。在典型的分层架构
中,提供平台虚拟化的层称为 hypervisor (有时称为虚拟机管理程
序 或 VMM)。来宾操作系统称为虚拟机(VM),因为对这些 VM
而言,硬件是专门针对它们虚拟化的。
*/
hypervisor_init();
/* These are also core pieces, but must come after the
* core core pieces.
*/
platform_bus_init();
/*初始化system_bus,即在sys/devices目录下创建system目录*/
system_bus_init();
/*cpu_dev初始化*/
cpu_dev_init();
/*在/sys/devices/system目录下创建memory目录文件
该函数需要定义的相关宏在本机器上没有定义
*/
memory_dev_init();
}
/*在sys文件系统中建立几个文件夹*/
int __init devices_init(void)
{
/*根目录sys下创建devices文件夹*/
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
if (!devices_kset)
return -ENOMEM;
/*根目录下创建dev文件夹*/
dev_kobj = kobject_create_and_add("dev", NULL);
if (!dev_kobj)
goto dev_kobj_err;
/*在dev文件夹下创建block文件夹*/
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
if (!sysfs_dev_block_kobj)
goto block_kobj_err;
/*在dev文件夹下创建cha