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