3

実際には 2 つの別々の質問があると思いますが、両方を含めるのに十分な関連性があると思います。コンテキストは Linux USB デバイス ドライバーです (ユーザー空間ではありません)。

  1. complete要求 URB を送信した後、コールバックが呼び出されたときに応答を受け取るにはどうすればよいですか?
  2. 実際の連続割り込みポーリング (意図されている) としてではなく、単一の要求/応答ペアに割り込み URB を使用するにはどうすればよいですか?

そのため、背景として、GPIO を備えた Microchip MCP2210の USB-to-SPI プロトコル コンバーター (USB 2.0、データシートはこちら)のドライバーに取り組んでいます。このデバイスは汎用 HID としてアドバタイズし、2 つの割り込みエンドポイント (インとアウト) と制御エンドポイントを公開します。

私は、他の誰かによって書かれ、コミュニティと親切に共有された、動作する (ただしアルファ品質の)デモ ドライバーから始めています。ただし、これは 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 は 1 つの構成、1 つのインターフェース、および 2 つの割り込みエンドポイントのみを提供します。(私はすべてが制御インターフェースを持っていることを知っていますが、それが写真のどこに収まるかはわかりません。)

この質問をlsusb -vでスパムするのではなく、貼り付けます。

4

1 に答える 1

3

通常、要求/応答通信は次のように機能します。

  1. 応答 URB を送信します。
  2. 要求 URB を送信します。
  3. リクエスト完了ハンドラで、リクエストが実際に送信されなかった場合は、レスポンス URB をキャンセルして中止します。
  4. 応答完了ハンドラーで、応答データを処理します。

ほぼ即座に完了する単一の URB がある場合、非同期完了ハンドラーのすべてが非常に面倒です。usb_interrupt_msg()したがって、同期的に動作するヘルパー関数があります。

ポーリングに使用される URB は、(通常は完了ハンドラーから) 再送信する必要があります。URB を再送信しない場合、ポーリングは行われません。

于 2013-04-29T11:26:28.330 に答える