xref: /haiku/src/kits/device/USBDevice.cpp (revision 7b3e89c0944ae1efa9a8fc66c7303874b7a344b2)
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 
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 
35 BUSBDevice::~BUSBDevice()
36 {
37 	Unset();
38 }
39 
40 
41 status_t
42 BUSBDevice::InitCheck()
43 {
44 	return (fRawFD >= 0 ? B_OK : B_ERROR);
45 }
46 
47 
48 status_t
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
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 *
117 BUSBDevice::Location() const
118 {
119 	if (!fPath || strlen(fPath) < 12)
120 		return NULL;
121 
122 	return &fPath[12];
123 }
124 
125 
126 bool
127 BUSBDevice::IsHub() const
128 {
129 	return fDescriptor.device_class == 0x09;
130 }
131 
132 
133 uint16
134 BUSBDevice::USBVersion() const
135 {
136 	return fDescriptor.usb_version;
137 }
138 
139 
140 uint8
141 BUSBDevice::Class() const
142 {
143 	return fDescriptor.device_class;
144 }
145 
146 
147 uint8
148 BUSBDevice::Subclass() const
149 {
150 	return fDescriptor.device_subclass;
151 }
152 
153 
154 uint8
155 BUSBDevice::Protocol() const
156 {
157 	return fDescriptor.device_protocol;
158 }
159 
160 
161 uint8
162 BUSBDevice::MaxEndpoint0PacketSize() const
163 {
164 	return fDescriptor.max_packet_size_0;
165 }
166 
167 
168 uint16
169 BUSBDevice::VendorID() const
170 {
171 	return fDescriptor.vendor_id;
172 }
173 
174 
175 uint16
176 BUSBDevice::ProductID() const
177 {
178 	return fDescriptor.product_id;
179 }
180 
181 
182 uint16
183 BUSBDevice::Version() const
184 {
185 	return fDescriptor.device_version;
186 }
187 
188 
189 const char *
190 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 *
207 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 *
224 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 *
241 BUSBDevice::Descriptor() const
242 {
243 	return &fDescriptor;
244 }
245 
246 
247 size_t
248 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 *
268 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
313 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
335 BUSBDevice::CountConfigurations() const
336 {
337 	return fDescriptor.num_configurations;
338 }
339 
340 
341 const BUSBConfiguration *
342 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 *
352 BUSBDevice::ActiveConfiguration() const
353 {
354 	if (fConfigurations == NULL)
355 		return NULL;
356 
357 	return fConfigurations[fActiveConfiguration];
358 }
359 
360 
361 status_t
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
380 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
403 void BUSBDevice::_ReservedUSBDevice1() {};
404 void BUSBDevice::_ReservedUSBDevice2() {};
405 void BUSBDevice::_ReservedUSBDevice3() {};
406 void BUSBDevice::_ReservedUSBDevice4() {};
407 void BUSBDevice::_ReservedUSBDevice5() {};
408