xref: /haiku/src/add-ons/kernel/drivers/bus/usb/usb_raw.cpp (revision 0f9ffb37c166a9d9257044c8937f6450f4257b75)
1 /*
2  * Copyright 2006-2018, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  *		Adrien Destugues <pulkomandy@pulkomandy.tk>
8  */
9 
10 #include "usb_raw.h"
11 
12 #include <KernelExport.h>
13 #include <Drivers.h>
14 #include <algorithm>
15 #include <lock.h>
16 #include <malloc.h>
17 #include <stdio.h>
18 #include <string.h>
19 
20 #include <kernel.h>
21 
22 
23 //#define TRACE_USB_RAW
24 #ifdef TRACE_USB_RAW
25 #define TRACE(x)	dprintf x
26 #else
27 #define TRACE(x)	/* nothing */
28 #endif
29 
30 #define DRIVER_NAME		"usb_raw"
31 #define DEVICE_NAME		"bus/usb/raw"
32 
33 typedef struct {
34 	usb_device			device;
35 	mutex				lock;
36 	uint32				reference_count;
37 
38 	char				name[64];
39 	void				*link;
40 
41 	sem_id				notify;
42 	status_t			status;
43 	size_t				actual_length;
44 } raw_device;
45 
46 int32 api_version = B_CUR_DRIVER_API_VERSION;
47 static usb_module_info *gUSBModule = NULL;
48 static raw_device *gDeviceList = NULL;
49 static uint32 gDeviceCount = 0;
50 static mutex gDeviceListLock;
51 static char **gDeviceNames = NULL;
52 
53 static status_t
54 usb_raw_device_added(usb_device newDevice, void **cookie)
55 {
56 	TRACE((DRIVER_NAME": device_added(0x%08" B_PRIx32 ")\n", newDevice));
57 	raw_device *device = (raw_device *)malloc(sizeof(raw_device));
58 
59 	mutex_init(&device->lock, "usb_raw device lock");
60 
61 	device->notify = create_sem(0, "usb_raw callback notify");
62 	if (device->notify < B_OK) {
63 		mutex_destroy(&device->lock);
64 		free(device);
65 		return B_NO_MORE_SEMS;
66 	}
67 
68 	char deviceName[64];
69 	memcpy(deviceName, &newDevice, sizeof(usb_device));
70 	if (gUSBModule->usb_ioctl('DNAM', deviceName, sizeof(deviceName)) >= B_OK) {
71 		snprintf(device->name, sizeof(device->name), "bus/usb/%s", deviceName);
72 	} else {
73 		snprintf(device->name, sizeof(device->name), "bus/usb/%08" B_PRIx32,
74 			newDevice);
75 	}
76 
77 	device->device = newDevice;
78 	device->reference_count = 0;
79 
80 	mutex_lock(&gDeviceListLock);
81 	device->link = (void *)gDeviceList;
82 	gDeviceList = device;
83 	gDeviceCount++;
84 	mutex_unlock(&gDeviceListLock);
85 
86 	TRACE((DRIVER_NAME": new device: 0x%p\n", device));
87 	*cookie = (void *)device;
88 	return B_OK;
89 }
90 
91 
92 static status_t
93 usb_raw_device_removed(void *cookie)
94 {
95 	TRACE((DRIVER_NAME": device_removed(0x%p)\n", cookie));
96 	raw_device *device = (raw_device *)cookie;
97 
98 	mutex_lock(&gDeviceListLock);
99 	if (gDeviceList == device) {
100 		gDeviceList = (raw_device *)device->link;
101 	} else {
102 		raw_device *element = gDeviceList;
103 		while (element) {
104 			if (element->link == device) {
105 				element->link = device->link;
106 				break;
107 			}
108 
109 			element = (raw_device *)element->link;
110 		}
111 	}
112 	gDeviceCount--;
113 	mutex_unlock(&gDeviceListLock);
114 
115 	device->device = 0;
116 	if (device->reference_count == 0) {
117 		mutex_lock(&device->lock);
118 		mutex_destroy(&device->lock);
119 		delete_sem(device->notify);
120 		free(device);
121 	}
122 
123 	return B_OK;
124 }
125 
126 
127 //
128 //#pragma mark -
129 //
130 
131 
132 static const usb_configuration_info *
133 usb_raw_get_configuration(raw_device *device, uint32 configIndex,
134 	status_t *status)
135 {
136 	const usb_configuration_info *result = gUSBModule->get_nth_configuration(
137 		device->device, configIndex);
138 	if (result == NULL) {
139 		*status = B_USB_RAW_STATUS_INVALID_CONFIGURATION;
140 		return NULL;
141 	}
142 
143 	return result;
144 }
145 
146 
147 static const usb_interface_info *
148 usb_raw_get_interface(raw_device *device, uint32 configIndex,
149 	uint32 interfaceIndex, uint32 alternateIndex, status_t *status)
150 {
151 	const usb_configuration_info *configurationInfo
152 		= usb_raw_get_configuration(device, configIndex, status);
153 	if (configurationInfo == NULL)
154 		return NULL;
155 
156 	if (interfaceIndex >= configurationInfo->interface_count) {
157 		*status = B_USB_RAW_STATUS_INVALID_INTERFACE;
158 		return NULL;
159 	}
160 
161 	const usb_interface_info *result = NULL;
162 	if (alternateIndex == B_USB_RAW_ACTIVE_ALTERNATE)
163 		result = configurationInfo->interface[interfaceIndex].active;
164 	else {
165 		const usb_interface_list *interfaceList =
166 			&configurationInfo->interface[interfaceIndex];
167 		if (alternateIndex >= interfaceList->alt_count) {
168 			*status = B_USB_RAW_STATUS_INVALID_INTERFACE;
169 			return NULL;
170 		}
171 
172 		result = &interfaceList->alt[alternateIndex];
173 	}
174 
175 	return result;
176 }
177 
178 
179 //
180 //#pragma mark -
181 //
182 
183 
184 static status_t
185 usb_raw_open(const char *name, uint32 flags, void **cookie)
186 {
187 	TRACE((DRIVER_NAME": open()\n"));
188 	mutex_lock(&gDeviceListLock);
189 	raw_device *element = gDeviceList;
190 	while (element) {
191 		if (strcmp(name, element->name) == 0) {
192 			element->reference_count++;
193 			*cookie = element;
194 			mutex_unlock(&gDeviceListLock);
195 			return B_OK;
196 		}
197 
198 		element = (raw_device *)element->link;
199 	}
200 
201 	mutex_unlock(&gDeviceListLock);
202 	return B_NAME_NOT_FOUND;
203 }
204 
205 
206 static status_t
207 usb_raw_close(void *cookie)
208 {
209 	TRACE((DRIVER_NAME": close()\n"));
210 	return B_OK;
211 }
212 
213 
214 static status_t
215 usb_raw_free(void *cookie)
216 {
217 	TRACE((DRIVER_NAME": free()\n"));
218 	mutex_lock(&gDeviceListLock);
219 
220 	raw_device *device = (raw_device *)cookie;
221 	device->reference_count--;
222 	if (device->device == 0) {
223 		mutex_lock(&device->lock);
224 		mutex_destroy(&device->lock);
225 		delete_sem(device->notify);
226 		free(device);
227 	}
228 
229 	mutex_unlock(&gDeviceListLock);
230 	return B_OK;
231 }
232 
233 
234 static void
235 usb_raw_callback(void *cookie, status_t status, void *data, size_t actualLength)
236 {
237 	TRACE((DRIVER_NAME": callback()\n"));
238 	raw_device *device = (raw_device *)cookie;
239 
240 	switch (status) {
241 		case B_OK:
242 			device->status = B_USB_RAW_STATUS_SUCCESS;
243 			break;
244 		case B_TIMED_OUT:
245 			device->status = B_USB_RAW_STATUS_TIMEOUT;
246 			break;
247 		case B_CANCELED:
248 			device->status = B_USB_RAW_STATUS_ABORTED;
249 			break;
250 		case B_DEV_CRC_ERROR:
251 			device->status = B_USB_RAW_STATUS_CRC_ERROR;
252 			break;
253 		case B_DEV_STALLED:
254 			device->status = B_USB_RAW_STATUS_STALLED;
255 			break;
256 		default:
257 			device->status = B_USB_RAW_STATUS_FAILED;
258 			break;
259 	}
260 
261 	device->actual_length = actualLength;
262 	release_sem(device->notify);
263 }
264 
265 
266 static status_t
267 usb_raw_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
268 {
269 	TRACE((DRIVER_NAME": ioctl\n"));
270 	raw_device *device = (raw_device *)cookie;
271 	if (device->device == 0)
272 		return B_DEV_NOT_READY;
273 
274 	usb_raw_command command;
275 	if (length < sizeof(command.version.status))
276 		return B_BUFFER_OVERFLOW;
277 	if (!IS_USER_ADDRESS(buffer)
278 		|| user_memcpy(&command, buffer, min_c(length, sizeof(command)))
279 			!= B_OK) {
280 		return B_BAD_ADDRESS;
281 	}
282 
283 	command.version.status = B_USB_RAW_STATUS_ABORTED;
284 	status_t status = B_DEV_INVALID_IOCTL;
285 
286 	switch (op) {
287 		case B_USB_RAW_COMMAND_GET_VERSION:
288 		{
289 			command.version.status = B_USB_RAW_PROTOCOL_VERSION;
290 			status = B_OK;
291 			break;
292 		}
293 
294 		case B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR:
295 		{
296 			if (length < sizeof(command.device))
297 				return B_BUFFER_OVERFLOW;
298 
299 			status = B_OK;
300 			const usb_device_descriptor *deviceDescriptor =
301 				gUSBModule->get_device_descriptor(device->device);
302 			if (deviceDescriptor == NULL)
303 				return B_OK;
304 
305 			if (!IS_USER_ADDRESS(command.device.descriptor)
306 				|| user_memcpy(command.device.descriptor, deviceDescriptor,
307 					sizeof(usb_device_descriptor)) != B_OK) {
308 				return B_BAD_ADDRESS;
309 			}
310 
311 			command.device.status = B_USB_RAW_STATUS_SUCCESS;
312 			break;
313 		}
314 
315 		case B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR:
316 		case B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC:
317 		{
318 			if (op == B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC
319 					&& length < sizeof(command.config_etc))
320 				return B_BUFFER_OVERFLOW;
321 
322 			if (length < sizeof(command.config))
323 				return B_BUFFER_OVERFLOW;
324 
325 			status = B_OK;
326 			const usb_configuration_info *configurationInfo =
327 				usb_raw_get_configuration(device, command.config.config_index,
328 					&command.config.status);
329 			if (configurationInfo == NULL)
330 				break;
331 
332 			size_t sizeToCopy = sizeof(usb_configuration_descriptor);
333 			if (op == B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC) {
334 				sizeToCopy = std::min(command.config_etc.length,
335 					(size_t)configurationInfo->descr->total_length);
336 			}
337 
338 			if (!IS_USER_ADDRESS(command.config.descriptor)
339 				|| user_memcpy(command.config.descriptor,
340 					configurationInfo->descr, sizeToCopy) != B_OK) {
341 				return B_BAD_ADDRESS;
342 			}
343 
344 			command.config.status = B_USB_RAW_STATUS_SUCCESS;
345 			break;
346 		}
347 
348 		case B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT:
349 		case B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX:
350 		{
351 			if (length < sizeof(command.alternate))
352 				return B_BUFFER_OVERFLOW;
353 
354 			status = B_OK;
355 			const usb_configuration_info *configurationInfo =
356 				usb_raw_get_configuration(device,
357 					command.alternate.config_index,
358 					&command.alternate.status);
359 			if (configurationInfo == NULL)
360 				break;
361 
362 			if (command.alternate.interface_index
363 				>= configurationInfo->interface_count) {
364 				command.alternate.status = B_USB_RAW_STATUS_INVALID_INTERFACE;
365 				break;
366 			}
367 
368 			const usb_interface_list *interfaceList
369 				= &configurationInfo->interface[
370 					command.alternate.interface_index];
371 			if (op == B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT) {
372 				command.alternate.alternate_info = interfaceList->alt_count;
373 			} else {
374 				for (size_t i = 0; i < interfaceList->alt_count; i++) {
375 					if (&interfaceList->alt[i] == interfaceList->active) {
376 						command.alternate.alternate_info = i;
377 						break;
378 					}
379 				}
380 			}
381 
382 			command.alternate.status = B_USB_RAW_STATUS_SUCCESS;
383 			break;
384 		}
385 
386 		case B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR:
387 		case B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC:
388 		{
389 			const usb_interface_info *interfaceInfo = NULL;
390 			status = B_OK;
391 			if (op == B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR) {
392 				if (length < sizeof(command.interface))
393 					return B_BUFFER_OVERFLOW;
394 
395 				interfaceInfo = usb_raw_get_interface(device,
396 					command.interface.config_index,
397 					command.interface.interface_index,
398 					B_USB_RAW_ACTIVE_ALTERNATE,
399 					&command.interface.status);
400 			} else {
401 				if (length < sizeof(command.interface_etc))
402 					return B_BUFFER_OVERFLOW;
403 
404 				interfaceInfo = usb_raw_get_interface(device,
405 					command.interface_etc.config_index,
406 					command.interface_etc.interface_index,
407 					command.interface_etc.alternate_index,
408 					&command.interface_etc.status);
409 			}
410 
411 			if (interfaceInfo == NULL)
412 				break;
413 
414 			if (!IS_USER_ADDRESS(command.interface.descriptor)
415 				|| user_memcpy(command.interface.descriptor, interfaceInfo->descr,
416 					sizeof(usb_interface_descriptor)) != B_OK) {
417 				return B_BAD_ADDRESS;
418 			}
419 
420 			command.interface.status = B_USB_RAW_STATUS_SUCCESS;
421 			break;
422 		}
423 
424 		case B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR:
425 		case B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC:
426 		{
427 			uint32 endpointIndex = 0;
428 			const usb_interface_info *interfaceInfo = NULL;
429 			status = B_OK;
430 			if (op == B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR) {
431 				if (length < sizeof(command.endpoint))
432 					return B_BUFFER_OVERFLOW;
433 
434 				interfaceInfo = usb_raw_get_interface(device,
435 					command.endpoint.config_index,
436 					command.endpoint.interface_index,
437 					B_USB_RAW_ACTIVE_ALTERNATE,
438 					&command.endpoint.status);
439 				endpointIndex = command.endpoint.endpoint_index;
440 			} else {
441 				if (length < sizeof(command.endpoint_etc))
442 					return B_BUFFER_OVERFLOW;
443 
444 				interfaceInfo = usb_raw_get_interface(device,
445 					command.endpoint_etc.config_index,
446 					command.endpoint_etc.interface_index,
447 					command.endpoint_etc.alternate_index,
448 					&command.endpoint_etc.status);
449 				endpointIndex = command.endpoint_etc.endpoint_index;
450 			}
451 
452 			if (interfaceInfo == NULL)
453 				break;
454 
455 			if (endpointIndex >= interfaceInfo->endpoint_count) {
456 				command.endpoint.status = B_USB_RAW_STATUS_INVALID_ENDPOINT;
457 				break;
458 			}
459 
460 			if (!IS_USER_ADDRESS(command.endpoint.descriptor)
461 				|| user_memcpy(command.endpoint.descriptor,
462 					interfaceInfo->endpoint[endpointIndex].descr,
463 					sizeof(usb_endpoint_descriptor)) != B_OK) {
464 				return B_BAD_ADDRESS;
465 			}
466 
467 			command.endpoint.status = B_USB_RAW_STATUS_SUCCESS;
468 			break;
469 		}
470 
471 		case B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR:
472 		case B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR_ETC:
473 		{
474 			uint32 genericIndex = 0;
475 			size_t genericLength = 0;
476 			const usb_interface_info *interfaceInfo = NULL;
477 			status = B_OK;
478 			if (op == B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR) {
479 				if (length < sizeof(command.generic))
480 					return B_BUFFER_OVERFLOW;
481 
482 				interfaceInfo = usb_raw_get_interface(device,
483 					command.generic.config_index,
484 					command.generic.interface_index,
485 					B_USB_RAW_ACTIVE_ALTERNATE,
486 					&command.generic.status);
487 				genericIndex = command.generic.generic_index;
488 				genericLength = command.generic.length;
489 			} else {
490 				if (length < sizeof(command.generic_etc))
491 					return B_BUFFER_OVERFLOW;
492 
493 				interfaceInfo = usb_raw_get_interface(device,
494 					command.generic_etc.config_index,
495 					command.generic_etc.interface_index,
496 					command.generic_etc.alternate_index,
497 					&command.generic_etc.status);
498 				genericIndex = command.generic_etc.generic_index;
499 				genericLength = command.generic_etc.length;
500 			}
501 
502 			if (interfaceInfo == NULL)
503 				break;
504 
505 			if (genericIndex >= interfaceInfo->generic_count) {
506 				command.endpoint.status = B_USB_RAW_STATUS_INVALID_ENDPOINT;
507 				break;
508 			}
509 
510 			usb_descriptor *descriptor = interfaceInfo->generic[genericIndex];
511 			if (descriptor == NULL)
512 				break;
513 
514 			if (!IS_USER_ADDRESS(command.generic.descriptor)
515 				|| user_memcpy(command.generic.descriptor, descriptor,
516 					min_c(genericLength, descriptor->generic.length)) != B_OK) {
517 				return B_BAD_ADDRESS;
518 			}
519 
520 			if (descriptor->generic.length > genericLength)
521 				command.generic.status = B_USB_RAW_STATUS_NO_MEMORY;
522 			else
523 				command.generic.status = B_USB_RAW_STATUS_SUCCESS;
524 			break;
525 		}
526 
527 		case B_USB_RAW_COMMAND_GET_STRING_DESCRIPTOR:
528 		{
529 			if (length < sizeof(command.string))
530 				return B_BUFFER_OVERFLOW;
531 
532 			size_t actualLength = 0;
533 			uint8 firstTwoBytes[2];
534 			status = B_OK;
535 
536 			if (gUSBModule->get_descriptor(device->device,
537 				USB_DESCRIPTOR_STRING, command.string.string_index, 0,
538 				firstTwoBytes, 2, &actualLength) < B_OK
539 				|| actualLength != 2
540 				|| firstTwoBytes[1] != USB_DESCRIPTOR_STRING) {
541 				command.string.status = B_USB_RAW_STATUS_ABORTED;
542 				command.string.length = 0;
543 				break;
544 			}
545 
546 			uint8 stringLength = MIN(firstTwoBytes[0], command.string.length);
547 			char *string = (char *)malloc(stringLength);
548 			if (string == NULL) {
549 				command.string.status = B_USB_RAW_STATUS_ABORTED;
550 				command.string.length = 0;
551 				status = B_NO_MEMORY;
552 				break;
553 			}
554 
555 			if (gUSBModule->get_descriptor(device->device,
556 				USB_DESCRIPTOR_STRING, command.string.string_index, 0,
557 				string, stringLength, &actualLength) < B_OK
558 				|| actualLength != stringLength) {
559 				command.string.status = B_USB_RAW_STATUS_ABORTED;
560 				command.string.length = 0;
561 				free(string);
562 				break;
563 			}
564 
565 			if (!IS_USER_ADDRESS(command.string.descriptor)
566 				|| user_memcpy(command.string.descriptor, string,
567 					stringLength) != B_OK) {
568 				free(string);
569 				return B_BAD_ADDRESS;
570 			}
571 
572 			command.string.status = B_USB_RAW_STATUS_SUCCESS;
573 			command.string.length = stringLength;
574 			free(string);
575 			break;
576 		}
577 
578 		case B_USB_RAW_COMMAND_GET_DESCRIPTOR:
579 		{
580 			if (length < sizeof(command.descriptor))
581 				return B_BUFFER_OVERFLOW;
582 
583 			size_t actualLength = 0;
584 			uint8 firstTwoBytes[2];
585 			status = B_OK;
586 
587 			if (gUSBModule->get_descriptor(device->device,
588 				command.descriptor.type, command.descriptor.index,
589 				command.descriptor.language_id, firstTwoBytes, 2,
590 				&actualLength) < B_OK
591 				|| actualLength != 2
592 				|| firstTwoBytes[1] != command.descriptor.type) {
593 				command.descriptor.status = B_USB_RAW_STATUS_ABORTED;
594 				command.descriptor.length = 0;
595 				break;
596 			}
597 
598 			uint8 descriptorLength = MIN(firstTwoBytes[0],
599 				command.descriptor.length);
600 			uint8 *descriptorBuffer = (uint8 *)malloc(descriptorLength);
601 			if (descriptorBuffer == NULL) {
602 				command.descriptor.status = B_USB_RAW_STATUS_ABORTED;
603 				command.descriptor.length = 0;
604 				status = B_NO_MEMORY;
605 				break;
606 			}
607 
608 			if (gUSBModule->get_descriptor(device->device,
609 				command.descriptor.type, command.descriptor.index,
610 				command.descriptor.language_id, descriptorBuffer,
611 				descriptorLength, &actualLength) < B_OK
612 				|| actualLength != descriptorLength) {
613 				command.descriptor.status = B_USB_RAW_STATUS_ABORTED;
614 				command.descriptor.length = 0;
615 				free(descriptorBuffer);
616 				break;
617 			}
618 
619 			if (!IS_USER_ADDRESS(command.descriptor.data)
620 				|| user_memcpy(command.descriptor.data, descriptorBuffer,
621 					descriptorLength) != B_OK) {
622 				free(descriptorBuffer);
623 				return B_BAD_ADDRESS;
624 			}
625 
626 			command.descriptor.status = B_USB_RAW_STATUS_SUCCESS;
627 			command.descriptor.length = descriptorLength;
628 			free(descriptorBuffer);
629 			break;
630 		}
631 
632 		case B_USB_RAW_COMMAND_SET_CONFIGURATION:
633 		{
634 			if (length < sizeof(command.config))
635 				return B_BUFFER_OVERFLOW;
636 
637 			status = B_OK;
638 			const usb_configuration_info *configurationInfo =
639 				usb_raw_get_configuration(device, command.config.config_index,
640 					&command.config.status);
641 			if (configurationInfo == NULL)
642 				break;
643 
644 			if (gUSBModule->set_configuration(device->device,
645 				configurationInfo) < B_OK) {
646 				command.config.status = B_USB_RAW_STATUS_FAILED;
647 				break;
648 			}
649 
650 			command.config.status = B_USB_RAW_STATUS_SUCCESS;
651 			break;
652 		}
653 
654 		case B_USB_RAW_COMMAND_SET_ALT_INTERFACE:
655 		{
656 			if (length < sizeof(command.alternate))
657 				return B_BUFFER_OVERFLOW;
658 
659 			status = B_OK;
660 			const usb_configuration_info *configurationInfo =
661 				usb_raw_get_configuration(device,
662 					command.alternate.config_index,
663 					&command.alternate.status);
664 			if (configurationInfo == NULL)
665 				break;
666 
667 			if (command.alternate.interface_index
668 				>= configurationInfo->interface_count) {
669 				command.alternate.status = B_USB_RAW_STATUS_INVALID_INTERFACE;
670 				break;
671 			}
672 
673 			const usb_interface_list *interfaceList =
674 				&configurationInfo->interface[command.alternate.interface_index];
675 			if (command.alternate.alternate_info >= interfaceList->alt_count) {
676 				command.alternate.status = B_USB_RAW_STATUS_INVALID_INTERFACE;
677 				break;
678 			}
679 
680 			if (gUSBModule->set_alt_interface(device->device,
681 				&interfaceList->alt[command.alternate.alternate_info]) < B_OK) {
682 				command.alternate.status = B_USB_RAW_STATUS_FAILED;
683 				break;
684 			}
685 
686 			command.alternate.status = B_USB_RAW_STATUS_SUCCESS;
687 			break;
688 		}
689 
690 		case B_USB_RAW_COMMAND_CONTROL_TRANSFER:
691 		{
692 			if (length < sizeof(command.control))
693 				return B_BUFFER_OVERFLOW;
694 
695 			void *controlData = malloc(command.control.length);
696 			if (controlData == NULL)
697 				return B_NO_MEMORY;
698 			bool inTransfer = (command.control.request_type
699 				& USB_ENDPOINT_ADDR_DIR_IN) != 0;
700 			if (!IS_USER_ADDRESS(command.control.data)
701 				|| (!inTransfer && user_memcpy(controlData,
702 					command.control.data, command.control.length) != B_OK)) {
703 				free(controlData);
704 				return B_BAD_ADDRESS;
705 			}
706 
707 			mutex_lock(&device->lock);
708 			if (gUSBModule->queue_request(device->device,
709 				command.control.request_type, command.control.request,
710 				command.control.value, command.control.index,
711 				command.control.length, controlData,
712 				usb_raw_callback, device) < B_OK) {
713 				command.control.status = B_USB_RAW_STATUS_FAILED;
714 				command.control.length = 0;
715 				mutex_unlock(&device->lock);
716 				free(controlData);
717 				status = B_OK;
718 				break;
719 			}
720 
721 			acquire_sem(device->notify);
722 			command.control.status = device->status;
723 			command.control.length = device->actual_length;
724 			mutex_unlock(&device->lock);
725 
726 			status = B_OK;
727 			if (inTransfer && user_memcpy(command.control.data, controlData,
728 				command.control.length) != B_OK) {
729 				status = B_BAD_ADDRESS;
730 			}
731 
732 			free(controlData);
733 			break;
734 		}
735 
736 		case B_USB_RAW_COMMAND_INTERRUPT_TRANSFER:
737 		case B_USB_RAW_COMMAND_BULK_TRANSFER:
738 		case B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER:
739 		{
740 			if (length < sizeof(command.transfer))
741 				return B_BUFFER_OVERFLOW;
742 
743 			status = B_OK;
744 			const usb_configuration_info *configurationInfo =
745 				gUSBModule->get_configuration(device->device);
746 			if (configurationInfo == NULL) {
747 				command.transfer.status = B_USB_RAW_STATUS_INVALID_CONFIGURATION;
748 				break;
749 			}
750 
751 			if (command.transfer.interface >= configurationInfo->interface_count) {
752 				command.transfer.status = B_USB_RAW_STATUS_INVALID_INTERFACE;
753 				break;
754 			}
755 
756 			const usb_interface_info *interfaceInfo =
757 				configurationInfo->interface[command.transfer.interface].active;
758 			if (interfaceInfo == NULL) {
759 				command.transfer.status = B_USB_RAW_STATUS_ABORTED;
760 				break;
761 			}
762 
763 			if (command.transfer.endpoint >= interfaceInfo->endpoint_count) {
764 				command.transfer.status = B_USB_RAW_STATUS_INVALID_ENDPOINT;
765 				break;
766 			}
767 
768 			const usb_endpoint_info *endpointInfo =
769 				&interfaceInfo->endpoint[command.transfer.endpoint];
770 			if (!endpointInfo->handle) {
771 				command.transfer.status = B_USB_RAW_STATUS_INVALID_ENDPOINT;
772 				break;
773 			}
774 
775 			size_t descriptorsSize = 0;
776 			usb_iso_packet_descriptor *packetDescriptors = NULL;
777 			void *transferData = NULL;
778 			bool inTransfer = (endpointInfo->descr->endpoint_address
779 				& USB_ENDPOINT_ADDR_DIR_IN) != 0;
780 			if (op == B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER) {
781 				if (length < sizeof(command.isochronous))
782 					return B_BUFFER_OVERFLOW;
783 
784 				descriptorsSize = sizeof(usb_iso_packet_descriptor)
785 					* command.isochronous.packet_count;
786 				packetDescriptors
787 					= (usb_iso_packet_descriptor *)malloc(descriptorsSize);
788 				if (packetDescriptors == NULL) {
789 					command.transfer.status = B_USB_RAW_STATUS_NO_MEMORY;
790 					command.transfer.length = 0;
791 					break;
792 				}
793 
794 				if (!IS_USER_ADDRESS(command.isochronous.data)
795 					|| !IS_USER_ADDRESS(command.isochronous.packet_descriptors)
796 					|| user_memcpy(packetDescriptors,
797 						command.isochronous.packet_descriptors,
798 						descriptorsSize) != B_OK) {
799 					free(packetDescriptors);
800 					return B_BAD_ADDRESS;
801 				}
802 			} else {
803 				transferData = malloc(command.transfer.length);
804 				if (transferData == NULL) {
805 					command.transfer.status = B_USB_RAW_STATUS_NO_MEMORY;
806 					command.transfer.length = 0;
807 					break;
808 				}
809 
810 				if (!IS_USER_ADDRESS(command.transfer.data) || (!inTransfer
811 						&& user_memcpy(transferData, command.transfer.data,
812 							command.transfer.length) != B_OK)) {
813 					free(transferData);
814 					return B_BAD_ADDRESS;
815 				}
816 			}
817 
818 			status_t status;
819 			mutex_lock(&device->lock);
820 			if (op == B_USB_RAW_COMMAND_INTERRUPT_TRANSFER) {
821 				status = gUSBModule->queue_interrupt(endpointInfo->handle,
822 					transferData, command.transfer.length,
823 					usb_raw_callback, device);
824 			} else if (op == B_USB_RAW_COMMAND_BULK_TRANSFER) {
825 				status = gUSBModule->queue_bulk(endpointInfo->handle,
826 					transferData, command.transfer.length,
827 					usb_raw_callback, device);
828 			} else {
829 				status = gUSBModule->queue_isochronous(endpointInfo->handle,
830 					command.isochronous.data, command.isochronous.length,
831 					packetDescriptors, command.isochronous.packet_count, NULL,
832 					0, usb_raw_callback, device);
833 			}
834 
835 			if (status < B_OK) {
836 				command.transfer.status = B_USB_RAW_STATUS_FAILED;
837 				command.transfer.length = 0;
838 				free(packetDescriptors);
839 				free(transferData);
840 				mutex_unlock(&device->lock);
841 				status = B_OK;
842 				break;
843 			}
844 
845 			acquire_sem(device->notify);
846 			command.transfer.status = device->status;
847 			command.transfer.length = device->actual_length;
848 			mutex_unlock(&device->lock);
849 
850 			status = B_OK;
851 			if (op == B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER) {
852 				if (user_memcpy(command.isochronous.packet_descriptors,
853 						packetDescriptors, descriptorsSize) != B_OK) {
854 					status = B_BAD_ADDRESS;
855 				}
856 
857 				free(packetDescriptors);
858 			} else {
859 				if (inTransfer && user_memcpy(command.transfer.data,
860 					transferData, command.transfer.length) != B_OK) {
861 					status = B_BAD_ADDRESS;
862 				}
863 				free(transferData);
864 			}
865 
866 			break;
867 		}
868 	}
869 
870 	if (user_memcpy(buffer, &command, min_c(length, sizeof(command))) != B_OK)
871 		return B_BAD_ADDRESS;
872 
873 	return status;
874 }
875 
876 
877 static status_t
878 usb_raw_read(void *cookie, off_t position, void *buffer, size_t *length)
879 {
880 	TRACE((DRIVER_NAME": read()\n"));
881 	*length = 0;
882 	return B_OK;
883 }
884 
885 
886 static status_t
887 usb_raw_write(void *cookie, off_t position, const void *buffer, size_t *length)
888 {
889 	TRACE((DRIVER_NAME": write()\n"));
890 	*length = 0;
891 	return B_OK;
892 }
893 
894 
895 //
896 //#pragma mark -
897 //
898 
899 
900 status_t
901 init_hardware()
902 {
903 	TRACE((DRIVER_NAME": init_hardware()\n"));
904 	return B_OK;
905 }
906 
907 
908 status_t
909 init_driver()
910 {
911 	TRACE((DRIVER_NAME": init_driver()\n"));
912 	static usb_notify_hooks notifyHooks = {
913 		&usb_raw_device_added,
914 		&usb_raw_device_removed
915 	};
916 
917 	gDeviceList = NULL;
918 	gDeviceCount = 0;
919 	mutex_init(&gDeviceListLock, "usb_raw device list lock");
920 
921 	TRACE((DRIVER_NAME": trying module %s\n", B_USB_MODULE_NAME));
922 	status_t result = get_module(B_USB_MODULE_NAME,
923 		(module_info **)&gUSBModule);
924 	if (result < B_OK) {
925 		TRACE((DRIVER_NAME": getting module failed 0x%08" B_PRIx32 "\n",
926 			result));
927 		mutex_destroy(&gDeviceListLock);
928 		return result;
929 	}
930 
931 	gUSBModule->register_driver(DRIVER_NAME, NULL, 0, NULL);
932 	gUSBModule->install_notify(DRIVER_NAME, &notifyHooks);
933 	return B_OK;
934 }
935 
936 
937 void
938 uninit_driver()
939 {
940 	TRACE((DRIVER_NAME": uninit_driver()\n"));
941 	gUSBModule->uninstall_notify(DRIVER_NAME);
942 	mutex_lock(&gDeviceListLock);
943 
944 	if (gDeviceNames) {
945 		for (int32 i = 1; gDeviceNames[i]; i++)
946 			free(gDeviceNames[i]);
947 		free(gDeviceNames);
948 		gDeviceNames = NULL;
949 	}
950 
951 	mutex_destroy(&gDeviceListLock);
952 	put_module(B_USB_MODULE_NAME);
953 }
954 
955 
956 const char **
957 publish_devices()
958 {
959 	TRACE((DRIVER_NAME": publish_devices()\n"));
960 	if (gDeviceNames) {
961 		for (int32 i = 0; gDeviceNames[i]; i++)
962 			free(gDeviceNames[i]);
963 		free(gDeviceNames);
964 		gDeviceNames = NULL;
965 	}
966 
967 	int32 index = 0;
968 	gDeviceNames = (char **)malloc(sizeof(char *) * (gDeviceCount + 2));
969 	if (gDeviceNames == NULL)
970 		return NULL;
971 
972 	gDeviceNames[index++] = strdup(DEVICE_NAME);
973 
974 	mutex_lock(&gDeviceListLock);
975 	raw_device *element = gDeviceList;
976 	while (element) {
977 		gDeviceNames[index++] = strdup(element->name);
978 		element = (raw_device *)element->link;
979 	}
980 
981 	gDeviceNames[index++] = NULL;
982 	mutex_unlock(&gDeviceListLock);
983 	return (const char **)gDeviceNames;
984 }
985 
986 
987 device_hooks *
988 find_device(const char *name)
989 {
990 	TRACE((DRIVER_NAME": find_device()\n"));
991 	static device_hooks hooks = {
992 		&usb_raw_open,
993 		&usb_raw_close,
994 		&usb_raw_free,
995 		&usb_raw_ioctl,
996 		&usb_raw_read,
997 		&usb_raw_write,
998 		NULL,
999 		NULL,
1000 		NULL,
1001 		NULL
1002 	};
1003 
1004 	return &hooks;
1005 }
1006