linux 设备驱动程序 过滤,Linux驱动发开,usb设备的probe全过程
本文将详细讲述2.6.22 下的一个USB 设备插上linux 系统的PC 后是如何一步一步调到我们的usb 设备驱动的probe 函数的,我们知道我们的USB 驱动的probe 函数中的一个参数是interface 结构,因此一般来说,一个USB 设备中的任何一个接口都应该有对应的一个驱动程序, 当然也有例外( 如cdc-acm).
我们知道USB 设备都是通过插入上层HUB 的一个Port 来连入系统并进而被系统发现的,当USB 设备插入一个HUB 时, 该HUB 的那个port 的状态就会改变,从而系统就会知道这个改变,此时会调用hub_port_connect_change() /*driver/usb/core/hub.c*/
static void hub_connect_change(struct usb_hub *hub, int portl, u16 portstatus, u16 portchange)
{
….
usb_new_device(udev);
…
}
该函数创建一个usb_device 的对象udev,并初始化它, 接着调用usb_new_device() 来获取这个usb 设备的各种描述符并为每个interface 找到对用的driver.
int usb_new_device(struct usb_device *udev)
{
….
err = usb_get_configuration(udev);
….
device_add(&udev->dev);
}
该函数首先调用usb_get_configuration() 来获取设备的各种描述符( 设备描述符, 配置描述符等), 接着调用device_add() 来把这个USB 设备添加到USB 系统中去,也就是在这个过程中系统回去为这个设备找到相应的驱动.在2.6 的早期的一些版本中在分析配置描述符后得到interface 的同时把interface 作为设备来调用device_add() 的
int device_add(struct device *dev)
{
….
if((error = bus_add_device(dev)))
…
bus_attach_device(dev);
…
}
这个函数是个通用的设备管理函数, 它会为每个设备调用bus_add_device 来把这个设备添加到相应bus 的设备列表中去.接着调用bus_attach_device() 来匹配对应的驱动程序,对于USB 设备来说第一次调用bus_attach_device() 时的参数dev 代表的是整个usb 设备( 以后usb 设备中的interface 也会作为设备调用这个函数).
int bus_attach_device(struct device *dev)
{
…
ret = device_attach(dev);
…
}
这个函数就是用来为设备找到相应的设备驱动程序的( 通过调用device_attach() 实现).
int device_attach(struct device *dev)
{
…
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
…
}
该函数调用bus_for_each_drv() 来从总线上已注册的所有驱动中找出匹配的驱动程序.
int bus_for_each_drv(struct bus_type *bus,
struct device_driver *start,
void *data,
int (*fn)(struct device_driver *, void *))
{
….
while((drv = next_driver(&i)) && !error)
error = fn(drv, data); // 返回0 将继续搜索, 返回错误值将停止搜索.
…
}
该函数遍历bus 上的所有驱动程序, 并为每个驱动调用fn() 来查看是否匹配.这里的fn 就是__device_attach.
static int __device_attach(struct device_driver *drv, void *data)
{
struct device *dev = data;
return driver_probe_device(drv, dev);
}
int driver_probe_device(struct device *drv, struct device *dev)
{
…
if(drv->bus->match && !drv->bus_match(dev, drv))
…
ret = really_probe(dev, drv);
}
对于usb 驱动来说, 我们通过usb_registe()r 来注册我们的驱动程序, 这个函数会为我们的驱动程序对象(usb_driver) 中的bus 指定为usb_bus_type:
Struct bus_type usb_bus_type = {
…
.match = usb_device_match,
….
}
因此对于usb 驱动会首先调用usb_device_match().
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
if(is_usb_device(dev)) { /*dev 代表整个usb 设备*/
….
}
else /*dev 代表一个usb 设备interface*/
{
…
usb_match_id();
…
usb_match_dynamic_id();
…
}
}
这个函数只是做一些粗略的匹配,如果匹配成功则返回1, 然后由really_probe 来做进一步的匹配,如果匹配失败则返回0,并且really_probe 也不会在执行.这个函数的调用保证了dev, drv 要么都是设备级别的( 即dev 代表usb 设备,drv 代表usb 设备驱动),要么都是接口级别的( 即dev 代表usb 设备的一个interface,drv 代表usb 接口驱动).
static int really_probe(struct device *dev, struct device_driver *drv)
{
…
dev->driver = drv; // 先赋值, 以后的probe 过程中会用到
else if(drv->probe)
ret = drv->probe(dev);
…
probe_failed:
dev->drvier = NULL; //probe 失败,重设它
…
}
对于usb 来说这个函数的调用有2 种分支, 1: dev,drv 代表的是设备级别的, 2 dev,drv 代表的是接口级别的.其他情况组合在usb_device_match 中被过滤掉了,
分支1: dev,drv 代表的是设备级别:
此时的drv 肯定是usb_generic_driver.因为在当前的usb 系统中只有这个driver 是代表整个设备的驱动, 它是在usb_init 中被注册的,而我们通常写的usb 驱动都是代表一个interface 的.
struct usb_device_driver usb_generic_driver = {
…
.probe = generic_probe,
…
}
因此, 此时的drv->probe 将调用generic_probe().
static int generic_probe(struct usb_device *udev)
{
…
c = choose_configuration(dev);
if(c >= 0) {
err = usb_set_configuration(udev, c); // 设置配置, 并注册interface.
…
}
…
}
该函数为这个usb 设备选择一个合适的配置, 并注册这个配置下面的interface.
int usb_set_configuration(struct usb_device *dev, int configuration)
{
…
for(I = 0; I < nintf; i++) {
struct usb_interface *intf = cp->interface[i];
…
device_add(&intf->dev);
…
}
…
}
该函数比较重要,但我们只关心probe 过程因此省掉了很多东西.它为当前配置下的每个interface 调用device_add() 函数,根据前面的分析可知,这个过程将会走到接下来我们要分析的分支2.
分支2: dev,drv 代表的是interface 级别:
此时的dev 代表着一个interface,而drv 就代表了我们自己的usb 驱动.但是我们应当看到drv 是device_driver 类型,而我们写的usb 驱动的类型一般是usb_driver,因此这里的probe 和我们自己写的probe 显然不是同一个.实际上这里的drv 是我们的驱动对象里内嵌的一个子对象( 因为linux 下所以的驱动都必须用device_driver 来代表,).那这个子对象的probe 函数是在哪里赋值的呢?这就要看usb_register 函数了,
跟踪这个函数我们可以看到这里的probe 函数实际上是usb_probe_interface( 所有的usb interface 驱动都是一样的).
static int usb_probe_interface(struct device *dev)
{
struct driver = to_usb_driver(dev->driver); //dev->driver 在really_probe 中设置.
…
error = driver->probe(intf, id); // 这个就是我们自己写的probe 函数了.
…
}
driver->probe(intf, id);这就调用到我们自己写的代码里面了,
整个流程大概就是这样:
linux 设备驱动程序 过滤,Linux驱动发开,usb设备的probe全过程相关推荐
- 嵌入式linux查看usb设备驱动程序,嵌入式Linux下USB驱动程序的设计
嵌入式Linux下USB驱动程序的设计 usb概念: USB(Universal Serial Bus)即通用串行总线,是一种全新的双向同步传输的支持热插拔的数据传输总线,其目的是为了提供一种兼容不 ...
- linux u 驱动程序,在uClinux中增加自己的设备驱动程序
驱动程序的使用可以按照两种方式编译,一种是静态编译进内核,另一种是编译成模块以供动态加载.由于 uClinux不支持模块动态加载,而且嵌入式Linux不能够象桌面Linux那样灵活的使用insmod/ ...
- linux红外驱动程序,基于Linux操作系统和红外发射器实现系统模块的设计
引 言 随着嵌入式系统及集成电路技术的飞速发展,针对移动手持终端的专用芯片获得了长足发展.芯片的RAM和ROM的容量越大,在上面跑操作系统也越来越容易.Linux是当今流行的操作系统之一.由于其内核健 ...
- linux gpio设备驱动程序,嵌入式Linux设备驱动开发之:GPIO驱动程序实例-嵌入式系统-与非网...
11.3 GPIO驱动程序实例 11.3.1 GPIO工作原理 FS2410开发板的S3C2410处理器具有117个多功能通用I/O(GPIO)端口管脚,包括GPIO 8个端口组,分别为GPA(2 ...
- 从零开始之驱动发开、linux驱动(二十三、platform总线之数据驱动分离)
本节开始引入总线概念. 总线是一种虚拟的概念,不针对任何具体的外设,但是它可以比较好的管理外设. 总线对外设的管理从设备和驱动两个方面说明. 比如我们有3个led灯要控制,一种是向我们之前的那样在软件 ...
- 从零开始之驱动发开、linux驱动(四十四、虚拟网卡驱动)
网卡驱动的书写格式很简单 1.申请一个网卡设备结构体 2.设置这个结构体,硬件相关初始化 3.注册这个网卡设备 参考的韦东山老师的视屏,代码如下 #include <linux/module.h ...
- 从零开始之驱动发开、linux驱动(四十七、linux下的IIC框架【1】)
I2C总线仅仅使用SCL. SDA这两根信号线就实现了设备之间的数据交互, 极大地简化了对硬件资源和PCB板布线空间的占用. 因此, I2C总线非常广泛地应用在EEPROM. 实时钟. 小型LCD等设 ...
- 从零开始之驱动发开、linux驱动(二十五、framebuffer 子系统框架)
一.概念 Framebuffer,也叫帧缓冲,其内容对应于屏幕上的界面显示,可以将其简单理解为屏幕上显示内容对应的缓存,修改Framebuffer中的内容,即表示修改屏幕上的内容,所以,直接操作Fra ...
- 从零开始之驱动发开、linux驱动(六十七、内核调试篇--printk使用)
printk的使用我们在内核,驱动调试的时候使用的非常多 比如前面在调试usb驱动的时候 #include <linux/init.h> #include <linux/usb/in ...
最新文章
- ListView和数据适配器SimpleAdapter例子
- 数学建模 随机动态规划
- Linux-进程内存占用情况
- SSM+Netty项目结合思路
- 通过回调函数阻止进程创建(验证结束,方案完全可行)
- Java 对用户密码加密(Jeecg 登录密码加密方式)MD5andDES方式
- android shape使用总结
- 阿里广告技术最新突破!全链路联动——面向最终目标的全链路一致性建模
- 关于android隐式启动activity的分析和说明,Android学习之Intent中显示意图和隐式意图的用法实例分析...
- [导入]DotNetNuke 模組偵錯(DNN module debug)
- Asp.Net异步加载
- handlersocket mysql_[原创]MongoDB、HandlerSocket和MySQL性能测试及其结果分析
- IE8-阿里icon字体引用不显示的问题
- win7设置自动开机时间_使计算机自动开机
- Vue教程-day05-2018年12月25日笔记
- 程序员接私活的7大利器以及建议
- 你投的简历提示不合适,建议参考STAR法则
- 在Home Assistant中配置天气信息
- windows搭建Git服务器之Bonobo Git Server
- Wireless Communication学习笔记-路径损耗,阴影和多径效应