USB hub检测过程
一、USB的电气特性
参考链接:USB协议
在电气结构上,USB设备与主机的连接也很有讲究:
主机端的D-和D+数据线各自被串联15KR电阻下拉到地,当没有USB设备插入的时候,这两条数据线就一直呈现低电平状态。
设备端的D-或者D+数据线,串联一个1.5KR的电阻上拉到3.3V,一旦设备插入主机,那么当主机捕捉到自身的D-或者D+被拉到高电平时,就知道有USB设备连接进来了,这样就检测到有外来USB设备接入了。
对于从机设备中到底是D-还是D+串联1.5KR电阻,这个就要有传输协议的模式来决定了,当配置成全速或高速时,就由D+串联电阻;当配置成低速时,就是D-串联电阻了。
简单来说就是快的就连D+,慢的就连D-。
二、USB hub驱动识别过程
1、USB hub检测log
[ 1400.949084] usb 1-1.2: new high-speed USB device number 31 using xhci-hcd
[ 1401.089506] usb 1-1.2: New USB device found, idVendor=1f75, idProduct=0918
[ 1401.096708] usb 1-1.2: New USB device strings: Mfr=0, Product=3, SerialNumber=4
[ 1401.104758] usb 1-1.2: Product: STORAGE DEVICE
[ 1401.109495] usb 1-1.2: SerialNumber: 02071638
[ 1401.130553] usb-storage 1-1.2:1.0: USB Mass Storage device detected
[ 1401.140091] scsi host1: usb-storage 1-1.2:1.0
[ 1402.189010] scsi 1:0:0:0: Direct-Access Specific STORAGE DEVICE 0009 PQ: 0 ANSI: 4
[ 1402.210918] sd 1:0:0:0: [sdg] Write Protect is off
[ 1402.215912] sd 1:0:0:0: [sdg] Mode Sense: 23 00 00 00
[ 1402.234091] sdg: sdg1
[ 1403.028002] init: Untracked pid 7638 received signal 15
[ 1403.033724] init: Untracked pid 7638 did not have an associated service entry and will not be reaped
[ 1403.042762] FAT-fs (sdg1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
[ 1403.098610] sdcardfs version 2.0
[ 1403.101958] sdcardfs: dev_name -> /mnt/media_rw/B67C-36B5
[ 1403.107547] sdcardfs: options -> fsuid=1023,fsgid=1023,mask=6,userid=0,gid=1015
[ 1403.115133] sdcardfs: mnt -> 00000000836b699d
[ 1403.119731] sdcardfs: mounted on top of /mnt/media_rw/B67C-36B5 type vfat
[ 1403.132000] Remount options were mask=18,gid=9997 for vfsmnt 00000000ee1d03d3.
[ 1403.139458] sdcardfs : options - debug:1
[ 1403.143531] sdcardfs : options - gid:9997
[ 1403.147660] sdcardfs : options - mask:18
[ 1403.156331] Remount options were mask=18,gid=9997 for vfsmnt 00000000467b1290.
[ 1403.163787] sdcardfs : options - debug:1
[ 1403.167849] sdcardfs : options - gid:9997
[ 1403.172008] sdcardfs : options - mask:18
[ 1403.180705] Remount options were mask=7,gid=9997 for vfsmnt 0000000076034062.
[ 1403.188041] sdcardfs : options - debug:1
[ 1403.192191] sdcardfs : options - gid:9997
[ 1403.196322] sdcardfs : options - mask:7
2、驱动代码检测过程过程
上一篇博客刚好从平台设备、驱动的匹配分析到 hub_irq 这个函数这里。
static void hub_irq(struct urb *urb)
{
struct usb_hub *hub = urb->context;
int status = urb->status;
unsigned i;
unsigned long bits;
switch (status) {
....
case 0: // 端口的状态发生了变化
bits = 0;
for (i = 0; i < urb->actual_length; ++i)
bits |= ((unsigned long) ((*hub->buffer)[i]))
<< (i*8);
hub->event_bits[0] = bits; // 保存状态改变的信息
break;
}
hub->nerrors = 0;
/* Something happened, let khubd figure it out */
kick_khubd(hub); // 重要函数 唤醒hub线程
resubmit:
if (hub->quiescing)
return;
if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
&& status != -ENODEV && status != -EPERM)
dev_err (hub->intfdev, "resubmit --> %d\n", status);
}
在 kick_khubd (hub) 中会唤醒执行 wake_up (&khubd_wait) 来唤醒一个程序。那么唤醒的到底是哪个程序呢?
int usb_hub_init(void)
{
// 这里注册了hub_driver 这个在上一篇博客中提到过
if (usb_register(&hub_driver) < 0) {
}
// 这里创建了一个hub_thread 名字叫"khubd"
khubd_task = kthread_run(hub_thread, NULL, "khubd");
/* Fall through if kernel_thread failed */
usb_deregister(&hub_driver);
printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);
return -1;
}
现在可以看看在 hub_thread 这个线程中做一些什么事?
static int hub_thread(void *__unused)
{
set_freezable();
do {
hub_events(); wait_event_freezable(khubd_wait,!list_empty(&hub_event_list) ||
kthread_should_stop());
} while (!kthread_should_stop() || !list_empty(&hub_event_list));
return 0;
}
在这个内核线程中主要执行 hub_events (),但是平时应该是休眠状态,直到有事情发生,其他程序中将其唤醒。因此可以说是在 hub_irq 函数中唤醒了 hub_thread,使得 hub_thread 能够执行 hub_events ()
函数。
当有 usb 设备插入时,主机控制器检测到 hub 端口状态的变化,会执行 hub_irq 函数,然后按照下图的函数调用顺序一路往下执行,实现 usb 设备的识别过程:
(1)给新设备分配地址
(2)并将该地址告诉 usb 设备即设置 usb 地址
(3)发出命令读取描述符
(4)执行 usb_new_device 和 device_add(向总线上添加 usb 设备)
(5)device_add 之后又会执行 usb_device_match 函数和 generic_probe 函数,在 generic_probe 函数中 选择和设置 配置 之后又会执行 device_add(向 usb 总线上添加接口设备)
(6)device_add 之后又会执行 usb_device_match 函数(这个时候应该就根据 id_table 和自己写的设备驱动进行匹配操作了)和 xx_probe 函数(自己驱动的 probe 函数)。
四、USB hub识别出错检错流程
- 检测VCC 5V供电是否正常。
- 检测D+ D-在插入U盘后是否被拉高。
- 如果上面两个条件满足,说明U盘有被检测到。
- 加打印分析驱动流程哪块有阻塞。