USB 驱动程序(五)————USB 驱动函数总结
pipe 管道
管道是USB 设备通信的通道,内核中提供了创建管道的宏,从宏中我们可以分析出,管道是⼀个 int 型的变量,由设备号、端点地址、端点类型组合⽽成。URB
分配URB 填充URB
控制传输
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
#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
static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint){ return (dev->devnum << 8) | (endpoint << 15);}
1
2
3
4
5 usb_alloc_urb(int iso_packets, gfp_t mem_flags)
1
中断传输批量传输等时传输
鬼谷子技能static inline void usb_fill_control_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, unsigned char *tup_packet, void *transfer_buffer, int buffer_length, usb_complete_t complete_fn, void *context){
urb->dev = dev; urb->pipe = pipe; urb->tup_packet = tup_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
17static 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); el 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
21static 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; ur
b->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
不幸的是,等时urb 没有和中断、控制、批量urb 类似的初始化函数,因此它们在提交到USB 核⼼之前,需要在驱动程序中⼿动的初始化。例如:同步提交URB
有时候 USB 驱动程序只是要发送或者接收⼀些简单的 USB 数据,⽽不是想创建⼀个 struct urb ,初始化它,然后等待该 urb 接收函数运⾏这些⿇烦事都⾛⼀遍。内核提供了同步提交 urb 的接⼝。
控制传输 如果函数调⽤成功,返回值为 0 ,如果返回⼀个负数,表⽰发⽣⼀个错误。如果成功 actual_lenth 参数包含从该消息发送或者接收的字节数。
举例: 控制传输,通过 pipe 可以看出传输⽅向是设备到主机,和默认端点0通信,请求类型是请求描述符,具体的类型和索引。传输完成时,描述符就被存放在 buf 所指向的缓冲区中了。
usb_ctrl_msg 分析
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].offt = j; urb->ios_frame_desc[j].length = 1;}
1
2
3
4
5
6
7
8
9
10
qq音乐听歌识曲11
12
13int 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/* 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
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; // 填充 tup 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;}123456789101112131415161718192021222324252627282930static 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; el return le
ngth ;}123456789101112131415161718192021222324
static inline void usb_fill_control_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, unsigned char *tup_packet, void *transfer_buffer, int buffer_length, usb_complete_t complete_fn, void *context){ urb->dev = dev; urb->pipe = pipe; urb->tup_packet = tup_packet; urb->transfer_buffer = transfer_buffer; urb->transfer_buffer_length = buffer_length; urb->complete = complete_fn; urb->context = context;}1234567891011121314151617struct 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 ? mcs_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); }
el retval = ctx.status;out : if (actual_length) *actual_length = urb->actual_length; usb_free_urb(urb); return retval;}123456789101112131415161718192021222324252627282930313233343536373839