从零开始学USB(二十七、usb鼠标驱动驱动实例分析[2]管道)
端点是USB设备的唯一可识别部分,其是主机和设备之间的通信流的终点。
管道,就是一个USB主机和USB设备端点之间的数据传输的通道。
站在主机的角度,它的目的是设备的某个端点。
而管道这算是主机和端点之间的连线。
这里我们先看一下管道在usb里的定义
/*
* For various legacy reasons, Linux has a small cookie that's paired with
* a struct usb_device to identify an endpoint queue. Queue characteristics
* are defined by the endpoint's descriptor. This cookie is called a "pipe",
* an unsigned int encoded as:
*
* - direction: bit 7 (0 = Host-to-Device [Out],
* 1 = Device-to-Host [In] ...
* like endpoint bEndpointAddress)
* - device address: bits 8-14 ... bit positions known to uhci-hcd
* - endpoint: bits 15-18 ... bit positions known to uhci-hcd
* - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt,
* 10 = control, 11 = bulk)
*
* Given the device address and endpoint descriptor, pipes are redundant.
*/
先看看管道,也就是这个整型值的构成, bit7 用来表示方向, bit8~14 表示设备地址,bit15~18 表示端点号,早先说过,设备地址用 7 位来表示,端点号用 4 位来表示,剩下来的 bit30~31 表示管道类型。
这里我们先看一下usb协议中给出来的管道类型(属性)的表示
#define PIPE_ISOCHRONOUS 0
#define PIPE_INTERRUPT 1
#define PIPE_CONTROL 2
#define PIPE_BULK 3
#define usb_pipetype(pipe) (((pipe) >> 30) & 3) //用30和31bit来表示管道类型
#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT)
#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL)
#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK)
接下来看一下usb中知道管道的如何辨别端点方向
/*
* USB directions
*
* This bit flag is used in endpoint descriptors' bEndpointAddress field.
* It's also one of three fields in control requests bRequestType.
*/
#define USB_DIR_OUT 0 /* to device */
#define USB_DIR_IN 0x80 /* to host */
#define usb_pipein(pipe) ((pipe) & USB_DIR_IN) //第7位表示usb端点方向,1表示输入端点
#define usb_pipeout(pipe) (!usb_pipein(pipe))
最后我们看一下知道管道,如何知道设备地址和端点号
/* 8~14位表示设备地址 */
#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f)
/* 15~18位表示端点地址 */
#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
当然也可以反过来。知道了其它信息也可以得到管道信息。
usb的端点有四种传输类型,2种方向,所以总共有8中组合
/* Create various pipes... */
#define usb_sndctrlpipe(dev, endpoint) \
((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint))
#define usb_rcvctrlpipe(dev, endpoint) \
((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndisocpipe(dev, endpoint) \
((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint))
#define usb_rcvisocpipe(dev, endpoint) \
((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndbulkpipe(dev, endpoint) \
((PIPE_BULK << 30) | __create_pipe(dev, endpoint))
#define usb_rcvbulkpipe(dev, endpoint) \
((PIPE_BULK << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
#define usb_sndintpipe(dev, endpoint) \
((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint))
#define usb_rcvintpipe(dev, endpoint) \
((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
这里的 __create_pipe也就是设备地址和端点号放在pipe这个32bit变量的合适位置了。
static inline unsigned int __create_pipe(struct usb_device *dev,
unsigned int endpoint)
{
return (dev->devnum << 8) | (endpoint << 15);
}
其实在usb协议传输时,这两个东西也就是一块传输的。
回到我们程序最使用的地方,很明显通过端点号和设备号,计算输入类型的中断管道。
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);