USB驱动程序(五)————USB驱动函数总结

来源:互联网 发布:itools for mac录屏 编辑:程序博客网 时间:2024/05/18 01:29

pipe 管道

  管道是USB设备通信的通道,内核中提供了创建管道的宏,从宏中我们可以分析出,管道是一个 int 型的变量,由设备号、端点地址、端点类型组合而成。

usb_[snd|rcv][ctrl|int|bulk|isoc]pipe(dev, endpoint)例:struct usb_device *dev = interface_to_usbdev(intf);struct usb_endpoint_descriptor *endpoint;int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
#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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
static inline unsigned int __create_pipe(struct usb_device *dev,        unsigned int endpoint){    return (dev->devnum << 8) | (endpoint << 15);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

URB

分配URB

 usb_alloc_urb(int iso_packets, gfp_t mem_flags)
  • 1
  • 1

填充URB

控制传输

static inline void usb_fill_control_urb(struct urb *urb,                    struct usb_device *dev,                    unsigned int pipe,                    unsigned char *setup_packet,                    void *transfer_buffer,                    int buffer_length,                    usb_complete_t complete_fn,                    void *context){    urb->dev  = dev;    urb->pipe = pipe;    urb->setup_packet = setup_packet;    urb->transfer_buffer = transfer_buffer;    urb->transfer_buffer_length = buffer_length;    urb->complete = complete_fn;    urb->context  = context;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

中断传输

static inline void usb_fill_int_urb(struct urb *urb,                    struct usb_device *dev,                    unsigned int pipe,                    void *transfer_buffer,                    int buffer_length,                    usb_complete_t complete_fn,                    void *context,                    int interval){    urb->dev  = dev;    urb->pipe = pipe;    urb->transfer_buffer = transfer_buffer;    urb->transfer_buffer_length = buffer_length;    urb->complete = complete_fn;    urb->context = context;    if (dev->speed == USB_SPEED_HIGH)   // 相比批量传输和控制传输,实时传输和中断传输多这个参数,表示周期        urb->interval = 1 << (interval - 1);    else        urb->interval = interval;    urb->start_frame = -1;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

批量传输

static inline void usb_fill_bulk_urb(struct urb *urb,                     struct usb_device *dev,                     unsigned int pipe,                     void *transfer_buffer,                     int buffer_length,                     usb_complete_t complete_fn,                     void *context){    urb->dev = dev;    urb->pipe = pipe;    urb->transfer_buffer = transfer_buffer;    urb->transfer_buffer_length = buffer_length;    urb->complete = complete_fn;    urb->context = context;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

等时传输

  不幸的是,等时urb 没有和中断、控制、批量urb 类似的初始化函数,因此它们在提交到USB核心之前,需要在驱动程序中手动的初始化。例如:

urb->dev = dev;urb->context = uvd;urb->pipe = usb_rcvisocpipe(dev,uvd->video_endp-1);urb->interval = 1;urb->transfer_flags = URB_IOS_ASAP;urb->transfer_buffer = can->sts_buf[i];urb_complete = konicawc_isoc_irq;urb->number_of_packets = FRAMES_PRE_DESC;urb->transfer_buffer_lenth = FRAMES_PRE_DESC;for (j=0; j < FRAMES_PRE_DESC; j++){    urb->ios_frame_desc[j].offset  = j;    urb->ios_frame_desc[j].length  = 1;}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

同步提交URB

  有时候 USB 驱动程序只是要发送或者接收一些简单的 USB 数据,而不是想创建一个 struct urb ,初始化它,然后等待该 urb 接收函数运行这些麻烦事都走一遍。内核提供了同步提交 urb 的接口。

控制传输

int usb_control_msg(struct usb_device *dev,                     unsigned int pipe,                     __u8 request,                    __u8 requesttype,                     __u16 value,                     __u16 index,                     void *data,                    __u16 size,                     int timeout  // 超时时间,以jiffies为单位                    )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

  如果函数调用成功,返回值为 0 ,如果返回一个负数,表示发生一个错误。如果成功 actual_lenth 参数包含从该消息发送或者接收的字节数。 
举例:

/* usb_get_descriptor */    result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),            USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,            (type << 8) + index, 0, buf, size,            USB_CTRL_GET_TIMEOUT);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

  控制传输,通过 pipe 可以看出传输方向是设备到主机,和默认端点0通信,请求类型是请求描述符,具体的类型和索引。传输完成时,描述符就被存放在 buf 所指向的缓冲区中了。

usb_ctrl_msg 分析

int usb_control_msg(struct usb_device *dev,                     unsigned int pipe,                     __u8 request,                    __u8 requesttype,                     __u16 value,                     __u16 index,                     void *data,                    __u16 size,                     int timeout){    struct usb_ctrlrequest *dr;    int ret;    dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);    if (!dr)        return -ENOMEM;    // 填充 setup packet    dr->bRequestType = requesttype;    dr->bRequest = request;    dr->wValue   = cpu_to_le16(value);    dr->wIndex   = cpu_to_le16(index);    dr->wLength  = cpu_to_le16(size);    /* dbg("usb_control_msg"); */    ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);    kfree(dr);    return ret;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
static int usb_internal_control_msg(struct usb_device *usb_dev,                                    unsigned int pipe,                                    struct usb_ctrlrequest *cmd,                                    void *data,                                     int len,                                     int timeout){    struct urb *urb;    int retv;    int length;    urb = usb_alloc_urb(0, GFP_NOIO);    if (!urb)        return -ENOMEM;    usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,                 len, usb_api_blocking_completion, NULL);    retv = usb_start_wait_urb(urb, timeout, &length);    if (retv < 0)        return retv;    else        return length;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
static inline void usb_fill_control_urb(struct urb *urb,                    struct usb_device *dev,                    unsigned int pipe,                    unsigned char *setup_packet,                    void *transfer_buffer,                    int buffer_length,                    usb_complete_t complete_fn,                    void *context){    urb->dev  = dev;    urb->pipe = pipe;    urb->setup_packet = setup_packet;    urb->transfer_buffer = transfer_buffer;    urb->transfer_buffer_length = buffer_length;    urb->complete = complete_fn;    urb->context  = context;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
struct api_context {    struct completion   done;    int         status;};static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length){    struct api_context ctx;    unsigned long expire;    int retval;    // 完成量    init_completion(&ctx.done);    urb->context = &ctx;    urb->actual_length = 0;    retval = usb_submit_urb(urb, GFP_NOIO);    if (unlikely(retval))        goto out;    expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;    // 等待完成,返回值为0表示超时    if (!wait_for_completion_timeout(&ctx.done, expire)) {        usb_kill_urb(urb);        retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);        dev_dbg(&urb->dev->dev,            "%s timed out on ep%d%s len=%u/%u\n",            current->comm,            usb_endpoint_num(&urb->ep->desc),            usb_urb_dir_in(urb) ? "in" : "out",            urb->actual_length,            urb->transfer_buffer_length);    } else        retval = ctx.status;out:    if (actual_length)        *actual_length = urb->actual_length;    usb_free_urb(urb);    return retval;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
static void usb_api_blocking_completion(struct urb *urb){    struct api_context *ctx = urb->context;    ctx->status = urb->status;    complete(&ctx->done);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

  不难分析,内核帮助我们分配设置了 urb ,并且提供了一个统一的完成函数,在提交 urb 时有一点需要注意,内核初始化了一个完成量,并且内核在提交 urb 之后在 wait_for_completion_timeout ,等待的过程中线程自然就休眠了,何时完成呢?在统一的完成函数中 complete(&ctx->done) 。所以称这种方式为同步提交 urb 。

中断、批量传输

int usb_interrupt_msg(...){  return usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout);}int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,         void *data, int *actual_length, int timeout)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

批量和控制传输的参数简单一点,举例:

/* 进行阻塞的批量读取,从设备获取数据 */retval = usb_bulk_msg(dev->udev,    usb_rcvbulkpipe(dev->udev,dev->bulk_in_endpointAddr),    dev->bulk_in_buffer,    min(dev->bulk_in_size,count),    &count,    HZ*10)/* 如果读取成功 */if (!retval){    if (copy_to_user(buffer, dev->bulk_in_buffer, count))        retval = -EFAULT;    else        retval = count;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

  批量传输,传输方向设备到主机,和端点bulk_in_endpoint通信。

usb_bulk_msg分析

int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,         void *data, int len, int *actual_length, int timeout){    struct urb *urb;    struct usb_host_endpoint *ep;    // 在 usb_device 的 ep_in[] 和 ep_out[] 数组中找到管道对应的断点    ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out)            [usb_pipeendpoint(pipe)];    if (!ep || len < 0)        return -EINVAL;    // 分配 urb    urb = usb_alloc_urb(0, GFP_KERNEL);    if (!urb)        return -ENOMEM;    // 如果是中断端点    if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==            USB_ENDPOINT_XFER_INT) {        pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);        usb_fill_int_urb(urb, usb_dev, pipe, data, len,                usb_api_blocking_completion, NULL,                ep->desc.bInterval);    } else  // 如果是 bulk 端点        usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,                usb_api_blocking_completion, NULL);    return usb_start_wait_urb(urb, timeout, actual_length);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

异步提交urb

  异步提交 urb 需要我们自己去创建、设置、提交urb,并且提供一个完成函数。 
举例:

static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id){    struct usb_device *dev = interface_to_usbdev(intf);    struct usb_host_interface *interface;    struct usb_endpoint_descriptor *endpoint;    int pipe;    interface = intf->cur_altsetting;    endpoint = &interface->endpoint[0].desc; //endpoint = &intf->cur_altsetting->endpoint[0].desc    pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);    len = endpoint->wMaxPacketSize;    //分配缓冲区,dma    usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);    //分配urb    um_urb = usb_alloc_urb(0, GFP_KERNEL);    //填充urb    usb_fill_int_urb(um_urb, dev, pipe, usb_buf, len, usb_mouse_irq, NULL, endpoint->bInterval);    um_urb->transfer_dma = usb_buf_phys;    um_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;  //使用dma传输    /* 使用URB */    usb_submit_urb(um_urb, GFP_KERNEL);    return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
static void usb_mouse_irq(struct urb *urb){    static unsigned char pre_val;    /* USB鼠标数据含义     * data[0]: bit0-左键, 1-按下, 0-松开     *          bit1-右键, 1-按下, 0-松开     *          bit2-中键, 1-按下, 0-松开      *     */    if ((pre_val & (1<<0)) != (usb_buf[0] & (1<<0)))    {        /* 左键发生了变化 */        input_event(um_dev, EV_KEY, KEY_L, (usb_buf[0] & (1<<0)) ? 1 : 0);        input_sync(um_dev);    }    if ((pre_val & (1<<1)) != (usb_buf[0] & (1<<1)))    {        /* 右键发生了变化 */        input_event(um_dev, EV_KEY, KEY_S, (usb_buf[0] & (1<<1)) ? 1 : 0);        input_sync(um_dev);    }    if ((pre_val & (1<<2)) != (usb_buf[0] & (1<<2)))    {        /* 中键发生了变化 */        input_event(um_dev, EV_KEY, KEY_ENTER, (usb_buf[0] & (1<<2)) ? 1 : 0);        input_sync(um_dev);    }    pre_val = usb_buf[0];    /* 重新提交urb */    usb_submit_urb(um_urb, GFP_KERNEL);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

销毁URB

usb_free_urb(struct urb * urb)
  • 1
  • 1

取消URB

  应该调用 usb_fill_urb 或 usb_unlink_urb 函数来终止一个已经被提交到USB核心的urb。 
  如果调用 usb_kill_urb ,urb 的生命周期将终止,通常是当设备从系统中断开时,在断开回调函数中调用此函数。 
  对于某些驱动程序而言,应该使用 usb_ublink_urb 函数来告诉USB核心终止一个urb,该函数并不等到urb完全被终止之后才返回回调函数。这对于在中断处理例程中或者持有一个自旋锁时终止一个urb是很有用,因为等待一个urb完全被终止需要USB核心具有使调用进程休眠的能力。该函数需要被要求终止的urb中的URB_ASYNC_UNLINK标志值被设置才能正确地工作。

阅读全文
0 0
原创粉丝点击