首页 > 系统相关 >windows USB 设备驱动开发- USB管道的通讯(一)

windows USB 设备驱动开发- USB管道的通讯(一)

时间:2024-07-07 22:26:05浏览次数:23  
标签:USB WDF windows 例程 管道 驱动程序 读取器 客户端

Windows WDF框架提供一 个名为连续读取器的专用对象。 此对象使 USB 客户端驱动程序能够连续读取批量和中断终结点中的数据,只要有数据可用。 若要使用读取器,客户端驱动程序必须具有与驱动程序从中读取数据的终结点关联的 USB 目标管道对象的句柄。 终结点必须位于活动配置中。 可以通过以下两种方式之一激活配置:选择 USB 配置或更改当前配置中的备用设置。 

创建连续读取器后,客户端驱动程序可以根据需要启动和停止读取器。 连续读取器,确保读取请求始终在目标管道对象上可用,并且客户端驱动程序始终准备好从终结点接收数据。

连续读取器不会自动由框架管理。 这意味着当设备进入较低电源状态时,客户端驱动程序必须停止读取器,并在设备进入工作状态时重启读取器。

准备工作

在客户端驱动程序可以使用连续读取器之前,请确保满足以下要求:

1. USB 设备必须具有 IN 终结点。 检查 USBView 中的设备配置。 Usbview.exe是一个应用程序,可用于浏览所有 USB 控制器和连接到它们的 USB 设备。 通常,USBView 安装在 Windows 驱动程序工具包(WDK)的调试器 文件夹中;

2. 客户端驱动程序必须已创建框架 USB 目标设备对象;

如果使用 Microsoft Visual Studio Professional 2012 随附的 USB 模板,则模板代码会执行这些任务。 模板代码会获取目标设备对象的句柄并将其存储在设备上下文中。

KMDF 客户端驱动程序:KMDF 客户端驱动程序必须调用 WdfUsbTargetDeviceCreateWithParameters 方法来获取 WDFUSBDEVICE 句柄。 

UMDF 客户端驱动程序:UMDF 客户端驱动程序必须通过查询框架目标设备对象获取 IWDFUsbTargetDevice 指针。

3. 设备必须具有活动配置:

如果使用 USB 模板,代码将在每个接口中选择第一个配置和默认备用设置。 

KMDF 客户端驱动程序:KMDF 客户端驱动程序必须调用 WdfUsbTargetDeviceSelectConfig 方法。

UMDF 客户端驱动程序:对于 UMDF 客户端驱动程序,框架为该配置中的每个接口选择第一个配置和默认备用设置。客户端驱动程序必须具有 IN 终结点的框架目标管道对象的句柄。

在 KMDF 客户端驱动程序中使用连续读取器

在开始使用连续读取器之前,必须通过初始化 WDF_USB_CONTINUOUS_READER_CONFIG 结构来配置它。

在 KMDF 客户端驱动程序中配置连续读取器
  • 通过调用WDF_USB_CONTINUOUS_READER_CONFIG_INIT宏初始化WDF_USB_CONTINUOUS_READER_CONFIG结构;
  • 在 WDF_USB_CONTINUOUS_READER_CONFIG 结构中指定其配置选项;
  • 调用 WdfUsbTargetPipeConfigContinuousReader 方法;

以下示例代码为指定的目标管道对象配置连续读取器。

NTSTATUS FX3ConfigureContinuousReader(
    _In_ WDFDEVICE Device,
    _In_ WDFUSBPIPE Pipe)
{
    NTSTATUS status;
    PDEVICE_CONTEXT                     pDeviceContext;
    WDF_USB_CONTINUOUS_READER_CONFIG    readerConfig;
    PPIPE_CONTEXT                       pipeContext;

    PAGED_CODE();

    pDeviceContext = WdfObjectGet_DEVICE_CONTEXT(Device);
    pipeContext = GetPipeContext (Pipe);

    WDF_USB_CONTINUOUS_READER_CONFIG_INIT(
        &readerConfig,
        FX3EvtReadComplete,
        pDeviceContext,
        pipeContext->MaxPacketSize);

    readerConfig.EvtUsbTargetPipeReadersFailed=FX3EvtReadFailed;

    status = WdfUsbTargetPipeConfigContinuousReader(
        Pipe,
        &readerConfig);

    if (!NT_SUCCESS (status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
            "%!FUNC! WdfUsbTargetPipeConfigContinuousReader failed 0x%x", status);

        goto Exit;
    }

Exit:
    return status;
}

客户端驱动程序在枚举活动设置中的目标管道对象后,在 EvtDevicePrepareHardware 回调函数中配置连续读取器。

在前面的示例中,客户端驱动程序以两种方式指定其配置选项。 首先通过调用WDF_USB_CONTINUOUS_READER_CONFIG_INIT,然后通过设置WDF_USB_CONTINUOUS_READER_CONFIG成员。 请注意WDF_USB_CONTINUOUS_READER_CONFIG_INIT的参数。 这些值是必需的。 在此示例中,客户端驱动程序指定:

  • 指向驱动程序实现的完成例程的指针。 框架在完成读取请求时调用此例程。 在完成例程中,驱动程序可以访问包含已读取数据的内存位置;
  • 指向驱动程序定义的上下文的指针;
  • 可以在单个传输中从设备读取的字节数。 客户端驱动程序可以通过调用 WdfUsbInterfaceGetConfiguredPipe 或 WdfUsbTargetPipeGetInformation 方法获取WDF_USB_PIPE_INFORMATION结构中的信息;

WDF_USB_CONTINUOUS_READER_CONFIG_INIT将连续读取器配置为使用 NumPendingReads 的默认值。 该值确定框架添加到挂起队列的读取请求数。 默认值已确定为许多处理器配置上的许多设备提供相当良好的性能。

除了WDF_USB_CONTINUOUS_READER_CONFIG_INIT中指定的配置参数外,该示例还在WDF_USB_CONTINUOUS_READER_CONFIG中设置故障例程。 此失败例程是可选的。

除了故障例程之外,还有WDF_USB_CONTINUOUS_READER_CONFIG客户端驱动程序可用于指定传输缓冲区布局的其他成员。 例如,请考虑使用连续读取器接收网络数据包的网络驱动程序。 每个数据包都包含标头、有效负载和页脚数据。 若要描述数据包,驱动程序必须首先在其调用中指定数据包的大小以 WDF_USB_CONTINUOUS_READER_CONFIG_INIT。 然后,驱动程序必须通过设置WDF_USB_CONTINUOUS_READER_CONFIG的 HeaderLength 和 TrailerLength 成员来指定页眉和页脚的长度。 框架使用这些值计算有效负载两侧的字节偏移量。 从终结点读取有效负载数据时,框架会将该数据存储在偏移量之间的缓冲区部分。

实现完成例程

每次请求完成时,框架都会调用客户端驱动程序实现的完成例程。 框架传递读取的字节数和一个 WDFMEMORY 对象,其缓冲区包含从管道读取的数据。

以下示例代码显示了完成例程实现。

EVT_WDF_USB_READER_COMPLETION_ROUTINE FX3EvtReadComplete;

VOID FX3EvtReadComplete(
    __in  WDFUSBPIPE Pipe,
    __in  WDFMEMORY Buffer,
    __in  size_t NumBytesTransferred,
    __in  WDFCONTEXT Context
    )
{
    PDEVICE_CONTEXT  pDeviceContext;
    PVOID  requestBuffer;

    pDeviceContext = (PDEVICE_CONTEXT)Context;

    if (NumBytesTransferred == 0)
    {
        return;
    }

    requestBuffer = WdfMemoryGetBuffer(Buffer, NULL);

    if (Pipe == pDeviceContext->InterruptPipe)
    {
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL,
                                "Interrupt endpoint: %s.\n",
                                requestBuffer ));
    }

    return;
}

每次请求完成时,框架都会调用客户端驱动程序实现的完成例程。 框架为每个读取操作分配一个内存对象。 在完成例程中,框架将读取的字节数和 WDFMEMORY 句柄传递给内存对象。 内存对象缓冲区包含从管道读取的数据。 客户端驱动程序不得释放内存对象。 框架在每个完成例程返回后释放对象。 如果客户端驱动程序想要存储收到的数据,驱动程序必须在完成例程中复制缓冲区的内容。

实现失败例程

框架调用客户端驱动程序实现的失败例程,以通知驱动程序连续读取器在处理读取请求时报告了错误。 框架将指针传递给请求失败的目标管道对象和错误代码值。 根据这些错误代码值,驱动程序可以实现其错误恢复机制。 驱动程序还必须返回一个适当的值,该值指示框架是否应重启连续读取器。

以下示例代码演示失败例程实现。

EVT_WDF_USB_READERS_FAILED FX3EvtReadFailed;

BOOLEAN
FX3EvtReadFailed(
    WDFUSBPIPE      Pipe,
    NTSTATUS        Status,
    USBD_STATUS     UsbdStatus
    )
{
    UNREFERENCED_PARAMETER(Status);

    TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
            "%!FUNC! ReadersFailedCallback failed NTSTATUS 0x%x, UsbdStatus 0x%x\n",
                    status,
                    UsbdStatus);

    return TRUE;
}

在前面的示例中,驱动程序返回 TRUE。 此值向框架指示它必须重置管道,然后重启连续读取器。

或者,客户端驱动程序可以返回 FAL标准版并在管道上出现停止条件时提供错误恢复机制。 例如,驱动程序可以检查 USBD 状态,并发出重置管道请求以清除停止条件。

启动和停止连续读取器

指示框架在设备进入工作状态时启动连续读取器;设备离开工作状态时停止读取器。 调用这些方法,并将目标管道对象指定为 I/O 目标对象。

  • WdfIoTargetStart
  • WdfIoTargetStop

连续读取器不会自动由框架管理。 因此,当设备电源状态发生更改时,客户端驱动程序必须显式启动或停止目标管道对象。 驱动程序在驱动程序的 EvtDeviceD0Entry 实现中调用 WdfIoTargetStart。 此调用可确保队列仅在设备处于工作状态时传递请求。 相反,驱动程序在驱动程序 EvtDeviceD0Exit 实现中调用 WdfIoTargetStop,以便在设备进入较低电源状态时队列停止传送请求。

以下示例代码为指定的目标管道对象配置连续读取器。

EVT_WDF_DEVICE_D0_ENTRY FX3EvtDeviceD0Entry;

NTSTATUS FX3EvtDeviceD0Entry(
    __in  WDFDEVICE Device,
    __in  WDF_POWER_DEVICE_STATE PreviousState
    )
{
    PDEVICE_CONTEXT  pDeviceContext;
    NTSTATUS status;

    PAGED_CODE();

    pDeviceContext = WdfObjectGet_DEVICE_CONTEXT(Device);
    status = WdfIoTargetStart (WdfUsbTargetPipeGetIoTarget (pDeviceContext->InterruptPipe));

    if (!NT_SUCCESS (status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
            "%!FUNC! Could not start interrupt pipe failed 0x%x", status);
    }
}

EVT_WDF_DEVICE_D0_EXIT FX3EvtDeviceD0Exit;

NTSTATUS FX3EvtDeviceD0Exit(
    __in  WDFDEVICE Device,
    __in  WDF_POWER_DEVICE_STATE TargetState
    )
{
    PDEVICE_CONTEXT  pDeviceContext;
    NTSTATUS status;
    PAGED_CODE();
    pDeviceContext = WdfObjectGet_DEVICE_CONTEXT(Device);
    WdfIoTargetStop (WdfUsbTargetPipeGetIoTarget (pDeviceContext->InterruptPipe), WdfIoTargetCancelSentIo));
}

前面的示例显示了 EvtDeviceD0Entry 和 EvtDeviceD0Exit 回调例程的实现。 WdfIoTargetStop 的 Action 参数允许客户端驱动程序在设备离开工作状态时决定队列中挂起请求的操作。 在此示例中,驱动程序指定 WdfIoTargetCancelSentIo。 此选项指示框架取消队列中的所有挂起请求。 或者,驱动程序可以指示框架等待挂起的请求在停止 I/O 目标之前完成,或保留挂起的请求并在 I/O 目标重启时恢复。

标签:USB,WDF,windows,例程,管道,驱动程序,读取器,客户端
From: https://blog.csdn.net/m0_72813396/article/details/140165993

相关文章

  • Windows系统组合键
    前言到目前为止,使用Windows系统的用户占全球量,微软为了使用户更便捷,更有效的工作和提高工作效率,因此许多功能组合键就出现了。那么,今天,我们就跟随我的介绍,一步步来解释常用快捷键组合,以此为大家节省时间,提高效率目录本文分为几个部分来介绍1.win键2.ctrl键3alt键4.特......
  • Windows 电源管理中的 "快速启动(推荐)" 是一种功能选项,它允许电脑在关机后以一种较快的
    Windows电源管理中的"快速启动(推荐)"是一种功能选项,它允许电脑在关机后以一种较快的方式启动。这个功能通过将系统的部分内容保存到硬盘上的一个文件中,而不是完全关闭电脑,从而实现更快的启动速度。具体来说,当你选择启用快速启动时,Windows会将当前的系统状态保存到一个名为hibe......
  • 2024-07-07 如何把ipad当作windows副屏使用 ==》 通过软件dute display和数据线连接
    windows:进入dutedisplay官网https://www.duetdisplay.com/zh#download,下载并安装ipad:在苹果应用商店搜索dutedisplay,选中并下载 注意:你需要注册一个dutedisplay账号,才能登录该软件,它是付费的,so,我看到付费我就放弃了。如果,你给钱了,那么,接下来我也不知道对不对,你用ipad充电线......
  • QML仿Windows开机动画
    importQtQuick2.5importQtQuick.Window2.2Window{visible:truewidth:640height:320id:roottitle:qsTr("win10loading")color:"#1086a2"Repeater{model:5id:repeaterRe......
  • Windows 11 中使用 Win10的文件资源管理器!
    1.在Windows11中恢复旧文件资源管理器,首先打开记事本并粘贴以下文本代码:WindowsRegistryEditorVersion5.00[HKEY_CURRENT_USER\Software\Classes\CLSID\{2aa9162e-c906-4dd9-ad0b-3d24a8eef5a0}]@="CLSID_ItemsViewAdapter"[HKEY_CURRENT_USER\Software\Classes\CLS......
  • 这些 PowerShell 命令适用于清理 Windows 中更多不同组件和服务的日志。通过定期执行
    清理临时文件:powershellCopyCodeRemove-Item-Path"$env:TEMP\*"-Force-RecurseRemove-Item-Path"$env:LOCALAPPDATA\Temp\*"-Force-Recurse清理回收站:powershellCopyCodeClear-RecycleBin-Force清理浏览器缓存(例如清理Chrome缓存):powershellCopy......
  • Windows如何查看端口是否占用,并结束端口进程
    需求与问题:前后端配置了跨域操作,但是仍然报错,可以考虑端口被两个程序占用,找不到正确端口或者后端接口书写是否规范,特别是利用PythonFlask书写时要保证缩进是否正确!Windows操作系统中,查看端口是否占用并结束占用端口的程序是一个常见的操作,特别是在进行网络配置或软件安装时。......
  • 安装MySQL(Windows10和Linux CentOS7) 很详细的
    Windows10下安装MySQL1.下载MySQL官网下载MySQL:https://www.mysql.com/进入官网点击DOWNLOADS下滑点击MySQLCommunity(GPL)Downloads点击MySQLInstallerforWindows选择版本下载这里就不需要登录注册了,直接下载2.安装MySQL找到下载的文件双击之后选择Se......
  • windows下C++配置googletest过程记录
    文章目录下载googletest将googletest解压到项目目录并创建build文件夹编译googletest在项目的CMakeLists.txt文件中添加相关依赖编写测试并执行参考下载googletestReleasev1.14.0·google/googletest·GitHub将googletest解压到项目目录并创建build文件夹在g......
  • Windows防火墙 日志 自定义 以记录被丢弃的数据包和成功的连接日志。以下是一个示例.r
     配置注册表,以记录被丢弃的数据包和成功的连接日志 WindowsRegistryEditorVersion5.00;WindowsDefender防火墙日志记录设置[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy];以下是针对不同配置文件的设置,例如......