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