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