1. BUS/DEV/DRV 模型
"USB接口"是逻辑上的 USB 设备,编写的 usb_driver 驱动程序,支持的是"USB 接口":
- USB控制器或 Hub 识别出 USB 设备后,会创建、注册 usb_device
- usb_device 被"driversusbcoregeneric.c" 驱动认领后,会选择、设置某个配置
- 这个配置下面的接口,都会分配、设置、注册一个 usb_interface
- 左边的 usb_driver 和右边的 usb_interface 如果匹配,则调用 usb_driver.probe
2. 接口函数
在 USB 设备驱动程序中,能使用的 USB 函数都在这个头文件里:includelinuxusb.h
。
2.1pipe
使用这些接口函数的主要目的是传输数据,传输数据的对象是 USB 设备里的某个 endpoint,这被称为 pipe:
/* Create various pipes... */#defineusb_sndctrlpipe(dev, endpoint) ((PIPE_CONTROL < <30) | __create_pipe(dev, endpoint))#defineusb_rcvctrlpipe(dev, endpoint) ((PIPE_CONTROL < <30) | __create_pipe(dev, endpoint) | USB_DIR_IN)#defineusb_sndisocpipe(dev, endpoint) ((PIPE_ISOCHRONOUS < <30) | __create_pipe(dev, endpoint))#defineusb_rcvisocpipe(dev, endpoint) ((PIPE_ISOCHRONOUS < <30) | __create_pipe(dev, endpoint) | USB_DIR_IN)#defineusb_sndbulkpipe(dev, endpoint) ((PIPE_BULK < <30) | __create_pipe(dev, endpoint))#defineusb_rcvbulkpipe(dev, endpoint) ((PIPE_BULK < <30) | __create_pipe(dev, endpoint) | USB_DIR_IN)#defineusb_sndintpipe(dev, endpoint) ((PIPE_INTERRUPT < <30) | __create_pipe(dev, endpoint))#defineusb_rcvintpipe(dev, endpoint) ((PIPE_INTERRUPT < <30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
2.2 同步传输函数
对于控制传输、批量传输、中断传输,有 3 个同步函数可以用来直接发起传输。这些函数内部会创建、填充、提交一个 URB("usb request block"),并等待它完成或超时。
函数原型如下:
intusb_control_msg(structusb_device *dev, unsignedintpipe, __u8 request, __u8 requesttype, __u16value, __u16 index,void*data, __u16 size,inttimeout);intusb_bulk_msg(structusb_device *usb_dev, unsignedintpipe,void*data,intlen,int*actual_length,inttimeout);intusb_interrupt_msg(structusb_device *usb_dev, unsignedintpipe,void*data,intlen,int*actual_length,inttimeout);
2.3 异步传输函数
使用 URB 进行传输时,它是异步方式:需要先分配、构造、提交一个 URB("usb request block"),当传输完成后,它的回调函数被调用。
关键就在于需要填充 URB:
- dev:跟谁传输数据
- pipe:跟哪个 pipe 传输数据
- buffer:里面存有要发送的数据,或者用来接收要读取的数据
- 数据长度
- 回调函数
2.3.1 分配和释放 URB
函数原型如下:
structurb *usb_alloc_urb(intiso_packets, gfp_t mem_flags);voidusb_free_urb(structurb *urb);
2.3.2 分配/释放DMABuffer
发起 USB 传输时,数据保存在 buffer 里。这个 buffer 可以是一般的 buffer,也可以是 DMA Buffer。
对于一般的 buffer,在提交 URB 时会临时分配一个 DMA Buffer:
- 发送数据时:函数内部会先从一般 buffer 中把数据复制到 DMA Buffer,在提交给 USB 控制器
- 读取数据时:USB 控制器先把数据传到 DMA Buffer,函数内部在把 DMA Buffer 的数据复制到一般 buffer
- 中间增加了一次数据的拷贝,效率低
我们可以直接使用 DMA Buffer,函数原型如下:
void*usb_alloc_coherent(struct usb_device *dev,size_tsize,gfp_tmem_flags,dma_addr_t*dma);voidusb_free_coherent(struct usb_device *dev,size_tsize,void*addr,dma_addr_tdma);
2.3.3 填充 URB
对于控制传输、批量传输、中断传输,分别有如下函数:
staticinlinevoidusb_fill_control_urb(struct urb *urb, struct usb_device *dev,unsignedintpipe,unsignedchar*setup_packet,void*transfer_buffer,intbuffer_length,usb_complete_tcomplete_fn,void*context);staticinlinevoidusb_fill_bulk_urb(struct urb *urb, struct usb_device *dev,unsignedintpipe,void*transfer_buffer,intbuffer_length,usb_complete_tcomplete_fn,void*context);staticinlinevoidusb_fill_int_urb(struct urb *urb, struct usb_device *dev,unsignedintpipe,void*transfer_buffer,intbuffer_length,usb_complete_tcomplete_fn,void*context,intinterval);
如果 URB 使用 DMA Buffer,那么还需要设置一个 flag 表明这点:
urb- >transfer_dma = DMA address of buffer;// usb_alloc_coherent的输出参数urb- >transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
2.3.4 提交 URB
构造好 URB 后,需要提交到 USB 系统里,才能启动传输。
intusb_submit_urb(structurb *urb, gfp_t mem_flags);
2.3.5 取消 URB
已经提交的 URB,可以取消它,有 2 个函数:
- usb_kill_urb:这是一个同步函数,它会等待 URB 结束
- usb_unlink_urb:这是一个异步函数,它不会等待 URB 结束,USB 控制器驱动会调用它的回调函数
voidusb_kill_urb(structurb *urb);intusb_unlink_urb(structurb *urb);
- usb
+关注
关注
60文章
7732浏览量
261752 - 驱动
+关注
关注
12文章
1769浏览量
84794 - 鼠标
+关注
关注
6文章
586浏览量
39496
发布评论请先登录
相关推荐
评论