Linux内核自定义USB驱动中两个URB超时问题求助
Linux内核USB驱动URB超时问题排查
问题背景
学习Linux内核USB驱动开发,使用Seeeduino Xiao SAMD21设备,修改其VID/PID作为自定义设备使用。设备端逻辑为:接收串口数据做ROT13转换后回传。使用默认cdc_acm驱动时功能正常,为测试需求将该驱动加入黑名单,自行编写驱动后出现异常。
驱动关键代码
Probe函数
static int probe(struct usb_interface *interface, const struct usb_device_id *id) { if (...make sure idVendor/Product match ...) { struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *epd; unsigned int i; struct usb_device *dev = interface_to_usbdev(interface); my_usb_device->dev = dev; iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { epd = &iface_desc->endpoint[i].desc; pr_info("Endpoint %d",i); pr_info(" bLength %d bDescriptorType %d",epd->bLength,epd->bDescriptorType); pr_info(" bEndpointAddress %d bmAttributes %d wMaxPacketSize %d", epd->bEndpointAddress, epd->bmAttributes, epd->wMaxPacketSize); if (usb_endpoint_is_int_in(epd)) { my_usb_device->int_endpoint = epd; pr_info("Set Int endpoint"); } if (usb_endpoint_is_bulk_in(epd)) { my_usb_device->bulk_in_endpoint = epd; pr_info("Set Bulk In endpoint"); } if (usb_endpoint_is_bulk_out(epd)) { my_usb_device->bulk_out_endpoint = epd; pr_info("Set Bulk Out endpoint"); } } my_usb_device->probed = 1; } }
URB请求触发函数
void try_urbs() { if (!my_usb_device->probed) { return; } pr_info("Sending URBS\n"); int actual_length=8; int result = -1; result = usb_interrupt_msg(my_usb_device->dev, usb_rcvintpipe(my_usb_device->dev, my_usb_device->int_endpoint->bEndpointAddress), my_usb_device->intbuffer, MAX_PACKET_SIZE_INT, &actual_length, my_usb_device->int_endpoint->bInterval); pr_info("USB Interrupt in Address %d Message result %d %d\n",my_usb_device->int_endpoint->bEndpointAddress,result,actual_length); result = usb_bulk_msg(my_usb_device->dev, usb_sndbulkpipe(my_usb_device->dev, my_usb_device->bulk_out_endpoint->bEndpointAddress), my_usb_device->writebuffer, MAX_PACKET_SIZE, &actual_length, 5000); pr_info("USB Send Bulk Message result %d %d\n",result,actual_length); result = usb_bulk_msg(my_usb_device->dev, usb_rcvbulkpipe(my_usb_device->dev, my_usb_device->bulk_in_endpoint->bEndpointAddress), my_usb_device->readbuffer, MAX_PACKET_SIZE, &actual_length, 5000); pr_info("USB Recv Bulk Message Address %d result %d %d\n",my_usb_device->bulk_in_endpoint->bEndpointAddress,result,actual_length); return; }
运行日志
[ 117.048729] Endpoint 0 [ 117.048733] bLength 7 bDescriptorType 5 [ 117.048735] bEndpointAddress 129 bmAttributes 3 wMaxPacketSize 16 [ 117.048737] Set Int endpoint [ 117.048801] Endpoint 0 [ 117.048802] bLength 7 bDescriptorType 5 [ 117.048803] bEndpointAddress 2 bmAttributes 2 wMaxPacketSize 64 [ 117.048805] Set Bulk Out endpoint [ 117.048806] Endpoint 1 [ 117.048807] bLength 7 bDescriptorType 5 [ 117.048808] bEndpointAddress 131 bmAttributes 2 wMaxPacketSize 64 [ 117.048809] Set Bulk In endpoint [ 117.050378] Sending URBS [ 117.068767] USB Interrupt in Address 129 Message result -110 0 [ 117.069142] USB Send Bulk Message result 0 64 [ 122.428806] USB Recv Bulk Message Address 131 result -110 0
问题现象
- 中断IN和批量IN的URB请求均超时(错误码-110)
- 批量OUT请求返回正常,但设备端接收指示灯未触发(cdc_acm驱动下可正常触发)
排查方向
- 缺少CDC类控制请求处理:原cdc_acm驱动会处理CDC规范的控制命令(如
SET_LINE_CODING、SET_CONTROL_LINE_STATE),设备端可能依赖这些请求初始化串口功能。即使修改了VID/PID,设备端依旧是CDC ACM逻辑,需要在自定义驱动中实现这些必要的控制请求,否则设备不会响应端点数据传输。比如发送SET_CONTROL_LINE_STATE设置DTR有效,设备端通常需要该信号启动串口接收。 - 中断URB超时参数错误:
usb_interrupt_msg的最后一个参数是超时时间(单位毫秒),你直接传入了端点的bInterval(单位是帧,1帧=1ms),这会导致超时时间过短(比如bInterval为1时,超时仅1ms),必然触发超时。应改为合理的毫秒值,如1000。 - probe函数返回值异常:当前probe函数没有明确的return语句,会返回随机值,可能导致内核认为probe失败,驱动未正确绑定设备。需在probe成功时返回0,失败时返回对应错误码(如-EINVAL)。同时要调用
usb_set_intfdata(interface, my_usb_device)完成接口与设备数据的关联。 - 端点数据未正确同步到设备:虽然批量OUT请求返回0,但数据可能仅停留在USB主机控制器,设备端因未初始化(如未收到DTR信号)未开启接收,所以指示灯不亮。可以通过USB抓包工具(如usbmon)确认主机是否发送了必要的控制请求,设备是否响应。
- 端点描述符引用问题:确保
my_usb_device中保存的端点描述符是有效且稳定的,避免使用临时结构的指针。可直接复制端点描述符内容到自定义结构体,而非保存指针。
内容的提问来源于stack exchange,提问作者BarkerChippy
相关产品推荐
相关产品推荐

