1. USB拓扑结构
- 设备、配置、接口和端点
1.2 设置、配置、接口、端点
在 USB 设备的逻辑组织中,包含设备、配置、接口和端点 4 个层次。 每个 USB 设备都提供了不同级别的配置信息,可以包含一个或多个配置,不同的配置使设备表现出不同的功能组合(在探测/连接期间需从其中选定一个) ,配置由多个接口组成。 每个配置中可以有多个接口,而设备接口是端点的汇集(collection) 。例如 USB 扬声器可以包含一个音频接口以及对旋钮和按钮的接口。一个配置中的所有接口可以同时有效,并可被不同的驱动程序连接。每个接口可以有备用接口,以提供不同质量的服务参数。
端点是 USB 通信的最基本形式,每一个 USB 设备接口在主机看来就是一个端点的集合。主机只能通过端点与设备进行通信,以使用设备的功能。在 USB 系统中每一个端点都有惟一的地址,这是由设备地址和端点号给出的。 每个端点都有一定的属性,其中包括传输方式、总线访问频率、带宽、端点号和数据包的最大容量等。一个USB 端点只能在一个方向承载数据,或者从主机到设备(称为输出端点) ,或者从设备到主机(称为输入端点) ,因此端点可看作一个单向的管道。端点 0 通常为控制端点,用于设备初始化参数等。只要设备连接到 USB 上并且上电端点 0 就可以被访问。端点 1、2 等一般用作数据端点,存放主机与设备间往来的数据
- 设备通常有一个或多个配置;
- 配置通常有一个或多个接口;
- 接口通常有一个或多个设置;
- 接口有零或多个端点。这种层次化配置信息在设备中通过一组标准的描述符来描述,如下所。
- 设备描述符:关于设备的通用信息,如供应商 ID、产品 ID 和修订 ID,支持的设备类、子类和适用的协议以及默认端点的最大包大小等。
1.2.1 设备描述符
关于设备的通用信息,如供应商 ID、产品 ID 和修订 ID,支持的设备类、子类和适用的协议以及默认端点的最大包大小等。在 Linux 内核中,USB 设备用 usb_device 结构体来描述,USB 设备描述符定义为usb_device_descriptor 结构体,如代码清单 20.1 所示。代码清单 20.1 usb_device_descriptor 结构体
struct usb_device_descriptor
{
_ _u8 bLength; //描述符长度
_ _u8 bDescriptorType; //描述符类型编号
_ _le16 bcdUSB; //USB 版本号
_ _u8 bDeviceClass; //USB 分配的设备类 code
_ _u8 bDeviceSubClass;// USB 分配的子类 code
_ _u8 bDeviceProtocol; //USB 分配的协议 code
_ _u8 bMaxPacketSize0; //endpoint0 最大包大小
_ _le16 idVendor; //厂商编号
_ _le16 idProduct; //产品编号
_ _le16 bcdDevice; //设备出厂编号
_ _u8 iManufacturer; //描述厂商字符串的索引
_ _u8 iProduct; //描述产品字符串的索引
_ _u8 iSerialNumber; //描述设备序列号字符串的索引
_ _u8 bNumConfigurations; //可能的配置数量
} _ _attribute_ _ ((packed));
1.2.2 配置描述符
配置中的接口数、支持的挂起和恢复能力以及功率要求。USB配置在内核中使用 usb_host_config 结构体描述,USB 配置描述符定义为结构体usb_config_descriptor,如代码清单 20.2 所示
struct usb_config_descriptor
{
_ _u8 bLength; //描述符长度
_ _u8 bDescriptorType; //描述符类型编号
_ _le16 wTotalLength; //配置所返回的所有数据的大小
_ _u8 bNumInterfaces; // 配置所支持的接口数
_ _u8 bConfigurationValue; //Set_Configuration 命令需要的参数值
_ _u8 iConfiguration; //描述该配置的字符串的索引值
_ _u8 bmAttributes; //供电模式的选择
_ _u8 bMaxPower; //设备从总线提取的最大电流
} _ _attribute_ _ ((packed));
1.2.3 接口描述符
接口类、子类和适用的协议, 接口备用配置的数目和端点数目。 USB接口在内核中使用 usb_interface 结构体描述,USB 接口描述符定义为结构体usb_interface_descriptor,如代码清单 20.3 所示。
struct usb_interface_descriptor
{
_ _u8 bLength; //描述符长度
_ _u8 bDescriptorType; //描述符类型
_ _u8 bInterfaceNumber; // 接口的编号
_ _u8 bAlternateSetting; //备用的接口描述符编号
_ _u8 bNumEndpoints; //该接口使用的端点数,不包括端点 0
_ _u8 bInterfaceClass; //接口类型
_ _u8 bInterfaceSubClass; //接口子类型
_ _u8 bInterfaceProtocol; //接口所遵循的协议
_ _u8 iInterface; //描述该接口的字符串索引值
} _ _attribute_ _ ((packed));
1.2.4 端点描述符
端点地址、方向和类型,支持的最大包大小,如果是中断类型的端点则还包括轮询频率。在 Linux 内核中, USB 端点使用usb_host_endpoint 结 构 体 来 描 述 , USB 端 点 描 述 符 定 义 为usb_endpoint_descriptor 结构体,如代码清单 20.4 所示。
struct usb_endpoint_descriptor
{
_ _u8 bLength; //描述符长度
_ _u8 bDescriptorType; //描述符类型
/* 端点地址:0~3 位是端点号,第 7 位是方向(0-OUT,1-IN) */
_ _u8 bEndpointAddress;
/* 端点属性:bit[0:1] 的值为00 表示控制,为01 表示同步,
* 为02表示批量,为03表示中断
*/
_ _u8 bmAttributes;
_ _le16 wMaxPacketSize; 本端点接收或发送的最大信息包的大小
_ _u8 bInterval; //轮询数据传送端点的时间间隔
//对于批量传送的端点以及控制传送的端点,此域忽略
//对于同步传送的端点,此域必须为 1
//对于中断传送的端点,此域值的范围为 1~255
_ _u8 bRefresh;
_ _u8 bSynchAddress;
} _ _attribute_ _ ((packed));
2 linux系统USB调试命令
- 查看USB总线拓扑
lsusb -t
or
lsusb
- 检查系统下有多少可用的USB Port
find /dev/bus/
- 获取USB设备的详细信息
lsusb -D /dev/bus/usb/002/005
- 获取所有可用的USB Port
lsusb -v
- 罗列系统下所有大容量存储设备
lsusb -v | grep -Ei '(idVendor|Mass Storage)'
- 查找USB设备的协议版本
lsusb -v | grep -i bcdusb
USB设备依据协议版本的不同,传输速率也是不同的。下面是USB协议版本与传输速率的对应关系:
USB 1.10 12Mb/s
USB 2.00 480Mb/s
USB 3.00 5Gb/s
- 查看USB控制器的ID
cd /sys/bus/pci/drivers/xhci_hcd
ls
result
0000:00:xx.y
- 一旦知道了设备的ID,那么就可以通过命令disable和enable设备控制器。
//disable controller
echo -n "0000:00:xx.y" > unbind
//enable the controller
echo -n "0000:00:xx.y" > bind
- USB Power On/Off
#disable external wake-up; do this only once
echo disabled > /sys/bus/usb/devices/usb1/power/wakeup
echo on > /sys/bus/usb/devices/usb1/power/control # turn on
echo suspend > /sys/bus/usb/devices/usb1/powercontrol # turn off
According to the docs, there were several changes to the USB power management from kernels 2.6.32, which seem to settle in 2.6.38. Now you'll need to wait for the device to become idle, which is governed by the particular device driver. The driver needs to support it, otherwise the device will never reach this state. Unluckily, now the user has no chance to force this. However, if you're lucky and your device can become idle, then to turn this off you need to:
echo "0" > "/sys/bus/usb/devices/usbX/power/autosuspend"
echo "auto" > "/sys/bus/usb/devices/usbX/power/level"
or, for kernels around 2.6.38 and above:
echo "0" > "/sys/bus/usb/devices/usbX/power/autosuspend_delay_ms"
echo "auto" > "/sys/bus/usb/devices/usbX/power/control"
This literally means, go suspend at the moment the device becomes idle.
So unless your fan is something "intelligent" that can be seen as a device and controlled by a driver, you probably won't have much luck on current kernels.