使用 USB 管道

框架将 USB 接口中的每个管道表示为框架 USB 管道对象。 当驱动程序 配置 USB 设备时,框架会为每个所选接口中的每个管道创建一个框架 USB 管道对象。 管道对象方法使驱动程序能够执行以下操作:

获取管道信息

调用 WdfUsbInterfaceGetConfiguredPipe 以获取框架 USB 管道对象的句柄后,驱动程序可以调用 USB 管道对象为获取有关 USB 管道的信息而定义的以下方法:

WdfUsbTargetPipeGetIoTarget
返回与 USB 管道关联的 I/O 目标对象的句柄。 驱动程序可以将此句柄传递给 WdfRequestSend

WdfUsbTargetPipeGetInformation
检索有关 USB 管道及其终结点的信息。

WdfUsbTargetPipeGetType
返回 USB 管道的类型。

WdfUsbTargetPipeIsInEndpoint
确定 USB 管道是否连接到输入终结点。

WdfUsbTargetPipeIsOutEndpoint
确定 USB 管道是否连接到输出终结点。

WDF_USB_PIPE_DIRECTION_IN
确定 USB 终结点是否为输入终结点。

WDF_USB_PIPE_DIRECTION_OUT
确定 USB 终结点是否为输出终结点。

有关信息,请参阅 如何枚举 USB 管道

从管道读取

若要从 USB 输入管道读取数据,驱动程序可以使用以下三种技术中的任何 (或所有) :

  • 同步读取数据

    若要从 USB 输入管道同步读取数据,驱动程序可以调用 WdfUsbTargetPipeReadSynchronously 方法。 此方法生成并发送读取请求,并在 I/O 操作完成后返回。

  • 异步读取数据

    若要从 USB 输入管道异步读取数据,驱动程序可以调用 WdfUsbTargetPipeFormatRequestForRead 方法来生成读取请求。 然后,驱动程序可以调用 WdfRequestSend 以异步 (或同步) 发送请求。

  • 以异步方式连续读取数据

    连续读取器是一种框架提供的机制,用于确保读取请求始终可用于 USB 管道。 此机制保证驱动程序始终准备好从提供异步、未经请求的输入流的设备接收数据。 例如,网络接口卡 (NIC) 的驱动程序可能会使用连续读取器来接收输入数据。

    若要为输入管道配置连续读取器,驱动程序的 EvtDevicePrepareHardware 回调函数必须调用 WdfUsbTargetPipeConfigContinuousReader 方法。 此方法将一组读取请求排队到设备的 I/O 目标。

    此外,驱动程序的 EvtDeviceD0Entry 回调函数必须调用 WdfIoTargetStart 才能启动连续读取器,驱动程序的 EvtDeviceD0Exit 回调函数必须调用 WdfIoTargetStop 来停止连续读取器。

    每次从设备获取数据时,I/O 目标都将完成读取请求,框架将调用以下两个回调函数之一: EvtUsbTargetPipeReadComplete(如果 I/O 目标成功读取数据),如果 I/O 目标报告错误,则调用 EvtUsbTargetPipeReadersFailed

    如果不提供可选的 EvtUsbTargetPipeReadersFailed 回调,框架将通过发送另一个读取请求来响应失败的读取尝试。 因此,如果总线处于不接受读取的状态,框架会不断发送新的请求,以从失败的读取中恢复。

    驱动程序调用 WdfUsbTargetPipeConfigContinuousReader 后,驱动程序无法使用 WdfUsbTargetPipeReadSynchronouslyWdfRequestSend 将 I/O 请求发送到管道,除非调用了驱动程序的 EvtUsbTargetPipeReadersFailed 回调函数并返回 FALSE

默认情况下,如果驱动程序指定的读取缓冲区不是管道最大数据包大小的倍数,框架将报告错误。 驱动程序可以调用 WdfUsbTargetPipeSetNoMaximumPacketSizeCheck 来禁用读取缓冲区大小的此测试。

如需相关信息,请参阅:

写入管道

若要将数据写入 USB 输出管道,驱动程序可以使用一 (或两者) 以下技术:

  • 同步写入数据

    若要将数据同步写入 USB 输出管道,驱动程序可以调用 WdfUsbTargetPipeWriteSynchronously 方法。 此方法生成并发送写入请求,并在 I/O 操作完成后返回。

  • 异步写入数据

    若要将数据异步写入 USB 输入管道,驱动程序可以调用 WdfUsbTargetPipeFormatRequestForWrite 方法来生成写入请求。 然后,驱动程序可以调用 WdfRequestSend 以异步发送请求。

有关信息,请参阅 如何发送 USB 批量传输请求

停止和重置管道

驱动程序可以调用以下方法来停止或重置 USB 管道:

WdfUsbTargetPipeAbortSynchronously
同步发送停止 USB 管道的请求。

WdfUsbTargetPipeFormatRequestForAbort
设置停止 USB 管道的请求的格式。 驱动程序可以调用 WdfRequestSend 以同步或异步方式发送请求。

WdfUsbTargetPipeResetSynchronously
同步发送重置 USB 管道的请求。

WdfUsbTargetPipeFormatRequestForReset
设置重置 USB 管道的请求的格式。 驱动程序必须调用 WdfRequestSend 以同步或异步方式发送请求。

如果驱动程序的 USB 目标以错误状态值 完成 I/O 请求,则驱动程序应执行以下操作:

  1. 如果目标尚未完成请求,请停止管道并取消驱动程序已发送到 USB 目标的任何其他 I/O 请求。

    调用 设置了 WdfIoTargetCancelSentIo 标志的 WdfIoTargetStop

  2. 向管道同步发送中止请求。

    调用 WdfUsbTargetPipeAbortSynchronously,或调用 WdfUsbTargetPipeFormatRequestForAbort ,后跟 WdfRequestSend 并设置 WDF_REQUEST_SEND_OPTION_SYNCHRONOUS 标志。

  3. 同步向管道发送重置请求。

    调用 WdfUsbTargetPipeResetSynchronously,或调用 WdfUsbTargetPipeFormatRequestForReset ,然后调用 WdfRequestSend 并设置 WDF_REQUEST_SEND_OPTION_SYNCHRONOUS 标志。

  4. 重启管道。

    调用 WdfIoTargetStart

  5. 重新发送失败的 I/O 请求,以及失败请求后的所有 I/O 请求。

多次失败后,驱动程序应尝试通过执行以下操作来重置 USB 端口:

  1. 如果目标尚未完成,请停止所有活动管道,并取消驱动程序发送到每个管道的 USB 目标的任何其他 I/O 请求。

    对于每个活动管道,调用 设置了 WdfIoTargetCancelSentIo 标志的 WdfIoTargetStop

  2. 同步发送重置 USB 端口的请求。

    调用 WdfUsbTargetDeviceResetPortSynchronously

  3. 重启管道。

    为驱动程序停止的每个管道调用 WdfIoTargetStart

  4. 重新发送失败的最后一个 I/O 请求,以及失败请求后的所有 I/O 请求。

有关相关信息,请参阅 如何从 USB 管道错误中恢复

将 URB 发送到管道

如果 KMDF 驱动程序通过发送包含 URB 的 I/O 请求与 USB 管道通信,则驱动程序可以调用以下方法:

WdfUsbTargetPipeSendUrbSynchronously 仅 (KMDF)
同步发送包含 URB 的 I/O 请求。

WdfUsbTargetPipeFormatRequestForUrb 仅 (KMDF)
设置包含 URB 的 I/O 请求的格式。 驱动程序可以调用 WdfRequestSend 以同步或异步方式发送请求。

WdfUsbTargetPipeWdmGetPipeHandle (KMDF 仅)
返回设备的 USBD 管道句柄。 某些 URB 需要此句柄。