usb hub 设备流程图
在此处负责而来:http://blog.csdn.net/xuelin273/article/details/38646851
Linux下usb驱动调用流程
- driver/usb/core/hub.c :
- usb->hun_thread()->hub->events()->hub_port_connect_change()
- driver/usb/core/hub.c
- hub_port_connect_change() //检测到新设备连接
- usb_new_device(udev) //注册新设备
- usb_get_configuration(udev) //获得设备各种描述符
- device_add(&udev->dev) //把这个设备注册到usb系统中
- bus_attach_device(dev) //把这个设备天骄到相应bus的设备列表中
- device_attach() //为设备找到相应的设备驱动程序
- bus_for_each_drv(dev->bus,NULL,dev,__device_attach) //从总线上已注册的所有驱动中找出匹配的驱动程序
- while((drv=next_driver(&i))&&!error)
- error=fn(drv,data);//返回0将机械搜索,返回错误将停止搜索
- next_driver(&i) //遍历bus上的所有驱动程序
- fn(drv,data) //查看驱动是否匹配
- driver_probe_device(drv,dev) //检查设备
- usb_register_device_driver() //注册我们的驱动程序
- //bus_register(&usb_bus_type) drivers/usb/core/usb.c
- //usb_bus_type drivers/usb/core/driver.c
- usb/core/driver.c
- 对于usb驱动会首先调用usb_device_match()
- is_usb_device(dev) //dev代表整个usb设备
- usb_match_id()
- usb_math_dynamic_id() //dev代表usb设备interface
- really_probe() //进一步匹配
- usb设备两种分支:设备级别的,接口级别的。其他的被usb_device_match过滤掉了
- 设备级别
- drv肯定是usb_generic_driver
- 在usb系统中只有driver是代表整个设备的驱动,它是在usb_init中被注册的,而我们通常写的usb驱动都是代表一个interface
- choose_configuration()
- usb_set_configuration(); //设置配置,并注册interface
- device_add() //这里进行相应的接口分析,就会进入我们所说的分支2,接口。
- usb_probe_interface()
- driver->probe(); //这里调用自己的代码就可以了。这个函数就是我们自己写的probe函数。
以上内容是我对下面转载的简单简写,可以提供些参考。
2.6.22下的一个USB设备插上linux系统的PC后是如何一步一步调到我们的usb设备驱动的probe函数的, 我们知道我们的USB驱动的probe函数中的一个参数是interface结构, 因此一般来说, 一个USB设备中的任何一个接口都应该有对应的一个驱动程序,当然也有例外(如cdc-acm).
/*driver/usb/core/hub.c*/:usb_hub_init()-->hub_thread()-->hub_events()-->hub_port_connect_change()
我们知道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_device_driver()来注册我们的驱动程序,这个函数会为我们的驱动程序对象(usb_driver)中的bus指定为usb_bus_type:
//bus_register(&usb_bus_type)---drivers/usb/core/usb.c
//usb_bus_type----drivers/usb/core/driver.c
Struct bus_type usb_bus_type = {
…
.match = usb_device_match,
….
}
usb/core/driver.c
因此对于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/core/driver.c*/ (所有的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); 这就调用到我们自己写的代码里面了,
usb hub 设备流程图的更多相关文章
- 分析USB平台设备模型框架(1)
start_kernel rest_init(); kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); do_basic_setup ...
- USB组合设备 Interface Association Descriptor (IAD)
Communication Device Class,简称CDCUSB Compound Device,USB复合设备USB Composite Device,USB组合设备 摘要USB复合设备 Co ...
- USB Compound Device,USB复合设备 ; USB Composite Device,USB组合设备【转】
本文转载自:https://blog.csdn.net/autumn20080101/article/details/52776863 科普下USB复合设备和USB组合设备的区别. 关键字 Commu ...
- USB之设备插入波形变化2
============= 本系列参考 ============= <圈圈教你玩USB>.<Linux那些事儿之我是USB> 协议文档:https://www.usb.or ...
- MA8601升级版 PL2586|USB HUB 工控级芯片方案PL2586|可直接替代FE1.1S芯片方案
MA8601升级版 PL2586|USB HUB 工控级芯片方案PL2586|可直接替代FE1.1S芯片方案 旺玖在2022年新推出的一款USB HUB 芯片其性能和参数可以完全替代FE1.1S,是M ...
- 如何查找Mac上的USB存储设备使用痕迹
最近刚好有个案子的证物主机是MBP, OS X版本为El Capitan,案况与营业秘密外泄有关,当中要找有关USB存储设备的使用痕迹. 要提醒大家的是,不同版本的OS X,各种迹证的存放文件名称及路 ...
- C# 访问USB(HID)设备
原文:C# 访问USB(HID)设备 二话不说,直接给代码,如果您真想做这方面的东西,还是稍微研究下,没有现成的好类用,就需要自己了解其原理 //引用空间 using System; using Sy ...
- android usb Host模式下与usb Hid 设备的通信
做android 与USB HID设备的通信有段时间了,总结一下遇到的问题和解决方法: 1,第一次遇到的问题:android 版本低不支持usb hid, 被要求做相关项目的时候,就从mUsbMana ...
- OpenWrt挂载USB储存设备实现Samba共享
没有USB接口的路由器不是好路由器,有了USB接口OpenWrt才有更多的玩法,比如挂载U盘.移动硬盘等USB储存设备实现Samba共享,打造小型家庭服务器. 1.安装与USB相关的软件包: opkg ...
随机推荐
- 从0到1分步实现一个出生日期的正则表达式(JavaScript)
简言 在表单验证中,经常会用正则表达式做出生日期校验.本文把出生日期分割成几个部分,分步地介绍了实现一个出生日期校验的完整过程.相信您在理解了本篇的内容后,对如何编写和如何应用正则表达式会有进一步的理 ...
- 根据用户ID生成不重复的最小6位随机邀请码
网上看到一个例子,借鉴修改一下 实现根据long类型的用户ID生成6位随机邀请码,并且根据邀请码能算出用户ID.代码如下: /** 自定义进制(选择你想要的进制数,不能重复且最好不要0.1这些容易混淆 ...
- 安装cadence遇到vcredist.msi找不到问题
在新装的win7 64位系统上安装cadence遇到了如下问题,最后一个群里面的大哥帮了大忙,解决办法如下: 用windowsinstallercleanup 将KB2467175清理掉再装caden ...
- 【js类库AngularJs】解决angular+springmvc的post提交问题
[js类库AngularJs]解决angular+springmvc的post提交问题 AngularJS诞生于2009年,由Misko Hevery 等人创建,后为Google所收购.是一款优秀的前 ...
- [ros]编译ORBSLAM2时候,ros路径问题
CMake Error at CMakeLists.txt:2 (include): include could not find load file: /core/rosbuild/rosbuild ...
- 如何提高Mysql的查询效率???
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...
- Monitorix系统和网络监控工具
Monitorix 系统和网络监控公工具一.monitorixMonitorix是一款功能非常强大的免费开源轻型工具,目的在于监测Linux中的系统和网络资源.它可以定期收集系统和网络数据,并使用自己 ...
- jsp另外五大内置对象之config
//配置web.xml <?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi=&q ...
- 爬去酷狗top500的数据
import requests from bs4 import BeautifulSoup import time headers={ #'User-Agent':'Nokia6600/1.0 (3. ...
- HTTP 错误 404.15 - Not Found请求筛选模块被配置为拒绝包含的查询字符串过长的请求
web项目中,get方式传值是通过地址栏中的url参数进行传递的.除了浏览器对url长度的限制大小不一之外,出于安全考虑, IIS中对于URL中参数大小也是有限制的,默认为2048KB. 如果参数大于 ...