Linux的总线设备驱动模型
裸机编写驱动比较自由,按照手册实现其功能即可,每个人写出来都有很大不同;
而Linux中还需要按照Linux的驱动模型来编写,也就是需要按照“模板”来写,写出来的驱动就比较统一。
一、 Linux采用总线设备驱动模型。主要包含总线、设备、驱动三个部分。
总线:最先注册,有几个重要的回调函数,例如match函数用于匹配device和driver。
设备:设备的物理信息,例如设备名、物理地址、中断号等;
驱动:设备的驱动程序和设备名等信息,例如初始化函数、波特率设置函数、启动停止函数、中断函数等。
现实中,很多设备都是接在总线上的,例如SPI Flash接在SPI总线上,EEPROM接在I2C总线上。
但也有很多芯片内部设备没有挂在总线上,例如UART、SPI控制器。为了统一使用Linux总线设备驱动模型,内核中定义了一个虚拟总线 platform_bus_type,将这些设备(叫做平台设备)注册到该虚拟总线上统一管理。
二、Linux驱动注册顺序(总线、设备、驱动三者关系)
1、注册总线 xxx_bus_type:
在系统初始化阶段,会首先向内核注册各种常用的总线类型,比如pci, usb, spi, i2c, platform等等。
有两个重要的链表挂在bus上,一个是设备device链表,一个是驱动driver链表。
它包含的最关键的函数:match()用于匹配device和driver。
//例子:
static int __init spi_init(void)
{
int status;
printk("@@ spi_init :spi_bus_type\n");
buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
if (!buf) {
status = -ENOMEM;
goto err0;
}
status = bus_register(&spi_bus_type);
if (status < 0)
goto err1;
status = class_register(&spi_master_class);
if (status < 0)
goto err2;
return 0;
err2:
bus_unregister(&spi_bus_type);
err1:
kfree(buf);
buf = NULL;
err0:
return status;
}
2、注册设备:将系统设备注册进内核的对应总线上,大多是调用xxx_device_regisger注册。
(xxx_device_regisger:将自己加到xxx总线的device链表,然后使用总线bus匹配对应的driver )
3、注册驱动:将系统设备的driver注册进内核的对应总线上:大多是调用xxx_drvier_register()注册。
(xxx_drvier_register:将自己加到xxx总线的driver链表,然后使用总线bus匹配对应的device )
2和3很多是在同一个函数中注册的,所以一起举例:
例子1:
platform_driver_register(&uart_driver); //将uart的driver注册到platform_bus上;
platform_device_register(&uart_device); //将uart的device注册到platform_bus上;
例子2:
SPI Master控制器:drivers/spi/my_spi_master.c
platform_device_register(&dw_spi0_device); //注册device
platform_driver_probe(&dw_spi0_driver, dw_spi0_probe); //1、注册driver
//2、spi_new_device子函数会注册SPI Flash的device到spi总线上;
//3、这里实现Master和Flash的绑定,即flash要使用哪个控制器控制;
例子3:
SPI Flash:drivers/mtd/gd25q_spi.c
spi_register_driver(&spi_flash_drv); //注册SPI Flash的driver到spi总线
上面几个例子的device和driver都成功注册后,对应总线的match回调函数会成功匹配driver和device,
并调用driver的probe函数完成设备初始化。
可以看到,不同设备的device和driver注册位置可能不同、注册顺序可能不同、注册函数名可能不同!!
4、设备和驱动的匹配:
老版内核的匹配大部分是看device和driver的name属性是否相同;新版使用设备树的内核中,是根据程序中driver的compatible 与设备树节点的compatible 是否相同来匹配!
match的工作是由总线(bus)来完成。
在xxx_device_register()或xxx_drvier_register(),即设备或驱动注册的时候,都会引发总线调用自己的match函数来寻找是否挂载有与该设备(或驱动)名字匹配的驱动(或设备);
如果只注册了设备或者只注册了驱动,总线会判定匹配失败,则暂时不会调用driver中的probe函数进行初始化等操作; 要等到设备、驱动都注册成功并匹配绑定后才会调用。
Linux的总线设备驱动模型的更多相关文章
- Linux中总线设备驱动模型及平台设备驱动实例
本文将简要地介绍Linux总线设备驱动模型及其实现方式,并不会过多地涉及其在内核中的具体实现,最后,本文将会以平台总线为例介绍设备和驱动程序的实现过程. 目录: 一.总线设备驱动模型总体介绍及其实现方 ...
- Linux I2C总线设备驱动模型分析(ov7740)
1. 框架1.1 硬件协议简介1.2 驱动框架1.3 bus-drv-dev模型及写程序a. 设备的4种构建方法a.1 定义一个i2c_board_info, 里面有:名字, 设备地址 然后i2c_r ...
- Linux学习 : 总线-设备-驱动模型
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.Linux 2.6的设备驱动模型中,把I2C.RTC.LCD等都归纳为pl ...
- usb驱动开发4之总线设备驱动模型
在上文说usb_init函数,却给我们留下了很多岔路口.这次就来好好聊聊关于总线设备驱动模型.这节只讲理论,不讲其中的函数方法,关于函数方法使用参考其他资料. 总线.设备.驱动对应内核结构体分别为bu ...
- 总线设备驱动模型---platform篇
总线设备驱动模型----驱动篇 http://blog.chinaunix.net/uid-27664726-id-3334923.html http://blog.chinaunix.net/uid ...
- 芯灵思SinlinxA33开发板 Linux平台总线设备驱动
1.什么是platform(平台)总线? 相对于USB.PCI.I2C.SPI等物理总线来说,platform总线是一种虚拟.抽象出来的总线,实际中并不存在这样的总线. 那为什么需要platform总 ...
- Linux总线设备驱动模型
1. Linux2.6内核引入总线.设备.驱动模型来描述各种总线(PCI.USB.I2C.SPI)与外围设备及其驱动之间的关系. 2. 在Linux内核中,总线用bus_type结构来描述,定义于文件 ...
- Linux平台总线设备驱动
1. 平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备(没有挂到真实总线的设备)与驱动进行了管理,这样提高了程序的可移植性. 2. 平台总 ...
- Linux下 USB设备驱动分析(原创)
之前做过STM32的usb HID复合设备,闲来看看linux下USB设备驱动是怎么一回事, 参考资料基于韦东山JZ2440开发板,以下,有错误欢迎指出. 1.准备知识 1.1USB相关概念: USB ...
随机推荐
- 在Excel VBA中使用SQL到底优势在哪儿
小爬在之前的博文中多次提到,可以在VBA中写SQL来操作Excel文件,实现各类数据处理和分析需求.那么,你可能有这样的疑问:Excel原生的VBA,数据透视表,数据分析功能不够吗,为啥一定要用SQL ...
- MATLAB基础学习(3)——数值数组及运算
rand('state',s)表示随机产生数的状bai态state,一般情百况du下不用指定状态.rand('state',0)作用在于如果指容定zhi状态,产生dao随机结果就相同了.一般情况下不用 ...
- 框架4--NFS网络共享
目录 框架4--NFS网络共享 1.练习 2.昨日问题 3.今日内容 4.NFS简介 5.NFS应用 6.NFS实践 6.1.服务端 6.2.客户端 7.NFS配置详解 8.搭建考试系统 8.1.搭建 ...
- suse 12 脚本部署docker(二进制文件)
suse-linux:~ # cat /etc/issue Welcome to SUSE Linux Enterprise Server 12 SP3 (x86_64) - Kernel \r (\ ...
- pytest(12)-Allure常用特性allure.attach、allure.step、fixture、environment、categories
上一篇文章pytest Allure生成测试报告我们学习了Allure中的一些特性,接下来继续学习其他常用的特性. allure.attach allure.attach用于在测试报告中添加附件,补充 ...
- 使用Flask开发简单接口
作为测试人员,在工作或者学习的过程中,有时会没有可以调用的现成的接口,导致我们的代码没法调试跑通的情况. 这时,我们使用python中的web框架Flask就可以很方便的编写简单的接口,用于调用或调试 ...
- curl常用参数详解及示例
curl简介 curl是一个开源的命令行工具,它基于网络协议,对指定URL进行网络传输,得到数据后不任何具体处理(如:html的渲染等),直接显示在"标准输出"(stdout)上. ...
- 【转】int和Integer的区别
int和Integer的区别: 1.Integer是int的包装类,int则是java的一种基本数据类型 2.Integer变量必须实例化后才能使用,而int变量不需要 3.Integer实际是对象的 ...
- 【C# 线程】 atomic action原子操作|primitive(基元、原语)
概念 原子操作(atomic action):也叫primitive(原语.基元),它是操作系统用语范畴.指由若干条指令组成的,用于完成一定功能的一个过程. 原语是由若干个机器指令构成的完成某种特定 ...
- POJ1990 题解
题目大意:有若干头牛,每个牛有一个音量值,两头牛能互相听见对方说话需要发出两头牛中音量值较大者的音量*两头牛的距离的音量,求使任意两头牛都互相听见对方需要发出的音量总和.每头牛的音量值可以相同,但坐标 ...