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