我想我实际上有两个独立的问题,但我认为它们足够相关,可以将它们都包括在内。上下文是 Linux USB 设备驱动程序(不是用户空间)。
complete
发送请求 URB 后,调用回调后如何接收响应?- 如何将中断 URB 用于单个请求/响应对,而不是实际的连续中断轮询(如预期的那样)?
因此,对于一些背景知识,我正在开发 Microchip MCP2210的驱动程序,这是一个带有 GPIO 的 USB 到 SPI 协议转换器(USB 2.0,此处的数据表)。该设备宣传为通用 HID 并公开两个中断端点(一个输入和一个输出)以及它的控制端点。
我从一个由其他人编写并与社区分享的工作(但 alpha 质量)演示驱动程序开始。然而,这是一个 HID 驱动程序,它用于与设备通信的机制非常昂贵!(发送一个 64 字节的消息需要分配一个 6k HID 报告结构,并且分配有时是在中断的上下文中执行的,需要 GFP_ATOMIC!)。我们将从嵌入式低内存设备访问它。
我是 USB 驱动程序的新手,一般来说 Linux 设备驱动程序还是很绿色的。但是,我正在尝试将其转换为普通的 jane USB 驱动程序(不是 HID),这样我就可以使用更便宜的中断 URB 进行通信。这是我传输请求的代码。为了(尝试)简洁起见,我不包括我的结构的定义等,但如果您需要更多我的代码,请告诉我。 dev->cur_cmd
是我保存当前正在处理的命令的地方。
/* use a local for brevity */
cmd = dev->cur_cmd;
if (cmd->state == MCP2210_CMD_STATE_NEW) {
usb_fill_int_urb(dev->int_out_urb,
dev->udev,
usb_sndintpipe(dev->udev, dev->int_out_ep->desc.bEndpointAddress),
&dev->out_buffer,
sizeof(dev->out_buffer), /* always 64 bytes */
cmd->type->complete,
cmd,
dev->int_out_ep->desc.bInterval);
ret = usb_submit_urb(dev->int_out_urb, GFP_KERNEL);
if (ret) {
/* snipped: handle error */
}
cmd->state = MCP2210_CMD_STATE_XMITED;
}
这是我完整的fn:
/* note that by "ctrl" I mean a control command, not the control endpoint */
static void ctrl_complete(struct urb *)
{
struct mcp2210_device *dev = urb->context;
struct mcp2210_command *cmd = dev->cur_cmd;
int ret;
if (unlikely(!cmd || !cmd->dev)) {
printk(KERN_ERR "mcp2210: ctrl_complete called w/o valid cmd "
"or dev\n");
return;
}
switch (cmd->state) {
/* Time to rx the response */
case MCP2210_CMD_STATE_XMITED:
/* FIXME: I think that I need to check the response URB's
* status to find out if it was even transmitted or not */
usb_fill_int_urb(dev->int_in_urb,
dev->udev,
usb_sndintpipe(dev->udev, dev->int_in_ep->desc
.bEndpointAddress),
&dev->in_buffer,
sizeof(dev->in_buffer),
cmd->type->complete,
dev,
dev->int_in_ep->desc.bInterval);
ret = usb_submit_urb(dev->int_in_urb, GFP_KERNEL);
if (ret) {
dev_err(&dev->udev->dev,
"while attempting to rx response, "
"usb_submit_urb returned %d\n", ret);
free_cur_cmd(dev);
return;
}
cmd->state = MCP2210_CMD_STATE_RXED;
return;
/* got response, now process it */
case MCP2210_CMD_STATE_RXED:
process_response(cmd);
default:
dev_err(&dev->udev->dev, "ctrl_complete called with unexpected state: %d", cmd->state);
free_cur_cmd(dev);
};
}
所以我至少离这里很近吗?其次,两者dev->int_out_ep->desc.bInterval
和dev->int_in_ep->desc.bInterval
都等于1
,这会继续每 125 微秒发送一次我的请求吗?如果是这样,我该怎么说“好的,ty,现在停止这个中断”。MCP2210 仅提供一种配置、一个接口并且只有两个中断端点。(我知道所有东西都有控制界面,但不确定它在图片中的位置。)
我不会使用lsusb -v向这个问题发送垃圾邮件,而是将其粘贴。