《Linux那些事儿之我是USB》我是U盘(22)通往春天的通道--总结

(1)
有管道都是用来传输东西的,只不过有些管道传输的是实实在在的物质,而有些管道传输的是数据。

在USB代码中管道就是用来传输数据及通信。通信是双方的,不可能自言自语。而在USB的通信中,一方肯定是主机,另一方是什么?是设备吗?说得更确切一点,真正和主机进行通信的是设备内的端点。关于端点,我们也可以专业一点说,从硬件上来看它是实实在在存在的,它被实现为一种FIFO,支持多少个端点是接口芯片的一个重要指标。

端点是主机和USB设备之间通信流的终点。主机和设备可以进行不同种类的通信,或者说数据传输。首先,设备连接在USB总线上,USB总线为了分辨每一个设备,给每一个设备编上号,然后为了实现多种通信,设备方于是提供了端点,端点多了,自然也要编上号,而让主机最终和端点去联系。

在USB的世界里,有四种管道,它们对应USB世界中的四种传输方式:
控制传输对应控制管道、中断传输对应中断管道、批量传输对应批量管道及等时传输对应等时管道。每一个USB世界中的设备要在USB世界里生存,就得有它生存的管道。而管道的出现,正是为了让我们分辨端点,或者说连接端点。“主机与端点之间的数据链接就称为管道。”
在USB里面,知道设备号和端点号,知道了这两个号,主机就可以和设备通信,而USB主机就能知道和它通信的是哪个端点。

而管道除了包含着两个号以外,通信的方向,管道里还包含了管道的类型,同样管道也如此,因为USB设备的端点有不同的类型,所以管道里就包含了一个字段来记录这一点。

int usb_stor_probe2(struct us_data *us)--->
static int get_pipes(struct us_data *us)
{
      /* Calculate and store the pipe values */                                 
    us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);                    
    us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);                 
//给us的控制输入和控制输出管道赋了值,管道是单向的。但是控制端点。控制端点是双向的,而USB规范规定了,每一个USB设备至少得有一个控制端点,其端点号为0。其他端点有没有得看具体设备而定,但这个端点是不管是什么设备,传递的endpoint变量值为0。显然其构造的两个管道就是对应这个0号控制端点的。

    us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,                        
        usb_endpoint_num(ep_out));                                            
    us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
        usb_endpoint_num(ep_in));//获得端点号
    if (ep_int) {
        us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
            usb_endpoint_num(ep_int));
        us->ep_bInterval = ep_int->bInterval; //对于中断端点,还得使用端点描述符中的bInterval字段,表示端点的中断请求间隔时间。
    }

}
static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)              {       
    return (dev->devnum << 8) | (endpoint << 15);                             
}
//__create_pipe是一个宏,由上面的定义可以看出它为构造一个宏提供了设备号和端点号。在内核中使用一个unsigned int类型的变量来表征一个管道,其中8位~14位是设备号,即devnum,15位~18位是端点号,即endpoint。而咱们还看到有这么一个宏,USB_DIR_IN,是用来在管道里面标志数据传输方向的,一个管道要么只能输入,要么只能输出。      

            
/* 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)

#define PIPE_CONTROL            2

在管道里面,第7位(bit 7)是表示方向的。所以这里0x80也就是说设bit 7为1,这就表示传输方向是由设备向主机的,也就是IN;而如果这一位是0,就表示传输方向是由主机向设备的,也就是OUT。而正是因为USB_DIR_OUT是0,而USB_DIR_IN是1,所以我们看到定义管道时只有用到了USB_DIR_IN,而没有用到USB_DIR_OUT。

#define PIPE_ISOCHRONOUS        0                                                                                
#define PIPE_INTERRUPT          1                                                                                
#define PIPE_CONTROL            2                                                                                
#define PIPE_BULK   


USB有四种传输方式,即等时传输、中断传输、控制传输和批量传输。一个设备能支持这四种传输中的哪一种或者哪几种是设备本身的属性,在硬件设计时就确定了。比如一个纯粹的U盘,它肯定是支持批量传输和控制传输的。

不同的传输要求有不同的端点,所以对于U盘来说,它一定会有批量端点和控制端点,于是就得使用相应的管道来跟不同的端点联系。PIPE_ISOCHRONOUS就是标志等时通道,PIPE_INTERRUPT就是中断通道,PIPE_CONTROL就是控制通道,PIPE_BULK就是批量通道


static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
{
    return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
}
//对于批量端点和中断端点,在它们的端点描述符里有一个字段bEndpointAddress,这个字段共八位,但是它包含挺多信息的,比如这个端点是输入端点还是输出端点,比如这个端点的地址(总线枚举时给它分配的),以及这个端点的端点号。不过要取得它的端点号得用一个掩码USB_ENDPOINT_NUMBER_MASK,让bEndpointAddress和USB_ENDPOINT_NUMBER_MASK相与就能得到它的端点号。

/* Initialize all the dynamic resources we need */
static int usb_stor_acquire_resources(struct us_data *us)
{
    int p;
    struct task_struct *th;

    us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
    if (!us->current_urb) {
        usb_stor_dbg(us, "URB allocation failed\n");
        return -ENOMEM;
    }    

    /* Just before we start our control thread, initialize
     * the device if it needs initialization */
    if (us->unusual_dev->initFunction) {
        p = us->unusual_dev->initFunction(us);
        if (p)
            return p;
    }

    /* Start up our control thread */
    th = kthread_run(usb_stor_control_thread, us, "usb-storage");
    if (IS_ERR(th)) {
        dev_warn(&us->pusb_intf->dev,
                "Unable to start control thread\n");
        return PTR_ERR(th);
    }
    us->ctl_thread = th;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/sinat_37817094/article/details/80399051
今日推荐