admin 管理员组

文章数量: 887007

USB笔记 USB设备识别当前接入的操作系统-Windows系统篇

概述

我们在进行USB设备相关的产品开发中,会在某些场景下需要知道USB设备所接入的操作系统是什么,例如区分是Windows操作系统,Mac操作系统,还是Ubuntu系统,等等。本文提供一种用于区分当前USB设备接入的操作系统是否是Windows系统的方法。

方法概述

我用于区分Windows操作系统的方法是使用Microsoft OS Descriptors,该描述符为Windows操作系统独有,可以在开发USB设备时加入该描述符的支持,然后在USB设备接入电脑后通过判断操作系统是否有读取该描述符来得知该系统是否是Windows系统。

下面开始详细介绍:

Microsoft OS Descriptors

首先介绍下Microsoft OS Descriptors,该描述符的用途是让独立的硬件供应商(Independent hardware vendors (IHVs) )使用 Microsoft OS Descriptors将信息存储在固件中,而不是单独提供,然后 Window 通过读取 Microsoft OS Descriptors来检索该信息,并使用它来安装和配置设备,而无需任何用户交互。

Microsoft OS descriptor有两种类型:

  • OS string descriptor

这是一个标准的USB字符串描述符(string descriptor)。每个支持Microsoft OS string descriptor的设备必须在其固件的标准索引中存储一个OS string descriptor。这个描述符将设备标识为支持Microsoft OS descriptor,并包含检索相关特性描述符所需的数据。

  • OS feature descriptors

    设备可以有一个或多个OS feature descriptors,这些描述符包含详细的特性信息。

要检索设备的OS feature descriptors,Windows系统会做如下操作:

  1. 向设备发送一个控制请求,以检索其OS string descriptor。

  2. 检查返回的描述符以验证它是否是一个有效的OS string descriptor。

  3. 如果是有效的,那么就使用OS string descriptor的bMS_VendorCode字段中的数据来检索设备的OS feature descriptors。

下面详细介绍下OS string descriptor和OS feature descriptors。

OS String Descriptor

OS string descriptor是一个标准的USB字符串描述符(string descriptor),所以windows系统是通过向设备发送一个标准的GET_DESCRIPTOR控制请求(control request)来获取这个描述符。

请求的格式
bmRequestTypebRequestwValuewIndexwLengthData
1000 0000BGET_DESCRIPTOR0x03EE0x00000x12Returned String

bmRequestType

bmRequestType10000000B
  bmRequestType.Recipient0b00000(Device)
  bmRequestType.Type0b00(Standard)
  bmRequestType.Direction0b1(Device-to-Host)

接收端:设备(Device)

类型:标准(Standard)

方向:设备到主机(Device-to-Host)

因为是标准的USB字符串描述符(string descriptor),所以该字段必须为10000000B,也就是0x80。

bRequest

该字段指定请求类型,这里为GET_DESCRIPTOR请求,数值为0x06。

wValue

该字段在高字节中指定描述符类型,在低字节中指定描述符索引。

对于USB字符串描述符,指定的描述符类型为STRING,对应的数值为0x03,字符串索引被Microsoft指定为0xEE,所以该字段的数值为0x03EE。

wIndex

对于字符串描述符,该字段为语言ID(Language ID)。但是OS string descriptors该字段必须设置为0x0000。

wLength

该字段指定要返回的数据长度(字节数)。对于OS string descriptors,该字段在协议文档中固定设置为0x12,但是实际可能下发的是0xFF。

Data

如果OS string descriptors请求成功,那么设备将在数据阶段(Data stage)的数据包(Data packet)中返回请求的描述符。其数据结构见下一小节。

数据的格式

OS string descriptor的数据结构和标准字符串描述符的UNICODE String Descriptor的格式略有差异。该格式由Microsoft定义,所有OS string descriptors都必须使用该格式。结构如下图所示。

FieldLength (Bytes)ValueDescription
bLength10x12Length of the descriptor
bDescriptorType10x03Descriptor type
qwSignature14‘MSFT100’Signature field
bMS_VendorCode1Vendor-specificVendor code
bPad10x00Pad field

bLength

该字段表示描述符大小,以字节为单位。OS string descriptor的数据长度固定为18个字节,即为0x12。

bDescriptorType

该字段表示描述符类型,为String(0x03)。

qwSignature

该字段包含一个Unicode字符数组,它将描述符标识为一个OS string descriptor,并包含版本号。对于版本1.00,该数组必须设置为’ MSFT100 ’ (0x4D00 0x5300 0x4600 0x5400 0x3100 0x3000 0x3000)。

bMS_VendorCode

该字段用于检索相关的OS feature descriptors。该数值由厂商定义(vendor-defined),也就是由我们自己来定义,例如定义为0x01。这个值会在下面的OS feature descriptors用到。

bPad

用于填充的字段,固定为0x00。

OS Feature Descriptors

OS feature descriptor包含与设备特性(device feature)相关的数据。对于version 1.00,Microsoft已经为三种OS feature descriptor定义了标准格式,分别是Extended compat ID OS feature descriptor,Extended properties OS feature descriptor,Genre OS feature descriptor。我们接下来会使用到的是Extended compat ID OS feature descriptor。

请求的格式
bmRequestTypebRequestwValuewIndexwLengthData
1100 0000BGET_MS_DESCRIPTORInterface/ PageFeature IndexLengthReturned Descriptor

bmRequestType

bmRequestType10000000B
  bmRequestType.Recipient0b00000(Device)
  bmRequestType.Type0b10(Vendor)
  bmRequestType.Direction0b1(Device-to-Host)

接收端:设备(Device)

类型:厂商(Vendor)

方向:设备到主机(Device-to-Host)

OS feature descriptors是厂商自定义的描述符,因此该字段必须被设置为11000000B ,也就是0xC0。

bRequest

该字段指定请求类型,这里是一个厂商自定义(vendor-defined)的描述符,是一个特殊的类型GET_MS_DESCRIPTOR,该类型本质上是一个厂商自定义数值的占位符,该值因设备而异。这个数值由设备的OS string descriptor的bMS_VendorCode字段中返回。要请求一个OS feature descriptor,需要将bRequest设置为设备OS string descriptor中的bMS_VendorCode值。例如我们在OS string descriptor中将bMS_VendorCode字段的值定义为0x01,那么在OS feature descriptors下发请求查询时,bRequest的值就会为0x01。

wValue

该字段分为两部分:

在高字节中表示InterfaceNumber。wValue的高位字节包含与描述符关联的接口或功能的编号。这个特性对于组合设备(composite devices)特别有用。然而,大多数描述符都与设备相关联,而不是特定的接口,而且有些描述符必须是设备级的。对于设备级(device-level)描述符,将InterfaceNumber设置为0。

在低字节中表示PageNumber。wValue的低字节包含一个页码,它允许OS feature descriptor超过由wLength的最大值设置的64KB的限制。如果描述符小于64KB,则将wValue设置为0。

对于我们所要应用的场景,这里我们只会用到0x0000。

wIndex

这个字段包含被请求的OS feature descriptor的index。version 1.00描述符的index是:

  • Genre: 0x0001

  • Extended compat ID: 0x0004

  • Extended properties: 0x0005

对于我们所要应用的场景,这里我们只会用到Extended compat ID,也就是0x0004,表示请求是一个extended compat ID OS descriptor。

wLength

这个字段指定了分配给Data字段的长度(以字节为单位)。如果描述符大于指定的wLength大小,则只返回wLength字节。如果描述符小于wLength,返回的数据包含整个描述符,并且多余部分用零填充。

对于我们所要应用的场景,只会用到长度为16字节,也就是0x0010。

Data

这个字段是返回请求的描述符。其数据结构见下一小节。

Extended compat ID OS feature descriptor

我们这里使用的是Extended compat ID OS feature descriptor。

数据的格式

Extended compat ID OS feature descriptor分为两个部分

  • 一个固定长度的报头部分(header section),它包含关于整个描述符的信息,包括版本号、功能部分的数量和描述符的总长度。
  • 一个或多个固定长度的功能部分(function sections),紧跟在报头部分(header section)之后。每个功能部分包含设备的数据,或单个接口、功能或单功能接口组的数据。

我们的应用场景下,只有用到报头部分(header section),下面是具体格式:

Header Section
OffsetFieldSize(bytes)TypeDescription
0dwLength4DWORDThe length, in bytes, of the complete extended compat ID descriptor
4bcdVersion2BCDThe descriptor’s version number, in binary coded decimal (BCD) format
6wIndex2WORDAn index that identifies the particular OS feature descriptor
8bCount1BYTEThe number of custom property sections
9RESERVED7BYTEsReserved

dwLength

整个描述符的长度,包括报头部分(header section)。Windows使用这个值来检索完整的描述符。

bcdVersion

版本号。该字段允许Windows区分不同的OS descriptor versions版本。对于版本1.00,bcdVersion设置为0x0100。

wIndex

描述符的索引。该值用于区分不同的OS feature descriptors。它与用于请求描述符的值相同,对于extended compat ID descriptors来说就是设置为0x04。

bCount

功能部分(function sections)的数量。

我们的应用场景下,该数值为0。

实现准备

  1. 支持Microsoft OS Descriptors

    USB设备可以任意的速率,比如high-speed,full-speed或者low-speed,但是协议必须是USB 2.0或更高版本的USB协议,也就是USB设备描述符(Device Descriptor)的bcdUSB字段必须是USB 2.0及以上。

  2. 支持OS string descriptor

    在解析GET_DESCRIPTOR的部分加入对wValue数值为0x03EE的解析,给予正确的回复。

    回复的数据,这里举例如下,其中的bMS_VendorCode字段可自定义:

    OffsetFieldSize(Bytes)Data
    0bLength10x12
    1bDescriptorType10x03
    2qwSignature140x4D00 0x5300 0x4600 0x5400 0x3100 0x3000 0x3000
    16bMS_VendorCode10x01
    17bPad10x00

    例如下图的USB抓包示意图:
    其中的bMS_VendorCode字段请根据实际情况来。

  3. 支持Extended properties OS feature descriptor

    增加对厂商自定义(vendor-defined)的描述符的解析,也就是bmRequestType字段为0xC0。然后在此之中增加对bRequest字段为GET_MS_DESCRIPTOR时的解析。

    回复的数据,这里举例如下,可根据实际情况来:

    OffsetFieldSize(bytes)Data
    0dwLength40x00000010
    4bcdVersion20x0100
    6wIndex20x0004
    8bCount10x00
    9RESERVED70x00000000000000

    最后只要正确地回复就可以了,例如下图的USB抓包示意图:

    其中的GET_MS_DESCRIPTOR字段请根据实际情况来。

这样就完成了对Microsoft OS Descriptors整体的支持,下面看下流程。

实现流程和判断系统

windows系统下发Microsoft OS Descriptors的流程如下:

可以看到OS string descriptor只会在第一次才会下发,而Extended properties OS feature descriptor则会在每次接入电脑时都会下发。因此判断接入的电脑操作系统是否是Windows系统,需要通过判断是否有来获取Extended properties OS feature descriptor来实现。如下图所示:

注意事项

设备在首次接入后,Windows系统会下发OS string descriptor,不管该字符串描述符获取成功与否,Windows电脑都会将该操作记录下来。如果是成功获取,那么后续会继续下发Extended properties OS feature descriptor,并且重新插拔后也会下发获取Extended properties OS feature descriptor;但是如果获取失败了,后续就不会去获取Extended properties OS feature descriptor,并且重新插拔后,也不会去获取OS string descriptor和Extended properties OS feature descriptor。

在USB设备调试阶段,很容易出现系统在下发OS string descriptor的时候,没有回复消息或者回复消息错误或者失败,导致Windows系统记录下该操作,进而导致后续再也无法获取到OS string descriptor。

遇到这种情况,有几种方法:

  1. 修改USB设备的VID或者PID,让电脑认为这是另外一个设备。
  2. 修改USB设备描述符(Device Descriptor)的bcdDevice字段,相当于修改了设备版本号。
  3. 从注册表中删除该设备的记录。

注意,通过删除设备驱动,重装设备驱动,这些操作并不能让Windows系统再次去向USB设备获取Microsoft OS Descriptors。

[参考资料]

Microsoft OS Descriptors Overview

Extended Compat ID OS Feature Descriptor Specification

Extended Properties OS Feature Descriptor Specification

【USB笔记】 设备描述符Device Descriptor

【USB笔记】字符串描述符String Descriptor


本文链接:https://blog.csdn/u012028275/article/details/122384011

本文标签: 操作系统 笔记 设备 系统 USB