Skip to content

Commit c486bc2

Browse files
committed
Print descriptive USB class info
1 parent c89e99b commit c486bc2

File tree

2 files changed

+258
-6
lines changed

2 files changed

+258
-6
lines changed

examples/enumerate/src/main/java/net/codecrete/usb/examples/Enumerate.java

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
import net.codecrete.usb.*;
1111

12+
import java.util.Optional;
13+
1214
/**
1315
* Sample application enumerating connected USB devices.
1416
*/
@@ -30,9 +32,12 @@ private static void printDevice(USBDevice device) {
3032
System.out.printf(" Product name: %s%n", device.product());
3133
if (device.serialNumber() != null)
3234
System.out.printf(" Serial number: %s%n", device.serialNumber());
33-
System.out.printf(" Device class: 0x%02x%n", device.classCode());
34-
System.out.printf(" Device subclass: 0x%02x%n", device.subclassCode());
35-
System.out.printf(" Device protocol: 0x%02x%n", device.protocolCode());
35+
System.out.printf(" Device class: 0x%02x", device.classCode());
36+
printInParens(USBClassInfo.lookupClass(device.classCode()));
37+
System.out.printf(" Device subclass: 0x%02x", device.subclassCode());
38+
printInParens(USBClassInfo.lookupSubclass(device.classCode(), device.subclassCode()));
39+
System.out.printf(" Device protocol: 0x%02x", device.protocolCode());
40+
printInParens(USBClassInfo.lookupProtocol(device.classCode(), device.subclassCode(), device.protocolCode()));
3641

3742
for (var intf: device.interfaces())
3843
printInterface(intf);
@@ -41,6 +46,14 @@ private static void printDevice(USBDevice device) {
4146
System.out.println();
4247
}
4348

49+
private static void printInParens(Optional<String> text) {
50+
if (text.isPresent()) {
51+
System.out.printf(" (%s)%n", text.get());
52+
} else {
53+
System.out.println();
54+
}
55+
}
56+
4457
private static void printInterface(USBInterface intf) {
4558
for (var alt : intf.alternates())
4659
printAlternate(alt, intf.number(), alt == intf.alternate());
@@ -54,9 +67,12 @@ private static void printAlternate(USBAlternateInterface alt, int intferaceNumbe
5467
System.out.printf(" Interface %d (alternate %d)%n", intferaceNumber, alt.number());
5568
}
5669

57-
System.out.printf(" Interface class: 0x%02x%n", alt.classCode());
58-
System.out.printf(" Interface subclass: 0x%02x%n", alt.subclassCode());
59-
System.out.printf(" Interface protocol: 0x%02x%n", alt.protocolCode());
70+
System.out.printf(" Interface class: 0x%02x", alt.classCode());
71+
printInParens(USBClassInfo.lookupClass(alt.classCode()));
72+
System.out.printf(" Interface subclass: 0x%02x", alt.subclassCode());
73+
printInParens(USBClassInfo.lookupProtocol(alt.classCode(), alt.subclassCode(), alt.protocolCode()));
74+
System.out.printf(" Interface protocol: 0x%02x", alt.protocolCode());
75+
printInParens(USBClassInfo.lookupProtocol(alt.classCode(), alt.subclassCode(), alt.protocolCode()));
6076

6177
for (var endpoint : alt.endpoints())
6278
printEndpoint(endpoint);
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
//
2+
// Java Does USB
3+
// Copyright (c) 2022 Manuel Bleichenbacher
4+
// Licensed under MIT License
5+
// https://opensource.org/licenses/MIT
6+
//
7+
8+
package net.codecrete.usb.examples;
9+
10+
import java.io.BufferedReader;
11+
import java.io.IOException;
12+
import java.io.StringReader;
13+
import java.util.ArrayList;
14+
import java.util.List;
15+
import java.util.Optional;
16+
17+
/**
18+
* Provides the names of known USB classes, subclasses and protocols.
19+
*/
20+
public class USBClassInfo {
21+
22+
private static final List<ClassCode> classCodes = new ArrayList<>();
23+
private static final List<SubclassCode> subclassCodes = new ArrayList<>();
24+
private static final List<ProtocolCode> protocolCodes = new ArrayList<>();
25+
26+
// List of known device classes, subclasses and
27+
// from http://www.linux-usb.org/usb.ids
28+
private static final String RAW_DATA = """
29+
C 00 (Defined at Interface level)
30+
C 01 Audio
31+
01 Control Device
32+
02 Streaming
33+
03 MIDI Streaming
34+
C 02 Communications
35+
01 Direct Line
36+
02 Abstract (modem)
37+
00 None
38+
01 AT-commands (v.25ter)
39+
02 AT-commands (PCCA101)
40+
03 AT-commands (PCCA101 + wakeup)
41+
04 AT-commands (GSM)
42+
05 AT-commands (3G)
43+
06 AT-commands (CDMA)
44+
fe Defined by command set descriptor
45+
ff Vendor Specific (MSFT RNDIS?)
46+
03 Telephone
47+
04 Multi-Channel
48+
05 CAPI Control
49+
06 Ethernet Networking
50+
07 ATM Networking
51+
08 Wireless Handset Control
52+
09 Device Management
53+
0a Mobile Direct Line
54+
0b OBEX
55+
0c Ethernet Emulation
56+
07 Ethernet Emulation (EEM)
57+
C 03 Human Interface Device
58+
00 No Subclass
59+
00 None
60+
01 Keyboard
61+
02 Mouse
62+
01 Boot Interface Subclass
63+
00 None
64+
01 Keyboard
65+
02 Mouse
66+
C 05 Physical Interface Device
67+
C 06 Imaging
68+
01 Still Image Capture
69+
01 Picture Transfer Protocol (PIMA 15470)
70+
C 07 Printer
71+
01 Printer
72+
00 Reserved/Undefined
73+
01 Unidirectional
74+
02 Bidirectional
75+
03 IEEE 1284.4 compatible bidirectional
76+
ff Vendor Specific
77+
C 08 Mass Storage
78+
01 RBC (typically Flash)
79+
00 Control/Bulk/Interrupt
80+
01 Control/Bulk
81+
50 Bulk-Only
82+
02 SFF-8020i, MMC-2 (ATAPI)
83+
03 QIC-157
84+
04 Floppy (UFI)
85+
00 Control/Bulk/Interrupt
86+
01 Control/Bulk
87+
50 Bulk-Only
88+
05 SFF-8070i
89+
06 SCSI
90+
00 Control/Bulk/Interrupt
91+
01 Control/Bulk
92+
50 Bulk-Only
93+
C 09 Hub
94+
00 Unused
95+
00 Full speed (or root) hub
96+
01 Single TT
97+
02 TT per port
98+
C 0a CDC Data
99+
00 Unused
100+
30 I.430 ISDN BRI
101+
31 HDLC
102+
32 Transparent
103+
50 Q.921M
104+
51 Q.921
105+
52 Q.921TM
106+
90 V.42bis
107+
91 Q.932 EuroISDN
108+
92 V.120 V.24 rate ISDN
109+
93 CAPI 2.0
110+
fd Host Based Driver
111+
fe CDC PUF
112+
ff Vendor specific
113+
C 0b Chip/SmartCard
114+
C 0d Content Security
115+
C 0e Video
116+
00 Undefined
117+
01 Video Control
118+
02 Video Streaming
119+
03 Video Interface Collection
120+
C 58 Xbox
121+
42 Controller
122+
C dc Diagnostic
123+
01 Reprogrammable Diagnostics
124+
01 USB2 Compliance
125+
C e0 Wireless
126+
01 Radio Frequency
127+
01 Bluetooth
128+
02 Ultra WideBand Radio Control
129+
03 RNDIS
130+
02 Wireless USB Wire Adapter
131+
01 Host Wire Adapter Control/Data Streaming
132+
02 Device Wire Adapter Control/Data Streaming
133+
03 Device Wire Adapter Isochronous Streaming
134+
C ef Miscellaneous Device
135+
01 ?
136+
01 Microsoft ActiveSync
137+
02 Palm Sync
138+
02 ?
139+
01 Interface Association
140+
02 Wire Adapter Multifunction Peripheral
141+
03 ?
142+
01 Cable Based Association
143+
05 USB3 Vision
144+
C fe Application Specific Interface
145+
01 Device Firmware Update
146+
02 IRDA Bridge
147+
03 Test and Measurement
148+
01 TMC
149+
02 USB488
150+
C ff Vendor Specific Class
151+
ff Vendor Specific Subclass
152+
ff Vendor Specific Protocol""";
153+
154+
155+
/**
156+
* Provides the name of the specified USB class.
157+
* @param classCode the USB class code
158+
* @return an optional name
159+
*/
160+
public static Optional<String> lookupClass(int classCode) {
161+
loadData();
162+
return classCodes.stream()
163+
.filter((cc) -> cc.classCode == classCode)
164+
.map((cc) -> cc.name)
165+
.findFirst();
166+
}
167+
168+
/**
169+
* Provides the name of the specified USB subclass.
170+
* @param classCode the USB class code
171+
* @param subclassCode the USB subclass code
172+
* @return an optional name
173+
*/
174+
public static Optional<String> lookupSubclass(int classCode, int subclassCode) {
175+
loadData();
176+
return subclassCodes.stream()
177+
.filter((scc) -> scc.classCode == classCode && scc.subclassCode == subclassCode)
178+
.map((cc) -> cc.name)
179+
.findFirst();
180+
}
181+
182+
/**
183+
* Provides the name of the specified USB protocol.
184+
* @param classCode the USB class code
185+
* @param subclassCode the USB subclass code
186+
* @param protocolCode the USB protocol code
187+
* @return an optional name
188+
*/
189+
public static Optional<String> lookupProtocol(int classCode, int subclassCode, int protocolCode) {
190+
loadData();
191+
return protocolCodes.stream()
192+
.filter((scc) -> scc.classCode == classCode && scc.subclassCode == subclassCode
193+
&& scc.protocolCode == protocolCode)
194+
.map((cc) -> cc.name)
195+
.findFirst();
196+
}
197+
198+
private static void loadData() {
199+
if (classCodes.size() > 0)
200+
return;
201+
202+
try (var stringReader = new StringReader(RAW_DATA);
203+
var reader = new BufferedReader(stringReader)) {
204+
205+
int classCode = 0;
206+
int subclassCode = 0;
207+
String line;
208+
209+
while ((line = reader.readLine()) != null) {
210+
// protocol line
211+
if (line.startsWith("\t\t")) {
212+
int protocol = Integer.parseInt(line.substring(2, 4), 16);
213+
protocolCodes.add(new ProtocolCode(classCode, subclassCode, protocol, line.substring(6)));
214+
// subclass line
215+
} else if (line.startsWith("\t")) {
216+
subclassCode = Integer.parseInt(line.substring(1, 3), 16);
217+
subclassCodes.add(new SubclassCode(classCode, subclassCode, line.substring(5)));
218+
// class line
219+
} else if (line.startsWith("C ")) {
220+
classCode = Integer.parseInt(line.substring(2, 4), 16);
221+
classCodes.add(new ClassCode(classCode, line.substring(6)));
222+
223+
} else {
224+
throw new IllegalStateException("Invalid raw data");
225+
}
226+
}
227+
228+
} catch (IOException e) {
229+
throw new RuntimeException(e);
230+
}
231+
}
232+
233+
record ClassCode(int classCode, String name) { }
234+
record SubclassCode(int classCode, int subclassCode, String name) { }
235+
record ProtocolCode(int classCode, int subclassCode, int protocolCode, String name) { }
236+
}

0 commit comments

Comments
 (0)