在android 平台,我们再调试所有usb 设备时,硬件焊接好后,在内核usb 核心驱动正常情况下(当然只要USB外设遵循标准协议基本没有问题),我们都会通过lsusb 指令在确认usb 设置是否正常接入且被识别到,并且得到usb 设备的vid,pid,及bus id,device id。
lsub 命令
通过命令,我们可以查询到当前系统中,在usb 的三条总线分别插入的6个USB设备。
lsusb 源码分析
toyboy工具箱中的lsusb 工具源码在 external\toybox\toys\other\lsusb.c中
/* lsusb.c - list available USB devices
*
* Copyright 2013 Andre Renaud <[email protected]>
USE_LSUSB(NEWTOY(lsusb, NULL, TOYFLAG_USR|TOYFLAG_BIN))
config LSUSB
bool "lsusb"
default y
help
usage: lsusb
List USB hosts/devices.
*/
#include "toys.h"
static int list_device(struct dirtree *new)
{
FILE *file;
char *name;
int busnum = 0, devnum = 0, pid = 0, vid = 0;
if (!new->parent) return DIRTREE_RECURSE;
if (new->name[0] == '.') return 0;
name = dirtree_path(new, 0);
snprintf(toybuf, sizeof(toybuf), "%s/%s", name, "/uevent");
file = fopen(toybuf, "r"); // 打开uevent 设备文件
if (file) {
int count = 0;
// 循环读取/sys/bus/usb/devices/xxx/uevent 设备节点下的文件信息,一行一行读取
while (fgets(toybuf, sizeof(toybuf), file))
if (sscanf(toybuf, "BUSNUM=%u\n", &busnum) // 解析bus num
|| sscanf(toybuf, "DEVNUM=%u\n", &devnum) // 解析device num
|| sscanf(toybuf, "PRODUCT=%x/%x/", &pid, &vid)) count++; // 解析pid,vid
if (count == 3) // 解析完成后打印
printf("Bus %03d Device %03d: ID %04x:%04x\n", busnum, devnum, pid, vid);
fclose(file);
}
free(name);
return 0;
}
void lsusb_main(void)
{
// dirtree_read 在/sys/bus/usb/devices目录下树状遍历uevent ,并传入回调函数list_device
dirtree_read("/sys/bus/usb/devices/", list_device);
}
整个过程就是树状解析/sys/bus/usb/device/ 目录下(包括子目录)的uevent 文件节点,解析到bus num,device num,pid,vid 成功后,就打印出来。如上面的lsusb 执行指令结果。
http://linux-usb.sourceforge.net/FAQ.html#gs3
uevent 节点信息分析
shell@cv6a648_base:/ $ cat /sys/bus/usb/devices/usb1/uevent
MAJOR=189
MINOR=0
DEVNAME=bus/usb/001/001
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=1d6b/2/310
TYPE=9/0/1
BUSNUM=001
DEVNUM=001
shell@cv6a648_base:/ $ cat /sys/bus/usb/devices/usb2/uevent
MAJOR=189
MINOR=128
DEVNAME=bus/usb/002/001
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=1d6b/2/310
TYPE=9/0/1
BUSNUM=002
DEVNUM=001
shell@cv6a648_base:/ $ cat /sys/bus/usb/devices/usb3/uevent
MAJOR=189
MINOR=256
DEVNAME=bus/usb/003/001
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=1d6b/2/310
TYPE=9/0/1
BUSNUM=003
DEVNUM=001
shell@cv6a648_base:/sys/bus/usb/devices $ cat 1-1.3/uevent
MAJOR=189
MINOR=2
DEVNAME=bus/usb/001/003
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=90c/1000/1100
TYPE=0/0/0
BUSNUM=001
DEVNUM=003
通过上面节点我们可以分析BUSNUM,DEVNUM,PRODUCT 得到四个id,其中PRODUCT 得到pid,vid。其中还有一个DEVNAME 属性可以得到usb 总线和device 的树形关系。DEVNAME=bus/usb/001/003 表示第1条总线上面的第3个设备
130|root@cv6a648_base:/ # lsusb
Bus 001 Device 002: ID 1a40:0101
Bus 001 Device 001: ID 1d6b:0002
Bus 002 Device 001: ID 1d6b:0002
Bus 003 Device 001: ID 1d6b:0002
Bus 001 Device 003: ID 090c:1000
Bus 001 Device 006: ID 0bda:b82c
root@cv6a648_base:/ # ls /dev/bus/usb/001/ // 总线1下有4个设备
001
002
003
006
root@cv6a648_base:/ # ls /dev/bus/usb/002/ // 总线2下有1个设备
001
root@cv6a648_base:/ # ls /dev/bus/usb/003/ // 总线1下有1个设备
001
其它属性分析
我们先分析上面bus-1 下面的第4个usb (也即Bus 001 Device 006 )设备属性:
如下:
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/bMaxPower
500mA
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/devpath
1.4
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/product
802.11ac NIC
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/bNumConfigurations
1
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/bNumInterfaces
3
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/quirks
0x0
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/removable
unknown
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/removable
unknown
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/authorized
1
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/bcdDevice
0210
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/idProduct
b82c
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/remove
/system/bin/sh: cat: /sys/bus/usb/devices/1-1.4/remove: Permission denied
root@cv6a648_base:/ #
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/avoid_reset_quirk
0
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/bmAttributes
80
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/idVendor
0bda
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/serial
123456
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/bConfigurationValue
1
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/busnum
1
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/ltm_capable
no
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/speed
480
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/bDeviceClass
ef
root@cv6a648_base:/ #
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/configuration
root@cv6a648_base:/ #
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/manufacturer
Realtek
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/bDeviceProtocol
01
root@cv6a648_base:/ # cat /sys/bus/usb/devices/1-1.4/version
2.10
其中bDeviceClass 在USB协议中取值范围是:00h ~ FFh 此处为EF 为一个杂项设备,其实就是realtek的一个wifi 模组,起采用的是usb 接口。
USB class CODE 详细说明
上面bDeviceClass 值对应的用途如下:
Class code 用途 详细说明
00h Device 表示CLASS的信息在接口的描述符中定义
01h Interface Audio 音频设备
02h Both Communications and CDC Control通信设备
03h Interface HID (Human Interface Device) 人机接口设备
05h Interface Physical 物理设备
06h Interface Image 图像设备
07h Interface Printer 打印机
08h Interface Mass Storage 大容量存储
09h Device Hub
0Ah Interface CDC-Data 通信设备
0Bh Interface Smart Card 智能卡
0Dh Interface Content Security 内容安全设备
0Eh Interface Video 视频设备
0Fh Interface Personal Healthcare 个人健康设备
10h Interface Audio/Video Devices 音频/视频设备
DCh Both Diagnostic Device 诊断设备
E0h Interface Wireless Controller 无线控制器(蓝牙设备等)
EFh Both Miscellaneous 杂项(ActiveSync,PalmSync,各种协会等)
FEh Interface Application Specific 应用专有规范(固件升级,红外,USB测试与测量等)
FFh Both Vendor Specific 供应商自定义规范
注:各类设备的class subclass protocol的详细定义可以参考http://www.usb.org/developers/defined_class
又如,总线2 上面的1号设备是hub设备,对应的USB Class code 是09h,并且制定驱动类型
又如U盘设备,驱动是标注的usb-storage驱动,USB class code 是08h
wifi,bluetooth设备,驱动分别是厂商的驱动,对应的USB class code 是0xE0,0xFF
2.4 G HID 空鼠输入设备,USB Class code 为0x03 为HID 人机接口设备,使用的驱动是usbhid 驱动
麦克风输入设备,USB Class code 为0x01, 对应的驱动是snd-usb-audio
后续继续学习usb 协议规范及libusb 开源库中 USB API 接口的使用。