linux2.6.35 mx535
usbserial modem老是disconnect,分析一下usb主控制器驱动原理及linux下主机对设备的枚举过程。
硬件接口
Chapter 77
Universal Serial Bus Controller (USB)
架构图如下,共计4个主机控制器,使用host 1
hi3518的架构更简单一些,
对比一下:
和mx535一样,hi3518控制器和收发器phy之间使用utmi。
并且root hub位于控制器内部。mx535架构图上没体现出来。
通用usb枚举过程
几个概念
传输transfer的分类:
1.控制传输:对设备进行控制,使用控制端点进行传输,主要用在usb枚举时
2.等时传输:
3.中断传输:鼠标键盘等hid设备均是
4.批量传输:u盘
事务transaction的分类:
1.in
2.out
3.setup
包packet的分类:
1.setup(令牌)
2.data(数据)
3.ack(握手)
几个概念的关系:
传输由若干个事务组成,事务由若干个包组成,包又域组成。
usb枚举过程:
1.获取设备描述符
2.复位
3.设置地址
4.再次获取设备描述符
5.获取配置描述符
6.获取接口,端点描述符
7.获取字符串描述符
8.选择设备配置
每个传输由主机发起,在usb枚举时的各个动作都是由传输完成,大部分是一个传输即可完成:
1.获取设备描述符----使用一个控制传输
2.复位----使用一个reset包
3.设置地址----使用一个控制传输
4.再次获取设备描述符----使用一个控制传输
5.获取配置描述符----使用n个控制传输
6.获取接口,端点描述符----使用一个控制传输
7.获取字符串描述符----使用n个控制传输
8.选择设备配置----使用一个控制传输
监视鼠标枚举:
关于端点:
端点的输入和输出都是以host而言的。
端点是成对出现的。
usb主机和usb设备如鼠标等都会有输入端点0和输出端点0,分别是芯片内部的若干字节的buffer,大于8bytes。
在枚举阶段,
usb设备将数据如设备描述符写入自身的输入端点0(对host而言输入),然后经过物理传输,host会在自身的输入端点收到数据。
usb设备读自身的输出端点0(对host而言的输出),将会读到host传来的命令信息比如获取设备描述符,host是通过将命令写入自身的输出端点0,然后经过物理传输,到达设备的输出端点0的。
比如d12芯片包括控制端点在内的3个端点,如下:
驱动实现
先看插上modem之后的打印信息:
root@freescale /$ hub 2-1.4:1.0: drivers/usb/core/hub.c,hub_events,3403, state 7 ports 7 chg 0000 evt 0010
drivers/usb/core/hub.c,hub_events,3447: ----------------------hub->descriptor->bNbrPorts=7,i=1
drivers/usb/core/hub.c,hub_events,3447: ----------------------hub->descriptor->bNbrPorts=7,i=2
drivers/usb/core/hub.c,hub_events,3447: ----------------------hub->descriptor->bNbrPorts=7,i=3
drivers/usb/core/hub.c,hub_events,3447: ----------------------hub->descriptor->bNbrPorts=7,i=4
drivers/usb/core/hub.c,hub_port_status,407: status=101,change=1
hub 2-1.4:1.0: drivers/usb/core/hub.c,hub_port_connect_change,3100, port 4, status 0101, change 0001, 12 Mb/s
drivers/usb/core/hub.c,hub_port_connect_change,3102: portstatus=101,portchange=1
drivers/usb/core/hub.c,hub_port_status,407: status=101,change=0
drivers/usb/core/hub.c,hub_port_status,407: status=101,change=0
drivers/usb/core/hub.c,hub_port_status,407: status=101,change=0
drivers/usb/core/hub.c,hub_port_status,407: status=101,change=0
drivers/usb/core/hub.c,hub_port_status,407: status=101,change=0
hub 2-1.4:1.0: debounce: port 4: total 100ms stable 100ms status 0x101
drivers/usb/core/hub.c,hub_port_status,407: status=103,change=10
usb 2-1.4.4: ------new full speed USB device using fsl-ehci and address 18
drivers/usb/core/hub.c,hub_port_status,407: status=111,change=0
hub 2-1.4:1.0: port 4 not reset yet, waiting 10ms
drivers/usb/core/hub.c,hub_port_status,407: status=103,change=10
usb 2-1.4.4: udev 18, busnum 2, minor = 145
usb 2-1.4.4: New USB device found, idVendor=1ab7, idProduct=5740
usb 2-1.4.4: New USB device strings: Mfr=0, Product=0, SerialNumber=0
option 2-1.4.4:1.0: GSM modem (1-port) converter detected
usb 2-1.4.4: GSM modem (1-port) converter now attached to ttyUSB5
option 2-1.4.4:1.1: GSM modem (1-port) converter detected
usb 2-1.4.4: GSM modem (1-port) converter now attached to ttyUSB6
option 2-1.4.4:1.2: GSM modem (1-port) converter detected
usb 2-1.4.4: GSM modem (1-port) converter now attached to ttyUSB7
option 2-1.4.4:1.3: GSM modem (1-port) converter detected
usb 2-1.4.4: GSM modem (1-port) converter now attached to ttyUSB8
option 2-1.4.4:1.4: GSM modem (1-port) converter detected
usb 2-1.4.4: GSM modem (1-port) converter now attached to ttyUSB9
option 2-1.4.4:1.5: GSM modem (1-port) converter detected
usb 2-1.4.4: GSM modem (1-port) converter now attached to ttyUSB10
line 15 hub 2-1.4:1.0: drivers/usb/core/hub.c,hub_port_connect_change,3100, port 4, status 0101, change 0001, 12 Mb/s
hub 2-1.4:1.0 其中
hub表示2-1.4是一个hub.
2表示2号总线或2号主机控制器或2号root hub。
1表示2号hub下的第一个口所接的东东(可以是hub或device)
4表示上面第一个口所接的东东(hub)的第4个口所接的东东表示2-1.4是一个hub.
即2号root hub下的第1个口接了一个hub,这个hub的第4个口也接的是个hub
line 28 usb 2-1.4.4: udev 18, busnum 2, minor = 145
usb 表示2-1.4.4是一个usb设备
合起来是2号root hub下的第1个口接了一个hub,这个hub下的第4个口接了一个接了一个hub,这hub下的第4个口接了一个usb device
line 31 option 2-1.4.4:1.0: GSM modem (1-port) converter detected
2-1.4.4:1.0表示最后一层hub的第4个口接了一个usb device,此device的配置1的接口0 (被转换成一个串口)
usb/serial/usbserial.c usb转串口驱动
usb/serial/bus.c
usb/host/ehci-hcd.c usb主机控制器驱动
usb/host/ehci-arc.c
usb/host/ehci-hub.c
usb/core/hub.c 负责usb设备的枚举
linux中使用usb_hcd描述usb主机控制器驱动,
在ehci-hcd.c进行平台设备ehci_fsl_driver的注册
#ifdef CONFIG_USB_EHCI_FSL
#include "ehci-fsl.c"
#define PLATFORM_DRIVERehci_fsl_driver
#endif
retval = platform_driver_register(&PLATFORM_DRIVER);
而ehci_fsl_driver则是定义在ehci-arc.c的平台驱动:
static struct platform_driver ehci_fsl_driver = {
.probe = ehci_fsl_drv_probe,
.remove = ehci_fsl_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ehci_fsl_drv_suspend,
.resume = ehci_fsl_drv_resume,
#endif
.driver = {
.name = "fsl-ehci",
},
};
平台驱动ehci_fsl_driver的probe函数中创建了usb_hcd, hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); 位于ehci-arc.c
usb_hcd的hc_driver ehci_fsl_hc_driver很重要,实现usb很多操作的函数指针
ehci主机控制器用ehci_hcd结构体描述,和usb_hcd结构体使用私有数据指针联系。
ehci_hcd结构体的初始化位于ehci-hcd.c的ehci_init()
struct ehci_hcd
*ehci = hcd_to_ehci(hcd);
ehci->need_io_watchdog = 1;
init_timer(&ehci->watchdog);
ehci->watchdog.function = ehci_watchdog;
ehci->watchdog.data = (unsigned long) ehci;
init_timer(&ehci->iaa_watchdog);
ehci->iaa_watchdog.function = ehci_iaa_watchdog;
ehci->iaa_watchdog.data = (unsigned long) ehci;
在hub_port_connect_change函数中所调用的函数中,有两个函数很重要
分别是hub_port_init和usb_new_device,如下
hub_events()------->hub_port_connect_change()------->hub_port_init()------->hub_port_reset------->hub_port_wait_reset------->hub_port_status获取此口所接设备的速度
hub_events()------->hub_port_connect_change()------->usb_new_device()------->usb_enumerate_device()------->usb_get_configuration()获取设备描述符
usb driver中的提交函数usb_submit_urb()最终是通过usb core机制调用了主机控制器的urb_enqueue(),将数据通过phy发出
usb_submit_urb()------->usb_hcd_submit_urb()(位于usb/core/hcd.c)-------> hcd->driver->urb_enqueue()(位于usb/host/ehci-arc.c)-------> ehci_urb_enqueue()(位于usb/host/ehci-hcd.c)
windows下监视usb
在任务管理器中可以观察到usb host ctrl和root hub
使用 usb bound更清楚,并可以监视usb数据传输。
从下图一目了然,每个控制器下挂的hub,每个hub下挂的设备:
一般笔记本上引出的usb口,都是位于不同的hub下的.
在device页选中要监视的设备,在capture点击run即可监视。
linux下监视usb
lsusb -v