当前位置: 首页 > news >正文

windows USB 设备驱动开发-USB 等时传输

客户端驱动程序可以生成 USB 请求块 (URB) 以在 USB 设备中向/从常时等量端点传输数据。虽然USB设备一向以非等时传输出名,USB提供的是一种串行数据,而非等时,但是USB仍然设计了等时传输的机制,但根据笔者的经验,等时传输也许使用1394更好一些。

通用串行总线 (USB) 设备可以支持常时等量端点,以稳定速率传输依赖于时间的数据,例如音频/视频流。 若要传输数据,客户端驱动程序会发出请求,以将数据读取或写入常量端点。 因此,主机控制器启动常时等量传输,该传输通过定期轮询设备来发送或接收数据。

对于高速和全速设备,轮询通过使用 (IN/OUT) 令牌数据包来完成。 当端点准备好发送数据时,设备将通过发送数据来响应其中一个 IN 令牌数据包。 若要写入设备,主机控制器会发送 OUT 令牌数据包,后跟数据包。 主机控制器或设备不发送任何握手数据包,因此无法保证传递。 由于主机控制器不会尝试重试传输,因此如果发生错误,数据可能会丢失。

对于常时等量传输,主机控制器在总线上保留特定时间段。 为了管理常时等量端点的保留时间,将时间划分为连续的逻辑间隔,称为 总线间隔。 总线间隔的单位取决于总线速度。

  • 对于全速,总线间隔是 帧。 帧的长度为 1 毫秒。
  • 对于高速和超高速,总线间隔是微帧。 微帧的长度为 125 微秒。 八个连续的微帧构成一个高速或超高速帧。

常时等量传输基于数据包。 这里的术语 常时等量数据包 是指在一个总线间隔内传输的数据量。 端点的特征决定了每个数据包的大小是固定的,由端点的特征决定。

客户端驱动程序通过为请求创建 URB 并将 URB 提交到 USB 驱动程序堆栈来启动常时等量传输。 请求由 USB 驱动程序堆栈中的某个较低驱动程序处理。 收到 URB 后,USB 驱动程序堆栈将执行一组验证并计划请求的事务。 对于全速,要在每个总线间隔内传输的常时等量数据包包含在线路上的单个事务中。 某些高速设备允许在一个总线间隔内进行多个事务。 在这种情况下,客户端驱动程序可以在单个请求中发送或接收常量数据包中的更多数据 (URB) 。 SuperSpeed 设备支持多个事务和突发传输,允许每个总线间隔更多的字节数。 

准备工作

在创建常时等量传输请求之前,必须具有有关为常时等量端点打开的管道的信息。

使用 Windows 驱动程序模型 (WDM) 例程的客户端驱动程序在USBD_INTERFACE_LIST_ENTRY数组的某个USBD_PIPE_INFORMATION结构中具有管道信息。 客户端驱动程序在驱动程序的上一个请求中获取了该数组,以选择设备中的配置或接口。

Windows 驱动程序框架 (WDF) 客户端驱动程序必须获取对框架的目标管道对象的引用,并调用 WdfUsbTargetPipeGetInformation 以获取 WDF_USB_PIPE_INFORMATION 结构中的管道信息。

根据管道信息确定这组信息:

  • 主机控制器可以向每个数据包中的管道发送多少数据。

客户端驱动程序可以在请求中发送的数据量不能超过主机控制器可从端点发送或接收的最大字节数。 最大字节数由 USBD_PIPE_INFORMATION 和 WDF_USB_PIPE_INFORMATION 结构的 MaximumPacketSize 成员指示。 USB 驱动程序堆栈在选择配置或选择接口请求期间设置 MaximumPacketSize 值。

对于全速设备, MaximumPacketSize 派生自端点描述符的 wMaxPacketSize 字段的前 11 位,该字段指示端点可以在事务中发送或接收的最大字节数。 对于全速设备,控制器为每个总线间隔发送一个事务。

在高速常时等量传输中,如果端点允许,主机控制器可以在总线间隔内发送其他事务。 其他事务数由设备设置,并在 wMaxPacketSize 的位 12..11 中指示。 该数字可以是 0、1 或 2。 如果 12..11 指示 0,则端点不支持每个微帧的其他事务。 如果数字为 1,则主机控制器可以发送额外的事务 (每个微帧) 总共两个事务;2 表示每个微帧) 两个事务 (总共三个事务。 由 USB 驱动程序堆栈设置的 MaximumPacketSize 值包括可在其他事务中发送的字节数。

对于 SuperSpeed 常时等时传输,USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR (的某些值请参阅 Usbspec.h) 非常重要。 USB 驱动程序堆栈使用这些值来计算总线间隔内的最大字节数。

端点配套描述符的等时常量.Mult 字段。 在 SuperSpeed 等时常量传输中, (与高速设备) 的附加事务称为突发事务。 Mult 值指示端点支持的突发事务的最大数目。 在一个服务间隔内,最多可以有三个突发事务 (索引为 0 到 2) 。

端点配套描述符的 bMaxBurst 字段。 此值指示单个突发事务中可以存在的 wMaxPacketSize 区块数。 突发事务中最多可以有 16 个区块, (索引为 0 到 15) 。

wBytesPerInterval 指示主机在总线间隔内可以发送或接收的总字节数。 尽管每个总线间隔的最大字节数可以计算为 (bMaxBurst+1) * (Mult+1) * wMaxPacketSize,但 USB 3.0 规范建议改用 wBytesPerInterval 值。 wBytesPerInterval 值必须小于或等于该计算值。

对于客户端驱动程序,前面所述的值仅供信息使用。 驱动程序必须始终使用端点描述符的 MaximumPacketSize 值来确定传输缓冲区的布局。

  • 端点多久发送或接收一次数据?

Interval 成员用于确定端点可以发送或接收数据的频率。 设备设置该值,客户端驱动程序无法更改该值。 USB 驱动程序堆栈使用另一个数字来确定将常时等量数据包插入数据流的频率:从 Interval 值派生的轮询周期。

对于全速传输, 间隔 和轮询周期值始终为 1;USB 驱动程序堆栈忽略其他值。

下表显示了高速和超高速传输的 间隔 和计算轮询周期:

  • 每个总线速度的数据包数有哪些限制。

在 URB 中,对于一个全速设备,最多只能发送 255 个常时等量数据包;适用于高速和超高速设备的 URB 中的 1024 个数据包。 在 URB 中发送的数据包数必须是每个帧中数据包数的倍数。

请考虑 wMaxPacketSize 为 1,023 的示例全速端点。 对于此示例,应用程序提供了 25,575 字节的缓冲区。 该缓冲区的传输需要 25 个常时等量数据包 (25575/1023) 。

请考虑一个高速端点示例,其端点描述符中指示了以下特征。

  • wMaxPacketSize 为 1,024;
  • 位 12..11 指示另外两个事务;
  • 间隔 为 1;

客户端驱动程序选择配置后,常时常量管道的 MaximumPacketSize 指示 3,072 字节 (总事务 * wMaxPacketSize) 。 其他事务允许客户端驱动程序在每个微帧中传输 3,072 个字节,在一个帧中传输总共 24,576 个字节。 下图显示了在一个微帧中传输常量数据包的频率,以便进行高速传输。


请考虑一个示例 SuperSpeed 端点,其特征在端点和 SuperSpeed 端点点配套描述符中指示:

  • wMaxPacketSize 为 1,024;
  • bMaxBurst 为 15;
  • 间隔 为 1;
  • Isochronous.Mult 为 2;
  • wBytesPerInterval 为 45000;

在前面的示例中,即使最大字节数可以计算为 wMaxPacketSize * (bMaxBurst +1) * (Mult + 1) 导致 49,152 个字节,设备也会将值限制为 45,000 字节的 wBytesPerInterval 值。 该值也反映在 MaximumPacketSize 45,000 中。 客户端驱动程序只能使用 MaximumPacketSize 值。 在此示例中,请求可分为三个突发事务。 前两个突发事务各包含 16 个 wMaxPacketSize 区块。 最后一个突发事务包含 12 个用于保存剩余字节的区块。 此图显示了轮询间隔以及通过超速传输常量数据包传输的字节数。


生成常时等量传输的请求:

  1. 获取每个常量数据包的大小;
  2. 确定每帧的常时等量数据包数;
  3. 计算保存整个传输缓冲区所需的常时等量数据包数;
  4. 分配 URB 结构以描述传输的详细信息;
  5. 指定每个常量数据包的详细信息,例如数据包偏移量;

本文中的此示例简化了常量传输的 USBSAMP 实现。 该示例计算传输所需的总帧数。 根据可以在帧中发送的数据量,传输缓冲区划分为较小的区块大小字节。

以下过程详细说明了上述步骤,并演示了客户端驱动程序可用于生成和发送高速常时等量端点的等时等传输请求的计算和例程。 过程中使用的值基于前面所述的示例端点特征。

步骤 1:获取常量数据包的大小

通过检查管道的 MaximumPacketSize 值来确定常时等量数据包的大小。

对于全速传输,常时等量数据包的大小是可以在一帧中传输的字节数。 对于高速和超高速传输,常量数据包的大小是可在一个微帧中传输的字节总数。 这些值在管道的 MaximumPacketSize 中指示。

在示例中, MaximumPacketSize 为每帧 1023 字节, (全速) ;每个微帧 3072 字节 (高速) ;每个微帧 45,000 字节 (SuperSpeed) 。

 备注 MaximumPacketSize 值指示常量数据包允许的最大大小。 客户端驱动程序可以将每个常量数据包的大小设置为小于 MaximumPacketSize 值的任何值。

步骤 2:确定每帧常时等量数据包数

对于全速传输,在每个帧中传输一个常量数据包。

对于高速和超高速传输,此值必须派生自 Interval 值。 在示例中,间隔为 1。 因此,常时等量数据包数必须为每帧 8 个。

步骤 3:计算保存整个传输缓冲区所需的常时等量数据包数

计算传输整个缓冲区所需的常时等量数据包数。 此值可以通过将传输缓冲区的长度除以常时等量数据包的大小来计算。

在此示例中,我们假设每个常时等量数据包的大小为 MaximumPacketSize ,传输缓冲区长度是 MaximumPacketSize 值的倍数。

例如,对于全速传输,提供的 25,575 字节的缓冲区需要 25 个常量数据包 (25575/1023) 。 对于高速传输,大小为 24,576 的缓冲区分为 8 个常量数据包, (24576 /3072) 进行传输。 对于 SuperSpeed,大小为 360,000 字节的缓冲区适合 8 个常量数据包, (360000/45000) 。

客户端驱动程序应验证以下要求:

  • 常时等量数据包数必须是每帧数据包数的倍数。
  • 对于全速设备,进行传输所需的常时等量数据包的最大数目不得超过 255 个;1024,适用于高速或超高速设备。
步骤 4:分配 URB 结构以描述传输的详细信息

1.在非分页池中分配 URB 结构:

如果客户端驱动程序使用 WDM 例程,则驱动程序必须调用USBD_IsochUrbAllocate(如果你有适用于Windows 8的 Windows 驱动程序工具包 (WDK) )。 客户端驱动程序可以使用 例程来面向 Windows Vista 和更高版本的 Windows 操作系统。 如果没有用于Windows 8的 WDK,或者客户端驱动程序适用于早期版本的操作系统,可以通过调用 ExAllocatePoolWithTag 在堆栈上或非分页池中分配结构。

WDF 客户端驱动程序可以调用 WdfUsbTargetDeviceCreateIsochUrb 方法,为 URB 结构分配内存。

2.URB 结构的 UrbIsochronousTransfer 成员指向描述常量传输详细信息的 _URB_ISOCH_TRANSFER 结构。 按如下所示初始化以下 UrbIsochronousTransfer 成员:

  • 将 UrbIsochronousTransfer.Hdr.Length 成员设置为 URB 的大小。 若要获取 URB 的大小,请调用 GET_ISO_URB_SIZE 宏并指定数据包数。
  • 将 UrbIsochronousTransfer.Hdr.Function 成员设置为 URB_FUNCTION_ISOCH_TRANSFER。
  • 将 UrbIsochronousTransfer.NumberOfPackets 成员设置为常量数据包数。
  • 将 UrbIsochronousTransfer.PipeHandle 设置为与端点关联的管道的不透明句柄。 确保管道句柄是通用串行总线 (USB) 驱动程序堆栈使用的 USBD 管道句柄。

若要获取 USBD 管道句柄,WDF 客户端驱动程序可以调用 WdfUsbTargetPipeWdmPipeHandle 方法,并将 WDFUSBPIPE 句柄指定为框架的管道对象。 WDM 客户端驱动程序必须使用在 USBD_PIPE_INFORMATION 结构的 PipeHandle 成员中获取的相同句柄。

  • 指定传输方向。 将 UrbIsochronousTransfer.TransferFlags 设置为 USBD_TRANSFER_DIRECTION_IN,以便从设备) 读取常时等量 IN 传输 (; (写入设备) ,USBD_TRANSFER_DIRECTION_OUT常量 OUT 传输。
  • 在 UrbIsochronousTransfer 中指定USBD_START_ISO_TRANSFER_ASAP标志。TransferFlags。 标志指示 USB 驱动程序堆栈在下一个适当的帧中发送传输。 客户端驱动程序首次为此管道发送常时等量 URB 时,驱动程序堆栈会尽快在 URB 中发送常时等量数据包。 USB 驱动程序堆栈跟踪要用于该管道上的后续 URL 的下一帧。 如果在发送使用 USBD_START_ISO_TRANSFER_ASAP 标志的后续常时常量 URB 时出现延迟,驱动程序堆栈会将该 URB 的部分或所有数据包视为延迟,并且不会传输这些数据包。

如果堆栈在完成该管道的上一个 URB 后未收到 1024 帧的常量 URB,USB 驱动程序堆栈将重置其USBD_START_ISO_TRANSFER_ASAP启动帧跟踪。 可以指定起始帧,而不是指定USBD_START_ISO_TRANSFER_ASAP标志。 。

  • 指定传输缓冲区及其大小。 可以在 UrbIsochronousTransfer.TransferBuffer 或用于描述 UrbIsochronousTransfer.TransferBufferMDL 中的缓冲区的 MDL 中设置指向缓冲区的指针。

若要检索传输缓冲区的 MDL,WDF 客户端驱动程序可以调用 WdfRequestRetrieveOutputWdmMdl 或 WdfRequestRetrieveInputWdmMdl,具体取决于传输的方向。

步骤 5:指定传输中每个常时等量数据包的详细信息

USB 驱动程序堆栈分配的新 URB 结构足够大,用于保存有关每个常时等量数据包的信息,但不包含数据包中包含的数据。 在 URB 结构中, UrbIsochronousTransfer.IsoPacket 成员是 一个USBD_ISO_PACKET_DESCRIPTOR 数组,用于描述传输中每个常时等量数据包的详细信息。 数据包必须是连续的。 数组中的元素数必须是 URB 的 UrbIsochronousTransfer.NumberOfPackets 成员中指定的常时等量数据包数。

对于高速传输,数组中的每个元素都与一个微帧中的一个常量数据包相关联。 对于全速,每个元素都与一帧中传输的一个常量数据包相关联。

对于每个元素,指定从请求的整个传输缓冲区开始的每个常时等量数据包的字节偏移量。 可以通过设置 UrbIsochronousTransfer.IsoPacket[i] 来指定该值。偏移 成员。 USB 驱动程序堆栈使用指定的值来跟踪要发送或接收的数据量。

设置 Full-Speed 传输的偏移量

例如,这些是全速传输缓冲区的数组条目。 在全速模式下,客户端驱动程序有一个帧用于传输一个常量数据包,最大为 1,023 个字节。 25,575 字节的传输缓冲区可以容纳 25 个常时等量数据包,每个数据包长度为 1,023 个字节。 整个缓冲区总共需要 25 帧。

Frame 1 IsoPacket [0].Offset = 0 (start address)
Frame 2 IsoPacket [1].Offset = 1023
Frame 3 IsoPacket [2].Offset = 2046
Frame 4 IsoPacket [3].Offset = 3069
...
Frame 25 IsoPacket [24].Offset = 24552Total length transferred is 25,575 bytes.
设置 High-Speed 传输的偏移量

例如,这些是高速传输缓冲区的数组条目。 该示例假定缓冲区为 24,576 字节,客户端驱动程序有一个帧用于传输 8 个常量数据包,每个包长 3,072 个字节。

Microframe 1 IsoPacket [0].Offset = 0 (start address)
Microframe 2 IsoPacket [1].Offset = 3072
Microframe 3 IsoPacket [2].Offset = 6144
Microframe 4 IsoPacket [3].Offset = 9216
Microframe 5 IsoPacket [4].Offset = 12288
Microframe 6 IsoPacket [5].Offset = 15360
Microframe 7 IsoPacket [6].Offset = 18432
Microframe 8 IsoPacket [7].Offset = 21504Total length transferred is 24,576 bytes.
设置超速传输的偏移量

例如,这是 SuperSpeed 的数组偏移量。 一个帧中最多可以传输 45,000 个字节。 大小为 360,000 的传输缓冲区适合 8 个微帧

Microframe 1 IsoPacket [0].Offset = 0 (start address)
Microframe 2 IsoPacket [1].Offset = 45000
Microframe 3 IsoPacket [2].Offset = 90000
Microframe 4 IsoPacket [3].Offset = 135000
Microframe 5 IsoPacket [4].Offset = 180000
Microframe 6 IsoPacket [5].Offset = 225000
Microframe 7 IsoPacket [6].Offset = 270000
Microframe 8 IsoPacket [7].Offset = 315000Total length transferred is 360,000 bytes.

UrbIsochronousTransfer.IsoPacket[i]。Length 成员并不表示常时等量 URB 的每个数据包的长度。 IsoPacket[i]。长度 由 USB 驱动程序堆栈更新,以指示从设备接收的实际字节数,用于常量 IN 传输。 对于常时等量 OUT 传输,驱动程序堆栈会忽略 IsoPacket[i] 中设置的值。长度。

指定传输的起始 USB 帧编号

URB 的 UrbIsochronousTransfer.StartFrame 成员指定传输的起始 USB 帧编号。 客户端驱动程序提交 URB 的时间和 USB 驱动程序堆栈处理 URB 的时间之间始终存在延迟。 因此,客户端驱动程序应始终指定一个晚于驱动程序提交 URB 时当前帧的起始帧。 若要检索当前帧编号,客户端驱动程序可以将URB_FUNCTION_GET_CURRENT_FRAME_NUMBER请求发送到 USB 驱动程序堆栈 (_URB_GET_CURRENT_FRAME_NUMBER) 。

对于常时等量传输,当前帧与 StartFrame 值之间的绝对差必须小于 USBD_ISO_START_FRAME_RANGE。 如果 StartFrame 不在适当的范围内,则 USB 驱动程序堆栈会将 URB 标头的状态成员 (看到 _URB_HEADER) 设置为USBD_STATUS_BAD_START_FRAME并放弃整个 URB。

URB 中指定的 StartFrame 值指示传输 URB 的第一个常时等量数据包的帧编号。 后续数据包的帧编号取决于端点的总线速度和轮询周期值。 例如,对于全速传输,第一个数据包在 StartFrame 中传输;第二个数据包在 StartFrame+1 中传输,依此类移。 USB 驱动程序堆栈以全速度以帧为单位传输常时等量数据包的方式如下所示:

Frame (StartFrame)   IsoPacket [0]
Frame (StartFrame+1) IsoPacket [1]
Frame (StartFrame+2) IsoPacket [2]
Frame (StartFrame+3) IsoPacket [3]
...

对于间隔值为 1 的高速设备,帧编号每八个微帧更改一次。 USB 驱动程序堆栈在帧中高速传输等时等量数据包的方式如下所示:

Frame (StartFrame) Microframe 1 IsoPacket [0]
...
Frame (StartFrame) Microframe 8 IsoPacket [7]
Frame (StartFrame+1) Microframe 1 IsoPacket [8]
...
Frame (StartFrame+1) Microframe 8 IsoPacket [15]
Frame (StartFrame+2) Microframe 1 IsoPacket [16]
...
Frame (StartFrame+2) Microframe 8 IsoPacket [23]

当 USB 驱动程序堆栈处理 URB 时,驱动程序会丢弃 URB 中帧数低于当前帧号的所有常时等量数据包。 驱动程序堆栈将每个丢弃数据包的数据包描述符 的状态 成员设置为USBD_STATUS_ISO_NA_LATE_USBPORT、USBD_STATUS_ISO_NOT_ACCESSED_BY_HW或USBD_STATUS_ISO_NOT_ACCESSED_LATE。 即使丢弃了 URB 中的某些数据包,驱动程序堆栈也会尝试仅传输帧号高于当前帧号的数据包。

有效 StartFrame 成员的检查在高速传输中稍微复杂一些,因为 USB 驱动程序堆栈将每个常量数据包加载到高速微帧中;但是,StartFrame 中的值是指 1 毫秒 (全速) 帧数,而不是微帧。 例如,如果 URB 中记录的 StartFrame 值比当前帧少一个,则驱动程序堆栈可以丢弃多达 8 个数据包。 丢弃的数据包的确切数量取决于与常时等量管道关联的轮询周期。

等时等量传输示例

下面的代码示例演示如何为全速、高速和超高速传输的常时等量传输创建 URB。

#define MAX_SUPPORTED_PACKETS_FOR_HIGH_OR_SUPER_SPEED 1024
#define MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED 255NTSTATUS CreateIsochURB  ( PDEVICE_OBJECT         DeviceObject,PUSBD_PIPE_INFORMATION  PipeInfo,ULONG                   TotalLength,PMDL                    RequestMDL,PURB                    Urb)
{PDEVICE_EXTENSION        deviceExtension;ULONG                    numberOfPackets;ULONG                    numberOfFrames;ULONG                    isochPacketSize = 0;ULONG                    transferSizePerFrame;ULONG                    currentFrameNumber;size_t                   urbSize;ULONG                    index;NTSTATUS                 ntStatus;deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;isochPacketSize = PipeInfo->MaximumPacketSize;// For high-speed transfersif (deviceExtension->IsDeviceHighSpeed || deviceExtension->IsDeviceSuperSpeed){// Ideally you can pre-calculate numberOfPacketsPerFrame for the Pipe and// store it in the pipe context.switch (PipeInfo->Interval){case 1:// Transfer period is every microframe (eight times a frame).numberOfPacketsPerFrame = 8;break;case 2:// Transfer period is every 2 microframes (four times a frame).numberOfPacketsPerFrame = 4;break;case 3:// Transfer period is every 4 microframes (twice in a frame).numperOfPacketsPerFrame = 2;break;case 4:default:// Transfer period is every 8 microframes (once in a frame).numberOfPacketsPerFrame = 1;break;}//Calculate the number of packets.numberOfPackets = TotalLength / isochPacketSize;if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_HIGH_OR_SUPER_SPEED){// Number of packets cannot be  greater than 1021.ntStatus = STATUS_INVALID_PARAMETER;goto Exit;}if (numberOfPackets % numberOfPacketsPerFrame != 0){// Number of packets should be a multiple of numberOfPacketsPerFramentStatus = STATUS_INVALID_PARAMETER;goto Exit;}}else if (deviceExtension->IsDeviceFullSpeed){//For full-speed transfers// Microsoft USB stack only supports bInterval value of 1 for// full-speed isochronous endpoints.//Calculate the number of packets.numberOfPacketsPerFrame = 1;numberOfPackets = TotalLength / isochPacketSize;if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED){// Number of packets cannot be greater than 255.ntStatus = STATUS_INVALID_PARAMETER;goto Exit;}}// Allocate an isochronous URB for the transferntStatus = USBD_IsochUrbAllocate (deviceExtension->UsbdHandle,numberOfPackets,&Urb);if (!NT_SUCCESS(ntStatus)){ntStatus = STATUS_INSUFFICIENT_RESOURCES;goto Exit;}urbSize = GET_ISO_URB_SIZE(numberOfPackets);Urb->UrbIsochronousTransfer.Hdr.Length = (USHORT) urbSize;Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;Urb->UrbIsochronousTransfer.PipeHandle = PipeInfo->PipeHandle;if (USB_ENDPOINT_DIRECTION_IN(PipeInfo->EndpointAddress)){Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN;}else{Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT;}Urb->UrbIsochronousTransfer.TransferBufferLength = TotalLength;Urb->UrbIsochronousTransfer.TransferBufferMDL = RequestMDL;Urb->UrbIsochronousTransfer.NumberOfPackets = numberOfPackets;Urb->UrbIsochronousTransfer.UrbLink = NULL;// Set the offsets for every packet for reads/writesfor (index = 0; index < numberOfPackets; index++){Urb->UrbIsochronousTransfer.IsoPacket[index].Offset = index * isochPacketSize;}// Length is a return value for isochronous IN transfers.// Length is ignored by the USB driver stack for isochronous OUT transfers.Urb->UrbIsochronousTransfer.IsoPacket[index].Length = 0;Urb->UrbIsochronousTransfer.IsoPacket[index].Status = 0;// Set the USBD_START_ISO_TRANSFER_ASAP. The USB driver stack will calculate the start frame.// StartFrame value set by the client driver is ignored.Urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;Exit:return ntStatus;
}

11111

相关文章:

windows USB 设备驱动开发-USB 等时传输

客户端驱动程序可以生成 USB 请求块 (URB) 以在 USB 设备中向/从常时等量端点传输数据。虽然USB设备一向以非等时传输出名&#xff0c;USB提供的是一种串行数据&#xff0c;而非等时&#xff0c;但是USB仍然设计了等时传输的机制&#xff0c;但根据笔者的经验&#xff0c;等时传…...

【文件共享 windows和linux】Windows Server 2016上开启文件夹共享,并在CentOS 7.4上访问和下载文件

要在Windows Server 2016上开启文件夹共享&#xff0c;并在CentOS 7.4上访问和下载文件&#xff0c;请按照以下步骤操作&#xff1a; 在Windows Server 2016上开启文件夹共享&#xff1a; 启用SMB服务&#xff1a; 打开“服务器管理器”。选择“文件和存储服务” > “共享…...

【知网CNKI-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…...

【Python_GUI】tkinter常用组件——文本类组件

文本时窗口中必不可少的一部分&#xff0c;tkinter模块中&#xff0c;有3种常用的文本类组件&#xff0c;通过这3种组件&#xff0c;可以在窗口中显示以及输入单行文本、多行文本、图片等。 Label标签组件 Label组件的基本使用 Label组件是窗口中比较常用的组件&#xff0c;…...

zdppy+onlyoffice+vue3解决文档加载和文档强制保存时弹出警告的问题

解决过程 第一次排查 最开始排查的是官方文档说的 https://api.onlyoffice.com/editors/troubleshooting#key 解决方案。参考的是官方的 https://github.com/ONLYOFFICE/document-server-integration/releases/latest/download/Python.Example.zip 基于Django的Python代码。 …...

C语言从头学31——与字符串变量相关的几个函数

strlen、strcpy、strcat、strcmp、sprintf这些函数都是与字符串相关的&#xff0c;除了sprintf是定义在stdio.h中外&#xff0c;其余几个都定义在string.h中&#xff0c;比较新的编译器版本stdio.h中已经含有string.h的内容&#xff0c;所以编程时不需要再包含string.h这个头文…...

Laravel批量插入数据:提升数据库操作效率的秘诀

Laravel批量插入数据&#xff1a;提升数据库操作效率的秘诀 Laravel作为PHP的现代Web应用框架&#xff0c;提供了优雅而简洁的方法来处理数据库操作。批量插入数据是数据库操作中常见的需求&#xff0c;尤其是在处理大量数据时&#xff0c;批量插入可以显著提高性能。本文将详…...

OpenCV:解锁计算机视觉的魔法钥匙

OpenCV&#xff1a;解锁计算机视觉的魔法钥匙 在人工智能与图像处理的世界里&#xff0c;OpenCV是一个响当当的名字。作为计算机视觉领域的瑞士军刀&#xff0c;OpenCV以其丰富的功能库、跨平台的特性以及开源的便利性&#xff0c;成为了开发者手中不可或缺的工具。本文将深入…...

手写简单模拟mvc

目录结构&#xff1a; 两个注解类&#xff1a; Controller&#xff1a; package com.heaboy.annotation;import java.lang.annotation.*;/*** 注解没有功能只是简单标记* .RUNTIME 运行时还能看到* .CLASS 类里面还有&#xff0c;构建对象久没来了&#xff0c;这个说明…...

【FreeRTOS】同步互斥与通信 FreeRTOS提供的方法

目录 各类方法的对比队列事件组信号量互斥量任务通知 各类方法的本质 使用全局变量可以实现通信&#xff0c;但是使用全局变量会有一些缺陷。 那我们怎么保证通信的正确性呢&#xff1f;&#xff1f;&#xff1f; 我们需要引入很多互斥的方法。除了互斥之外&#xff0c;还需要高…...

Kafka 面试题指南

Kafka 面试题指南 本文档提供了一份详细的 Kafka 面试题指南&#xff0c;涵盖了 Kafka 的核心概念、架构、配置、操作和实际应用场景等方面的内容。希望通过这份指南能够帮助你在 Kafka 面试中取得成功。 目录 Kafka 基础知识 什么是 Kafka&#xff1f;Kafka 的主要特点是什…...

2024年7月5日 (周五) 叶子游戏新闻

老板键工具来唤去: 它可以为常用程序自定义快捷键&#xff0c;实现一键唤起、一键隐藏的 Windows 工具&#xff0c;并且支持窗口动态绑定快捷键&#xff08;无需设置自动实现&#xff09;。 卸载工具 HiBitUninstaller: Windows上的软件卸载工具 《乐高地平线大冒险》为何不登陆…...

热门开源项目推荐:探索开源世界的精彩

热门开源项目推荐 随着开源程序的发展&#xff0c;越来越多的程序员开始关注并加入开源大模型的行列。开源不仅为个人学习和成长提供了绝佳的平台&#xff0c;也为整个技术社区带来了创新和进步。无论你是初学者还是经验丰富的开发者&#xff0c;参与开源项目都能让你受益匪浅…...

Codeforces Round #956 (Div. 2) and ByteRace 2024(A~D题解)

这次比赛也是比较吃亏的&#xff0c;做题顺序出错了&#xff0c;先做的第三个&#xff0c;错在第三个数据点之后&#xff0c;才做的第二个&#xff08;因为当时有个地方没检查出来&#xff09;所以这次比赛还是一如既往地打拉了 那么就来发一下题解吧 A. Array Divisibility …...

基于YOLOv9的脑肿瘤区域检测

数据集 脑肿瘤区域检测&#xff0c;我们直接采用kaggle公开数据集&#xff0c;Br35H 数据中已对医学图像中脑肿瘤位置进行标注 数据集我已经按照YOLO格式配置好&#xff0c;数据内容如下 数据集中共包含700张图像&#xff0c;其中训练集500张&#xff0c;验证集200张 模型训…...

阿里云 ECS 服务器的安全组设置

阿里云 ECS 服务器的安全组设置 缘由安全组多个安全组各司其职一些常见的IP段百度 IP 段华为云 IP 段搜狗蜘蛛 IP 段阿里云 IP 段 。。。 缘由 最近公司规模缩减&#xff0c;原有的托管在 IDC 机房的服务器&#xff0c;都被处理掉了&#xff0c;所有代码都迁移到了阿里云的云服…...

昇思25天学习打卡营第15天|应用实践之ShuffleNet图像分类

基本介绍 今天的应用实践的领域是计算机视觉领域&#xff0c;更确切的说是图像分类任务&#xff0c;不过&#xff0c;与昨日不同的是&#xff0c;今天所使用的模型是ShuffleNet模型。ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一…...

怀庄之醉适合搭配什么食物?

怀庄之醉作为一种独特的佳酿&#xff0c;其丰富的香气和层次感使其能够与多种食物搭配&#xff0c;提升餐饮体验。以下将具体探讨怀庄之醉适合搭配的食物类型&#xff0c;并分析为何这些搭配能够带来卓越的味觉享受。 一、肉类佳肴 怀庄之醉因其浓郁的口感&#xff0c;特别适…...

Java | Leetcode Java题解之第223题矩形面积

题目&#xff1a; 题解&#xff1a; class Solution {public int computeArea(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2) {int area1 (ax2 - ax1) * (ay2 - ay1), area2 (bx2 - bx1) * (by2 - by1);int overlapWidth Math.min(ax2, bx2) -…...

基于单片机的空调控制器的设计

摘 要 &#xff1a; 以单片机为核心的空调控制器因其体积小 、 成本低 、 功能强 、 简便易行而得到广泛应用 。 本设计通过 &#xff21;&#xff34;&#xff18;&#xff19;&#xff33;&#xff15;&#xff12; 控制&#xff24;&#xff33;&#xff11;&#xff18;&a…...

企业如何利用短视频平台做口碑塑造和品牌营销?

随着短视频平台的不断发展&#xff0c;新型的双微一抖小红书等新媒体平台&#xff0c;正在成为网民聚集的核心平台&#xff0c;小马识途营销顾问认为越来越多的企业应该利用这些平台进行品牌营销和宣传。其中&#xff0c;抖音和小红书作为短视频平台的代表&#xff0c;吸引了大…...

SQL INSERT批量插入方式

1、常规INSERT写法 INSERT INTO ... VALUES (...);INSERT INTO 表名( 字段1, 字段2) VALUES (字段1的值, 字段2的值);2、SELECT语句返回值INSERT INSERT INTO ...VALUES (..., (select ...));INSERT INTO 表名1(字段1, 字段2) VALUES (字段1的值, (select 查询字段 from 表名2 …...

2.5 C#视觉程序开发实例1----IO_Manager实现切换程序

2.5 C#视觉程序开发实例1----IO_Manager实现切换程序 1 IO_Manager中输入实现 1.0 IO_Manager中输入部分引脚定义 // 设定index 目的是为了今后可以配置这些参数、 // 输入引脚定义 private int index_trig0 0; // trig index private int index_cst 7; //cst index priva…...

【入门篇】STM32寻址范围(更新中)

写在前面 STM32的寻址范围涉及存储器映射和32位地址线的使用。并且STM32的内存地址访问是按字节编址的,即每个存储单元是1字节(8位)。 一、寻址大小与范围 地址线根数 地址编号(二进制) 地址编号数(即内存大小) <...

DDD架构

1.DDD架构的概念&#xff1a; 领域驱动设计&#xff08;Domain-Driven Design, DDD&#xff09;是一种软件设计方法&#xff0c;旨在将软件系统的设计和开发焦点集中在领域模型上&#xff0c;以解决复杂业务问题 2.DDD架构解决了什么问题: 在以前的mvc架构种&#xff0c;三层结…...

Open3D KDtree的建立与使用

目录 一、概述 1.1kd树原理 1.2kd树搜索原理 1.3kd树构建示例 二、常见的领域搜索方式 2.1K近邻搜索&#xff08;K-Nearest Neighbors, KNN Search&#xff09; 2.2半径搜索&#xff08;Radius Search&#xff09; 2.3混合搜索&#xff08;Hybrid Search&#xff09; …...

C语言编程3:运算符,运算符的基本用法

C语言3&#x1f525;&#xff1a;运算符&#xff0c;运算符的基本用法 一、运算符&#x1f33f; &#x1f387;1.1 定义 运算符是指进行运算的动作&#xff0c;比如加法运算符"“&#xff0c;减法运算符”-" 算子是指参与运算的值&#xff0c;这个值可能是常数&a…...

如何通过SPI机制去实现读取配置文件并动态加载对应实现类

最近写完鱼皮的RPC项目后&#xff0c;打算整理出来一些编程技巧的模版。 有两种实现&#xff1a;1.ServiceLoader 2.SpiLoader 一、直接使用java.util下的ServiceLoader 首先在resource目录下创建 META-INF/services 目录&#xff0c;并且创一个名称为对应要实现的接口的包…...

双链表(数组模拟)

双链表&#xff08;数组模拟&#xff09; 什么是双链表数组模拟双链表题目 什么是双链表 双链表不同于单链表的是 每一个节点不但存储了下一个节点的位置&#xff0c;也存储了上一个节点的位置。 数组模拟双链表 所以如果用数组的话&#xff0c;就需要创建三个数组。 题目 …...

ChatGPT 5.0:一年半后的展望与看法

在人工智能领域&#xff0c;每一次技术的飞跃都预示着未来生活与工作方式的深刻变革。随着OpenAI在人工智能领域的不断探索与突破&#xff0c;ChatGPT系列模型已成为全球关注的焦点。当谈及ChatGPT 5.0在未来一年半后可能发布的前景时&#xff0c;我们不禁充满期待&#xff0c;…...