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