基于mt6750T,Android 7.0,kernel 3.18.35,本文主要简述了USB的枚举过程,主要是从host的角度来看。

一.USB的拓扑结构

简单来说,USB由host和device两部分组成,hub和function device统称为device,最多支持128个设备。host和root hub是紧密联系的。

二.USB设备的枚举过程

1.host和hub已经初始化完,device并未插入hub的port,此时device处于UNATTACHED状态。

2.host通过status change ep(属于Interrupt类型)对hub进行轮询,当设备插入port,hub的状态发生改变,此时hub向host返回状态变更信息,此时device处于ATTACHED状态。

3.host查询hub的状态变更并确认变更信息

4.host已经确认有device插入,等待至少100ms等待device插好并且port口power保持稳定,此时device处于POWERED状态。

5.host对hub的port进行reset操作,port开始使能。device进入DEFAULT状态并且能够从port获取不超过100mA的电流,此时device的所有register和state都进行复位。

6.host给device分配一个特殊的地址(地址0,的确很特殊啊),此时device处于ADDRESSED状态。

7.device被分配为地址0,可以通过默认的控制管道(ep0)对device进行操作。host获取device的设备描述符,确认ep0最大的数据包长度。

8.host获取device的配置信息(配置描述符,接口描述符和端点描述符),从0~n-1,n是device的配置数。然后选取configuration和interface进行配置。此时设备处于CONFIGURED状态。

三.USB的状态变更图

四.代码分析

以下代码分析从bus->host controller->hub->device的顺序进行分析,代码分析以流程为主,细节这里就不列出来了。

4.1 Bus

//usb/core/usb.c

static int __init usb_init(void)

{

......

//注册usb总线

retval= bus_register(&usb_bus_type);

......//注册hub driver并创建workqueue “usb_hub_wq”

retval=usb_hub_init();

......

//注册usb设备驱动usb_generic_driver

retval= usb_register_device_driver(&usb_generic_driver, THIS_MODULE);

......

}

usb_bus_type的match函数。usb里面区分设备和接口的概念,接口对应功能,一个usb设备可能包含多个接口,比如我们的android手机属于usb设备,插入usb可以选择usb模式,MTP、PTP、ADB等等,这些模式对应接口的概念。

设备包含一个或多个配置

配置包含一个或多个接口

接口包含零个或多个端点

struct bus_type usb_bus_type ={

.name= "usb",

.match=usb_device_match,

.uevent=usb_uevent,

};

/*

* 将usb设备及设备驱动,usb接口及接口驱动区分对待

*/static int usb_device_match(struct device *dev, struct device_driver *drv)

{//属于usb设备?

if(is_usb_device(dev)) {//不是usb设备驱动则直接返回

if (!is_usb_device_driver(drv))return 0;

return 1;

//属于usb接口?

}else if(is_usb_interface(dev)) {struct usb_interface *intf;struct usb_driver *usb_drv;const struct usb_device_id *id;//为usb设备类型则直接返回

if(is_usb_device_driver(drv))return 0;

intf=to_usb_interface(dev);

usb_drv=to_usb_driver(drv);

//接口和driver的id_table进行匹配

id= usb_match_id(intf, usb_drv->id_table);if(id)return 1;

//动态匹配相关

id=usb_match_dynamic_id(intf, usb_drv);if(id)return 1;

}return 0;

}

usb_hub_init分析,hub_driver的函数等到hub这节再进行分析

int usb_hub_init(void)

{//注册hub驱动

if (usb_register(&hub_driver) < 0) {

printk(KERN_ERR"%s: can't register hub driver\n",

usbcore_name);return -1;

}//创建workqueue

hub_wq = alloc_workqueue("usb_hub_wq", WQ_FREEZABLE, 0);

......

}

usb_register

#define usb_register(driver) \usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)int usb_register_driver(struct usb_driver *new_driver, struct module *owner,const char *mod_name)

{//for_devices为0表明这是interface driver,属于接口范畴

new_driver->drvwrap.for_devices = 0;

new_driver->drvwrap.driver.name = new_driver->name;

new_driver->drvwrap.driver.bus = &usb_bus_type;//接口匹配probe函数,最终执行interface driver的probe

new_driver->drvwrap.driver.probe =usb_probe_interface;

new_driver->drvwrap.driver.remove =usb_unbind_interface;

new_driver->drvwrap.driver.owner =owner;

new_driver->drvwrap.driver.mod_name =mod_name;

spin_lock_init(&new_driver->dynids.lock);

INIT_LIST_HEAD(&new_driver->dynids.list);//驱动注册

retval = driver_register(&new_driver->drvwrap.driver);

}

usb_register_device_driver

int usb_register_device_driver(struct usb_device_driver *new_udriver,struct module *owner)

{//for_devices为1表明这是device driver,属于设备范畴

new_udriver->drvwrap.for_devices = 1;

new_udriver->drvwrap.driver.name = new_udriver->name;

new_udriver->drvwrap.driver.bus = &usb_bus_type;//之前的match函数匹配上则执行drvwrap.driver.probe函数

//usb_probe_device最终调用driver的probe   new_udriver->drvwrap.driver.probe =usb_probe_device;

new_udriver->drvwrap.driver.remove =usb_unbind_device;

new_udriver->drvwrap.driver.owner =owner;//驱动注册

retval = driver_register(&new_udriver->drvwrap.driver);

}

4.2 Host Controller

host controller主要围绕usb_create_hcd&usb_add_hcd 展开

//usb/core/hcd.c

struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,struct device *dev, const char *bus_name)

{//直接甩锅给其他函数,主要就是hcd的分配空间及初始化,不细究了

returnusb_create_shared_hcd(driver, dev, bus_name, NULL);

}

//usb/core/hcd.c/** 完成hcd的初始化并进行注册*/

int usb_add_hcd(struct usb_hcd *hcd,

unsignedint irqnum, unsigned longirqflags)

{//从phy_bind_list中获取phy device,并进行初始化

usb_get_phy_dev(hcd->self.controller, 0);

usb_phy_init(phy);//初始化buffer pools,分两种情况:DMA memory和非DMA memory//DMA memory则调用dma_pool_create,后续调用dma_poll_alloc//非DMA则后续直接调用kmalloc

hcd_buffer_create(hcd);//注册usb host controller,一个host controller对应一条总线

usb_register_bus(&hcd->self);//申请root hub设备

rhdev = usb_alloc_dev(NULL, &hcd->self, 0);//hcd的reset

if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {gotoerr_hcd_driver_setup;

}//申请hcd的中断处理函数,即hcd->driver->irq

usb_hcd_request_irqs(hcd, irqnum, irqflags);//hcd start

hcd->driver->start(hcd);//注册root hub设备

register_root_hub(hcd);

}

usb_alloc_dev

struct usb_device *usb_alloc_dev(struct usb_device *parent,struct usb_bus *bus, unsigned port1)

{//申请设备内存空间

dev = kzalloc(sizeof(*dev), GFP_KERNEL);//调用usb_hcd->driver->alloc_dev

if (usb_hcd->driver->alloc_dev && parent &&

!usb_hcd->driver->alloc_dev(usb_hcd, dev)) {

usb_put_hcd(bus_to_hcd(bus));

kfree(dev);returnNULL;

}//设备隶属总线usb_bus_type,属于usb设备类型而非接口类型

device_initialize(&dev->dev);

dev->dev.bus = &usb_bus_type;

dev->dev.type = &usb_device_type;

dev->dev.groups =usb_device_groups;//设备状态标记为ATTACHED

dev->state =USB_STATE_ATTACHED;//初始化并使能ep0

INIT_LIST_HEAD(&dev->ep0.urb_list);

dev->ep0.desc.bLength =USB_DT_ENDPOINT_SIZE;

dev->ep0.desc.bDescriptorType =USB_DT_ENDPOINT;

usb_enable_endpoint(dev,&dev->ep0, false);//设置portnum

dev->portnum =port1;

}

register_root_hub

static int register_root_hub(struct usb_hcd *hcd)

{//root hub的address设置为1

const int devnum = 1;

usb_dev->devnum =devnum;//下一个注册在该总线上的设备address从2开始

usb_dev->bus->devnum_next = devnum + 1;//标记设备状态为ADDRESSED

usb_set_device_state(usb_dev, USB_STATE_ADDRESS);//ep0最大包长度

usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);//获取设备描述符,18个byte

usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);//注册root hub设备

usb_new_device (usb_dev);

}

usb_new_device

int usb_new_device(struct usb_device *udev)

{//获取描述符(包括配置,接口,端点描述符)

usb_enumerate_device(udev); /*Read descriptors*/

//注册设备,加入统一设备模型

device_add(&udev->dev);

}

usb_enumerate_device

static int usb_enumerate_device(struct usb_device *udev)

{//获取描述符(包括配置,接口,端点描述符),解析描述符的过程这里就不贴了^_^

usb_get_configuration(udev);//获取产品序列,制造序列和序列号

udev->product = usb_cache_string(udev, udev->descriptor.iProduct);

udev->manufacturer =usb_cache_string(udev,

udev->descriptor.iManufacturer);

udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);//otg相关,偷个懒,暂时放着不考虑

usb_enumerate_device_otg(udev);

}

4.3 Hub

上面已经注册了root hub设备,此时属于usb设备的范畴,首先执行drvwrap_driver_probe函数(usb_probe_device),之后调用usb_generic_driver->probe函数(generic_probe)

static int generic_probe(struct usb_device *udev)

{//前面添加root hub,通过usb_new_device已经获取到了配置描述符,这里选择配置描述符,大多数设备只有一种配置usb_choose_configuration(udev);//创建接口设备,设置配置usb_set_configuration(udev, c);

usb_notify_add_device(udev);return 0;

}

usb_set_configuration

int usb_set_configuration(struct usb_device *dev, intconfiguration)

{for (i = 0; i < nintf; ++i) {

//使用setting num为0的altsetting,这里setting num和数组下标并不存在一一对应关系

alt= usb_altnum_to_altsetting(intf, 0);

//没有num为0则使用第一个settingif (!alt)

alt= &intf->altsetting[0];

//使能接口,里面调用使能端点 usb_enable_interface(dev, intf,true);

//表明属于接口设备类型 intf->dev.bus = &usb_bus_type;

intf->dev.type = &usb_if_device_type;

intf->dev.groups =usb_interface_groups;

device_initialize(&intf->dev);

}

//控制传输,设置配置 ret= usb_control_msg(dev, usb_sndctrlpipe(dev, 0),

USB_REQ_SET_CONFIGURATION,0, configuration, 0,

NULL,0, USB_CTRL_SET_TIMEOUT);

//usb设备状态为CONFIGURED

usb_set_device_state(dev, USB_STATE_CONFIGURED);for (i = 0; i < nintf; ++i) {

//添加接口设备并创建端点设备

ret= device_add(&intf->dev);

create_intf_ep_devs(intf);

}

}

注册了接口设备,那必然要与总线上的接口驱动相match,与驱动的id_table或者动态id匹配。hub设备顾名思义就是与hub_driver匹配,执行hub_driver->probe函数

整个以上过程可以用下面图展示

static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)

{//判断端点是否属于中断类型,前面提到host通过中断端点进行轮询hub

if (!usb_endpoint_is_int_in(endpoint))gotodescriptor_error;//初始化hub_event任务,hub_event处理设备插入hub端口时的事件

INIT_WORK(&hub->events, hub_event);//hub配置

hub_configure(hub, endpoint);

}

hub_configure

static int hub_configure(struct usb_hub *hub,struct usb_endpoint_descriptor *endpoint)

{//获取hub描述符,之后对hub描述符进行分析,分析bNbrPorts,wHubCharacteristics,bDeviceProtocol这些字段

ret = get_hub_descriptor(hdev, hub->descriptor);//获取USB设备状态,这里属于标准请求,主要是D0 bit的设备是否self powered

ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);//获取hub的状态,属于hub类型请求,由两个2byte的字段组成,wHubStatus和wHubChange,跟供电状态和是否过流相关

ret = hub_hub_status(hub, &hubstatus, &hubchange);//创建pipe

pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);

maxp=usb_maxpacket(hdev, pipe, usb_pipeout(pipe));//创建中断urb,urb完成函数hub_irq,当hub有状态发生变化时就调用kick_hub_wq将hub->events加入workqueue,这种针对热插拔时USB枚举的情况

hub->urb = usb_alloc_urb(0, GFP_KERNEL);

usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval);//创建端口设备,有多少个端口就创建多少个端口设备

usb_hub_create_port_device(hub, i + 1);//hub初始化,分为三部曲

hub_activate(hub, HUB_INIT);

}

hub初始化三部曲

static void hub_activate(struct usb_hub *hub, enumhub_activation_type type)

{//init第一部曲,hub上电

if (type ==HUB_INIT) {

unsigned delay=hub_power_on_good_delay(hub);

hub_power_on(hub,false);

INIT_DELAYED_WORK(&hub->init_work, hub_init_func2);

queue_delayed_work(system_power_efficient_wq,&hub->init_work,

msecs_to_jiffies(delay));return;

}//初始化第二部曲,检测端口状态变化

init2:for (port1 = 1; port1 <= hdev->maxchild; ++port1) {

status= hub_port_status(hub, port1, &portstatus, &portchange);

set_bit(port1, hub->change_bits);

}if(need_debounce_delay) {

delay=HUB_DEBOUNCE_STABLE;if (type ==HUB_INIT2) {

INIT_DELAYED_WORK(&hub->init_work, hub_init_func3);

queue_delayed_work(system_power_efficient_wq,&hub->init_work,

msecs_to_jiffies(delay));

device_unlock(hub->intfdev);return; /*Continues at init3: below*/}else{

msleep(delay);

}

}//初始化第三部曲,hub->events加入workqueue,进行端口状态变化的后续处理,这种针对hub初始化时候USB设备的枚举过程

init3:

status= usb_submit_urb(hub->urb, GFP_NOIO);

kick_hub_wq(hub);

}

hub_event

static void hub_event(struct work_struct *work)

{for (i = 1; i <= hdev->maxchild; i++) {//hub端口状态发生改变,调用port_event函数,里面主要为usb设备的枚举过程

port_event(hub, i);

}

}

4.4 Device

port_event

static void port_event(struct usb_hub *hub, intport1)

__must_hold(&port_dev->status_lock)

{//主要调用下面函数

hub_port_connect_change(hub, port1, portstatus, portchange);

}

hub_port_connect_change

static void hub_port_connect_change(struct usb_hub *hub, intport1,

u16 portstatus, u16 portchange)

__must_hold(&port_dev->status_lock)

{//继续直接甩锅

hub_port_connect(hub, port1, portstatus, portchange);

}

下面开始正戏了

static void hub_port_connect(struct usb_hub *hub, intport1, u16 portstatus, u16 portchange)

{//创建usb设备,此时设备处于ATTACHED状态

udev = usb_alloc_dev(hdev, hdev->bus, port1);//设备处于POWERED状态

usb_set_device_state(udev, USB_STATE_POWERED);//选择devicemap中第一个不为0的bit数作为设备number

choose_devnum(udev);//复位,分配地址,获取设备描述符

status =hub_port_init(hub, udev, port1, i);

//注册usb设备,之后的流程参考前面root hub,设置configuration&interface

status = usb_new_device(udev);

}

hub_port_init

static inthub_port_init (struct usb_hub *hub, struct usb_device *udev, intport1,intretry_counter)

{//更新udev->devnum为0,最终调用hcd->driver->reset_device函数,复位后设备处于DEFAULT状态,默认状态下的设备地址为0

hub_port_reset(hub, port1, udev, delay, false);//根据设备类型,设置ep0最大传输包长度,高速和低速确定,但是全速不确定,需要从设备描述符中获取

switch (udev->speed) {caseUSB_SPEED_SUPER:case USB_SPEED_WIRELESS: /*fixed at 512*/udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);break;case USB_SPEED_HIGH: /*fixed at 64*/udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);break;case USB_SPEED_FULL: /*8, 16, 32, or 64*/

/*to determine the ep0 maxpacket size, try to read

* the device descriptor to get bMaxPacketSize0 and

* then correct our initial guess.*/udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);break;case USB_SPEED_LOW: /*fixed at 8*/udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);break;default:gotofail;

}//获取设备描述符,获取长度为64byte,来确定ep0的最大传输包长度

usb_control_msg(udev, usb_rcvaddr0pipe(),

USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,

USB_DT_DEVICE<< 8, 0,

buf, GET_DESCRIPTOR_BUFSIZE,

initial_descriptor_timeout);//参考choose_devnum定义的devnum,分配设备地址,此时设备处于ADDRESSED状态

hub_set_address(udev, devnum);//先获取前8个字节,第一个byte即是该描述符的长度

usb_get_device_descriptor(udev, 8);//再获取一次,得到完整的设备描述符

usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);

}

host速度 mtk usb_mtk-usb代码分析之枚举过程相关推荐

  1. DispatcherServlet代码分析及运行过程

    DispatcherServlet代码分析及运行过程 1    首先该类有一静态语块,用以加载缺省策略. static { ClassPathResource resource =new ClassP ...

  2. host速度 mtk usb_mtk-usb代码分析之usb gadget

    基于mt6750T,Android 7.0,kernel 3.18.35,本文主要从USB设备的角度进行分析.(代码部分有省略) 我们的android手机通过usb连入电脑,可以选择多种模式,例如传输 ...

  3. DRM驱动代码分析:开机过程中显示驱动做了什么

    前言: 有些信息是在网上查资料后总结的,没有去追代码验证.如果有说得不对的地方,欢迎提出指正.感谢! 手机启动的大致流程 1.长按开机键 2.执行存储在ROM里(应该是某一个固定地址或是预定义的地址) ...

  4. usb mass storage设备枚举过程

    8月份从PC开发岗位换到底层嵌入式驱动开发来了.接到的第二个活,是在高通8650平台上实现驻留支持SCSI指令.8650平台是高通推出的EVDO RevB的双核平台,和之前6085相比性能更强,软件结 ...

  5. host速度 mtk usb_[MTK] 如何修改usb驱动能力

    [MTK] 如何修改usb驱动能力 2020-03-5 阅读:2732 [DESCRIPTION] USB驱动能力调节方法: USB眼图测试fail处理方法: [SOLUTION] 1.USB眼图测试 ...

  6. Android MTK Camera驱动代码分析

    一.Camera调用过程:      imgsensor起到承上启下的作用,在系统起来时会创建整个camera驱动运行的环境,其中主要的文件和函数如下框图所示,先设备挂载时会调用注册platform设 ...

  7. host速度 mtk usb_Openwrt MTK USB3.0 識別UASP存儲失敗的解決方案

    手裏有個MT7621的設備自己鼓搗鼓搗廢物利用用來做NAS用 發現之前用USB3.0的U盤都可以正常使用 換了USB3.0的移動硬盤盒無法識別出硬盤 執行lsusb -t發現該設備的驅動標示爲uas ...

  8. STM32的USB例程JoyStickMouse代码分析

    https://blog.csdn.net/niepangu/article/details/45081081 本帖最后由 追风 于 2010-12-4 17:30 编辑 一.USB的"Jo ...

  9. USB NCM usbnet 枚举流程代码分析

    USB NCM usbnet 枚举流程代码分析 一.cdc_ncm.c 1.1 [id_table]struct usb_device_id结构体 1.1.1 match_flags 设备类型 1.1 ...

最新文章

  1. Visual C++ 2011-8-15
  2. 异常处理 课后作业2
  3. 整合NHibernate到Spring.Net (之一)
  4. (chap4 IP协议) 多播和子网掩码
  5. matlab radiogroup,RadioGroup和CheckBox的使用 | 学步园
  6. Ext.DomHelper类的使用示例(内容操作)
  7. eclipse 面包屑开关 / 查看class再哪个jar中
  8. ubuntu中,txt导入mysql数据库文件
  9. 使用 jQuery Mobile 与 HTML5 开发 Web App (八) —— jQuery Mobile 工具栏
  10. 【今日CV 计算机视觉论文速览】Mon, 18 Mar 2019
  11. 对于拼接进去的html原来绑定的jq事件失效
  12. Visual Studio 201~ Code 格式检查
  13. 奔图打印linux驱动下载,奔图P3405D打印机驱动下载
  14. linux下查看计划任务,linux查看计划任务.docx
  15. 计算机组成原理/计算机硬件基础第五章:存储器
  16. python单词表首字母排序_python3 列表排序(字母顺序排序、字母相反顺序排序和倒序)...
  17. chrome安装js插件
  18. [024] 微信公众帐号小q机器人实例.
  19. 利用人工势场法的最短路径寻找
  20. redshift 踩坑

热门文章

  1. sql server 2008怎样导入mdf,ldf文件,怎样解决导入mdf,ldf文件时出现附加数据库错误的问题
  2. 数据信号采集系统设计之数据采集系统整体设计
  3. python实例化是什么意思_Python实例化传值问题
  4. 中望CAD的lisp编辑器_CAD应用技巧:中望CAD中加载LISP程序
  5. 基于C++实现MFC简单的纸牌小游戏,附纸牌游戏引擎源码!
  6. 从华为离职了,从华为转正到离职的经历,一起看看他的故事
  7. 电脑上出现应用程序无法正常启动0xc0000142的解决方法
  8. S60手机使用putty进行ssh登录
  9. 在MAC 中修改虚拟机配置文件
  10. Error response from daemon: Get “https://xxx.xxx.com/xxx/“: unauthorized: