程序项目代做,有需求私信(vue、React、Java、爬虫、电路板设计、嵌入式linux等)

Rockchip RK3399 - linux通过usbmon抓取usb数据包

----------------------------------------------------------------------------------------------------------------------------

开发板 :SOM-RK3399核心板+定制底板
eMMC16GB
LPDDR34GB
显示屏 :15.6英寸HDMI接口显示屏
u-boot2017.09
linux4.19
----------------------------------------------------------------------------------------------------------------------------

注意:本节介绍的内容基于Rockchip RK3399 - 移植uboot 2017.09 & linux 4.19(友善之家脚本方式)》中移植的运行环境:内核版本4.19.193以及debian 11根文件系统。

一、安装usbmon

usbmonusb monitor,是linux内置的usb抓包工具。usbmon本质是一个内核模块,模块的位置:/lib/modules/4.19.193/kernel/drivers/usb/mon/usbmon.ko

想要启用usbmon,必须挂载debugfs并加载usbmon模块。

1.1 挂载debugfs文件系统

在开发板debian执行如下命令,如果提示已经挂载,则下次抓包就无需运行该命令了,表示系统默认会挂载该文件系统。

root@SOM-RK3399v2:/# mount -t debugfs none /sys/kernel/debug
mount: /sys/kernel/debug: none_debugs already mounted or mount point busy.

如上所示, debian系统默认已经挂载了debugfs文件系统,无需再去手动挂载。

1.2 安装usbmon模块

需要注意的是:如果你已经将usbmon编译到内核中,就不需要安装了。

确认内核支持usbmon模块

root@SOM-RK3399v2:/# ls /sys/module/usbmon
ls: cannot access '/sys/module/usbmon': No such file or directory

如上所示,目前内核不支持usbmon模块,需要手动安装usbmon模块。

执行如下命令安装usbmon

root@SOM-RK3399v2:/# modprobe usbmon
bash: modprobe: command not found

提示未找到命令则是因为/usr/sbin(或者/sbin)默认没有加到PATH;通过修改profile文件:

root@SOM-RK3399v2:/# vim /etc/profile

找到设置PATH的行,添加:

export PATH=/usr/sbin:$PATH

要想马上生效还要运行 source /etc/profile不然只能在下次重进此用户时生效。

重新运行命令:

root@SOM-RK3399v2:/# modprobe usbmon
root@SOM-RK3399v2:/# ls /sys/module/usbmon
coresize  holders  initsize  initstate  notes  refcnt  sections  srcversion  taint  uevent

这里的原理是,usbmon是一个模块,使用modprobe安装该模块后,该模块内部调用debugfs相关的API,这样在 /sys/kernel/debug/usb目录下便形成了usbmon这个目录。

查看/sys/kernel/debug/usb/usbmon目录,

root@SOM-RK3399v2:/# ls  /sys/kernel/debug/usb/usbmon
0s  0u  1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u  5s  5t  5u  6s  6t  6u

发现该目录下有以下内容:0s、0u、1s、1t、1u、2s、2t、2u等,其中1代表bus1,2代表bus2,0代表所有USB总线。

1.2.1 开机自动加载模块

这里有一个问题,就是内核4.19.193版本启动的时候为啥没有自动去加载/lib/modules/4.19.193/目录下的驱动模块,如果我们想让系统能自动加载该目录下的驱动模块,我们应该怎么做?

(1) 使用命令depmod -a

depmod命令用于分析可载入模块的相依性,-a参数的作用是探测所有的模块,建立模块的依赖关系,更新/lib/modules/4.19.193/modules.dep文件;

(2) 将模块设置为自动加载

/etc/modules文件里面添加我们要加载的驱动名(一个驱动占一行);

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
usbmon
1.2.2 重启验证

上述操作完成后,重启系统,使用 lsmodcat /proc/modulesls /sys/module/usbmon命令查看驱动是否已经加载。

root@SOM-RK3399v2:/# lsmod
Module                  Size  Used by
algif_hash             20480  1
algif_skcipher         16384  1
af_alg                 24576  6 algif_hash,algif_skcipher
bnep                   24576  2
hci_uart               61440  1
btbcm                  16384  1 hci_uart
serdev                 20480  1 hci_uart
hid_logitech_hidpp     36864  0
crct10dif_ce           16384  0
l2tp_ppp               24576  0
l2tp_netlink           24576  1 l2tp_ppp
l2tp_core              28672  2 l2tp_ppp,l2tp_netlink
ip6_udp_tunnel         16384  1 l2tp_core
udp_tunnel             16384  1 l2tp_core
pppox                  16384  1 l2tp_ppp
joydev                 28672  0
bcmdhd               1695744  0
cfg80211              638976  1 bcmdhd
hid_logitech_dj        20480  0
uio_pdrv_genirq        16384  0
uio                    20480  1 uio_pdrv_genirq
binfmt_misc            20480  1
usbmon                 36864  0                       # 这里
ledtrig_netdev         16384  0
nfsd                  344064  1
ip_tables              28672  0
root@SOM-RK3399v2:/# ls /sys/module/usbmon
coresize  holders  initsize  initstate  notes  refcnt  sections  srcversion  taint  uevent

二、抓取USB数据

2.1 确usb设备挂在哪条总线

首先需要获取想要监测的设备所在的总线以及设备号。linux中查看USB设备列表以及USB设备详细信息的有多种方法:

2.1.1 内核日志

我们在开发板上随便找一个USB接口插入USB触摸屏(使用的是Micro-B接口);

内核输出日志如下:

[   73.351785] usb 1-1.2: new full-speed USB device number 4 using ehci-platform
[   73.451527] usb 1-1.2: New USB device found, idVendor=1a86, idProduct=e5e3, bcdDevice= 0.00
[   73.451631] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[   73.451663] usb 1-1.2: Product: USB2IIC_CTP_CONTROL
[   73.451692] usb 1-1.2: Manufacturer: wch.cn
[   73.467736] input: wch.cn USB2IIC_CTP_CONTROL as /devices/platform/fe3c0000.usb/usb1/1-1/1-1.2/1-1.2:1.0/0003:1A86:E5E3.0007/input/input13
[   73.527068] hid-generic 0003:1A86:E5E3.0007: input,hidraw4: USB HID v1.00 Device [wch.cn USB2IIC_CTP_CONTROL] on usb-fe3c0000.usb-1.2/input0
[   73.678401] input: wch.cn USB2IIC_CTP_CONTROL as /devices/platform/fe3c0000.usb/usb1/1-1/1-1.2/1-1.2:1.0/0003:1A86:E5E3.0007/input/input14
[   73.737087] hid-multitouch 0003:1A86:E5E3.0007: input,hidraw4: USB HID v1.00 Device [wch.cn USB2IIC_CTP_CONTROL] on usb-fe3c0000.usb-1.2/input0

从上面的输出信息可以看到PID=e5e3,VID=1a86USB总线编号为1,设备地址为4。

查看接口子类、接口协议等信息:

root@SOM-RK3399v2:/# cat /sys/bus/usb/devices/1-1.2/
1-1.2:1.0/           bDeviceProtocol      bNumInterfaces       descriptors          driver/              manufacturer         quirks               subsystem/
authorized           bDeviceSubClass      bcdDevice            dev                  ep_00/               maxchild             removable            tx_lanes
avoid_reset_quirk    bMaxPacketSize0      bmAttributes         devnum               idProduct            port/                remove               uevent
bConfigurationValue  bMaxPower            busnum               devpath              idVendor             power/               rx_lanes             urbnum
bDeviceClass         bNumConfigurations   configuration        devspec              ltm_capable          product              speed                version
root@SOM-RK3399v2:/etc/profile.d# cat /sys/bus/usb/devices/1-1.2/1-1.2\:1.0/  
0003:1A86:E5E3.0007/  bAlternateSetting     bInterfaceNumber      bInterfaceSubClass    driver/               modalias              subsystem/            uevent
authorized            bInterfaceClass       bInterfaceProtocol    bNumEndpoints         ep_82/                power/                supports_autosuspend
root@SOM-RK3399v2:/etc/profile.d# cat /sys/bus/usb/devices/1-1.2/1-1.2\:1.0/bInterfaceSubClass
00
root@SOM-RK3399v2:/etc/profile.d# cat /sys/bus/usb/devices/1-1.2/1-1.2\:1.0/bInterfaceProtocol
00

其中1-1.2:表示第1个USB控制器的编号为1的硬件端口连接了一个hubhub编号为2的硬件端口上连接了一个设备;

1.0:表示设备的第一个配置(configuration)编号为0接口(interface)。

对于触摸屏设备,接口配置:

  • subclass:接口子类,配置为0,表示No Subclass
  • protocol:接口协议,配置为0;

查看HID报告描述符:

root@SOM-RK3399v2:/# hexdump /sys/bus/usb/devices/1-1.2/1-1.2\:1.0/0003\:1A86\:E5E3.0007/report_descriptor
0000000 0d05 0409 01a1 0185 2209 02a1 4209 0015
0000010 0125 0175 0195 0281 0795 0181 0875 5109
0000020 0195 0281 0105 0026 7510 5510 650e 0911
0000030 3530 4600 0879 0281 0026 4610 054c 3109
0000040 0281 0d05 4809 0281 09c0 a122 0902 1542
0000050 2500 7501 9501 8101 9502 8107 7501 0908
0000060 9551 8101 0502 2601 1000 1075 0e55 1165
0000070 3009 0035 7946 8108 2602 1000 4c46 0905
0000080 8131 0502 090d 8148 c002 2209 02a1 4209
0000090 0015 0125 0175 0195 0281 0795 0181 0875
00000a0 5109 0195 0281 0105 0026 7510 5510 650e
00000b0 0911 3530 4600 0879 0281 0026 4610 054c
00000c0 3109 0281 0d05 4809 0281 09c0 a122 0902
00000d0 1542 2500 7501 9501 8101 9502 8107 7501
00000e0 0908 9551 8101 0502 2601 1000 1075 0e55
00000f0 1165 3009 0035 7946 8108 2602 1000 4c46
0000100 0905 8131 0502 090d 8148 c002 2209 02a1
0000110 4209 0015 0125 0175 0195 0281 0795 0181
0000120 0875 5109 0195 0281 0105 0026 7510 5510
0000130 650e 0911 3530 4600 0879 0281 0026 4610
0000140 054c 3109 0281 0d05 4809 0281 09c0 a122
0000150 0902 1542 2500 7501 9501 8101 9502 8107
0000160 7501 0908 9551 8101 0502 2601 1000 1075
0000170 0e55 1165 3009 0035 7946 8108 2602 1000
0000180 4c46 0905 8131 0502 090d 8148 c002 0d05
0000190 ff27 00ff 7500 9510 0901 8156 0902 1554
00001a0 2500 957f 7501 8108 8502 0902 9555 2501
00001b0 b10a 8502 0603 ff00 c509 0015 ff26 7500
00001c0 9608 0100 02b1 00c0
00001c7
2.1.2 lsusb

我们可以通过lsusb命令查看USB设备信息:

root@SOM-RK3399v2:/# lsusb
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 004: ID 1a86:e5e3 QinHeng Electronics USB2IIC_CTP_CONTROL    # 这里
Bus 001 Device 003: ID 1a2c:4d7e China Resource Semico Co., Ltd USB Keyboard
Bus 001 Device 002: ID 14cd:8601 Super Top 4-Port hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 006 Device 002: ID 046d:c52b Logitech, Inc. Unifying Receiver
Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

USB总线1上,有1个root hub1d6b:0002),1个4-Port hub14cd:8601)、1个USB键盘(1a2c:4d7e)、1个USB触摸屏(1a86:e5e3)。

2.1.3 查看设备文件
root@SOM-RK3399v2:/# cat /sys/kernel/debug/usb/devices
T:  Bus=01 Lev=02 Prnt=02 Port=01 Cnt=02 Dev#=  4 Spd=12   MxCh= 0
D:  Ver= 0.01 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1a86 ProdID=e5e3 Rev= 0.00
S:  Manufacturer=wch.cn
S:  Product=USB2IIC_CTP_CONTROL
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr= 64mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=00 Prot=00 Driver=usbhid
E:  Ad=82(I) Atr=03(Int.) MxPS=  64 Ivl=1ms

这里看到的信息实际上和内核日志输出的信息一样的。

2.2 监测USB总线上的数据

点击触摸屏,查看USB总线上的数据;

root@SOM-RK3399v2:/# cat /sys/kernel/debug/usb/usbmon/1u | grep "1:004"
ffffffc0c88dab00 1925763364 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925763683 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925775309 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925775578 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925787174 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925787301 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925800237 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925800380 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925811243 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925811395 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925821178 C Ii:1:004:2 0:1 52 = 01000075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925821328 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925822163 C Ii:1:004:2 0:1 52 = 01000075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925822309 S Ii:1:004:2 -115:1 52 <

其中的1:004中1表示USB总线编号,004是设备编号,也就是USB触摸屏(1a86:e5e3)。

执行该命令的同时我们点击一下USB触摸屏,就可以查看USB总线上的数据传输。

三、USB传输基础

USB数据抓取到了,但是放眼一看,密密麻麻的全是数字,它们代表什么含义呢?

在解读usbmon抓取的数据包的含义之前,我们需要了解一下与USB传输有关的基础知识,这样才能更好的理解数据包的各个字段所代表的含义。

USB总线上传输的数据是以包为基本单位的,但是不能随意的使用包来传输数据,必须按照一定的关系把这些不同的包组织成事务(transaction)进行传输。

3.1 USB信息包的种类

USB传输由一个或多个事务组成,每个事务又进一步含有多个USB包(packets)。

USB包的种类,总体上分为四类:令牌包、数据包、握手包、特殊包;

3.1.1 令牌包

令牌包用来发起一次USB传输,因为USB是主从结构的拓扑结构,所有的数据传输都是由主机发起的,设备只能被动的响应,这就需要主机发送一个令牌包来通知哪个设备进行响应,如何响应。

令牌包有 4 种,分别为输出(OUT)、输入(IN)、建立(SETUP)和帧起始(SOF)。详情参考:USB协议详解第21讲(USB包-令牌类包)

3.1.2 数据包

数据包就是用来传输数据的,可以从主机到设备,也可以从设备到主机,方向由令牌包来指定。

3.1.3 握手包

握手包的发送者一般为数据接收者,用来表示一个传输是否被对方确认。在传输正常的情况下,主机/设备会发送一个表示传输正确的 ACK握手包。

3.1.4 特殊包

特殊包用在一些特殊的场合,这里就不介绍了。

3.2 USB事务

介绍了USB信息包的分类,下面就要着重介绍USB的事务及传输类型。前面已经说了,我们不能随意的使用USB包来传输数据,必须按照一定的关系把这些不同的包组织成事务才能传输数据。

那么事务是什么呢? 事务通常由三个包组成:令牌包、数据包和握手包。

        img

注意:usbmon只抓取事务中的数据包,不会抓取令牌包和握手包。

3.3 USB传输类型

USB协议规定了4种传输类型:批量传输、等时传输、中断传输和控制传输。其中;

  • 批量传输、等时传输、中断传输每传输一次数据都是一个事务;
  • 控制传输包括三个过程,建立过程和状态过程分别是一个事务,数据过程可能包含多个事务。
3.3.1 批量传输

批量传输用于传输大量数据。USB协议不保证这些数据传输可以在特定的时间内完成,但保证数据的准确性。如果总线上的带宽不足以发送整个批量包,则将数据拆分为多个包传输。批量传输数据可靠,但实时性较低。如USB硬盘、打印机等设备就采用的是批量传输方式;

img

3.3.2 等时传输

等时传输也可以传输大量数据,但数据的可靠性无法保证。采用等时传输的USB设备更加注重保持一个恒定的数据传输速度,对数据的可靠性要求不高。如USB摄像头就使用的是等时传输方式;

img

3.3.3 中断传输

USB主机请求USB设备传输数据时,中断传输以一个固定的速率传送少量的数据。中断端点的数据传输方式为中断传输,数据传输可靠,实时性高,这里的中断并不是USB设备产生中断,而是USB主机每隔一个固定的时间主动查询USB设备是否有数据要传输,以轮询的方式提高实时性。如USB鼠标采用的是中断传输;

img

3.3.4 控制传输

控制传输用于配置设备、获取设备信息、发送命令到设备、获取设备的状态。每个USB设备都有端点0的控制端点,当USB设备插入到USB主机拓扑网络中时,USB主机就通过端点0与USB设备通信,对USB设备进行配置,便于后续的数据传输。USB协议保证控制传输有足够的带宽。控制传输可靠,时间有保证,但传输的数据量不大。如USB设备的枚举过程就采用的是控制传输;

img

img

四、HID报告描述符

在分析HID设备数据包之前,我们必须要了解HID报告描述符,HID报告描述符(Report Descriptor)是HID设备中的一个描述符,它是比较复杂的一个描述符。

报告描述符,是描述一个报告以及报告里面的数据是用来干什么用的?

  • 通过它,USB HOST可以分析出报告里面的数据所表示的意思。它通过控制输入端点0返回,主机使用获取报告描述符命令来获取报告描述符,注意这个请求是发送到接口的,而不是到设备;
  • 一个报告描述符可以描述多个报告,不同的报告通过报告ID来识别,报告ID在报告最前面,即第一个字节。当报告描述符中没有规定报告ID时,报告中就没有ID字段,开始就是数据;
  • 更详细的说明请参看USB HID协议,该协议可从Http://www.usb.org下载;

一个HID报告描述符的数据结构可以使用下图来描述:

从上图可以看到一个HID报告描述符由若干个report组成,当超过1个report时,需要用collection去组合,collection可以嵌套collection。每个report都可以有多个用途(Usage),其它Main item/Report size/Report count/Logical minium等都是用于修饰Usage

HID报告描述符由若干个条目组成,某个条目由keyvalue对组成。key根据占用的字节分为长字和短字,短字占由一个字节组成,使用较多;格式如下;

7:4 3:2 1:0
bTag bType bSzie

其中:

  • bSize:描述value占用的字节;

    • 0:0字节;
    • 1:1个字节
    • 2:2个字节
    • 3:4个字节
  • bType:描述条目的类型;

    • 0:主条目(Main);

    • 1:全局条目(GLobal);

    • 2:局部条目(Local);

    • 3:保留;

  • bTagbTag与类型对象,每种类型有很多不同的bTag

4.1 主条目

Main item tag Valid Data
Input(输入) 1000 Bit 0
Bit 1
Bit 2
Bit 3
Bit 4
Bit 5
Bit 6
Bit 7
Bit 8
Bit 31-9
{Data(0) | Constant(1)}
{Array(0) |Variable(1)}
{Absolute(0) |Relative(1)}
{No Wrap(0) |Wrap(1)}
{Linear(0) |No Linear(1)}
{Preferred State(0) |No Preferred (1)}
{No Null position(0) |Null state(1)}
Reserved(0)
{Bit Field(0) |Buffered Bytes(1)}
Reserved(0)
Output(输出) 1001 Bit 0
Bit 1
Bit 2
Bit 3
Bit 4
Bit 5
Bit 6
Bit 7
Bit 8
Bit 31-9
{Data(0) |Constant(1)}
{Array(0) |Variable(1)}
{Absolute(0) |Relative(1)}
{No Wrap(0) |Wrap(1)}
{Linear(0) |No Linear(1)}
{Preferred State(0) |No Preferred (1)}
{No Null position(0) |Null state(1)}
{Non Volatile(0) | Volatile(1)}
{Bit Field(0) |Buffered Bytes(1)}
Reserved(0)
Feature(属性) 1011 Bit 0
Bit 1
Bit 2
Bit 3
Bit 4
Bit 5
Bit 6
Bit 7
Bit 8
Bit 31-9
{Data(0) |Constant(1)}
{Array(0) |Variable(1)}
{Absolute(0) |Relative(1)}
{No Wrap(0) |Wrap(1)}
{Linear(0) |No Linear(1)}
{Preferred State(0) |No Preferred (1)}
{No Null position(0) |Null state(1)}
{Non Volatile(0) |Volatile(1)}
{Bit Field(0) |Buffered Bytes(1)}
Reserved(0)
Collection(开集合) 1010 0x00
0x01
0x02
0x03
0x04
0x05
0x06
0x070x7F<br/>0x800xFF
Physical(group of axes)
Application(mouse,keyboard)
Logical(interrelated data)
Report
Named Array
Usage Switch
Usage Modifier
Reserved
Vendor~defined
End Collection(关集合) 1100 Not applicable Closes an item collection

下面对DataVariable等的意思作一下解释;

  • Data :表示是一个可写的数据;
  • Constant:表示是一个只读的数据;
  • Aarray : 表示数据里的值代表一个UsageReport Size表示位数,即Report Size的存储单元里的值是UsageIndexReport Count一般为1,如果大于则表示可以同时出现多个Usage
  • Variable: 则是一个Report Size存储单元表示一个Usage,其值表示Usage的状态;Report Size表示位数,Report Count表示长度;
  • Absolute:表示绝对数据,如触模屏数据,便使用Absolute
  • Relative: 表示相对数据,如鼠标数据,便使用Relative

主条目用来定义或者分组报告的数据域,例如,可以使用输入主条目将输入报告划分为不同的数据域,以及指定该域的属性。

4.1.1 例1
0xa1, 0x00, //   COLLECTION (Physical)  

key转换为二进制位1010 0001

  • bSize=1:值为1个字节
  • bType=0:表示主条目;
  • bTag=b`1010:表示开集合,条目的值为0x00,表示Physical(group of axes)
4.1.2 例2
0x81, 0x02,   //    INPUT (Data,Var,Abs)

key转换为二进制位1000 0001

  • bSize=1:值为1个字节
  • bType=0:表示主条目;
  • bTag=b`1000 :表示Input,条目的值为0x02,bit0为0、bit1为1、bit2为0,因此表示INPUT (Data,Var,Abs)

4.2 全局条目

Global item tag 描述
Usage Page 0000 HID Usage Pages Tables(Usage选项表文档)
Logical Minimum 0001 以逻辑单位表示的区段值。这是变量或数组项将报告的最小值。例如鼠标移动XY轴的最小值为-127
Logical Maximum 0010 以逻辑单位表示的区段值。这是变量或数组项将报告的最大值。
例如设备报表的一个电流值读数是500mA,而一个单位是2mA,则Logical Maximum值等于250。
如果逻辑最小范围和逻辑最大范围都定义为正值(0或大于0的值),则可以假定报告字段为无符号值。否则,所有整数值都是以2的补码格式表示的有符号值。
Physical Minimum 0011 变量项的物理范围的最小值。这表示逻辑最小值加上单位
Physical Maximum 0100 变量项的物理范围的最大值
上例中设备报表的一个电流值读数是500mA,单位是2mA,,Logical Maximum等于250,而Physical Maximum值是500。
Logical Minimum与Logical Maximum值说明了设备返回数值的边界,可以根据Physical Minimum和Physical Maximum值对数据进行偏移和比例变换。
Unit Exponent 0101 定义了使用逻辑范围和实际范围将设备的返回数值转换成实际数值时,使用10的多少次方对数值进行定标。
Unit Exponent的值的编码为4位补码,代表10的指数范围是-8~+7。
物理数据值 = 逻辑数据值/分辨率
分辨率 = (LogicalMaximum - LogicalMinimum) /((PhysicalMaximum - PhysicalMinimum) X 10^UnitExponent)
Unit 0110 单位值
Report Size 0111 无符号整数,以比特(Bit)为单位指定报表字段的大小。这允许解析器构建供报表处理程序使用的项映射。
Report ID 1000 当一个报告数据被分成数个部分单独上报时,需要为各部分添加一个ID前缀。例如,一个数据部分,其长为3字节,定义Report ID为01,则该设备将生成一个4字节的数据报告,其中第一个字节是01。
设备还可能生成其他报告,每个报告都有唯一的ID,ID值从1起始,不允许应用0作为ID值,0被保留给未赋值ID的报告使用。
Report Count 1001 无符号整数,指定该项的数据字段数;确定报告中为此特定项包含了多少个字段 (以及因此有多少位被添加到报告中)。
Size*Count = UsageDataSize;
注意的是,size的单位是Bit,这里涉及到不满一个字节场景下的常量填充问题,例如,鼠标中Usage Page(buttons),三个按键只需3bits,此时没有其它合适的有效数据字段时可以选择填充5bits常量:
Report Count (1)
Report Size (5)
Input (Constant)
Push 1010 当遇到Push项目时,项目状态表被复制并放置在堆栈上供以后检索。
Pop 1011 当找到一个Pop项目时,项目状态表被堆栈中的顶部表替换。
4.2.1 例1
0x05, 0x01,      // USAGE_PAGE (Generic Desktop)

key转换为二进制位0000 0101

  • bSize=1:值为1个字节
  • bType=1:表示全局条目;
  • bTag=b`0000:表示Usage Page,条目的值为0x01,表示USAGE_PAGE (Generic Desktop)
4.2.2 例2
0x05, 0x09,      //   USAGE_PAGE (Button)

key转换为二进制位0000 0101

  • bSize=1:值为1个字节
  • bType=1:表示全局条目;
  • bTag=b`0000:表示Usage Page,条目的值为0x09,表示USAGE_PAGE (Button)
4.2.3 例3

例如一个400DPI的鼠标,它的报告描述符的参数为:

参数
Logical Minimum -127
Logical Maximum 127
Physical Minimum -3175
Physical Maximum 3175
Unit Exponent -4
Unit Inches

那么它的分辨率计算公式为:

Resolution = (127-(-127)) / ((3175-(-3175)) * 10^-4) = 400 counts per inch

dpidots per inch的缩写,意思是每英寸的像素数。cpicount per inch的缩写,意思是每英寸的采样率。

dpicpi都可以用来表示鼠标的分辨率,但是dpi反应的是个静态指标,用在打印机或扫描仪上显得更为合适。由于鼠标移动是个动态的过程,用cpi来表示鼠标的分辨率更为恰当。
当我们把鼠标向左移动一英寸时,400cpi的鼠标会向计算机发出400左信号,而800cpi的鼠标就发送800次。做个假设,我们把鼠标移动1/800英寸,那么800cpi的鼠标会向计算机传送一次移动信号,而400cpi的鼠标却没有反应,我们必须再移动1/800英寸它才会传送移动信号。

4.2.4 Usage Page

Usage Page的值在HID Usage Pages Tables(Usage选项表文档)中有定义:

Page ID Page Name
0 Undefined
1 Generic Desktop Controls
2 Simulation Controls
3 VR Controls
4 Sport Controls
5 Game Controls
6 Generic Device Controls
7 Keyboard/Keypad
8 LEDs
9 Button
0A Ordinal
0B Telephony
0C Consumer
0D Digitizer
0E Reserved
0F PID Page
10 Unicode
11-13 Reserved
14 Alphanumeric Display
15-3f Reserved
40 Medical Instruments
41-7F Reserved
80-83 Monitor pages
84-87 Power pages
88-8B Reserved
8C Bar Code Scanner page
8D Scale page
8E Magnetic Stripe Reading (MSR) Devices
8F Reserved Point of Sale pages
FF00~FFFF Vendor-defined(厂商自定义)

4.3 局部条目

Local item tag 描述
Usage 0000 HID Usage Pages Tables(Usage选项表文档)
Usage Minimum 0001 定义Usage实例的起始值
Usage Maximum 0010 定义Usage实例的结束值。
起始值 - 结束值定义了一个连续范围,这个范围内都是实例,举例:
Usage Minimum(1),Usage Minimum(3)等效于Usage(1),Usage(2),Usage(3)
Designator Index 0011 确定控件使用的主体部分。Index指向Physical描述符中的一个指示符。
Designator Minimum 0100 定义与数组或位图关联的开始指示符的索引
Designator Maximum 0101 定义与数组或位图关联的结束指示符的索引。
String Index 0111 String描述符的String索引;允许将字符串与特定项或控件关联。
String Minimum 1000 指定将一组连续字符串分配给数组或位图中的控件时的第一个字符串索引。
String Maximum 1001 指定将一组连续字符串分配给数组或位图中的控件时的最后一个字符串索引
Delimiter 1010 定义一组局部项的开始或结束(1 = open set, 0 = close set)
4.3.1 例1
0x09, 0x02,  // USAGE (Mouse)

key转换为二进制位0000 1001

  • bSize=1:值为1个字节
  • bType=2:表示局部条目;
  • bTag=b`0000:表示Usage,条目的值为0x02,表示USAGE (Mouse)
4.3.2 例2
0x09, 0x01,  //   USAGE (Pointer)

key转换为二进制位0000 1001

  • bSize=1:值为1个字节
  • bType=2:表示局部条目;
  • bTag=b`0000:表示Usage,条目的值为0x01,表示USAGE (Pointer)

如果将Usage Page看做是一级分类,Usage则是二级分类。

4.3.3Generic Desktop Page(0x01)

USAGE_PAGE (Generic Desktop)Usage的值定义:

Usage ID Usage Name
0 Undefined
1 Pointer
2 Mouse
3 Reserved
4 Joystick
5 Game Pad
6 Keyboard
7 Keypad
8 Multi-axis Controller
9 Tablet PC System Controls
0A-2F Reserved
30 X
31 Y
32 Z
33 Rx
34 Ry
35 Rz
36 Slider
37 Dial
38 Wheel
39 Hat switch
3A Counted Buffer
3B Byte Count
3C Motion Wakeup
3D Start OOC
3E Select OOC
3F Reserved
40 Vx
41 Vy
42 Vz
43 Vbrx
44 Vbry
45 Vbrz
46 Vno
47 Feature Notification
48 Resolution Multiplier
49-7F Reserved
80 System Control
81 System Power Down
82 System Sleep
83 System Wake Up
84 System Context Menu
85 System Main Menu
86 System App Menu
87 System Menu Help
88 System Menu Exit
89 System Menu Select
8A System Menu Right
8B System Menu Left
8C System Menu Up
8D System Menu Down
8E System Cold Restart
8F System Warm Restart
90 D-pad Up
91 D-pad Down
92 D-pad Right
93 D-pad Left
94-9F Reserved
A0 System Dock
A1 System Undock
A2 System Setup
A3 System Break
A4 System Debugger Break
A5 Application Break
A6 Application Debugger Break
A7 System Speaker Mute
A8 System Hibernate
A9-AF Reserved
B0 System Display Invert
B1 System Display Internal
B2 System Display External
B3 System Display Both
B4 System Display Dual
B5 System Display Toggle Int/Ext
B6 System Display Swap rimary/Secondary
B7 System Display LCD Autoscale
B8-FFFF Reserved
4.3.4Button Page(0x09)

USAGE_PAGE (Button)Usage的值定义:

Usage ID (Hex) Usage Name
00 No button pressed
01 Button 1 (primary/trigger)
02 Button 2 (secondary)
03 Button 3 (tertiary)
04 Button 4
... ...
FFFF Button 65535

五、USB触摸屏数据包分析

我们之前说过usbmon只抓取事务中的数据包,不会抓取令牌包和握手包;下面是我点击USB触摸屏通过usbmon 抓取到的数据包:

root@SOM-RK3399v2:/# cat /sys/kernel/debug/usb/usbmon/1u | grep "1:004"
ffffffc0c88dab00 1925763364 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925763683 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925775309 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925775578 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925787174 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925787301 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925800237 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925800380 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925811243 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925811395 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925821178 C Ii:1:004:2 0:1 52 = 01000075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925821328 S Ii:1:004:2 -115:1 52 <
ffffffc0c88dab00 1925822163 C Ii:1:004:2 0:1 52 = 01000075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
ffffffc0c88dab00 1925822309 S Ii:1:004:2 -115:1 52 <

5.1 数据包格式

下面从左到右分析这些字段代表的含义:URB标签 时间戳 事件类型 地址 URB状态 数据包的长度 数据标签 数据流。

5.1.1 URB Tag - URB标签

该字段表示驱动中定义的struct urb结构体变量在内核空间的地址,可以使用该字段区分不同的URB数据包。

URB标签字段的长度和系统的位数相同,以64为系统为例,该字段的长度为8个字节。

5.1.2 Timestamp - 时间戳

该字段表示的是时间戳,单位是微秒。1微秒 = 10^(-6)秒。

该时间是由下面的mon_get_timestamp函数获取的,使用ktime_get_ts64获取的时间位与上了0xFFF,因此usbmon显示的秒数范围为0 ~ 4096s;

// drivers/usb/mon/mon_text.c
static inline unsigned int mon_get_timestamp(void)
{
        struct timespec64 now;
        unsigned int stamp;

        ktime_get_ts64(&now);  // 获取当前时间
        stamp = now.tv_sec & 0xFFF;  /* 2^32 = 4294967296. Limit to 4096s. */
        stamp = stamp * USEC_PER_SEC + now.tv_nsec / NSEC_PER_USEC;   //USEC_PER_SEC=1000000 NSEC_PER_USEC=1000
        return stamp;
}
5.1.3 Event Type - 事件类型

事件类型有三种:

  • S - submission,向USB Controller提交URB
  • C - callbackURB提交完成后的回调;
  • E - submission error,向usb controller提交URB发生错误;
5.1.4 Address word - 地址

这个字段包含4部分,各个部分之间使用分号隔开,这4部分分别是URB类型及传输方向、USB总线号、USB设备地址端点号。

Ii:1:004:2
|  |  |  |
|  |  |  |__________ 端口号
|  |  |_____________ USB设备地址  
|  |________________ USB总线号
|___________________ URB类型及传输方向

URB类型及传输方向:USB有四种传输方式,分别是控制传输、批量传输、等时传输和中断传输。USB数据的传输方向是以USB主机端为参考对象的,USB主机向USB设备发送数据那么传输方向就是OutputUSB主机读取USB设备的数据那么传输方向就是Input

    Ci Co   Control input and output
    Zi Zo   Isochronous input and output
    Ii Io   Interrupt input and output
    Bi Bo   Bulk input and output

USB总线号:该字段表示USB总线号,每个USB Controller都有一条对应的USB总线,使用USB总线号区分它们,USB设备可以挂接到某条总线上;

USB设备地址:该字段表示USB设备的地址,每一个USB设备经过枚举后在USB总线都有一个唯一的地址;

端点号:表明该次数据传输是Input/Output到设备的哪个端点。上图中该字段是2,就表示这次数据传输使用的是设备的端点2。

5.1.5 URB Status word - URB状态

这个字段有两种表示形式: 

  • s + 一串数字:
  • 一串以分号间隔的数字(或单个数字)构成的,这串数字包含下面几个部分:URB statusintervalstart frameerror count。特别注意一点,该字段不同于 地址字段,对于不同的传输方式这几部分是可选的,并非所有部分都是必须的。

下图是不同的传输方式包含的信息;

img

下面分析不同的传输方式所包含的信息:

(1) 批量传输:只包含URB status这个字段,它对应着struct urb结构体中的status成员变量,表示URB的状态。URB status仅仅对事件类型中的Callback有意义,对于Submission是无意义的,之所以这么做是为了统一格式,方便使用脚本分析usbmon的数数据;

(2) 中断传输:URB statusIntervalURB status见前面的分析,Interval表示该URB对端点轮询的间隔时间;

(3) 等时传输:URB statusIntervalstart frameerror count。等时传输包含了所有部分,start frameerror count 是等时传输所特有的字段;

(4) 控制传输:控制传输在提交时(S:submission)这个字段是s,这里的s后面紧跟的数据是控制传输的建立过程主机发送的数据包(Setup packet),可以参考前面控制传输的示意图。控制传输在回调时(C:callback),这个字段代表的是URB status

img

该字段从左到右的格式如下,括号中的数字表示该部分占用的字节大小:

bmRequestType(1) + bRequest(1) + wvalue(2) + wIndex(2) + wLength(2)

每个字段的含义可以在USB2.0规范中找到,这部分与USB的标准请求等相关。

5.1.6 Data Length - 数据包的长度

对于S(Submission)Data Length字段是主机请求发送/读取的数据长度,但是设备并不一定能够接收/发送主机请求的数据长度。实际接收/发送的数据长度在C(Callback)中的Data Length字段。

ffffffc0c88dab00 1925763683 S Ii:1:004:2 -115:1 52 <
							   |__ 输入		    |____ 请求读取的长度							
ffffffc0c88dab00 1925775309 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000
                               |__ 输入       |_______ 实际读取的长度 

这里显示我们实际读取的长度为52,但是在=之后的数据长度并没有52,很奇怪。

5.1.7 Data tag - 数据标签

数据标签有三种:

  • =:后面紧跟数据流;

  • > :表示这是一次Output数据传输;

  • <:表示这是一次Input数据传输;

5.1.8 Data words follow - 数据流

这个字段就是一个事务中的数据包,我们平时分析usbmon抓取的数据包,也主要是看这个字段。注意一点,这个字段实际显示的数据 <= Data Length的值。

5.2 解析HID报告描述符

5.2.1 获取报告描述符

在分析USB触摸屏数据包之前,我们首先需要获取到USB触摸屏设备的报告描述符;

root@SOM-RK3399v2:/#  cat /sys/kernel/debug/hid/0003\:1A86\:E5E3.0007/rdesc
05 0d 09 04 a1 01 85 01 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 07 81 01 75 08 09 51 95 01 81 02 05 01 26 00 10 75 10 55 0e 65 11 09 30 35 00 46 79 08 81 02 26 00 10 46 4c 05 09 31 81 02 05 0d 09 48 81 02 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 07 81 01 75 08 09 51 95 01 81 02 05 01 26 00 10 75 10 55 0e 65 11 09 30 35 00 46 79 08 81 02 26 00 10 46 4c 05 09 31 81 02 05 0d 09 48 81 02 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 07 81 01 75 08 09 51 95 01 81 02 05 01 26 00 10 75 10 55 0e 65 11 09 30 35 00 46 79 08 81 02 26 00 10 46 4c 05 09 31 81 02 05 0d 09 48 81 02 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 07 81 01 75 08 09 51 95 01 81 02 05 01 26 00 10 75 10 55 0e 65 11 09 30 35 00 46 79 08 81 02 26 00 10 46 4c 05 09 31 81 02 05 0d 09 48 81 02 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 07 81 01 75 08 09 51 95 01 81 02 05 01 26 00 10 75 10 55 0e 65 11 09 30 35 00 46 79 08 81 02 26 00 10 46 4c 05 09 31 81 02 05 0d 09 48 81 02 c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 95 07 81 01 75 08 09 51 95 01 81 02 05 01 26 00 10 75 10 55 0e 65 11 09 30 35 00 46 79 08 81 02 26 00 10 46 4c 05 09 31 81 02 05 0d 09 48 81 02 c0 05 0d 27 ff ff 00 00 75 10 95 01 09 56 81 02 09 54 15 00 25 7f 95 01 75 08 81 02 85 02 09 55 95 01 25 0a b1 02 85 03 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0

其中:

  • 0003描述的是hid类设备,对于hid类设备,接口描述符的bInterfaceClass字段值固定为0x03
  • 1A86为我使用的USB触摸屏的idVendor
  • E5E3为我使用的USB触摸屏的idProduct
  • 0007:具体含义还不是特别清楚;
5.2.2 解析报告描述符

根据之前介绍的HID报告描述符的规则描述,我们解析USB触摸屏的报告描述符;

0x05, 0x0d,    // USAGE_PAGE (Digitizer)
0x09, 0x04,    // USAGE (Touch Screen)
0xa1, 0x01,    // COLLECTION (Application)  
	/*  一、这个报告描述符值包含3个报告,第一个报告Report ID为1*/
    0x85, 0x01,    // Report ID (1)  该报告对应的ID是1
	
	/* 1.1、描述第1个触控点 */
    0x09, 0x22,    // USAGE (Finger)  
    0xa1, 0x02,    // COLLECTION (Physical)  下面所包含的是对指针的解释
		/* 1.1.1. 下面定义的是用途Digitizers.TipSwitch,占用1个字节 */
		0x09, 0x42,    // USAGE (Tip Switch)
        // 使用1位表示触摸点,值0或1,表示松开和按下
        0x15, 0x00,    // LOGICAL_MINIMUM (0)    
        0x25, 0x01,    // LOGICAL_MAXIMUM (1)
        // 有1个1位,即用1bit表示Digitizers.TipSwitch
        0x75, 0x01,    // REPORT_SIZE (1)  
        0x95, 0x01,    // REPORT_COUNT (1) 
        // 将这1个位加入本报告的数据中,这1位是可读写的绝对值
        0x81, 0x02,    // INPUT (Data,Var,Abs)
        0x95, 0x07,    // REPORT_COUNT (7)  这里7位和上面的1位组成1个字节
        0x81, 0x01,    // INPUT (Con,Arr,Abs)

		/* 1.1.2. 下面定义的是用途Digitizers.ContactID,占用1个字节 */
        0x75, 0x08,    // REPORT_SIZE (8)
		0x09, 0x51,    // USAGE (Contact Identifier)
		0x95, 0x01,    // REPORT_COUNT (1)  
        0x81, 0x02,    // INPUT (Data,Var,Abs)

	   /* 1.1.3. 下面定义的是用途GenericDesktop.X,占用2个字节 */
       0x05, 0x01,    // USAGE_PAGE (Generic Desktop)
       0x26, 0x00, 0x10,   // LOGICAL_MAXIMUM (0x1000 4096)
       0x75, 0x10,    // REPORT_SIZE (16)  
       0x55, 0x0e,    // UNIT_EXPONENT(-2)
	   0x65, 0x11,    // UNIT(SI Linear : Centimeter)
	   0x09, 0x30,    // Usage (X)
	   0x35, 0x00,    // PHYSICAL_MINIMUM (0)
	   0x46, 0x79, 0x08,   // PHYSICAL_MAXIMUM (0X0879 2169)
       0x81, 0x02,    // INPUT (Data,Var,Abs)

	   /* 1.1.4. 下面定义的是用途GenericDesktop.Y,占用2个字节 */
       0x26, 0x00, 0x10,  // LOGICAL_MAXIMUM (0x1000 4096)  
       0x46, 0x4c, 0x05,  // PHYSICAL_MAXIMUM (0X054C 1356)
       0x09, 0x31,   // Usage (Y)
       0x81, 0x02,    // INPUT (Data,Var,Abs)
 
	   /* 1.1.5. 下面定义的是用途Digitizers.Width,占用1个字节 */
       0x05, 0x0d,   // USAGE_PAGE (Digitizer)
       0x09, 0x48,   // Usage (Width)
       0x81, 0x02,   // INPUT (Data,Var,Abs)
    0xc0,   // End Collection

	/* 1.2、描述第2个触控点 */
    0x09, 0x22,    // USAGE (Finger)  
    0xa1, 0x02,    // COLLECTION (Physical)  下面所包含的是对指针的解释
		/* 1.2.1. 下面定义的是用途Digitizers.TipSwitch,占用1个字节 */
       0x09, 0x42,   // USAGE (Tip Switch)
	   // 使用1位表示触摸点,值0或1,表示松开和按下
       0x15, 0x00,   // LOGICAL_MINIMUM (0) 
       0x25, 0x01,   // LOGICAL_MAXIMUM (1)
       0x75, 0x01,   // REPORT_SIZE (1)  
       0x95, 0x01,   // REPORT_COUNT (1)
	   // 将这1个位加入本报告的数据中,这1位是可读写的绝对值
       0x81, 0x02,   // INPUT (Data,Var,Abs)
       0x95, 0x07,   // REPORT_COUNT (7)  这里7位和上面的1位组成1个字节
       0x81, 0x01,   // INPUT (Con,Arr,Abs)

       /* 1.2.2. 下面定义的是用途Digitizers.ContactID,占用1个字节 */
       0x75, 0x08,   // REPORT_SIZE (8)
       0x09, 0x51,   // USAGE (Contact Identifier)
       0x95, 0x01,   // REPORT_COUNT (1)  
       0x81, 0x02,   // INPUT (Data,Var,Abs)

       /* 1.2.3. 下面定义的是用途GenericDesktop.X,占用2个字节 */
       0x05, 0x01,   // USAGE_PAGE (Generic Desktop)
       0x26, 0x00, 0x10,  // LOGICAL_MAXIMUM (0x1000 4096)
       0x75, 0x10,   // REPORT_SIZE (16)  
       0x55, 0x0e,   // UNIT_EXPONENT(-2)
       0x65, 0x11,   // UNIT(SI Linear : Centimeter)
       0x09, 0x30,   // Usage (X)
       0x35, 0x00,   // PHYSICAL_MINIMUM (0)
       0x46, 0x79, 0x08,  // PHYSICAL_MAXIMUM (0X0879 2169)
       0x81, 0x02,   // INPUT (Data,Var,Abs)

       /* 1.2.4. 下面定义的是用途GenericDesktop.Y,占用2个字节 */
       0x26, 0x00, 0x10,  // LOGICAL_MAXIMUM (0x1000 4096)  
       0x46, 0x4c, 0x05,  // PHYSICAL_MAXIMUM (0X054C 1356)
       0x09, 0x31,  // Usage (Y)
       0x81, 0x02,  // INPUT (Data,Var,Abs)

       /* 1.2.5. 下面定义的是用途Digitizers.Width,占用1个字节 */
       0x05, 0x0d,  // USAGE_PAGE (Digitizer)
       0x09, 0x48,  // Usage (Width)
       0x81, 0x02,  // INPUT (Data,Var,Abs)
    0xc0,  // End Collection 
    
	/* 1.3、描述第3个触控点 */
    0x09, 0x22,    // USAGE (Finger)  
    0xa1, 0x02,    // COLLECTION (Physical)  下面所包含的是对指针的解释
		/* 1.3.1. 下面定义的是用途Digitizers.TipSwitch,占用1个字节 */
       0x09, 0x42,   // USAGE (Tip Switch)
	   // 使用1位表示触摸点,值0或1,表示松开和按下
       0x15, 0x00,   // LOGICAL_MINIMUM (0) 
       0x25, 0x01,   // LOGICAL_MAXIMUM (1)
       0x75, 0x01,   // REPORT_SIZE (1)  
       0x95, 0x01,   // REPORT_COUNT (1)
	   // 将这1个位加入本报告的数据中,这1位是可读写的绝对值
       0x81, 0x02,   // INPUT (Data,Var,Abs)
       0x95, 0x07,   // REPORT_COUNT (7)  这里7位和上面的1位组成1个字节
       0x81, 0x01,   // INPUT (Con,Arr,Abs)

       /* 1.3.2. 下面定义的是用途Digitizers.ContactID,占用1个字节 */
       0x75, 0x08,   // REPORT_SIZE (8)
       0x09, 0x51,   // USAGE (Contact Identifier)
       0x95, 0x01,   // REPORT_COUNT (1)  
       0x81, 0x02,   // INPUT (Data,Var,Abs)

       /* 1.3.3. 下面定义的是用途GenericDesktop.X,占用2个字节 */
       0x05, 0x01,   // USAGE_PAGE (Generic Desktop)
       0x26, 0x00, 0x10,  // LOGICAL_MAXIMUM (0x1000 4096)
       0x75, 0x10,   // REPORT_SIZE (16)  
       0x55, 0x0e,   // UNIT_EXPONENT(-2)
       0x65, 0x11,   // UNIT(SI Linear : Centimeter)
       0x09, 0x30,   // Usage (X)
       0x35, 0x00,   // PHYSICAL_MINIMUM (0)
       0x46, 0x79, 0x08,  // PHYSICAL_MAXIMUM (0X0879 2169)
       0x81, 0x02,   // INPUT (Data,Var,Abs)

       /* 1.3.4. 下面定义的是用途GenericDesktop.Y,占用2个字节 */
       0x26, 0x00, 0x10,  // LOGICAL_MAXIMUM (0x1000 4096)  
       0x46, 0x4c, 0x05,  // PHYSICAL_MAXIMUM (0X054C 1356)
       0x09, 0x31,  // Usage (Y)
       0x81, 0x02,  // INPUT (Data,Var,Abs)

       /* 1.3.5. 下面定义的是用途Digitizers.Width,占用1个字节 */
       0x05, 0x0d,  // USAGE_PAGE (Digitizer)
       0x09, 0x48,  // Usage (Width)
       0x81, 0x02,  // INPUT (Data,Var,Abs)
    0xc0,  // End Collection 

	/* 1.4、描述第4个触控点 */
    0x09, 0x22,    // USAGE (Finger)  
    0xa1, 0x02,    // COLLECTION (Physical)  下面所包含的是对指针的解释
		/* 1.4.1. 下面定义的是用途Digitizers.TipSwitch,占用1个字节 */
       0x09, 0x42,   // USAGE (Tip Switch)
	   // 使用1位表示触摸点,值0或1,表示松开和按下
       0x15, 0x00,   // LOGICAL_MINIMUM (0) 
       0x25, 0x01,   // LOGICAL_MAXIMUM (1)
       0x75, 0x01,   // REPORT_SIZE (1)  
       0x95, 0x01,   // REPORT_COUNT (1)
	   // 将这1个位加入本报告的数据中,这1位是可读写的绝对值
       0x81, 0x02,   // INPUT (Data,Var,Abs)
       0x95, 0x07,   // REPORT_COUNT (7)  这里7位和上面的1位组成1个字节
       0x81, 0x01,   // INPUT (Con,Arr,Abs)

       /* 1.4.2. 下面定义的是用途Digitizers.ContactID,占用1个字节 */
       0x75, 0x08,   // REPORT_SIZE (8)
       0x09, 0x51,   // USAGE (Contact Identifier)
       0x95, 0x01,   // REPORT_COUNT (1)  
       0x81, 0x02,   // INPUT (Data,Var,Abs)

       /* 1.4.3. 下面定义的是用途GenericDesktop.X,占用2个字节 */
       0x05, 0x01,   // USAGE_PAGE (Generic Desktop)
       0x26, 0x00, 0x10,  // LOGICAL_MAXIMUM (0x1000 4096)
       0x75, 0x10,   // REPORT_SIZE (16)  
       0x55, 0x0e,   // UNIT_EXPONENT(-2)
       0x65, 0x11,   // UNIT(SI Linear : Centimeter)
       0x09, 0x30,   // Usage (X)
       0x35, 0x00,   // PHYSICAL_MINIMUM (0)
       0x46, 0x79, 0x08,  // PHYSICAL_MAXIMUM (0X0879 2169)
       0x81, 0x02,   // INPUT (Data,Var,Abs)

       /* 1.4.4. 下面定义的是用途GenericDesktop.Y,占用2个字节 */
       0x26, 0x00, 0x10,  // LOGICAL_MAXIMUM (0x1000 4096)  
       0x46, 0x4c, 0x05,  // PHYSICAL_MAXIMUM (0X054C 1356)
       0x09, 0x31,  // Usage (Y)
       0x81, 0x02,  // INPUT (Data,Var,Abs)

       /* 1.4.5. 下面定义的是用途Digitizers.Width,占用1个字节 */
       0x05, 0x0d,  // USAGE_PAGE (Digitizer)
       0x09, 0x48,  // Usage (Width)
       0x81, 0x02,  // INPUT (Data,Var,Abs)
    0xc0,  // End Collection 

	/* 1.5、描述第5个触控点 */
    0x09, 0x22,    // USAGE (Finger)  
    0xa1, 0x02,    // COLLECTION (Physical)  下面所包含的是对指针的解释
		/* 1.5.1. 下面定义的是用途Digitizers.TipSwitch,占用1个字节 */
       0x09, 0x42,   // USAGE (Tip Switch)
	   // 使用1位表示触摸点,值0或1,表示松开和按下
       0x15, 0x00,   // LOGICAL_MINIMUM (0) 
       0x25, 0x01,   // LOGICAL_MAXIMUM (1)
       0x75, 0x01,   // REPORT_SIZE (1)  
       0x95, 0x01,   // REPORT_COUNT (1)
	   // 将这1个位加入本报告的数据中,这1位是可读写的绝对值
       0x81, 0x02,   // INPUT (Data,Var,Abs)
       0x95, 0x07,   // REPORT_COUNT (7)  这里7位和上面的1位组成1个字节
       0x81, 0x01,   // INPUT (Con,Arr,Abs)

       /* 1.5.2. 下面定义的是用途Digitizers.ContactID,占用1个字节 */
       0x75, 0x08,   // REPORT_SIZE (8)
       0x09, 0x51,   // USAGE (Contact Identifier)
       0x95, 0x01,   // REPORT_COUNT (1)  
       0x81, 0x02,   // INPUT (Data,Var,Abs)

       /* 1.5.3. 下面定义的是用途GenericDesktop.X,占用2个字节 */
       0x05, 0x01,   // USAGE_PAGE (Generic Desktop)
       0x26, 0x00, 0x10,  // LOGICAL_MAXIMUM (0x1000 4096)
       0x75, 0x10,   // REPORT_SIZE (16)  
       0x55, 0x0e,   // UNIT_EXPONENT(-2)
       0x65, 0x11,   // UNIT(SI Linear : Centimeter)
       0x09, 0x30,   // Usage (X)
       0x35, 0x00,   // PHYSICAL_MINIMUM (0)
       0x46, 0x79, 0x08,  // PHYSICAL_MAXIMUM (0X0879 2169)
       0x81, 0x02,   // INPUT (Data,Var,Abs)

       /* 1.5.4. 下面定义的是用途GenericDesktop.Y,占用2个字节 */
       0x26, 0x00, 0x10,  // LOGICAL_MAXIMUM (0x1000 4096)  
       0x46, 0x4c, 0x05,  // PHYSICAL_MAXIMUM (0X054C 1356)
       0x09, 0x31,  // Usage (Y)
       0x81, 0x02,  // INPUT (Data,Var,Abs)

       /* 1.5.5. 下面定义的是用途Digitizers.Width,占用1个字节 */
       0x05, 0x0d,  // USAGE_PAGE (Digitizer)
       0x09, 0x48,  // Usage (Width)
       0x81, 0x02,  // INPUT (Data,Var,Abs)
    0xc0,  // End Collection 
 
	/* 1.6、描述第6个触控点 */
    0x09, 0x22,    // USAGE (Finger)  
    0xa1, 0x02,    // COLLECTION (Physical)  下面所包含的是对指针的解释
		/* 1.6.1. 下面定义的是用途Digitizers.TipSwitch,占用1个字节 */
       0x09, 0x42,   // USAGE (Tip Switch)
	   // 使用1位表示触摸点,值0或1,表示松开和按下
       0x15, 0x00,   // LOGICAL_MINIMUM (0) 
       0x25, 0x01,   // LOGICAL_MAXIMUM (1)
       0x75, 0x01,   // REPORT_SIZE (1)  
       0x95, 0x01,   // REPORT_COUNT (1)
	   // 将这1个位加入本报告的数据中,这1位是可读写的绝对值
       0x81, 0x02,   // INPUT (Data,Var,Abs)
       0x95, 0x07,   // REPORT_COUNT (7)  这里7位和上面的1位组成1个字节
       0x81, 0x01,   // INPUT (Con,Arr,Abs)

       /* 1.6.2. 下面定义的是用途Digitizers.ContactID,占用1个字节 */
       0x75, 0x08,   // REPORT_SIZE (8)
       0x09, 0x51,   // USAGE (Contact Identifier)
       0x95, 0x01,   // REPORT_COUNT (1)  
       0x81, 0x02,   // INPUT (Data,Var,Abs)

       /* 1.6.3. 下面定义的是用途GenericDesktop.X,占用2个字节 */
       0x05, 0x01,   // USAGE_PAGE (Generic Desktop)
       0x26, 0x00, 0x10,  // LOGICAL_MAXIMUM (0x1000 4096)
       0x75, 0x10,   // REPORT_SIZE (16)  
       0x55, 0x0e,   // UNIT_EXPONENT(-2)
       0x65, 0x11,   // UNIT(SI Linear : Centimeter)
       0x09, 0x30,   // Usage (X)
       0x35, 0x00,   // PHYSICAL_MINIMUM (0)
       0x46, 0x79, 0x08,  // PHYSICAL_MAXIMUM (0X0879 2169)
       0x81, 0x02,   // INPUT (Data,Var,Abs)

       /* 1.6.4. 下面定义的是用途GenericDesktop.Y,占用2个字节 */
       0x26, 0x00, 0x10,  // LOGICAL_MAXIMUM (0x1000 4096)  
       0x46, 0x4c, 0x05,  // PHYSICAL_MAXIMUM (0X054C 1356)
       0x09, 0x31,  // Usage (Y)
       0x81, 0x02,  // INPUT (Data,Var,Abs)

       /* 1.6.5. 下面定义的是用途Digitizers.Width,占用1个字节 */
       0x05, 0x0d,  // USAGE_PAGE (Digitizer)
       0x09, 0x48,  // Usage (Width)
       0x81, 0x02,  // INPUT (Data,Var,Abs)
    0xc0,  // End Collection 

	/* 1.7. 下面定义的是用途Digitizers.ScanTime,占用2个字节 */
	0x05, 0x0d,  // USAGE_PAGE (Digitizer)
	0x27, 0xff, 0xff, 0x00, 0x00, // LOGICAL_MINIMUM (0x0000FFFF 65535) 
    0x75, 0x10,  // REPORT_SIZE (16)    
    0x95, 0x01,  // REPORT_COUNT (1)  
    0x09, 0x56,  // Usage (Scan Time)
    0x81, 0x02,  // INPUT (Data,Var,Abs)

    /* 1.8. 下面定义的是用途Digitizers.ContactCount,占用1个字节 */
    0x09, 0x54,  // Usage (Contact Count)
    0x15, 0x00,  // LOGICAL_MINIMUM (0)    
    0x25, 0x7f,  // LOGICAL_MAXIMUM (127)
    0x95, 0x01,  // REPORT_COUNT (1)  
    0x75, 0x08,  // REPORT_SIZE (8)    
    0x81, 0x02,  // INPUT (Data,Var,Abs)

	/*  二、第二个报告Report ID为2*/
    0x85, 0x02,  // Report ID (2)  该报告对应的ID是2

	/* 2.1. 下面定义的是用途Digitizers.ContactMaximumNumber,占用1个字节 */
    0x09, 0x55,  // Usage (Contact Count Maximum)
    0x95, 0x01,  // REPORT_COUNT (1)  
    0x25, 0x0a,  // LOGICAL_MAXIMUM (10)
    0xb1, 0x02,  // FEATURE (Data,Var,Abs)

	/*  三、第3个报告Report ID为3 */
    0x85, 0x03,  // Report ID (3)  该报告对应的ID是3

	/* 3.1. 下面定义的是用途ff00.00c5,占用256个字节 */
    0x06, 0x00, 0xff, // USAGE_PAGE (Vendor-defined 厂商自定义)
    0x09, 0xc5,  // USAGE (ff00.00c5)  
    0x15, 0x00,  // LOGICAL_MINIMUM (0) 
    0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (0x00ff 255)
    0x75, 0x08,  // REPORT_SIZE (8) 
    0x96, 0x00, 0x01,  // REPORT_COUNT (0x0100 256)  
    0xb1, 0x02, // FEATURE (Data,Var,Abs) 
0xc0   // End Collection

去除上面的数字,可以得到:

   INPUT(1)[INPUT]   // Report ID (1)
    Field(0)     // 第1个字段,占用1位 bit0表示第1个触触摸点是否按下
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.TipSwitch
      Logical Minimum(0)
      Logical Maximum(1)
      Report Size(1)
      Report Count(1)
      Report Offset(0)  // 偏移位
      Flags( Variable Absolute )
    Field(1)   // 第2个字段,占用1个字节  表示触摸点标识符,用于跟踪和区分不同的触摸点。这对于支持多点触控的设备特别重要
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.ContactID
      Logical Minimum(0)
      Logical Maximum(1)
      Report Size(8)
      Report Count(1)
      Report Offset(8)  // 偏移位
      Flags( Variable Absolute )
    Field(2)  // 第3个字段,占用2个字节,表示X坐标(绝对值)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.X
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(2169)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(16)
      Flags( Variable Absolute )
    Field(3)  // 第4个字段,占用2个字节,表示Y坐标(绝对值)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.Y
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(32)
      Flags( Variable Absolute )
    Field(4)    // 第5个字段,占用2个字节,表示触摸笔宽度
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.Width
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(48)
      Flags( Variable Absolute )
    Field(5)    // 字段5~字段9 同上,用于描述第二个触摸点
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.TipSwitch
      Logical Minimum(0)
      Logical Maximum(1)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(1)
      Report Count(1)
      Report Offset(64)
      Flags( Variable Absolute )
    Field(6)   
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.ContactID
      Logical Minimum(0)
      Logical Maximum(1)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(8)
      Report Count(1)
      Report Offset(72)
      Flags( Variable Absolute )
    Field(7)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.X
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(2169)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(80)
      Flags( Variable Absolute )
    Field(8)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.Y
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(96)
      Flags( Variable Absolute )
    Field(9)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.Width
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(112)
      Flags( Variable Absolute )
    Field(10)  // 字段10~字段14 同上,用于描述第三个触摸点
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.TipSwitch
      Logical Minimum(0)
      Logical Maximum(1)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(1)
      Report Count(1)
      Report Offset(128)
      Flags( Variable Absolute )
    Field(11)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.ContactID
      Logical Minimum(0)
      Logical Maximum(1)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(8)
      Report Count(1)
      Report Offset(136)
      Flags( Variable Absolute )
    Field(12)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.X
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(2169)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(144)
      Flags( Variable Absolute )
    Field(13)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.Y
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(160)
      Flags( Variable Absolute )
    Field(14)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.Width
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(176)
      Flags( Variable Absolute )
    Field(15)    // 字段15~字段19 同上,用于描述第四个触摸点
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.TipSwitch
      Logical Minimum(0)
      Logical Maximum(1)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(1)
      Report Count(1)
      Report Offset(192)
      Flags( Variable Absolute )
    Field(16)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.ContactID
      Logical Minimum(0)
      Logical Maximum(1)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(8)
      Report Count(1)
      Report Offset(200)
      Flags( Variable Absolute )
    Field(17)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.X
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(2169)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(208)
      Flags( Variable Absolute )
    Field(18)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.Y
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(224)
      Flags( Variable Absolute )
    Field(19)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.Width
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(240)
      Flags( Variable Absolute )
    Field(20)   // 字段20~字段14 同上,用于描述第五个触摸点
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.TipSwitch
      Logical Minimum(0)
      Logical Maximum(1)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(1)
      Report Count(1)
      Report Offset(256)
      Flags( Variable Absolute )
    Field(21)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.ContactID
      Logical Minimum(0)
      Logical Maximum(1)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(8)
      Report Count(1)
      Report Offset(264)
      Flags( Variable Absolute )
    Field(22)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.X
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(2169)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(272)
      Flags( Variable Absolute )
    Field(23)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.Y
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(288)
      Flags( Variable Absolute )
    Field(24)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.Width
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(304)
      Flags( Variable Absolute )
    Field(25)  // 字段25~字段29 同上,用于描述第六个触摸点
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.TipSwitch
      Logical Minimum(0)
      Logical Maximum(1)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(1)
      Report Count(1)
      Report Offset(320)
      Flags( Variable Absolute )
    Field(26)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.ContactID
      Logical Minimum(0)
      Logical Maximum(1)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(8)
      Report Count(1)
      Report Offset(328)
      Flags( Variable Absolute )
    Field(27)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.X
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(2169)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(336)
      Flags( Variable Absolute )
    Field(28)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        GenericDesktop.Y
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(352)
      Flags( Variable Absolute )
    Field(29)
      Logical(Digitizers.Finger)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.Width
      Logical Minimum(0)
      Logical Maximum(4096)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(368)
      Flags( Variable Absolute )
    Field(30)   // 第31个字段,占用2字节 表示检测和更新触摸点状态的时间间隔
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.0056
      Logical Minimum(0)
      Logical Maximum(65535)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(16)
      Report Count(1)
      Report Offset(384)
      Flags( Variable Absolute )
    Field(31)   // 第32个字段,占用1个字节 表示同时触摸的触摸点数量
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.ContactCount
      Logical Minimum(0)
      Logical Maximum(127)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(8)
      Report Count(1)
      Report Offset(400)
      Flags( Variable Absolute )
       
  FEATURE(2)[FEATURE]  // Report ID (2)
    Field(0)
      Application(Digitizers.TouchScreen)
      Usage(1)
        Digitizers.ContactMaximumNumber
      Logical Minimum(0)
      Logical Maximum(10)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(8)
      Report Count(1)
      Report Offset(0)
      Flags( Variable Absolute )
       
  FEATURE(3)[FEATURE]   // Report ID (3)
    Field(0)
      Application(Digitizers.TouchScreen)
      Usage(256)
		ff00.00c5  // 256次
        ......
      Logical Minimum(0)
      Logical Maximum(255)
      Physical Minimum(0)
      Physical Maximum(1356)
      Unit Exponent(-2)
      Unit(SI Linear : Centimeter)
      Report Size(8)
      Report Count(256)
      Report Offset(0)
      Flags( Variable Absolute )

Digitizers.TipSwitch ---> Sync.Report
Digitizers.ContactID ---> Sync.Report
GenericDesktop.X ---> Sync.Report
GenericDesktop.Y ---> Sync.Report
Digitizers.Width ---> Sync.Report
Digitizers.TipSwitch ---> Sync.Report
Digitizers.ContactID ---> Sync.Report
GenericDesktop.X ---> Sync.Report
GenericDesktop.Y ---> Sync.Report
Digitizers.Width ---> Sync.Report
Digitizers.TipSwitch ---> Sync.Report
Digitizers.ContactID ---> Sync.Report
GenericDesktop.X ---> Sync.Report
GenericDesktop.Y ---> Sync.Report
Digitizers.Width ---> Sync.Report
Digitizers.TipSwitch ---> Sync.Report
Digitizers.ContactID ---> Sync.Report
GenericDesktop.X ---> Sync.Report
GenericDesktop.Y ---> Sync.Report
Digitizers.Width ---> Sync.Report
Digitizers.TipSwitch ---> Sync.Report
Digitizers.ContactID ---> Sync.Report
GenericDesktop.X ---> Sync.Report
GenericDesktop.Y ---> Sync.Report
Digitizers.Width ---> Sync.Report
Digitizers.TipSwitch ---> Sync.Report
Digitizers.ContactID ---> Sync.Report
GenericDesktop.X ---> Sync.Report
GenericDesktop.Y ---> Sync.Report
Digitizers.Width ---> Sync.Report
Digitizers.0056 ---> Sync.Report
Digitizers.ContactCount ---> Sync.Report       

通过解析HID报告描述符我们可以当前报告描述符包含了三个报告,报告的ID依次为0x01、0x02、0x03。

其中ID为0x01的报告描述符极其重要,该报告可以用来同时描述6个触摸点,每个触摸点使用8个字节的数据进行描述。

5.2.3 数据包

以报告ID为1的数据包为例,数据包首字节为报告ID,接着就是6个触摸点的描述。由于1个触摸点使用8个字节进行描述,因此字节1~9描述了第一个触摸点:

位7 位6 位5 位4 位3 位2 位1 位0
字节0 报告编号
字节1 第一个触摸点状态
字节2 第一个触摸点标识符
字节3 X坐标低8位(绝对值)
字节4 X坐标高8位(绝对值)
字节5 Y坐标低8位(绝对值)
字节6 Y坐标高8位(绝对值)
字节7 触摸笔宽度低8位
字节8 触摸笔宽度高8位

报告描述符中X坐标的参数:

参数
Logical Minimum 0
Logical Maximum 4096(0x1000)
Physical Minimum 0
Physical Maximum 2169(0x0879 )
Unit Exponent -2
Unit SI Linear : Centimeter

那么它的分辨率计算公式为:

Resolution = (4096-(0)) / ((2169-(0)) * 10^-2) =  188.84

字节9~17描述了第二个触摸点:

位7 位6 位5 位4 位3 位2 位1 位0
字节9 第二个触摸点状态
字节10 第二个触摸点标识符
字节11 X坐标低8位(绝对值)
字节12 X坐标高8位(绝对值)
字节13 Y坐标低8位(绝对值)
字节14 Y坐标高8位(绝对值)
字节15 触摸笔宽度低8位
字节17 触摸笔宽度高8位

因此可以知道ID为1的报告包含实际读取的长度为52个字节:

字节索引 描述
字节0 报告ID(1)
字节1~8 描述第一个触摸点
字节9~16 描述第二个触摸点
字节17~24 描述第三个触摸点
字节25~32 描述第四个触摸点
字节33~40 描述第五个触摸点
字节41~48 描述第六个触摸点
字节49~50 描述检测和更新触摸点状态的时间间隔
字节51 描述触摸点数量

5.3 分析数据包

抓包使用命令:

cat /sys/kernel/debug/usb/usbmon/1u | grep "1:004"

其中的1:004中1表示USB总线编号,004是设备编号,也就是USB触摸屏(1a86:e5e3)。

5.3.1 1个触摸点

1个触摸点时,我们读取到的数据(=之后的才是真正的数据):

ffffffc0c88dab00 1925775309 C Ii:1:004:2 0:1 52 = 01010075 09080930 00000000 00000000 00000000 00000000 00000000 00000000													

第一个字节0x01表示报告ID,然后紧接着8个字节描述第一个触摸点:

1 2 3 4 5 6 7 8
0x01 0x00 0x75 0x09 0x08 0x09 0x30 0x00
第一个触摸点状态 第一个触摸点标识 X坐标低8位 X坐标高8位 Y坐标低8位 Y坐标高8位 触摸笔宽度低8位 触摸笔宽度高8位
被按下 ID为0x00 X坐标为0x0975 X坐标为0x0975 Y坐标为0x0908 Y坐标为0x0908 0x0030 0x0030

移动触摸点测试发现X坐标区间范围为0x0000~0x1000之间,也就是我们报告描述符中配置的;

 Logical Minimum(0)
 Logical Maximum(4096)

移动触摸点测试发现Y坐标区间范围为0x0000~0x1000之间,也就是我们报告描述符中配置的;

 Logical Minimum(0)
 Logical Maximum(4096)
5.3.2 2个触摸点

2个触摸点时,我们读取到的数据(=之后的才是真正的数据):

ffffffc0c88dab00 2543284410 C Ii:1:004:2 0:1 52 = 0101003d 02d50530 000101e1 035d0330 00000000 00000000 00000000 00000000

第一个字节0x01表示报告ID,然后紧接着每8个字节描述1个触摸点:

1 2 3 4 5 6 7 8
0x01 0x00 0x3d 0x02 0xd5 0x05 0x30 0x00
第一个触摸点状态 第一个触摸点标识 X坐标低8位 X坐标高8位 Y坐标低8位 Y坐标高8位 触摸笔宽度低8位 触摸笔宽度高8位
被按下 ID为0x00 X坐标为0x023d X坐标为0x023d Y坐标为0x05d5 Y坐标为0x05d5 0x0030 0x0030
9 11 12 13 14 15 16 17
0x01 0x01 0xe1 0x03 0x5d 0x03 0x30 0x00
第二个触摸点状态 第二个触摸点标识 X坐标低8位 X坐标高8位 Y坐标低8位 Y坐标高8位 触摸笔宽度低8位 触摸笔宽度高8位
被按下 ID为0x01 X坐标为0x03e1 X坐标为0x03e1 Y坐标为0x035d Y坐标为0x035d 0x0030 0x0030
5.3.3 3个触摸点

3个触摸点时,我们读取到的数据(=之后的才是真正的数据):

ffffffc0f087c700 796434242 C Ii:1:004:2 0:1 52 = 01010019 09910630 00010166 043b0b30 000102cc 076e0730 00000000 00000000

第一个字节0x01表示报告ID,然后紧接着每8个字节描述1个触摸点:

1 2 3 4 5 6 7 8
0x01 0x00 0x19 0x09 0x91 0x06 0x30 0x00
第一个触摸点状态 第一个触摸点标识 X坐标低8位 X坐标高8位 Y坐标低8位 Y坐标高8位 触摸笔宽度低8位 触摸笔宽度高8位
被按下 ID为0x00 X坐标为0x0919 X坐标为0x0919 Y坐标为0x0691 Y坐标为0x0691 0x0030 0x0030
9 11 12 13 14 15 16 17
0x01 0x01 0x66 0x04 0x3b 0x0b 0x30 0x00
第二个触摸点状态 第二个触摸点标识 X坐标低8位 X坐标高8位 Y坐标低8位 Y坐标高8位 触摸笔宽度低8位 触摸笔宽度高8位
被按下 ID为0x01 X坐标为0x0466 X坐标为0x0466 Y坐标为0x0b3b Y坐标为0x0b3b 0x0030 0x0030
18 19 20 21 22 23 24 25
0x01 0x02 0xcc 0x07 0x6e 0x07 0x30 0x00
第三个触摸点状态 第三个触摸点标识 X坐标低8位 X坐标高8位 Y坐标低8位 Y坐标高8位 触摸笔宽度低8位 触摸笔宽度高8位
被按下 ID为0x02 X坐标为0x07cc X坐标为0x07cc Y坐标为0x076e Y坐标为0x076e 0x0030 0x0030

同理可以解析到第4个触摸点,但是抓取到的真正的数据只有32个字节,小于数据长度52,因此这里是没法解析第5、6个触摸点。我们会在后面的文章介绍如何通过libusb库实现完整USB数据包的抓取。

参考文章

[1] LinuxUSB抓包工具UsbMon的使用和包数据格式解析

[2] 使用usbmon抓取usb总线上的数据

[3] 详解usbmon抓取的log各字段的含义

[4] debian11 modprobe:未找到命令

[5] Ubuntu开机自动加载驱动模块

[6] Documentation/usb/usbmon.txt

[7] USB鼠标HID描述符以及数据格式

[8] HID报告描述

[9] Device Class Definition for human interface device (HID)

[10] Universal Serial Bus HID Usage Tables

[11] HID键盘设备数据抓包分析实践

posted @ 2023-10-07 23:23  大奥特曼打小怪兽  阅读(713)  评论(0编辑  收藏  举报
如果有任何技术小问题,欢迎大家交流沟通,共同进步