xref: /haiku/src/kits/device/USBDevice.cpp (revision 4b3b81da9e459443d75329cfd08bc9a57ad02653)
1 /*
2  * Copyright 2007, 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 <USBKit.h>
10 #include <usb_raw.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <malloc.h>
14 
15 
16 BUSBDevice::BUSBDevice(const char *path)
17 	:	fPath(NULL),
18 		fRawFD(-1),
19 		fConfigurations(NULL),
20 		fActiveConfiguration(0),
21 		fManufacturerString(NULL),
22 		fProductString(NULL),
23 		fSerialNumberString(NULL)
24 {
25 	memset(&fDescriptor, 0, sizeof(fDescriptor));
26 
27 	if (path)
28 		SetTo(path);
29 }
30 
31 
32 BUSBDevice::~BUSBDevice()
33 {
34 	Unset();
35 }
36 
37 
38 status_t
39 BUSBDevice::InitCheck()
40 {
41 	return (fRawFD >= 0 ? B_OK : B_ERROR);
42 }
43 
44 
45 status_t
46 BUSBDevice::SetTo(const char *path)
47 {
48 	if (!path)
49 		return B_BAD_VALUE;
50 
51 	fPath = strdup(path);
52 	fRawFD = open(path, O_RDWR | O_CLOEXEC);
53 	if (fRawFD < 0) {
54 		Unset();
55 		return B_ERROR;
56 	}
57 
58 	usb_raw_command command;
59 	if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_VERSION, &command, sizeof(command))
60 		|| command.version.status != B_USB_RAW_PROTOCOL_VERSION) {
61 		Unset();
62 		return B_ERROR;
63 	}
64 
65 	command.device.descriptor = &fDescriptor;
66 	if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR, &command,
67 		sizeof(command)) || command.device.status != B_USB_RAW_STATUS_SUCCESS) {
68 		Unset();
69 		return B_ERROR;
70 	}
71 
72 	fConfigurations = new BUSBConfiguration *[fDescriptor.num_configurations];
73 	for (uint32 i = 0; i < fDescriptor.num_configurations; i++)
74 		fConfigurations[i] = new BUSBConfiguration(this, i, fRawFD);
75 
76 	return B_OK;
77 }
78 
79 
80 void
81 BUSBDevice::Unset()
82 {
83 	if (fRawFD >= 0)
84 		close(fRawFD);
85 	fRawFD = -1;
86 
87 	free(fPath);
88 	fPath = NULL;
89 
90 	delete[] fManufacturerString;
91 	delete[] fProductString;
92 	delete[] fSerialNumberString;
93 	fManufacturerString = fProductString = fSerialNumberString = NULL;
94 
95 	for (int32 i = 0; i < fDescriptor.num_configurations; i++)
96 		delete fConfigurations[i];
97 
98 	delete[] fConfigurations;
99 	memset(&fDescriptor, 0, sizeof(fDescriptor));
100 }
101 
102 
103 const char *
104 BUSBDevice::Location() const
105 {
106 	if (!fPath || strlen(fPath) < 12)
107 		return NULL;
108 
109 	return &fPath[12];
110 }
111 
112 
113 bool
114 BUSBDevice::IsHub() const
115 {
116 	return fDescriptor.device_class == 0x09;
117 }
118 
119 
120 uint16
121 BUSBDevice::USBVersion() const
122 {
123 	return fDescriptor.usb_version;
124 }
125 
126 
127 uint8
128 BUSBDevice::Class() const
129 {
130 	return fDescriptor.device_class;
131 }
132 
133 
134 uint8
135 BUSBDevice::Subclass() const
136 {
137 	return fDescriptor.device_subclass;
138 }
139 
140 
141 uint8
142 BUSBDevice::Protocol() const
143 {
144 	return fDescriptor.device_protocol;
145 }
146 
147 
148 uint8
149 BUSBDevice::MaxEndpoint0PacketSize() const
150 {
151 	return fDescriptor.max_packet_size_0;
152 }
153 
154 
155 uint16
156 BUSBDevice::VendorID() const
157 {
158 	return fDescriptor.vendor_id;
159 }
160 
161 
162 uint16
163 BUSBDevice::ProductID() const
164 {
165 	return fDescriptor.product_id;
166 }
167 
168 
169 uint16
170 BUSBDevice::Version() const
171 {
172 	return fDescriptor.device_version;
173 }
174 
175 
176 const char *
177 BUSBDevice::ManufacturerString() const
178 {
179 	if (fDescriptor.manufacturer == 0)
180 		return "";
181 
182 	if (fManufacturerString)
183 		return fManufacturerString;
184 
185 	fManufacturerString = DecodeStringDescriptor(fDescriptor.manufacturer);
186 	if (!fManufacturerString) {
187 		fManufacturerString = new char[1];
188 		fManufacturerString[0] = 0;
189 	}
190 
191 	return fManufacturerString;
192 }
193 
194 
195 const char *
196 BUSBDevice::ProductString() const
197 {
198 	if (fDescriptor.product == 0)
199 		return "";
200 
201 	if (fProductString)
202 		return fProductString;
203 
204 	fProductString = DecodeStringDescriptor(fDescriptor.product);
205 	if (!fProductString) {
206 		fProductString = new char[1];
207 		fProductString[0] = 0;
208 	}
209 
210 	return fProductString;
211 }
212 
213 
214 const char *
215 BUSBDevice::SerialNumberString() const
216 {
217 	if (fDescriptor.serial_number == 0)
218 		return "";
219 
220 	if (fSerialNumberString)
221 		return fSerialNumberString;
222 
223 	fSerialNumberString = DecodeStringDescriptor(fDescriptor.serial_number);
224 	if (!fSerialNumberString) {
225 		fSerialNumberString = new char[1];
226 		fSerialNumberString[0] = 0;
227 	}
228 
229 	return fSerialNumberString;
230 }
231 
232 
233 const usb_device_descriptor *
234 BUSBDevice::Descriptor() const
235 {
236 	return &fDescriptor;
237 }
238 
239 
240 size_t
241 BUSBDevice::GetStringDescriptor(uint32 index,
242 	usb_string_descriptor *descriptor, size_t length) const
243 {
244 	if (!descriptor)
245 		return B_BAD_VALUE;
246 
247 	usb_raw_command command;
248 	command.string.descriptor = descriptor;
249 	command.string.string_index = index;
250 	command.string.length = length;
251 
252 	if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_STRING_DESCRIPTOR, &command,
253 		sizeof(command)) || command.string.status != B_USB_RAW_STATUS_SUCCESS)
254 		return 0;
255 
256 	return command.string.length;
257 }
258 
259 
260 char *
261 BUSBDevice::DecodeStringDescriptor(uint32 index) const
262 {
263 	char buffer[300];
264 	usb_string_descriptor *stringDescriptor;
265 	stringDescriptor = (usb_string_descriptor *)&buffer;
266 
267 	size_t stringLength = GetStringDescriptor(index, stringDescriptor,
268 		sizeof(buffer) - sizeof(usb_string_descriptor));
269 
270 	if (stringLength < 3)
271 		return NULL;
272 
273 	// pseudo convert unicode string
274 	stringLength = (stringLength - 2) / 2;
275 	char *result = new char[stringLength + 1];
276 	for (size_t i = 0; i < stringLength; i++)
277 		result[i] = stringDescriptor->string[i * 2];
278 	result[stringLength] = 0;
279 	return result;
280 }
281 
282 
283 size_t
284 BUSBDevice::GetDescriptor(uint8 type, uint8 index, uint16 languageID,
285 	void *data, size_t length) const
286 {
287 	if (length > 0 && data == NULL)
288 		return B_BAD_VALUE;
289 
290 	usb_raw_command command;
291 	command.descriptor.type = type;
292 	command.descriptor.index = index;
293 	command.descriptor.language_id = languageID;
294 	command.descriptor.data = data;
295 	command.descriptor.length = length;
296 
297 	if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DESCRIPTOR, &command,
298 		sizeof(command)) || command.descriptor.status != B_USB_RAW_STATUS_SUCCESS)
299 		return 0;
300 
301 	return command.descriptor.length;
302 }
303 
304 
305 uint32
306 BUSBDevice::CountConfigurations() const
307 {
308 	return fDescriptor.num_configurations;
309 }
310 
311 
312 const BUSBConfiguration *
313 BUSBDevice::ConfigurationAt(uint32 index) const
314 {
315 	if (index >= fDescriptor.num_configurations)
316 		return NULL;
317 
318 	return fConfigurations[index];
319 }
320 
321 
322 const BUSBConfiguration *
323 BUSBDevice::ActiveConfiguration() const
324 {
325 	return fConfigurations[fActiveConfiguration];
326 }
327 
328 
329 status_t
330 BUSBDevice::SetConfiguration(const BUSBConfiguration *configuration)
331 {
332 	if (!configuration || configuration->Index() >= fDescriptor.num_configurations)
333 		return B_BAD_VALUE;
334 
335 	usb_raw_command command;
336 	command.config.config_index = configuration->Index();
337 
338 	if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_CONFIGURATION, &command,
339 		sizeof(command)) || command.config.status != B_USB_RAW_STATUS_SUCCESS)
340 		return B_ERROR;
341 
342 	fActiveConfiguration = configuration->Index();
343 	return B_OK;
344 }
345 
346 
347 ssize_t
348 BUSBDevice::ControlTransfer(uint8 requestType, uint8 request, uint16 value,
349 	uint16 index, uint16 length, void *data) const
350 {
351 	if (length > 0 && data == NULL)
352 		return B_BAD_VALUE;
353 
354 	usb_raw_command command;
355 	command.control.request_type = requestType;
356 	command.control.request = request;
357 	command.control.value = value;
358 	command.control.index = index;
359 	command.control.length = length;
360 	command.control.data = data;
361 
362 	if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command,
363 		sizeof(command)) || command.control.status != B_USB_RAW_STATUS_SUCCESS)
364 		return B_ERROR;
365 
366 	return command.control.length;
367 }
368 
369 
370 // definition of reserved virtual functions
371 void BUSBDevice::_ReservedUSBDevice1() {};
372 void BUSBDevice::_ReservedUSBDevice2() {};
373 void BUSBDevice::_ReservedUSBDevice3() {};
374 void BUSBDevice::_ReservedUSBDevice4() {};
375 void BUSBDevice::_ReservedUSBDevice5() {};
376