1 /*
2 * Copyright 2007-2008, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 */
8
9 #include <ByteOrder.h>
10 #include <USBKit.h>
11 #include <usb_raw.h>
12 #include <UTF8.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <new>
17
18
BUSBDevice(const char * path)19 BUSBDevice::BUSBDevice(const char *path)
20 : fPath(NULL),
21 fRawFD(-1),
22 fConfigurations(NULL),
23 fActiveConfiguration(0),
24 fManufacturerString(NULL),
25 fProductString(NULL),
26 fSerialNumberString(NULL)
27 {
28 memset(&fDescriptor, 0, sizeof(fDescriptor));
29
30 if (path)
31 SetTo(path);
32 }
33
34
~BUSBDevice()35 BUSBDevice::~BUSBDevice()
36 {
37 Unset();
38 }
39
40
41 status_t
InitCheck()42 BUSBDevice::InitCheck()
43 {
44 return (fRawFD >= 0 ? B_OK : B_ERROR);
45 }
46
47
48 status_t
SetTo(const char * path)49 BUSBDevice::SetTo(const char *path)
50 {
51 if (!path)
52 return B_BAD_VALUE;
53
54 fPath = strdup(path);
55 fRawFD = open(path, O_RDWR | O_CLOEXEC);
56 if (fRawFD < 0) {
57 Unset();
58 return B_ERROR;
59 }
60
61 usb_raw_command command;
62 if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_VERSION, &command, sizeof(command))
63 || command.version.status != B_USB_RAW_PROTOCOL_VERSION) {
64 Unset();
65 return B_ERROR;
66 }
67
68 command.device.descriptor = &fDescriptor;
69 if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR, &command,
70 sizeof(command)) || command.device.status != B_USB_RAW_STATUS_SUCCESS) {
71 Unset();
72 return B_ERROR;
73 }
74
75 fConfigurations = new(std::nothrow) BUSBConfiguration *[
76 fDescriptor.num_configurations];
77 if (fConfigurations == NULL)
78 return B_NO_MEMORY;
79
80 for (uint32 i = 0; i < fDescriptor.num_configurations; i++) {
81 fConfigurations[i] = new(std::nothrow) BUSBConfiguration(this, i,
82 fRawFD);
83 }
84
85 return B_OK;
86 }
87
88
89 void
Unset()90 BUSBDevice::Unset()
91 {
92 if (fRawFD >= 0)
93 close(fRawFD);
94 fRawFD = -1;
95
96 free(fPath);
97 fPath = NULL;
98
99 delete[] fManufacturerString;
100 delete[] fProductString;
101 delete[] fSerialNumberString;
102 fManufacturerString = fProductString = fSerialNumberString = NULL;
103
104 if (fConfigurations != NULL) {
105 for (int32 i = 0; i < fDescriptor.num_configurations; i++)
106 delete fConfigurations[i];
107
108 delete[] fConfigurations;
109 fConfigurations = NULL;
110 }
111
112 memset(&fDescriptor, 0, sizeof(fDescriptor));
113 }
114
115
116 const char *
Location() const117 BUSBDevice::Location() const
118 {
119 if (!fPath || strlen(fPath) < 12)
120 return NULL;
121
122 return &fPath[12];
123 }
124
125
126 bool
IsHub() const127 BUSBDevice::IsHub() const
128 {
129 return fDescriptor.device_class == 0x09;
130 }
131
132
133 uint16
USBVersion() const134 BUSBDevice::USBVersion() const
135 {
136 return fDescriptor.usb_version;
137 }
138
139
140 uint8
Class() const141 BUSBDevice::Class() const
142 {
143 return fDescriptor.device_class;
144 }
145
146
147 uint8
Subclass() const148 BUSBDevice::Subclass() const
149 {
150 return fDescriptor.device_subclass;
151 }
152
153
154 uint8
Protocol() const155 BUSBDevice::Protocol() const
156 {
157 return fDescriptor.device_protocol;
158 }
159
160
161 uint8
MaxEndpoint0PacketSize() const162 BUSBDevice::MaxEndpoint0PacketSize() const
163 {
164 return fDescriptor.max_packet_size_0;
165 }
166
167
168 uint16
VendorID() const169 BUSBDevice::VendorID() const
170 {
171 return fDescriptor.vendor_id;
172 }
173
174
175 uint16
ProductID() const176 BUSBDevice::ProductID() const
177 {
178 return fDescriptor.product_id;
179 }
180
181
182 uint16
Version() const183 BUSBDevice::Version() const
184 {
185 return fDescriptor.device_version;
186 }
187
188
189 const char *
ManufacturerString() const190 BUSBDevice::ManufacturerString() const
191 {
192 if (fDescriptor.manufacturer == 0)
193 return "";
194
195 if (fManufacturerString)
196 return fManufacturerString;
197
198 fManufacturerString = DecodeStringDescriptor(fDescriptor.manufacturer);
199 if (fManufacturerString == NULL)
200 return "";
201
202 return fManufacturerString;
203 }
204
205
206 const char *
ProductString() const207 BUSBDevice::ProductString() const
208 {
209 if (fDescriptor.product == 0)
210 return "";
211
212 if (fProductString)
213 return fProductString;
214
215 fProductString = DecodeStringDescriptor(fDescriptor.product);
216 if (fProductString == NULL)
217 return "";
218
219 return fProductString;
220 }
221
222
223 const char *
SerialNumberString() const224 BUSBDevice::SerialNumberString() const
225 {
226 if (fDescriptor.serial_number == 0)
227 return "";
228
229 if (fSerialNumberString)
230 return fSerialNumberString;
231
232 fSerialNumberString = DecodeStringDescriptor(fDescriptor.serial_number);
233 if (fSerialNumberString == NULL)
234 return "";
235
236 return fSerialNumberString;
237 }
238
239
240 const usb_device_descriptor *
Descriptor() const241 BUSBDevice::Descriptor() const
242 {
243 return &fDescriptor;
244 }
245
246
247 size_t
GetStringDescriptor(uint32 index,usb_string_descriptor * descriptor,size_t length) const248 BUSBDevice::GetStringDescriptor(uint32 index,
249 usb_string_descriptor *descriptor, size_t length) const
250 {
251 if (!descriptor)
252 return B_BAD_VALUE;
253
254 usb_raw_command command;
255 command.string.descriptor = descriptor;
256 command.string.string_index = index;
257 command.string.length = length;
258
259 if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_STRING_DESCRIPTOR, &command,
260 sizeof(command)) || command.string.status != B_USB_RAW_STATUS_SUCCESS)
261 return 0;
262
263 return command.string.length;
264 }
265
266
267 char *
DecodeStringDescriptor(uint32 index) const268 BUSBDevice::DecodeStringDescriptor(uint32 index) const
269 {
270 char buffer[300];
271 usb_string_descriptor *stringDescriptor;
272 stringDescriptor = (usb_string_descriptor *)&buffer;
273
274 int32 stringLength = GetStringDescriptor(index, stringDescriptor,
275 sizeof(buffer) - sizeof(usb_string_descriptor)) - 1;
276
277 if (stringLength < 3)
278 return NULL;
279
280 int32 resultLength = 0;
281
282 // USB is always little-endian, UCS-2 is big-endian.
283 uint16* ustr = (uint16*)stringDescriptor->string;
284 for (int32 i = 0; i < (stringLength / 2); i++) {
285 // Increase size of result as needed by source character.
286 const uint16 character = B_LENDIAN_TO_HOST_INT16(ustr[i]);
287 resultLength++;
288 if (character >= 0x80)
289 resultLength++;
290 if (character >= 0x800)
291 resultLength++;
292
293 ustr[i] = B_SWAP_INT16(ustr[i]);
294 }
295
296 char *result = new(std::nothrow) char[resultLength + 1];
297 if (result == NULL)
298 return NULL;
299
300 status_t status = convert_to_utf8(B_UNICODE_CONVERSION,
301 (const char*)stringDescriptor->string, &stringLength,
302 result, &resultLength, NULL);
303 if (status != B_OK) {
304 delete[] result;
305 return NULL;
306 }
307 result[resultLength] = 0;
308 return result;
309 }
310
311
312 size_t
GetDescriptor(uint8 type,uint8 index,uint16 languageID,void * data,size_t length) const313 BUSBDevice::GetDescriptor(uint8 type, uint8 index, uint16 languageID,
314 void *data, size_t length) const
315 {
316 if (length > 0 && data == NULL)
317 return B_BAD_VALUE;
318
319 usb_raw_command command;
320 command.descriptor.type = type;
321 command.descriptor.index = index;
322 command.descriptor.language_id = languageID;
323 command.descriptor.data = data;
324 command.descriptor.length = length;
325
326 if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DESCRIPTOR, &command,
327 sizeof(command)) || command.descriptor.status != B_USB_RAW_STATUS_SUCCESS)
328 return 0;
329
330 return command.descriptor.length;
331 }
332
333
334 uint32
CountConfigurations() const335 BUSBDevice::CountConfigurations() const
336 {
337 return fDescriptor.num_configurations;
338 }
339
340
341 const BUSBConfiguration *
ConfigurationAt(uint32 index) const342 BUSBDevice::ConfigurationAt(uint32 index) const
343 {
344 if (index >= fDescriptor.num_configurations || fConfigurations == NULL)
345 return NULL;
346
347 return fConfigurations[index];
348 }
349
350
351 const BUSBConfiguration *
ActiveConfiguration() const352 BUSBDevice::ActiveConfiguration() const
353 {
354 if (fConfigurations == NULL)
355 return NULL;
356
357 return fConfigurations[fActiveConfiguration];
358 }
359
360
361 status_t
SetConfiguration(const BUSBConfiguration * configuration)362 BUSBDevice::SetConfiguration(const BUSBConfiguration *configuration)
363 {
364 if (!configuration || configuration->Index() >= fDescriptor.num_configurations)
365 return B_BAD_VALUE;
366
367 usb_raw_command command;
368 command.config.config_index = configuration->Index();
369
370 if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_CONFIGURATION, &command,
371 sizeof(command)) || command.config.status != B_USB_RAW_STATUS_SUCCESS)
372 return B_ERROR;
373
374 fActiveConfiguration = configuration->Index();
375 return B_OK;
376 }
377
378
379 ssize_t
ControlTransfer(uint8 requestType,uint8 request,uint16 value,uint16 index,uint16 length,void * data) const380 BUSBDevice::ControlTransfer(uint8 requestType, uint8 request, uint16 value,
381 uint16 index, uint16 length, void *data) const
382 {
383 if (length > 0 && data == NULL)
384 return B_BAD_VALUE;
385
386 usb_raw_command command;
387 command.control.request_type = requestType;
388 command.control.request = request;
389 command.control.value = value;
390 command.control.index = index;
391 command.control.length = length;
392 command.control.data = data;
393
394 if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command,
395 sizeof(command)) || command.control.status != B_USB_RAW_STATUS_SUCCESS)
396 return B_ERROR;
397
398 return command.control.length;
399 }
400
401
402 // definition of reserved virtual functions
_ReservedUSBDevice1()403 void BUSBDevice::_ReservedUSBDevice1() {};
_ReservedUSBDevice2()404 void BUSBDevice::_ReservedUSBDevice2() {};
_ReservedUSBDevice3()405 void BUSBDevice::_ReservedUSBDevice3() {};
_ReservedUSBDevice4()406 void BUSBDevice::_ReservedUSBDevice4() {};
_ReservedUSBDevice5()407 void BUSBDevice::_ReservedUSBDevice5() {};
408