页面加载中,请稍候
来源:嵌入式Linux系统开发发布时间:2023-06-192087浏览
询问 AILinux 内核源码:include\linux\usb.h
Linux 内核源码:drivers\hid\usbhid\usbmouse.c

"USB 接口"是逻辑上的 USB 设备,编写的 usb_driver 驱动程序,支持的是"USB 接口":

USB 控制器或 Hub 识别出 USB 设备后,会创建、注册 usb_device
usb_device 被"drivers\usb\core\generic.c" 驱动认领后,会选择、设置某个配置
这个配置下面的接口,都会分配、设置、注册一个 usb_interface
左边的 usb_driver 和右边的 usb_interface 如果匹配,则调用 usb_driver.probe
在 USB 设备驱动程序中,能使用的 USB 函数都在这个头文件里:include\linux\usb.h。
使用这些接口函数的主要目的是传输数据,传输数据的对象是 USB 设备里的某个 endpoint,这被称为 pipe:
/*Createvariouspipes...*/
#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)
对于控制传输、批量传输、中断传输,有 3 个同步函数可以用来直接发起传输。这些函数内部会创建、填充、提交一个 URB("usb request block"),并等待它完成或超时。
函数原型如下:
intusb_control_msg(structusb_device*dev,unsignedintpipe,__u8request,
__u8requesttype,__u16value,__u16index,void*data,
__u16size,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);
使用 URB 进行传输时,它是异步方式:需要先分配、构造、提交一个 URB("usb request block"),当传输完成后,它的回调函数被调用。
关键就在于需要填充 URB:
函数原型如下:
structurb*usb_alloc_urb(intiso_packets,gfp_tmem_flags);2.3.2 分配/释放 DMA Buffer
voidusb_free_urb(structurb*urb);
发起 USB 传输时,数据保存在 buffer 里。这个 buffer 可以是一般的 buffer,也可以是 DMA Buffer。
对于一般的 buffer,在提交 URB 时会临时分配一个 DMA Buffer:
我们可以直接使用 DMA Buffer,函数原型如下:
void*usb_alloc_coherent(structusb_device*dev,size_tsize,gfp_tmem_flags,dma_addr_t*dma);2.3.3 填充 URB
voidusb_free_coherent(structusb_device*dev,size_tsize,void*addr,dma_addr_tdma);
对于控制传输、批量传输、中断传输,分别有如下函数:
staticinlinevoidusb_fill_control_urb(structurb*urb,
structusb_device*dev,
unsignedintpipe,
unsignedchar*setup_packet,
void*transfer_buffer,
intbuffer_length,
usb_complete_tcomplete_fn,
void*context);
staticinlinevoidusb_fill_bulk_urb(structurb*urb,
structusb_device*dev,
unsignedintpipe,
void*transfer_buffer,
intbuffer_length,
usb_complete_tcomplete_fn,
void*context);
staticinlinevoidusb_fill_int_urb(structurb*urb,
structusb_device*dev,
unsignedintpipe,
void*transfer_buffer,
intbuffer_length,
usb_complete_tcomplete_fn,
void*context,
intinterval);
如果 URB 使用 DMA Buffer,那么还需要设置一个 flag 表明这点:
urb->transfer_dma=DMAaddressofbuffer;//usb_alloc_coherent的输出参数2.3.4 提交 URB
urb->transfer_flags|=URB_NO_TRANSFER_DMA_MAP;
构造好 URB 后,需要提交到 USB 系统里,才能启动传输。
intusb_submit_urb(structurb*urb,gfp_tmem_flags);2.3.5 取消 URB
已经提交的 URB,可以取消它,有 2 个函数:
voidusb_kill_urb(structurb*urb);
intusb_unlink_urb(structurb*urb);
新闻来源:嵌入式Linux系统开发,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。
暂无评论哦,快来评论一下吧!
2026-07-15

2026-07-16
2026-07-01