Linux总线驱动模型

基本概念

1、什么是总线设备驱动模型?

设备模型是将硬件设备归纳、分类,并抽象出一套标准数据结构和接口方法;
随着技术的进步,系统的拓扑结构变得越来越复杂,Linux 内核使用了全新的设备模型—总线设备驱动模型,对设备与驱动分离管理,提高程序的可移植性;Linux分别使用了3个数据结构来描述总线设备模型,分别对应于总线、设备和驱动及它们之间的关系:
(1)所有的设备和驱动都必须挂载在某一总线上;
(2)通过总线可以绑定设备和驱动
在这里插入图片描述

2、总线(Bus)

总线是处理器和设备之间的通道,有多种类型(可为虚拟总线),可以挂载多个设备,在linux设备模型中,所有的设备都挂在某一总线上,使用总线来管理设备和驱动,总线使用bus_type结构体来描述:
注意:内核版本的不同,struct bus_type结构体不同!
#include<linux/device.h>
struct bus_type {
const char name; //总线名
//该名称与struct device结构中的init_name有关,某些设备(如批量化USB设备),
//允许设计者允许将设备名字留空,当设备注册到内核时会以
//“bus->dev_name+device ID”的形式生成设备名称;
const char *dev_name; //总线的设备名
//dev_root设备为bus的默认父设备,
//在内核实际实现中只与称为sub system的功能有关
struct device *dev_root; //根设备
//在bus总线添加到内核时自动添加相应的属性
struct bus_attribute *bus_attrs; //bus总线的默认属性
// 在device设备添加到内核时自动添加相应的属性
struct device_attribute *dev_attrs; // bus总线上设备的默认属性
//在device_driver驱动添加到内核时自动添加相应的属性
struct driver_attribute *drv_attrs; // bus总线上驱动的默认属性
//当新设备或驱动添加到总线上时match函数被调用,设备和驱动匹配成功返回0
int (*match)(struct device *dev, struct device_driver *drv);

//设备添加、移除或添加环境变量时,调用uevent函数;
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);

//新设备或驱动添加时,调用probe函数,并回调驱动的probe函数初始化关联
int (*probe)(struct device *dev);
//设备移除时调用remove函数
int (*remove)(struct device *dev);
//设备关闭时时调用shutdown函数
void (*shutdown)(struct device *dev);
//设备挂起时调用suspend函数
int (*suspend)(struct device *dev, pm_message_t state);
//设备唤醒时调用resume
int (*resume)(struct device *dev);
//总线电源管理选项,将回调设备驱动的电源管理模块
const struct dev_pm_ops *pm;
struct iommu_ops *iommu_ops;
// bus总线的私有数据
struct subsys_private *p;
};

Struct subsys_private {
struct kset subsys; //总线在/sys/bus/目录下的目录项
struct kset *devices_kset; //总线目录下的devices目录
struct kset *drivers_kset; //总线目录下的drivers目录
struct klist klist_devices; //挂在总线上的设备
struct klist klist_drivers; //挂在总线上的设备驱动
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus; //指向总线
struct list_head class_interfaces;
struct kset glue_dirs;
struct mutex class_mutex;
struct class *class;
}

3、设备(Device)

在linux总线设备模型中用struct device结构体表示设备
注意:内核版本的不同,struct device结构体不同!
<linux/device.h>
struct device {
//设备的父设备,常为是设备所从属的bus、controller等设备
struct device *parent;
//设备的私有数据结构指针,用于保存子设备链表
struct device_private *p;
//设备的kobject
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_pm_domain *pm_domain;

#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
//设备DMA相关的数据
u64 *dma_mask;
u64 coherent_dma_mask;
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 */
#ifdef CONFIG_CMA
struct cma cma_area; / contiguous memory area for dma allocations /
#endif
//设备架构相关数据
/
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” /
//设备标识符
u32 id; /
device instance */
//设备自旋锁
spinlock_t devres_lock;
//设备资源双向链表头
struct list_head devres_head;
//接入class链表时所需要的klist节点
struct klist_node knode_class;

//设备所属class的指针
struct class *class;
//设备的属性集合
const struct attribute_group *groups; / optional groups */
//设备释放时调用函数指针
void (*release)(struct device *dev);

};

4、设备驱动(Driver)

在linux总线设备模型中用struct device_driver结构体表示设备驱动
注意:内核版本的不同,struct device_driver结构体不同!
<linux/device.h>
struct device_driver {
//设备驱动的名称
const char *name;
//设备驱动所在的总线
struct bus_type *bus;
//设备驱动所属的内核模块
struct module *owner;
//内嵌内核模块名称
const char mod_name; / used for built-in modules /
//sys文件系统中的bind/unbind逻辑
bool suppress_bind_attrs; /
disables bind/unbind via sysfs */
//openfirmware框架中的匹配表
const struct 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);
//设备驱动组属性
const struct attribute_group **groups;
//设备驱动电源管理信息
const struct dev_pm_ops *pm;
//设备驱动私有数据
struct driver_private *p;
};

总线设备驱动模块步骤

1、总线模块

MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“Alan”);
MODULE_DESCRIPTION (“LEDS BUS");

//导出符号leds_bus_type,其它内核模块(device、device_driver)要使用到
EXPORT_SYMBOL(leds_bus_type);

//模块初始化
module_init(leds_bus_init);

//模块退出
module_exit(leds_bus_exit);

(a)定义总线

//LED的总线匹配函数
int leds_match(struct device *dev, struct device_driver *drv)
{
return !strncmp(dev->kobj.name,drv->name,strlen(drv->name));
}

//定义LEDS总线
struct bus_type leds_bus_type = {
.name = “leds_bus”, //总线名为leds_bus
.match = leds_match, //总线匹配函数
};

(b)注册总线

int leds_bus_init()
{
int ret;
//注册总线leds_bus_type
ret = bus_register(&leds_bus_type);
return ret;
}

(c)注销总线

void leds_bus_exit()
{

//注册总线leds_bus_type
bus_unregister(&leds_bus_type);
}

2、设备模块

MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“Alan”);
MODULE_DESCRIPTION (“LEDS DEVICE");

//模块初始化
module_init(leds_device_init);

//模块退出
module_exit(leds_device_exit);

(a)定义设备

//声明外部结构体变量,LED的总线匹配函数
extern struct bus_type leds_bus_type;
//定义LEDS总线
struct device leds_dev = {
//设备名称
.init_name = “leds_dev",
//设备所属的总线
.bus = &leds_bus_type,
// 设备的释放函数
.release = leds_dev_release,
.platform_data =& Tiny4412_LEDS,
};

(b)注册设备

int leds_device_init()
{
int ret;
//注册leds_dev设备
ret = device_register(&leds_dev);
return ret;
}

(c)注销设备

void leds_device_exit()
{
//注销设备
device_unregister(&my_dev);
}

3、设备驱动模块

MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“Alan”);
MODULE_DESCRIPTION (“LEDS DEVICE DRIVER");
//模块初始化
module_init(leds_driver_init);

//模块退出
module_exit(leds_driver_exit);

(a)定义设备驱动

//声明外部结构体变量,LED的总线匹配函数
extern struct bus_type leds_bus_type;
//设备驱动探测函数
int leds_probe(struct device *dev)
{
printk(“driver found the device it can handle!\n”);
//驱动相关的代码
struct Tiny4412_leds *pLEDS = dev->platform_data;
gpiocon = ioremap(pLEDS->CON_GPIOPA, 4);
gpiodat = ioremap(pLEDS->DAT_GPIOPA, 4);
return 0;
}
struct device_driver leds_driver = {
.name = “leds_dev",
//设备驱动所属总线
.bus = &leds_bus_type,
//在leds_bus_type总线找匹配设备后leds_probe;
//删除设备时调用leds_remove
.probe = leds_probe,
};
注意:设备驱动程序何时在总线上查找匹配的设备?如果匹配?
答:设备驱动注册时,设备驱动与设备都属于总线,调用总线中的match函数

(b)注册设备驱动

int leds_driver_init()
{
int ret;
//注册设备驱动
ret = driver_register(&leds_driver);
return ret;
}

(c)注销设备驱动

void leds_driver_exit()
{
//注销设备驱动
driver_unregister(&leds_driver);
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux总线设备模型是一种用于管理和操作硬件设备的框架。它提供了一种统一的方式来访问和控制连接到计算机系统上的各种设备,包括串口、USB、PCI、I2C等。 在Linux系统中,每个设备都被视为一个文件,并通过文件路径来访问。总线设备模型定义了设备之间的层次关系和通信机制,使得设备可以被识别、配置和操作。 Linux总线设备模型由以下几个重要组件组成: 1. 设备树(Device Tree):在启动过程中,设备树用于描述连接到系统的各种硬件设备和其相互关系。它是一个以文本方式描述的树状结构,包含了设备的类型、地址、中断等信息。 2. 设备驱动程序(Device Driver):驱动程序是用来控制和管理特定硬件设备的软件模块。每个设备都有相应的驱动程序,它们与设备进行通信,并提供对设备的访问接口。 3. 总线(Bus):总线是连接多个设备的物理或逻辑通道。例如,PCI总线、USB总线等。总线提供了设备之间通信的基础。 4. 设备类(Device Class):设备类是一组具有相似功能的设备的集合。例如,USB设备类包括存储设备、键盘、鼠标等。设备类可以帮助系统区分和管理不同类型的设备。 通过使用总线设备模型Linux系统可以自动检测和配置连接到系统的设备,使其能够正常工作。同时,开发者也可以编写自定义的驱动程序来支持新的硬件设备。总线设备模型的设计使得设备的添加、删除和管理变得更加灵活和可扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

威威攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值