title: Linux USB driver: Interrupt URBs
body: <p>I suppose I actually have two separate questions, but I think that they are related enough to include them both. The context is a Linux USB device driver (not userspace).</p>
  
  <ol>
  <li>After transmitting a request URB, how do I receive the response once my <code>complete</code> callback is called?</li>
  <li>How can I use interrupt URBs for <em>single</em> request/response pairs, and not as actual continuous interrupt polling (as they are intended)?</li>
  </ol>
  
  <p>So for some background, I'm working on a driver for the Microchip <a href="http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en556614" rel="nofollow">MCP2210</a> a USB-to-SPI Protocol Converter with GPIO (USB 2.0, <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/22288A.pdf" rel="nofollow">datasheet here</a>).  This device advertises as generic HID and exposes two interrupt endpoints (an in and an out) as well as it's control endpoint.</p>
  
  <p>I am starting from a working, (but alpha-quality) <a href="https://github.com/MathewKing/mcp2210-linux" rel="nofollow">demo driver</a> written by somebody else and kindly shared with the community.  However, this is a HID driver and the mechanism it uses to communicate with the device is very expensive!  (sending a 64 byte message requires allocating a 6k HID report struct, and allocation is sometimes performed in the context of an interrupt, requiring GFP_ATOMIC!).  We'll be accessing this from an embedded low-memory device.</p>
  
  <p>I'm new to USB drivers and still pretty green with Linux device drivers in general.  However, I'm trying to convert this to a plain-jane USB driver (not HID) so I can use the less expensive interrupt URBs for my communications.  Here is my code for transmitting my request.  For the sake of (attempted) brevity, I'm not including the definition of my structs, etc, but please let me know if you need more of my code.  <code>dev-&gt;cur_cmd</code> is where I'm keeping the current command I'm processing.</p>
  
  <pre><code>/* use a local for brevity */
  cmd = dev-&gt;cur_cmd;
  
  if (cmd-&gt;state == MCP2210_CMD_STATE_NEW) {
  
      usb_fill_int_urb(dev-&gt;int_out_urb,
              dev-&gt;udev,
              usb_sndintpipe(dev-&gt;udev, dev-&gt;int_out_ep-&gt;desc.bEndpointAddress),
              &amp;dev-&gt;out_buffer,
              sizeof(dev-&gt;out_buffer), /* always 64 bytes */
              cmd-&gt;type-&gt;complete,
              cmd,
              dev-&gt;int_out_ep-&gt;desc.bInterval);
  
      ret = usb_submit_urb(dev-&gt;int_out_urb, GFP_KERNEL);
      if (ret) {
          /* snipped: handle error */
      }
      cmd-&gt;state = MCP2210_CMD_STATE_XMITED;
  }
  </code></pre>
  
  <p>And here is my complete fn:</p>
  
  <pre><code>/* note that by "ctrl" I mean a control command, not the control endpoint */
  static void ctrl_complete(struct urb *)
  {
      struct mcp2210_device *dev = urb-&gt;context;
      struct mcp2210_command *cmd = dev-&gt;cur_cmd;
      int ret;
  
      if (unlikely(!cmd || !cmd-&gt;dev)) {
          printk(KERN_ERR "mcp2210: ctrl_complete called w/o valid cmd "
                  "or dev\n");
          return;
      }
  
      switch (cmd-&gt;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-&gt;int_in_urb,
                  dev-&gt;udev,
                  usb_sndintpipe(dev-&gt;udev, dev-&gt;int_in_ep-&gt;desc
                      .bEndpointAddress),
                  &amp;dev-&gt;in_buffer,
                  sizeof(dev-&gt;in_buffer),
                  cmd-&gt;type-&gt;complete,
                  dev,
                  dev-&gt;int_in_ep-&gt;desc.bInterval);
          ret = usb_submit_urb(dev-&gt;int_in_urb, GFP_KERNEL);
  
          if (ret) {
              dev_err(&amp;dev-&gt;udev-&gt;dev,
                  "while attempting to rx response, "
                  "usb_submit_urb returned %d\n", ret);
              free_cur_cmd(dev);
              return;
          }
  
          cmd-&gt;state = MCP2210_CMD_STATE_RXED;
          return;
  
      /* got response, now process it */
      case MCP2210_CMD_STATE_RXED:
          process_response(cmd);
  
      default:
          dev_err(&amp;dev-&gt;udev-&gt;dev, "ctrl_complete called with unexpected state: %d", cmd-&gt;state);
          free_cur_cmd(dev);
      };
  }
  </code></pre>
  
  <p>So am I at least close here?  Secondly, both <code>dev-&gt;int_out_ep-&gt;desc.bInterval</code> and <code>dev-&gt;int_in_ep-&gt;desc.bInterval</code> are equal to <code>1</code>, will this keep sending my request every 125 microseconds? And if so, how do I say "ok, ty, now stop this interrupt".  The MCP2210 offers only one configuration, one interface and that has just the two interrupt endpoints. (I know everything has the control interface, not sure where that fits into the picture though.)</p>
  
  <p>Rather than spam this question with the <a href="http://pastebin.ca/2368243" rel="nofollow">lsusb -v</a>, I'm going to pastebin it.</p>