Linux设备驱动编程模型之设备篇

  设备驱动程序模型建立在几个基本数据结构上,这些结构描述了总线、设备、设备驱动、属性以及他们之间的关系。我们首先认识一下这些数据结构。  

一、数据结构

设备表述符

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
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux设备驱动是一种软件程序,用于控制硬件设备的操作。它允许操作系统与硬件设备进行通信,从而实现对设备的控制和管理。Linux设备驱动通常由内核模块或用户空间程序实现,可以通过编写C语言代码来实现。设备驱动程序需要遵循Linux内核的规范,包括使用标准的设备文件接口和实现正确的设备操作函数等。在Linux系统中,设备驱动程序是非常重要的组成部分,它们为各种硬件设备提供了支持,包括网络适配器、磁盘驱动器、USB设备等。 ### 回答2: Linux设备驱动是指是在Linux操作系统中控制和管理硬件设备的软件模块,它使得操作系统能够与硬件设备进行通信和交互。在Linux系统中,每个硬件设备都需要由相应的设备驱动程序来支持,这些设备驱动程序负责向操作系统提供设备的操作接口,并处理设备的输入和输出。 Linux设备驱动可以分为字符设备驱动和块设备驱动两种。字符设备驱动用于管理字符设备,例如键盘、鼠标等;块设备驱动用于管理块设备,例如硬盘、固态硬盘等。在驱动程序中,通常会包含设备的初始化和配置、设备的打开和关闭、设备的读取和写入等功能。 为了方便设备驱动的开发和维护,Linux提供了一些设备驱动开发框架和接口,如字符设备驱动的主要接口为file_operations结构体,块设备驱动的主要接口为block_device_operations结构体。开发人员只需要实现这些接口,就可以将相应的设备驱动程序编译为内核模块,然后加载到Linux内核中。 Linux设备驱动的编写需要熟悉硬件设备的工作原理和寄存器的操作,同时还需要了解Linux内核的相关知识。开发人员需要通过阅读设备规格书、硬件设计手册等,了解硬件设备的寄存器地址和寄存器位域的含义,然后编写适当的代码来读取和写入这些寄存器。此外,还需要熟悉Linux内核的设备模型设备树等,以便正确地注册设备并与操作系统进行通信。 总之,Linux设备驱动是为了实现操作系统与硬件设备之间的通信和交互而编写的软件模块。通过适当配置和编写设备驱动程序,可以使得Linux操作系统能够正确地识别和管理各种硬件设备。 ### 回答3: Linux 设备驱动是指用于操作系统中的设备和外设的软件模块或程序。它负责对计算机和外围设备进行通信和控制,使它们能够正确地工作和与其他部分进行交互。 Linux 设备驱动由内核负责加载和管理,它提供了一种与硬件设备通信的接口,使应用程序能够通过系统调用与设备进行交互。设备驱动程序可以根据底层硬件设备的特定规格和功能进行开发,以确保设备可以和系统进行可靠而有效的通信。 Linux 设备驱动提供了一套标准接口和程序,使开发人员可以编写适用于不同硬件设备的通用驱动程序。这使得设备供应商和开发人员可以更轻松地将设备接入Linux系统,而不需要自行开发专门的驱动程序。此外,设备驱动程序可以提供一系列的API函数和工具,以便应用程序能够控制和访问设备的不同功能和特性。 Linux 设备驱动的开发需要一些特定的技能和知识,包括熟悉C语言编程、了解硬件设备的工作原理和接口规范、熟悉Linux内核和设备驱动开发的相关知识等。开发人员需要编写设备驱动程序的相关代码,并将其编译为内核模块,然后将模块加载到系统中。 总而言之,Linux 设备驱动在操作系统中起到了至关重要的作用,它使得Linux系统能够与各种硬件设备进行联通和交互,从而为应用程序提供了丰富的功能和特性。通过开源的特性,Linux 设备驱动的开发变得更加便捷和灵活,使得越来越多的硬件设备能够与Linux系统兼容,并为用户带来更好的使用体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值