Rockchip RK3399 - linux通过usbmon抓取usb数据包
----------------------------------------------------------------------------------------------------------------------------
开发板 :SOM-RK3399
核心板+定制底板
eMMC
:16GB
LPDDR3
:4GB
显示屏 :15.6
英寸HDMI
接口显示屏
u-boot
:2017.09
linux
:4.19
----------------------------------------------------------------------------------------------------------------------------
注意:本节介绍的内容基于《Rockchip RK3399
- 移植uboot 2017.09 & linux 4.19
(友善之家脚本方式)》中移植的运行环境:内核版本4.19.193
以及debian 11
根文件系统。
一、安装usbmon
usbmon
即usb 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 重启验证
上述操作完成后,重启系统,使用 lsmod
或 cat /proc/modules
、ls /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=1a86
,USB
总线编号为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的硬件端口连接了一个hub
,hub
编号为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 hub
(1d6b:0002
),1个4-Port hub
(14cd: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
包来传输数据,必须按照一定的关系把这些不同的包组织成事务才能传输数据。
那么事务是什么呢? 事务通常由三个包组成:令牌包、数据包和握手包。
注意:usbmon
只抓取事务中的数据包,不会抓取令牌包和握手包。
3.3 USB
传输类型
USB
协议规定了4种传输类型:批量传输、等时传输、中断传输和控制传输。其中;
- 批量传输、等时传输、中断传输每传输一次数据都是一个事务;
- 控制传输包括三个过程,建立过程和状态过程分别是一个事务,数据过程可能包含多个事务。
3.3.1 批量传输
批量传输用于传输大量数据。USB
协议不保证这些数据传输可以在特定的时间内完成,但保证数据的准确性。如果总线上的带宽不足以发送整个批量包,则将数据拆分为多个包传输。批量传输数据可靠,但实时性较低。如USB
硬盘、打印机等设备就采用的是批量传输方式;
3.3.2 等时传输
等时传输也可以传输大量数据,但数据的可靠性无法保证。采用等时传输的USB
设备更加注重保持一个恒定的数据传输速度,对数据的可靠性要求不高。如USB
摄像头就使用的是等时传输方式;
3.3.3 中断传输
当USB
主机请求USB
设备传输数据时,中断传输以一个固定的速率传送少量的数据。中断端点的数据传输方式为中断传输,数据传输可靠,实时性高,这里的中断并不是USB
设备产生中断,而是USB
主机每隔一个固定的时间主动查询USB
设备是否有数据要传输,以轮询的方式提高实时性。如USB
鼠标采用的是中断传输;
3.3.4 控制传输
控制传输用于配置设备、获取设备信息、发送命令到设备、获取设备的状态。每个USB
设备都有端点0的控制端点,当USB
设备插入到USB
主机拓扑网络中时,USB
主机就通过端点0与USB
设备通信,对USB
设备进行配置,便于后续的数据传输。USB
协议保证控制传输有足够的带宽。控制传输可靠,时间有保证,但传输的数据量不大。如USB
设备的枚举过程就采用的是控制传输;
四、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
报告描述符由若干个条目组成,某个条目由key
、value
对组成。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:保留;
-
-
bTag
:bTag
与类型对象,每种类型有很多不同的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 |
下面对Data
、Variable
等的意思作一下解释;
Data
:表示是一个可写的数据;Constant
:表示是一个只读的数据;Aarray
: 表示数据里的值代表一个Usage
,Report Size
表示位数,即Report Size
的存储单元里的值是Usage
的Index
。Report 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
dpi
是dots per inch
的缩写,意思是每英寸的像素数。cpi
是count per inch
的缩写,意思是每英寸的采样率。
dpi
和cpi
都可以用来表示鼠标的分辨率,但是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 - callback
,URB
提交完成后的回调;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
设备发送数据那么传输方向就是Output
,USB
主机读取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 status
、interval
、start frame
和error count
。特别注意一点,该字段不同于地址
字段,对于不同的传输方式这几部分是可选的,并非所有部分都是必须的。
下图是不同的传输方式包含的信息;
下面分析不同的传输方式所包含的信息:
(1) 批量传输:只包含URB status
这个字段,它对应着struct urb
结构体中的status
成员变量,表示URB
的状态。URB status
仅仅对事件类型中的Callback
有意义,对于Submission
是无意义的,之所以这么做是为了统一格式,方便使用脚本分析usbmon
的数数据;
(2) 中断传输:URB status
和Interval
,URB status
见前面的分析,Interval
表示该URB
对端点轮询的间隔时间;
(3) 等时传输:URB status
、Interval
、start frame
和error count
。等时传输包含了所有部分,start frame
和error count
是等时传输所特有的字段;
(4) 控制传输:控制传输在提交时(S:submission
)这个字段是s
,这里的s
后面紧跟的数据是控制传输的建立过程主机发送的数据包(Setup packet
),可以参考前面控制传输的示意图。控制传输在回调时(C:callback
),这个字段代表的是URB status
。
该字段从左到右的格式如下,括号中的数字表示该部分占用的字节大小:
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] Linux
下USB
抓包工具UsbMon
的使用和包数据格式解析
[5] Ubuntu
开机自动加载驱动模块
[6] Documentation/usb/usbmon.txt
[8] HID
报告描述
[9] 《Device Class Definition for human interface device (HID)
》
[10] 《Universal Serial Bus HID Usage Tables
》
[11] HID
键盘设备数据抓包分析实践