3

我想我實際上有兩個單獨的問題,但我認爲它們足夠相關以包含它們兩者。上下文是一個Linux USB設備驅動程序(不是用戶空間)。Linux USB驅動程序:中斷URBs

  1. 發送請求URB後,如何收到迴應一旦我的complete回調被調用?
  2. 如何使用中斷URB作爲單個請求/響應對,而不是作爲實際的連續中斷輪詢(如其預期的那樣)?

所以對於一些背景,我工作的一個驅動程序的Microchip MCP2210一個USB至SPI協議轉換器,GPIO(USB 2.0,datasheet here)。該設備作爲通用HID進行廣告宣傳,並公開兩個中斷端點(輸入和輸出)以及它的控制端點。

我從一個由其他人寫的工作(但是阿爾法品質)demo driver開始,並且友好地與社區分享。但是,這是一款HID驅動程序,它用於與設備通信的機制非常昂貴! (發送一個64字節的消息需要分配一個6k HID報告結構,並且有時在中斷的上下文中執行分配,需要GFP_ATOMIC!)。我們將通過嵌入式低內存設備訪問此內容。

我是新來的USB驅動程序,一般Linux設備驅動程序仍然很綠。但是,我試圖將其轉換爲簡單的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.bIntervaldev->int_in_ep->desc.bInterval等於1,這是否會每125微秒發送一次我的請求?如果是這樣,我怎麼說「好吧,現在停止這個中斷」。 MCP2210只提供一種配置,一種接口,並且只有兩個中斷端點。 (我知道一切都有控制界面,不知道哪裏適合圖片雖然)

而不是垃圾郵件這個問題與lsusb -v,我要pastebin它。

回答

3

典型地,請求/響應通信的工作原理如下:

  1. 提交響應URB;
  2. 提交請求URB;
  3. 在請求完成處理程序中,如果請求沒有被實際發送,則取消響應URB並中止;
  4. 在響應完成處理程序中處理響應數據。

如果您有一個幾乎立即完成的單個URB,那麼所有異步完成處理程序的東西都是一件很麻煩的事情;因此,有幫助功能usb_interrupt_msg()它同步工作。

要用於輪詢的URB必須重新提交(通常來自完成處理程序)。 如果您不重新提交URB,則不會發生輪詢。

+1

非常感謝您的迴應!這對我來說似乎很奇怪,你先提交響應URB,然後再提交請求。也許這是因爲即使您的任務在發送請求後被搶佔,USB主機驅動程序也可以*接收*響應。然而,我可以同時發送它們,當我可能處於可以睡眠並分配'GFP_KERNEL'的環境中,而不是在「完成」功能中(我相信)您無法入睡(我知道在一些spi主函數中就是這種情況)。 – 2013-05-05 04:12:17

+3

嘿,我想我會在3年多的時間裏爲你拍攝更新。 [驅動程序](https://github.com/daniel-santos/mcp2210-linux)運行得非常好,開始被很多人使用。感謝您幫助我到達那裏! :) – 2016-02-11 06:07:21