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