USB设备仿真框架设计指南——8.USB设备模拟器的设计

当你设计一个USB设备模拟器时,你应该考虑下面的设计选择:

  • 封装和编程语言(例如,DLL、EXE或组件对象)
  • USB设备配置
  • 轮询或事件驱动的数据处理
  • 测试应用接口

下面的主题详细地阐述了这些考虑中的每一个:

模拟器封装

配置SoftUSBDevice对象

配置

接口

端点

设备限定描述符

字符串

设备、类和特定于供应商的描述符

处理标准设备请求

事件驱动与轮询仿真

测试应用接口

使用端点诊断

使用设备上下文

DSF中的电源管理

使用外部集线器模拟器

模拟复合材料与复合设备

检查DSF版本


向微软发送有关此主题的评论

创建日期:2010/9/21

英文原文连接:https://docs.microsoft.com/zh-cn/previous-versions/windows/hardware/dsf/ff538285(v%3dvs.85)


模拟器封装

您必须用COM客户机语言编写USB设备模拟器。您可以使用任何COM客户端能力的语言,但是我们推荐编译语言以获得更好的性能。

您可以使用任何可执行格式,但是可重用表单(如COM)通常更便于测试应用程序的使用。在大多数情况下,模拟器应该公开它用来测试应用程序以控制设备到集线器的连接的 SoftUSBDevice对象(ISoftUSBDevice) ,尽管这种公开不是必需的(即,您可以设计一个模拟器自连接到默认的或测试应用程序提供的集线器上)。

如果您打算在托管代码中编写测试应用程序,则必须安装DSF接口(托管互操作程序集)。测试应用程序可以控制基于DSF的仿真并测试驱动程序。托管互操作程序集允许您使用.NETFramework访问DSF提供的COM接口。不能使用托管互操作程序集来创建或修改托管代码中的模拟设备。但是,可以使用托管互操作程序集来创建控制模拟设备的测试应用程序。

有关详细信息,请参阅Installing DSF.。

英文原文连接:https://docs.microsoft.com/zh-cn/previous-versions/windows/hardware/dsf/ff542306%28v%3dvs.85%29


配置SoftUSBDevice对象

模拟器必须创建一个SoftUSBDevice对象(ISoftUSBDevice) ,然后在将设备连接到集线器之前配置它。设备需要在SoftUSBDevice上设置至少一个配置和足够的属性,以便主机可以返回有效的设备描述符。设备需要的确切属性由设备的即插即用(PnP)要求及其驱动程序的INF文件确定。然而,大多数情况下包括以下性质:

  • DeviceClass属性是返回给主机的设备描述符的bDeviceClass字段的值,如USB 2.0规范的9.6.1节中所定义。
  • DeviceSubClass属性是返回到设备描述符的bDeviceSubClass字段的主机的值。
  • DeviceProtocol属性是返回到设备描述符的bDeviceProtocol字段的主机的值。
  • Vendor属性是返回到设备描述符的 idVendor字段的主机的值。
  • Product属性是返回到设备描述符的idProduct字段的主机的值。

设备默认为USB 2.0,但也可以通过设置 SoftUSBDevice::USB属性来配置为USB 1.1设备。此属性是返回到设备描述符的bcdUSB字段的主机的值。可以同时以USB 2.0和USB 1.1速度操作的设备还必须填充SoftUSBDevice::DeviceQualifier 和 SoftUSBDevice::USB1xConfigurations属性。

您可以设置SoftUSBDevice::MaxPacketSize0 属性,以确定控件端点的最大包大小。这个值被用作返回到设备描述符的bMaxPacketSize0字段的主机的值。

可以将SoftUSBDevice.Device属性设置为返回给主机的设备描述符的bcdDevice字段的值。

如果设备为制造商、产品描述和设备序列号定义了字符串描述符,则必须将SoftUSBDevice::ManufacturerSoftUSBDevice::ProductDesc, 和 SoftUSBDevice::SerialNumber属性设置为设备描述符的iManufacturer, iProduct, 和iSerialNumber字段的值设备描述符。如果设置了这些属性中的任何一个,则必须通过使用与相应的SoftUSBDevice属性的值匹配的整数索引值向 SoftUSBDevice::Strings 属性添加具有对应字符串内容的SoftUSBString对象(ISoftUSBString)。

您可以设置SoftUSBDevice::RemoteWakeup 属性以确定从发送给设备的GET_STATUS 请求返回的D1位的值,如USB 2.0规范的9.4.5节中所定义。

如果设备模拟器或测试应用程序需要在运行时与设备一起存储私有上下文数据,那么可以使用SoftUSBDevice::Context 属性,该属性为此返回DSFPropertyBag 对象(IDSFPropertyBag) 。DSF不检查这个对象的内容——它严格地用于设备模拟器和测试应用程序的使用。

在终止处理期间,设备模拟器(或者可选地是测试应用程序)必须调用ISoftUSBDevice::Destroy ,以确保清理SoftUSBDevice对象分配的所有资源。

要配置设备,请执行以下典型步骤:

  1. 创建一个SoftUSBDevice对象并设置其简单属性(例如,DeviceClassVendorProduct)。
  2. 创建一个SoftUSBConfiguration对象(ISoftUSBConfiguration),设置其简单属性(例如, Attributes 和MaxPower),并将其添加到 ISoftUSBDevice::Configurations属性返回的集合中。
  3. 对于配置中的每个接口和备用接口,创建一个 SoftUSBInterface对象,设置其简单属性(例如,InterfaceNumber 和InterfaceClass),并将其添加到 SoftUSBConfiguration::Interfaces属性返回的集合中。
  4. 对于每个接口和备用接口中的每个端点,创建一个 SoftUSBEndpoint 对象,设置其属性,然后将SoftUSBEndpoint对象添加到 ISoftUSBInterface::Endpoints属性返回的集合中。
  5. 对于每个字符串描述符,创建一个 SoftUSBString 对象,设置其属性,并将其添加到 ISoftUSBDevice::Strings中。

以下主题详细描述了这些对象中的每一个的使用:

配置

接口

端点

设备限定描述符

字符串

设备、类和特定于供应商的描述符

——————————————————————

      配置

每个设备都必须至少有一个配置,如USB硬件规范所要求的。配置存储在 SoftUSBDevice.Configurations属性返回的集合中。对于USB 2.0设备,此集合包含设备的高速配置。对于USB 1.1设备,此集合包含设备的完整和低速配置。如果一个设备可以同时以USB 2.0和USB 1.1速度工作,那么SoftUSBDevice::Configurations包含高速配置,SoftUSBDevice::USB1xConfigurations属性包含全速配置和低速配置。

USB配置描述符包含所有包含的接口及其端点的级联描述符。SoftUSBConfiguration 对象(ISoftUSBConfiguration)是在配置描述符之后建模的。如下图所示, SoftUSBConfigurationSoftUSBInterface (ISoftUSBInterface)和SoftUSBEndpoint 对象 (ISoftUSBEndpoint)的层次结构组成。

                                                              设备配置示意图

 ISoftUSBConfiguration::Interfaces 属性包含为配置定义的每个接口备用程序的SoftUSBInterface对象。 ISoftUSBInterface::Endpoints 属性包含为接口备用程序定义的每个端点的SoftUSBEndpoint对象。

您必须将 ISoftUSBConfiguration::ConfigurationValue 属性设置为要返回给主机的配置描述符的bConfigurationValue字段的值,如USB 2.0规范的9.6.3节所述。此值是主机在SET_CONFIGURATION设备请求中发送的配置号。

必须将 ISoftUSBConfiguration::Attributes属性设置为配置描述符的bmAttributes字段的值。

必须将 ISoftUSBConfiguration::MaxPower 属性设置为配置描述符的bMaxPower字段的值。

如果设备为其定义字符串描述符,则可以将ISoftUSBConfiguration::Configuration 属性设置为配置描述符的 iConfiguration字段的值。如果设置了此属性,则必须通过使用与此属性的值匹配的整数索引值向ISoftUSBDevice::Strings属性添加具有字符串内容的SoftUSBString 对象(ISoftUSBString) 。

如果配置描述符具有遵循标准描述符但在第一个接口描述符之前的设备特定部分,则可以使用ISoftUSBConfiguration::DeviceSpecificDescriptor属性设置该设备特定部分的原始数据。此属性是VARIANT值的SAFEARRAY,其中每个VARIANT使用VT_UI1数据类型,并且包含描述符的设备特定部分的一个字节。

如果设备模拟器或测试应用程序需要在运行时存储具有配置的私有上下文数据,那么可以使用SoftUSBConfiguration::Context 属性,该属性为此返回DSFPropertyBag 对象(DSFPropertyBag)。DSF不检查这个对象的内容——它严格地用于设备模拟器和测试应用程序的使用。

————————————————————————

      接口

ISoftUSBConfiguration::Interfaces 属性包含SoftUSBInterface对象(ISoftUSBInterface),该对象定义用于配置的接口备选集。集合必须包含一个SoftUSBInterface对象,用于每个接口编号/替换设置组合。

您必须将ISoftUSBInterface::InterfaceNumber属性设置为接口描述符的bInterfaceNumber字段要返回到主机的值,如USB 2.0规范的9.6.5节所述。此值是主机将在SET_INTERFACE请求中使用的值,以选择接口的替代项。

您必须将ISoftUSBInterface::AlternateSetting 属性设置为接口描述符的 bAlternateSetting字段的值。此值是主机将在SET_INTERFACE请求中使用的值来选择备用。

您必须将 ISoftUSBInterface::InterfaceClassISoftUSBInterface::InterfaceSubClass, 和ISoftUSBInterface::InterfaceProtocol属性设置为接口描述符的bInterfaceClass, bInterfaceSubClass, 和 bInterfaceProtocol 字段的值。

如果设备为接口定义字符串描述符,可以将 ISoftUSBInterface::Interface 属性设置为接口描述符的iInterface字段的值。如果设置了此属性,则必须通过使用与此属性的值匹配的整数索引值向ISoftUSBDevice::Strings属性添加具有字符串内容的 ISoftUSBString对象。

如果配置描述符具有遵循标准描述符但在第一个接口描述符之前的设备特定部分,则可以使用ISoftUSBConfiguration::DeviceSpecificDescriptor属性设置该设备特定部分的原始数据。此属性是VARIANT值的SAFEARRAY,其中每个VARIANT使用VT_UI1数据类型,并且包含描述符的设备特定部分的一个字节。

如果设备模拟器或测试应用程序需要在运行时存储具有配置的私有上下文数据,那么可以使用SoftUSBConfiguration::Context 属性,该属性为此返回DSFPropertyBag 对象(DSFPropertyBag)。DSF不检查这个对象的内容——它严格地用于设备模拟器和测试应用程序的使用。

      端点

 ISoftUSBInterface::Endpoints 属性包含SoftUSBEndpoint对象 (ISoftUSBEndpoint),该对象定义接口备用程序的端点集。集合必须为接口定义的每个端点包含一个SoftUSBEndpoint对象。

ISoftUSBDevice::Endpoint0 属性返回用作设备的控制端点的SoftUSBEndpoint对象。当SoftUSBDevice 对象(ISoftUSBDevice)被创建时,这个SoftUSBEndpoint对象被自动创建。

对于非控制端点,必须将ISoftUSBEndpoint::EndpointAddress 属性设置为端点描述符bEndpointAddress字段将返回到主机的值,如USB 2.0规范的第7.6节中所描述的。此值是主机将用于为总线事务的端点定位的值。

对于非控制端点,必须将 ISoftUSBEndpoint::Attributes属性设置为端点描述符的bmAttributes字段的值。

必须将ISoftUSBEndpoint::MaxPacketSize 属性设置为端点描述符的wMaxPacketSize字段的值。

必须将ISoftUSBEndpoint::Interval属性设置为端点描述符的 bInterval字段的值。

如果设备模拟器对端点使用事件驱动的处理,则可以选择是在创建SoftUSBEndpoint对象的线程上还是在任意线程上触发事件。 ISoftUSBEndpoint::MarshalEvents属性确定此设置。使用事件驱动处理的模拟器必须通过使用标准COM  IConnectionPointContainerIConnectionPoint接口在ISoftUSBEndpointEvents 连接点上安装事件接收器。如果安装了事件接收器,模拟器必须在其终止处理期间移除接收器。

对于事件驱动的OUT端点,模拟器必须处理ISoftUSBEndpointEvents::OnWriteTransfer事件。对于在端点中驱动的事件,模拟器必须处理ISoftUSBEndpointEvents::OnReadTransfer事件。

控制端点默认为事件驱动处理,并自动处理标准设备请求。模拟器可以通过安装 ISoftUSBEndpointEvents 事件接收器和处理ISoftUSBEndpointEvents::OnDeviceRequest 事件以及可选地处理ISoftUSBEndpointEvents::OnDeviceRequestComplete事件,使用事件驱动处理来处理控制端点上的设备特定请求。

在少数情况下,当设备模拟器需要处理标准设备请求时,它可以设置SoftUSBEndpoint::HandleStdDeviceRequests属性,并且它将接收OnSetupTransferOnWriteTransfer 或 OnReadTransferOnDeviceRequestComplete事件,通过这些事件,它可以完全定制和处理标准请求。

如果设备模拟器对OUT端点使用轮询处理,那么它可以通过设置ISoftUSBEndpoint::OutQueueSize属性来确定端点在被设备模拟器使用之前将保持在其队列中的OUT事务的最大数量。如果达到了这个限制,并且模拟器没有使用事务,那么将丢弃任何附加的事务并导致端点停止。

设备模拟器通过调用ISoftUSBEndpoint::QueueINData方法,可以将数据排队到IN端点以供后续主机使用。

对于控制端点,设备模拟器通过调用ISoftUSBEndpoint::QueueDeviceRequestResponse 方法,可以对来自主机的预期设备请求的响应进行排队。您可以使用该方法同时用于特定设备和标准设备请求。

您可以使用简单 loopback场景中的ISoftUSBEndpoint::LoopbackEndpoint属性通过设置来配对IN和OUT端点:

OutEndpoint.LoopbackEndpoint = InEndpoint

  当该配对就绪时,OUT端点将为它接收的每个OUT事务调用ISoftUSBEndpoint::QueueINData ,并且设备模拟器将不参与数据事务。

ISoftUSBEndpoint::Halted属性指示端点当前是否停止。模拟器或测试应用程序可以通过设置此属性来强制终结端点。

如果端点描述符具有遵循标准描述符但在下一个端点描述符之前的设备特定部分,则可以使用ISoftUSBEndpoint::DeviceSpecificDescriptor属性设置该设备特定部分的原始数据。此属性是VARIANT值的SAFEARRAY,其中每个VARIANT使用VT_UI1数据类型,并且包含描述符的设备特定部分的一个字节。

如果设备模拟器或测试应用程序需要在运行时存储具有配置的私有上下文数据,那么可以使用SoftUSBConfiguration::Context 属性,该属性为此返回DSFPropertyBag 对象(DSFPropertyBag)。DSF不检查这个对象的内容——它严格地用于设备模拟器和测试应用程序的使用。

      设备限定描述符

如果一个设备支持在USB 2.0和USB 1.1的速度下对模拟USB的连接,模拟器必须创建一个SoftUSBDeviceQualifier 对象(ISoftUSBDeviceQualifier),类似于它的SoftUSBDevice 对象 (ISoftUSBDevice)填充它,并设置ISoftUSBDevice::DeviceQualifier 属性到SoftUSBDeviceQualifier 对象。

您必须将ISoftUSBDevice::USB 属性设置为0x200,并且模拟器还必须用设备的低速或全速配置填充ISoftUSBDevice::USB1xConfigurations 属性。

SoftUSBDeviceQualifier 对象的属性将用于确定对针对设备限定符描述符的主机GET_DESCRIPTOR请求的响应。

      字符串

字符串描述符是通过使用SoftUSBString 对象 (ISoftUSBString)定义的。 ISoftUSBString::Value 属性包含响应对字符串描述符的GET_DESCRIPTOR 请求而返回给主机的文本字符串。

注意,在DSF的当前版本中,只支持默认语言;但是因为字符串是UNICODE BSTR,所以您可以使用任何语言作为默认语言。

必须将所有SoftUSBString 对象添加到集合中,以使ISoftUSBDevice::Strings属性返回。在调用SoftUSBDevice.Strings.Add (ISoftUSBStringList::Add)时,将Index参数指定为VT_I4,并将VARIANT.lVal设置为相应的对象属性的值,该值确定主机在GET_DESCRIPTOR请求中发送的描述符索引(即:ISoftUSBDevice::ManufacturerISoftUSBDevice::ProductDescISoftUSBDevice::SerialNumber,ISoftUSBConfiguration::Configuration, 或 ISoftUSBInterface::Interface)。

      设备、类和特定于供应商的描述符

SoftUSBDevice (ISoftUSBDevice)、SoftUSBConfiguration (ISoftUSBConfiguration), SoftUSBInterface (ISoftUSBInterface), 和SoftUSBEndpoint (ISoftUSBEndpoint) 对象具有DSF用来创建对主机GET_DESCRIPTOR请求的响应的属性。这些属性用于填充在USB 2规范中定义的描述符字段。设备类规范、设备特定和供应商特定特性以及接口关联描述符确定除了USB规范定义的标准字段之外还需要自定义描述符数据。自定义描述符数据总是附加到标准描述符字段中,并且更新标准描述符长度字段以反映标准数据和自定义数据的组合总和。

如果描述符具有非标准部分,则模拟器可以使用SoftUSBConfigurationSoftUSBInterface, 或SoftUSBEndpoint对象的DeviceSpecificDescriptor属性来定义它。此属性是VARIANT值的SAFEARRAY,其中每个VARIANT使用VT_UI1数据类型,并且包含描述符的设备特定部分的一个字节。如果为对象设置了DeviceSpecificDescriptor,则其描述符(返回到主机)将用附加到标准描述符部分的数组中定义的字节更新,并且标准描述符的长度字段将更新以反映附加数据。


处理标准设备请求

默认情况下,DSF通过使用SoftUSBDevice (ISoftUSBDevice) 的当前状态及其相关对象来处理所有标准设备请求。

在很少的情况下,设备模拟器可能需要通过使用自定义操作来处理一个或多个标准请求。设备模拟器可以通过将SoftUSBEndpoint::HandleStdDeviceRequests属性设置为FALSE来处理这些请求,并通过为控制端点使用事件驱动或轮询数据传输来处理必要的标准请求。

要实现事件驱动的标准设备请求,请执行以下操作:

  1. 为控件端点上的ISoftUSBEndpointEvents接口安装一个接收器( ISoftUSBDevice::Endpoint0属性)
  2. 处理以下一个或多个:

当接收到标准设备请求时,控制端点将检查 SoftUSBEndpoint::HandleStdDeviceRequests值;如果此属性为FALSE,则该端点将调用OnDeviceRequest事件。如果OnDeviceRequest返回S_OK,则端点假定已经处理了请求,并且其数据和状态已经在out参数中返回。对于请求,如果OnDeviceRequest没有返回S_OK,并且没有为设备请求排队响应,则端点根据请求的性质触发OnSetupTransfer事件、任何需要的OnSetupTransferOnWriteTransferevents,以及OnDeviceRequestComplete事件以获得最终状态。

为了通过使用轮询数据传输实现标准设备请求,在设备请求之前调用SoftUSBDevice.Endpoint0.QueueDeviceRequestResponse (ISoftUSBEndpoint::QueueDeviceRequestResponse),并且端点将使用如上所述的响应。


事件驱动与轮询仿真

USB设备仿真最终由SoftUSBEndpoint对象(ISoftUSBEndpoint)中的进出数据组成,以模拟USB上的输入、输出和设置事务。这种数据运动的机制在DSF文档中的其他地方进行了详细描述。下面的列表总结了设备模拟器的选择:

  • (事件驱动模拟)为端点上的ISoftUSBEndpointEvents 接口安装事件接收器,并处理相关数据以用于到端点和从端点移动数据的设备请求。
  • (轮询仿真)周期性地对端点进行轮询,并执行下列操作之一:

○将端点的数据队列用于OUT端点和用于处理从主机到设备的设备请求的控制端点。

○向端点的数据队列中添加IN端点和处理设备请求的控制端点的数据。

大部分情况下,您应该根据性能要求来确定端点是事件驱动的还是轮询的。由于这些原因,通常应该对等时端点使用轮询,而其他事务类型应该使用事件驱动。更高性能的大容量设备(如存储)也可能受益于轮询。

事件驱动的端点总是会将事务压缩,然后在用户模式下将事件发送到接收器。端点将继续NAK事务,直到事件处理程序已经运行并且它的结果已经返回到端点。这种情况排除了对于同步端点使用事件驱动模型,因为控制器将跳过用NAK处理的事务。

事件驱动的数据端点编程非常简单,并且只需要为事务类型实现ISoftUSBEndpointEvents接口的适当的事件处理程序方法,如以下列表所述:

如果多个端点是事件驱动的,模拟器必须在每个SoftUSBEndpoint对象上安装单独的事件接收器。对于C++实现,此安装通常涉及定义多个端点事件接收器类。您可以在 DSF USB Loopback Device Simulation中找到端点事件接收器类的示例(CLoopbackDevice类函数用作设备仿真器和端点事件接收器)。

对于大多数设备,事件处理程序应该非常快地完成,并且应该很少阻塞其他操作(例如,等待资源或等待高延迟I/O,如磁盘访问),因为事务将继续NAK直到事件处理程序返回。

轮询端点要求设备模拟器周期性地以将满足主机事务频率的速率耗尽或填充端点的内部数据队列。可以通过设置ISoftUSBEndpoint::OutQueueSize 属性(默认值为512)来配置OUT端点以保存特定数量的OUT事务。当队列包含这个数量的OUT事务时,端点将停止,因此设备模拟器必须经常调用ISoftUSBEndpoint::DrainOUTQueue ,以使队列保持在OutQueueSize设置的高水印之下。对于IN端点,模拟器必须足够频繁地调用ISoftUSBEndpoint::QueueINData,以便主机事务总是有数据等待它们。对于控制端点,模拟器必须调用SoftUSBDevice.Endpoint0.QueueDeviceRequestResponse (ISoftUSBEndpoint::QueueDeviceRequestResponse)。

没有一种简单的方法来确定轮询端点的频率。当你开发设备模拟器时,你必须执行“试验和错误”。要确定轮询速率,请考虑内存使用情况,因为端点数据队列是在非分页池(这是稀缺的系统资源)中维护的。设备模拟器必须使用轮询速率,该轮询速率在速度上既满足主机的事务速率,又不会通过提前为IN端点排队太多数据或为OUT端点太慢地取消数据队列来压倒系统对非分页池的使用。


测试应用接口

当你设计一个USB设备模拟器时,考虑它暴露给测试应用程序的接口。一个好的接口应该是:

  • 直观。
  • 易于学习和使用。
  • 启用超出明显范围的功能。

一个直观的测试应用程序接口应该用通常自我记录的单词来表示先前的手动操作。例如,考虑下面的代码示例。

SoftKbd.PressAndReleaseKey F12

前面的例子清楚地模拟了F12键的按下和释放。测试应用程序接口应该在任何可能的情况下用硬件反映真实的场景。一个直观的模型和真实硬件的接口将易于学习和使用。

除了设备的基本功能之外,测试应用程序还应该提供机会来驱动与真实硬件不可能或不切实际的代码路径。这些路径可能是正的(预期的操作)和负的(错误的)代码路径。您可以以实际硬件无法实现的方式测试正代码路径,例如检查I/O请求是否如预期到达设备或预期的设备行为是否导致I/O结果。

仿真还为测试负代码路径提供了难得的机会,否则这些负代码路径可能仅适用于可能被迫按需出错的硬件。当您为设备模拟器设计故障注入特性时,白盒测试和黑盒测试方法都是有价值的。对于白盒测试,研究您的驱动程序和设备应用程序代码,并为每个错误代码路径向模拟器添加故障注入接口。例如,如果驱动程序等待特定设备特定请求完成最多500毫秒(ms),则向设备模拟器添加属性,该属性在设置时将导致该请求延迟完成500毫秒以上。对于黑盒测试,寻找测试机会:

  • 数据损坏。
  • 错误的数据排序。
  • 不寻常的数据包使用。
  • 定时延迟。
  • 不寻常或不可接受的配置。

仿真还提供了压力机会,例如:

  • 即插即用(PNP)测试(例如,在连续循环中连接和断开设备)。
  • 数据速率(例如,将大量数据输入到端点)。
  • 多个设备(即,强制驱动程序同时使用单个控制器和多个控制器来处理设备的多个实例)。

原文链接:https://docs.microsoft.com/zh-cn/previous-versions/windows/hardware/dsf/ff542523(v%3dvs.85)


使用端点诊断

当在内核调试器下运行目标系统时,可以配置一个端点以向调试器输出诊断信息。在脚本中,可以通过调用SoftUSBEndpoint.SetObjectFlags 100, <flags>. 来配置端点。<flags>可以是以下任何组合(来自SoftUSB.h

const ULONG SOFTUSBENDPOINT_DONOTTRACETRANSFERS             = 0x00000000;
const ULONG SOFTUSBENDPOINT_TRACETRANSFERINPUT              = 0x00000001;
const ULONG SOFTUSBENDPOINT_TRACETRANSFEROUPUT              = 0x00000002;
const ULONG SOFTUSBENDPOINT_TRACETRANSFERINPUTANDOUPUT      = 0x00000003;
const ULONG SOFTUSBENDPOINT_TRACEOUTLISTOVERFLOW            = 0x00000020;

 在C++中,您可以通过为IID_IDSFDebug调用ISoftUSBEndpoint::QueryInterface 并通过使用前面描述的相同参数调用IDSFDebug::SetObjectFlags 来配置端点。

如果设置了SOFTUSBENDPOINT_TRACETRANSFERINPUT标志,则端点将关于传输的输入参数的信息发送到调试器。如果设置了SOFTUSBENDPOINT_TRACETRANSFEROUPUT标志,则端点将关于在运行传输之后返回到主机的数据的信息发送到调试器。

调试器输出的格式非常简洁,但通常应该是自解释的。当传输涉及数据时,跟踪机制将转储最多16字节以最小化性能开销。端点诊断通常会导致一些性能损失,因此您应该在性能敏感的情况下节省使用它们。

可以使用与轮询的OUT端点一起使用的SOFTUSBENDPOINT_TRACEOUTLISTOVERFLOW标志来确定数据队列何时填充到ISoftUSBEndpoint::OutQueueSize属性指定的限制。

原文链接:https://docs.microsoft.com/zh-cn/previous-versions/windows/hardware/dsf/ff542556(v%3dvs.85)


使用设备上下文

SoftUSBDevice (ISoftUSBDevice), SoftUSBConfiguration (ISoftUSBConfiguration), SoftUSBInterface (ISoftUSBInterface), and SoftUSBEndpoint (ISoftUSBEndpoint)对象具有Context属性,该属性返回DSFPropertyBag对象(IDSFPropertyBag) ,可以使用该对象将任意数据与对象关联。(DSFPropertyBag是一个对象,它管理一组名值对,其中值被存储为一个变量值。首次使用DSFPropertyBag.Write这个名称时,将创建新名称。

如果应用程序需要在特定端点上运行一组测试用例,则测试应用程序可能使用Context属性。应用程序可以在SoftUSBEndpoint::Context属性中设置测试用例参数,并且模拟器可以在其端点事件处理程序中检查这些参数的上下文。例如,考虑对loopback设备示例的增强,其中OUT端点的ISoftUSBEndpointEvents::OnWriteTransfer事件处理程序可能能够实现一系列错误注入测试,其中它向每个数据字节添加指定值。测试应用程序可能通过调用SoftUSBEndpoint.Context.Write "DataOffsetTest", 17开始运行该测试。

为了提高效率,loopback设备可以将IDSFPropertyBag接口和任何相关联的字符串作为成员变量存储在其构造函数中(省略了错误检查),如下面的代码示例所示。

m_piOUTEndpoint->get_Context(reinterpret_cast<DSFPropertyBag **>(&m_piContext);
m_bstrDataOffsetTest = ::SysAllocString("DataOffsetTest");

然后,loopback设备可以将这些项存储在OnWriteTransfer事件处理程序中,如下面的代码示例所示。 

VARIANT varValue; ::VariantInit(&varValue);
 if (SUCCEEDED(m_piContext->Read(m_bstrDataOffsetTest, &varValue))
 {
   if (VT_EMPTY != varValue.vt)
   {
       if (SUCCEEDED(::VariantChangeType(&varValue, &varValue, 0, VT_UI1))
       {
          for (i = 0; i < cbDataBuffer; i++)
          {
             pbDataBuffer[i] += varValue.bVal;
          }
       }
    }
 }

原文链接:https://docs.microsoft.com/zh-cn/previous-versions/windows/hardware/dsf/ff542550(v%3dvs.85) 


DSF中的电源管理

USB设备模拟包括模仿真实硬件的功率使用的行为。可以通过SoftUSBDevice 对象上的属性和配置描述符属性来控制这种行为,如USB 2.0规范第9.6.3节中所定义。

通过设置配置描述符属性,模拟USB设备可以是自供电的、总线供电的或两者兼备的。

对于可以自供电的设备,ISoftUSBDevice::HasExternalPower属性确定自供电设备当前是否具有外部电源。

ISoftUSBConfiguration::Attributes属性包含配置描述符的bmAttributes字段的值(如USB 2.0规范的9.6.3节所述)。此属性的默认值为零,指示配置为总线供电。

自供电的模拟USB设备可以插入根集线器端口或外部集线器端口,具有或不具有外部电源(由ISoftUSBDevice::HasExternalPower确定)。当设备连接到根集线器端口或外部集线器端口时,您可以随时更改HasExternalPower的值以测试电源更改。如果设备没有专用电源,则对HasExternalPower的更改将在总线电源和外部电源之间切换,并导致主机重新枚举设备。

ISoftUSBDevice::HasExternalPower的值也由GET_STATUS标准设备请求的默认处理程序使用,以确定D0位的值,如USB 2.0规范的9.4.5节中所定义。

总线段可以离线构建,然后作为一个整体连接到现场总线。例如,您可以创建外部集线器,将设备连接到它,然后将外部集线器连接到根集线器。

您可以设置ISoftUSBConfiguration::MaxPower 属性来确定配置描述符的bMaxPower字段的值,如USB 2.0规范的9.6.3节所述。

主机可以选择性地暂停设备。

测试应用程序可以通过启动I/O(例如,响应未完成的中断IN事务)来恢复挂起的设备。

ISoftEHCIRootHubPort::OverCurrentISoftUSBHub::ContrCurrentISoftUSBHub::OverCurrentProtectMode,ISoftUSBHub::OverCurrentISoftUSBHubPort::OverCurrent,  ISoftUSBHubPort::OverCurrentChange 等属性用于将描述符内容和状态返回给主机。

原文链接:https://docs.microsoft.com/zh-cn/previous-versions/windows/hardware/dsf/ff542270(v%3dvs.85)


使用外部集线器模拟器

因为USB 2.0控制器模拟器不包括伴随的USB 1.1控制器,所以它不能接受模拟的USB 1.1设备在它的根集线器端口中。提供外部集线器模拟器以克服此限制。外部集线器模拟器可以模拟具有可配置端口数的USB 1.1或USB 2外部集线器。因为外部集线器是USB设备,所以集线器被实现为COM对象中的USB设备模拟器。任何具有COM客户端能力的语言都可以使用这个COM对象。

为了使用外部集线器将USB 1.1设备模拟器连接到控制器,测试应用程序可以:

  • 创建一个外部集线器对象 ("SOFTUSB.SoftUSBHub")。
  • ISoftUSBHub::NbrPorts属性设置其默认值为四个端口,或将其设置为所需端口数。
  • SoftUSBHub.SoftUSBDevice.USB (ISoftUSBDevice::USB)设置为其默认值0x0200,以使用USB 2.0集线器。
  • 将外部集线器连接到控制器根集线器(例如,SoftEHCIRootHubPort.HotPlug(SoftUSBHub.SoftUSBDevice))。
  • 等待外部集线器枚举(使用设备管理器手动或通过使用诸如微软Windows Device Testing Framework [WDTF][WDTF]之类的工具进行编程)。
  • 创建一个模拟的USB设备(例如,loopback设备)。
  • 将USB设备连接到外部集线器(例如,SoftUSBHubPort.HotPlug(LoopbackDev.DSFDevice.Object(IID_ISoftUSBDevice)))。
  • 等待USB设备枚举。
  • 使用USB设备。
  • 将设备从外部集线器断开(ISoftUSBHubPort::Unplug)。
  • 等待主机删除设备(通过使用设备管理器或以编程方式)。
  • 从根集线器断开外部集线器(SoftEHCIRootHubPort::Unplug)。
  • 等待主机移除集线器。
  • 调用ISoftUSBHub::Destroy ,以便集线器可以释放内部分配的资源。

在DSF的当前版本中,您还不能将设备连接到外部集线器,然后将外部集线器连接到控制器。主机可以选择性地挂起外部集线器,并且连接到它们的设备可以选择性地挂起,并且可以通过启动I/O来恢复集线器和设备(例如,通过提交键盘上的击键来完成未完成的IN事务)。您可以级联外部集线器,但是必须在插入子集线器之前连接并枚举父集线器,并且必须在设备连接到子集线器之前枚举子集线器。

原文链接:https://docs.microsoft.com/zh-cn/previous-versions/windows/hardware/dsf/ff542560(v%3dvs.85)


模拟复合材料与复合设备

Composite USB devices(复合USB设备)通过使用多个接口向主机公开多个功能。为了创建复合模拟USB设备,向ISoftUSBConfiguration::Interfaces属性中添加必要的SoftUSBInterface对象(ISoftUSBInterface),然后处理各种端点内外的数据移动。没有其他特殊的编程是必要的。若要使复合设备公开以测试应用程序,可以选择适合于设备的任何接口。测试应用接口的选择不会影响仿真。

复合器件是与其它器件结合的外部集线器。在主机上,复合设备作为一个集线器,具有一个或多个不可拆卸的设备,这些设备连接到集线器的端口。虽然 ISoftUSBHubPort具有DeviceRemovable属性,但此属性在DSF的当前版本中不起作用。在将外部集线器连接到控制器之前,还不能将设备连接到外部集线器。

原文链接:https://docs.microsoft.com/zh-cn/previous-versions/windows/hardware/dsf/ff542304(v%3dvs.85)


检查DSF版本

通过IDSF::Version属性公开的IDSFVersion接口使设备模拟器和测试应用程序能够检查DSF和操作系统版本号。

IDSFVersion::MajorIDSFVersion::Minor 属性返回DSF运行时版本号,DSF的当前版本为1.0。

IDSFVersion::OSMajorIDSFVersion::OSMinor 属性返回操作系统的版本号,这些和GetVersionEx Microsoft Win32 API函数返回相同的主要和次要数字。

原文链接:https://docs.microsoft.com/zh-cn/previous-versions/windows/hardware/dsf/ff538271(v%3dvs.85)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值