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