Linux总线、设备、驱动模型

本文详细介绍了Linux的平台总线驱动模型,包括总线、设备和驱动的描述结构体、注册与注销过程。重点讲解了platform_driver和platform_device的注册流程,涉及到driver_register、platform_driver_register、device_add等函数,以及probe函数在设备与驱动匹配中的作用。此外,还提供了设备层和驱动层的编程思路及示例代码。
摘要由CSDN通过智能技术生成

 

 

一、Linux总线设备驱动模型框架

Linux2.6开始Linux加入了一套驱动管理和注册机制—platform平台总线驱动模型。platform平台总线是一条虚拟总线,platform_device为相应的设备,platform_driver为相应的驱动。与传统的bus/device/driver机制相比,platform由内核统一进行管理,提高了代码的可移植性和安全性。所谓的platform_device并不是与字符设备、块设备和网络设备并列的概念,而是Linux系统提供的一种附加手段。Linux总线设备驱动模型的框架如下图所示:

从图中我们可以很清楚的看出Linux平台总线设备驱动模型的整体架构。在总线设备驱动模型中,需关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。当系统向内核注册每一个驱动程序时,都要通过调用platform_driver_register函数将驱动程序注册到总线,并将其放入所属总线的drv链表中,注册驱动的时候会调用所属总线的match函数寻找该总线上与之匹配的每一个设备,如果找到与之匹配的设备则会调用相应的probe函数将相应的设备和驱动进行绑定;同样的当系统向内核注册每一个设备时,都要通过调用platform_device_register函数将设备注册到总线,并将其放入所属总线的dev链表中,注册设备的时候同样也会调用所属总线的match函数寻找该总线上与之匹配的每一个驱动程序,如果找到与之匹配的驱动程序时会调用相应的probe函数将相应的设备和驱动进行绑定;而这一匹配的过程是由总线自动完成的。

下面是基于linux3.10
   

1.总线

include/device.h

1.1描述结构体


/**
 * 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.
 * @bus_attrs:	Default attributes of the bus.
 * @dev_attrs:	Default attributes of the devices on the bus.
 * @drv_attrs:	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 nonzero value if the
 *		given device can be handled by the given driver.
 * @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.
 * @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.
 *
 * 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 bus_attribute	*bus_attrs;
	struct device_attribute	*dev_attrs;
	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 iommu_ops *iommu_ops;

	struct subsys_private *p;
	struct lock_class_key lock_key;
};

1.2注册

//若成功,新总线将被添加进系统,并可在/sys/bus下看到相应目录
extern int __must_check bus_register(struct bus_type *bus);

1.3注销

extern void bus_unregister(struct bus_type *bus);

1.4示例

Tbus.c

#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/device.h>
 

 
int Tmatch(struct device *dev, struct device_driver *drv)
{
	
	return 0;
}
 
struct bus_type Tbus_type = 
{
	.name = "Tbus",
	.match = Tmatch,
};
 
int Tbus_init(void)
{
	int ret;
	
	ret = bus_register(&Tbus_type);
	
	return ret;
}
 
void Tbus_exit(void)
{
	bus_unregister(&Tbus_type);
}
 
 
module_init(Tbus_init);
module_exit(Tbus_exit);
MODULE_LICENSE("GPL");


下面向上面的my_bus总线上挂载一个驱动!

二、platform驱动的相关数据结构

1. 结构体驱动对应的结构体platform_driver

include/platform_device.h


struct platform_driver {
	int (*probe)(struct platform_device *);
	int (*remove)(struct platform_device *);
	void (*shutdown)(struct platform_device *);
	int (*suspend)(struct platform_device *, pm_message_t state);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
	const struct platform_device_id *id_table;
};

可以看到platform_driver结构体中包含了probe和remove等相关操作,同时还内嵌了device_driver结构体。

2. device_driver结构体

include/device/h


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

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

其中有一个指向driver_private的指针p,一些与其他的组件相关的联系都被移到这个结构变量中。

3. driver_private结构体


struct driver_private {
	struct kobject kobj;// 在sysfs中代表目录本身
	struct klist klist_devices;// 驱动链表即我们上面所说的drv链表
	struct klist_node knode_bus;// 挂载在总线上的驱动链表的节点
	struct module_kobject *mkobj;// driver与相关的module之间的联系
	struct device_driver *driver;
};
#define to_driver(obj) container_of(obj, struct driver_private, kobj)

4.注册

int driver_register(struct device_driver *drv)

5.注销

void driver_unregister(struct device_driver *drv)

 

 

 

 

 

三、platform设备的相关数据结构

1. platform设备对应的结构体platform_device


struct mfd_cell;

struct platform_device {
	const char	*name;// 设备的名字这将代替device->dev_id,用作sys/device下显示的目录名
	int		id;// 设备id,用于给插入给该总线并且具有相同name的设备编号,如果只有一个设备的话填-1。
	bool		id_auto;
	struct device	dev;// 内嵌device结构
	u32		num_resources;// 资源的数目
	struct resource	*resource;// 资源

	const struct platform_device_id	*id_entry;

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

	/* arch specific additions */
	struct pdev_archdata	archdata;
};

 可以看出platform_device结构体中包含了名字、id、资源和内嵌device结构体。

2. resource结构体

struct resource {
	resource_size_t start;	// 资源的起始地址
	resource_size_t end;	// 资源的结束地址
	const char *name;
	unsigned long flags;	// 资源的类型
	struct resource *parent, *sibling, *child;
};

该结构体非常重要,用于存放设备的资源信息,如IO地址、中断号等。

3.设备注册

int device_register(struct device *dev)

4.设备注销

void device_unregister(struct device *dev)

 

简单示例

Tdevice.c

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
 

 
extern struct bus_type Tbus_type;

static void	Trelease(struct device *dev)
{

}

 
struct device Tdev = 
{
     .init_name = "Tdev",//和驱动名字一样
     .bus = &Tbus_type,	
     .release = Trelease,
};


int Tdevice_init(void)
{
	int ret;
     ret = device_register(&Tdev);
     return ret;
     
}
 
 
void Tdevice_exit(void)
{
	device_unregister(&Tdev);
}
 
module_init(Tdevice_init);
module_exit(Tdevice_exit);
MODULE_LICENSE("GPL");


 

Tdriver.c

#include<linux/module.h>
#include<linux/init.h>
#include<linux/device.h>
#include<linux/kernel.h>
 

 
extern struct bus_type Tbus_type;
 
int Tprobe(struct device *dev)
{
	printk(KERN_WARNING"driver found the device!!!\n");
	
	return 0;
}
 
struct device_driver Tdriver = 
{
	.name = "Tdev",
	.bus = &Tbus_type,
	.probe = Tprobe, //当找到这个设备时将调用这个函数
};
 
int Tdevice_init(void)
{
	int ret; 
	
	ret = driver_register(&Tdriver);//注册一个驱动
	
	return 0;
}
 
void Tdevice_exit(void)
{
	driver_unregister(&Tdriver);
}
 
module_init(Tdevice_init);
module_exit(Tdevice_exit);

MODULE_LICENSE("GPL");


 

Tbus.c

#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/device.h>
 

 
int Tmatch(struct device *dev, struct device_driver *drv)
{
	return 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值