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