19
19
import org .cgutman .usbip .server .protocol .dev .UsbIpDevicePacket ;
20
20
import org .cgutman .usbip .server .protocol .dev .UsbIpSubmitUrb ;
21
21
import org .cgutman .usbip .server .protocol .dev .UsbIpSubmitUrbReply ;
22
+ import org .cgutman .usbip .usb .DescriptorReader ;
23
+ import org .cgutman .usbip .usb .UsbDeviceDescriptor ;
22
24
23
25
import android .annotation .SuppressLint ;
24
26
import android .app .PendingIntent ;
@@ -82,19 +84,105 @@ public IBinder onBind(Intent intent) {
82
84
// Not currently bindable
83
85
return null ;
84
86
}
87
+
88
+ // Here we're going to enumerate interfaces and endpoints
89
+ // to eliminate possible speeds until we've narrowed it
90
+ // down to only 1 which is our speed real speed. In a typical
91
+ // USB driver, the host controller knows the real speed but
92
+ // we need to derive it without HCI help.
93
+ private final static int FLAG_POSSIBLE_SPEED_LOW = 0x01 ;
94
+ private final static int FLAG_POSSIBLE_SPEED_FULL = 0x02 ;
95
+ private final static int FLAG_POSSIBLE_SPEED_HIGH = 0x04 ;
96
+ private int detectSpeed (UsbDevice dev , UsbDeviceDescriptor devDesc ) {
97
+ int possibleSpeeds = FLAG_POSSIBLE_SPEED_LOW |
98
+ FLAG_POSSIBLE_SPEED_FULL |
99
+ FLAG_POSSIBLE_SPEED_HIGH ;
100
+
101
+ for (int i = 0 ; i < dev .getInterfaceCount (); i ++) {
102
+ UsbInterface iface = dev .getInterface (i );
103
+ for (int j = 0 ; j < iface .getEndpointCount (); j ++) {
104
+ UsbEndpoint endpoint = iface .getEndpoint (j );
105
+ if ((endpoint .getType () == UsbConstants .USB_ENDPOINT_XFER_BULK ) ||
106
+ (endpoint .getType () == UsbConstants .USB_ENDPOINT_XFER_ISOC )) {
107
+ // Low speed devices can't implement bulk or iso endpoints
108
+ possibleSpeeds &= ~FLAG_POSSIBLE_SPEED_LOW ;
109
+ }
110
+
111
+ if (endpoint .getType () == UsbConstants .USB_ENDPOINT_XFER_CONTROL ) {
112
+ if (endpoint .getMaxPacketSize () > 8 ) {
113
+ // Low speed devices can't use control transfer sizes larger than 8 bytes
114
+ possibleSpeeds &= ~FLAG_POSSIBLE_SPEED_LOW ;
115
+ }
116
+ if (endpoint .getMaxPacketSize () < 64 ) {
117
+ // High speed devices can't use control transfer sizes smaller than 64 bytes
118
+ possibleSpeeds &= ~FLAG_POSSIBLE_SPEED_HIGH ;
119
+ }
120
+ }
121
+ else if (endpoint .getType () == UsbConstants .USB_ENDPOINT_XFER_INT ) {
122
+ if (endpoint .getMaxPacketSize () > 8 ) {
123
+ // Low speed devices can't use interrupt transfer sizes larger than 8 bytes
124
+ possibleSpeeds &= ~FLAG_POSSIBLE_SPEED_LOW ;
125
+ }
126
+ if (endpoint .getMaxPacketSize () > 64 ) {
127
+ // Full speed devices can't use interrupt transfer sizes larger than 64 bytes
128
+ possibleSpeeds &= ~FLAG_POSSIBLE_SPEED_FULL ;
129
+ }
130
+ }
131
+ else if (endpoint .getType () == UsbConstants .USB_ENDPOINT_XFER_BULK ) {
132
+ // A bulk endpoint alone can accurately distiniguish between
133
+ // full and high speed devices
134
+ if (endpoint .getMaxPacketSize () == 512 ) {
135
+ // High speed devices can only use 512 byte bulk transfers
136
+ possibleSpeeds = FLAG_POSSIBLE_SPEED_HIGH ;
137
+ }
138
+ else {
139
+ // Otherwise it must be full speed
140
+ possibleSpeeds = FLAG_POSSIBLE_SPEED_FULL ;
141
+ }
142
+ }
143
+ else if (endpoint .getType () == UsbConstants .USB_ENDPOINT_XFER_ISOC ) {
144
+ // If the transfer size is 1024, it must be high speed
145
+ if (endpoint .getMaxPacketSize () == 1024 ) {
146
+ possibleSpeeds = FLAG_POSSIBLE_SPEED_HIGH ;
147
+ }
148
+ }
149
+ }
150
+ }
151
+
152
+ if (devDesc != null ) {
153
+ if (devDesc .bcdUSB < 0x200 ) {
154
+ // High speed only supported on USB 2.0 or higher
155
+ possibleSpeeds &= ~FLAG_POSSIBLE_SPEED_HIGH ;
156
+ }
157
+ }
158
+
159
+ // Return the lowest speed that we're compatible with
160
+ System .out .printf ("Speed heuristics for device %d left us with 0x%x\n " ,
161
+ dev .getDeviceId (), possibleSpeeds );
162
+
163
+ if ((possibleSpeeds & FLAG_POSSIBLE_SPEED_LOW ) != 0 ) {
164
+ return UsbIpDevice .USB_SPEED_LOW ;
165
+ }
166
+ else if ((possibleSpeeds & FLAG_POSSIBLE_SPEED_FULL ) != 0 ) {
167
+ return UsbIpDevice .USB_SPEED_FULL ;
168
+ }
169
+ else if ((possibleSpeeds & FLAG_POSSIBLE_SPEED_HIGH ) != 0 ) {
170
+ return UsbIpDevice .USB_SPEED_HIGH ;
171
+ }
172
+ else {
173
+ // Something went very wrong in speed detection
174
+ return UsbIpDevice .USB_SPEED_UNKNOWN ;
175
+ }
176
+ }
85
177
86
178
private UsbDeviceInfo getInfoForDevice (UsbDevice dev ) {
87
179
UsbDeviceInfo info = new UsbDeviceInfo ();
88
180
UsbIpDevice ipDev = new UsbIpDevice ();
89
181
90
- // TODO: Fill bcdDevice, bConfigurationValue, bNumConfigurations,
91
- // and speed from USB configuration descriptor
92
-
93
182
ipDev .path = dev .getDeviceName ();
94
183
ipDev .busid = String .format ("%d" , dev .getDeviceId ());
95
184
ipDev .busnum = 0 ;
96
185
ipDev .devnum = dev .getDeviceId ();
97
- ipDev .speed = UsbIpDevice .USB_SPEED_UNKNOWN ;
98
186
99
187
ipDev .idVendor = (short ) dev .getVendorId ();
100
188
ipDev .idProduct = (short ) dev .getProductId ();
@@ -121,6 +209,19 @@ private UsbDeviceInfo getInfoForDevice(UsbDevice dev) {
121
209
info .interfaces [i ].bInterfaceProtocol = (byte ) iface .getInterfaceProtocol ();
122
210
}
123
211
212
+ AttachedDeviceContext context = connections .get (dev .getDeviceId ());
213
+ UsbDeviceDescriptor devDesc = null ;
214
+ if (context != null ) {
215
+ // Since we're attached already, we can directly query the USB descriptors
216
+ // to fill some information that Android's USB API doesn't expose
217
+ devDesc = DescriptorReader .readDeviceDescriptor (context .devConn );
218
+
219
+ ipDev .bcdDevice = devDesc .bcdDevice ;
220
+ ipDev .bNumConfigurations = devDesc .bNumConfigurations ;
221
+ }
222
+
223
+ ipDev .speed = detectSpeed (dev , devDesc );
224
+
124
225
return info ;
125
226
}
126
227
0 commit comments