xref: /haiku/src/add-ons/kernel/drivers/bus/usb/usb_raw.cpp (revision 020cbad9d40235a2c50a81a42d69912a5ff8fbc4)
1 /*
2  * Copyright 2006, 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 <KernelExport.h>
10 #include <Drivers.h>
11 #include <malloc.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include "usb_raw.h"
15 #include "BeOSCompatibility.h"
16 
17 
18 //#define TRACE_USB_RAW
19 #ifdef TRACE_USB_RAW
20 #define TRACE(x)	dprintf x
21 #else
22 #define TRACE(x)	/* nothing */
23 #endif
24 
25 
26 #define DRIVER_NAME		"usb_raw"
27 #define DEVICE_NAME		"bus/usb/raw"
28 #define DRIVER_VERSION	0x0015
29 
30 int32 api_version = B_CUR_DRIVER_API_VERSION;
31 static usb_module_info *gUSBModule = NULL;
32 static raw_device *gDeviceList = NULL;
33 static uint32 gDeviceCount = 0;
34 static benaphore gDeviceListLock;
35 static char **gDeviceNames = NULL;
36 
37 static status_t
38 usb_raw_device_added(usb_device newDevice, void **cookie)
39 {
40 	TRACE((DRIVER_NAME": device_added(0x%08lx)\n", newDevice));
41 	raw_device *device = (raw_device *)malloc(sizeof(raw_device));
42 
43 	status_t result = benaphore_init(&device->lock, "usb_raw device lock");
44 	if (result < B_OK) {
45 		free(device);
46 		return result;
47 	}
48 
49 	device->notify = create_sem(0, "usb_raw callback notify");
50 	if (device->notify < B_OK) {
51 		benaphore_destroy(&device->lock);
52 		free(device);
53 		return B_NO_MORE_SEMS;
54 	}
55 
56 	char deviceName[32];
57 	memcpy(deviceName, &newDevice, sizeof(usb_device));
58 	if (gUSBModule->usb_ioctl('DNAM', deviceName, sizeof(deviceName)) >= B_OK) {
59 		sprintf(device->name, "bus/usb/%s", deviceName);
60 	} else {
61 		sprintf(device->name, "bus/usb/%08lx", newDevice);
62 	}
63 
64 	device->device = newDevice;
65 	device->reference_count = 0;
66 
67 	benaphore_lock(&gDeviceListLock);
68 	device->link = (void *)gDeviceList;
69 	gDeviceList = device;
70 	gDeviceCount++;
71 	benaphore_unlock(&gDeviceListLock);
72 
73 	TRACE((DRIVER_NAME": new device: 0x%08lx\n", (uint32)device));
74 	*cookie = (void *)device;
75 	return B_OK;
76 }
77 
78 
79 static status_t
80 usb_raw_device_removed(void *cookie)
81 {
82 	TRACE((DRIVER_NAME": device_removed(0x%08lx)\n", (uint32)cookie));
83 	raw_device *device = (raw_device *)cookie;
84 
85 	benaphore_lock(&gDeviceListLock);
86 	if (gDeviceList == device) {
87 		gDeviceList = (raw_device *)device->link;
88 	} else {
89 		raw_device *element = gDeviceList;
90 		while (element) {
91 			if (element->link == device) {
92 				element->link = device->link;
93 				break;
94 			}
95 
96 			element = (raw_device *)element->link;
97 		}
98 	}
99 	gDeviceCount--;
100 	benaphore_unlock(&gDeviceListLock);
101 
102 	device->device = 0;
103 	if (device->reference_count == 0) {
104 		benaphore_lock(&device->lock);
105 		benaphore_destroy(&device->lock);
106 		delete_sem(device->notify);
107 		free(device);
108 	}
109 
110 	return B_OK;
111 }
112 
113 
114 //
115 //#pragma mark -
116 //
117 
118 
119 static status_t
120 usb_raw_open(const char *name, uint32 flags, void **cookie)
121 {
122 	TRACE((DRIVER_NAME": open()\n"));
123 	benaphore_lock(&gDeviceListLock);
124 	raw_device *element = gDeviceList;
125 	while (element) {
126 		if (strcmp(name, element->name) == 0) {
127 			element->reference_count++;
128 			*cookie = element;
129 			benaphore_unlock(&gDeviceListLock);
130 			return B_OK;
131 		}
132 
133 		element = (raw_device *)element->link;
134 	}
135 
136 	benaphore_unlock(&gDeviceListLock);
137 	return B_NAME_NOT_FOUND;
138 }
139 
140 
141 static status_t
142 usb_raw_close(void *cookie)
143 {
144 	TRACE((DRIVER_NAME": close()\n"));
145 	return B_OK;
146 }
147 
148 
149 static status_t
150 usb_raw_free(void *cookie)
151 {
152 	TRACE((DRIVER_NAME": free()\n"));
153 	benaphore_lock(&gDeviceListLock);
154 
155 	raw_device *device = (raw_device *)cookie;
156 	device->reference_count--;
157 	if (device->device == 0) {
158 		benaphore_lock(&device->lock);
159 		benaphore_destroy(&device->lock);
160 		delete_sem(device->notify);
161 		free(device);
162 	}
163 
164 	benaphore_unlock(&gDeviceListLock);
165 	return B_OK;
166 }
167 
168 
169 static void
170 usb_raw_callback(void *cookie, status_t status, void *data, size_t actualLength)
171 {
172 	TRACE((DRIVER_NAME": callback()\n"));
173 	raw_device *device = (raw_device *)cookie;
174 
175 	switch (status) {
176 		case B_OK:
177 			device->status = RAW_STATUS_SUCCESS;
178 			break;
179 		case B_TIMED_OUT:
180 			device->status = RAW_STATUS_TIMEOUT;
181 			break;
182 		case B_CANCELED:
183 			device->status = RAW_STATUS_ABORTED;
184 			break;
185 		case B_DEV_CRC_ERROR:
186 			device->status = RAW_STATUS_CRC_ERROR;
187 			break;
188 		case B_DEV_STALLED:
189 			device->status = RAW_STATUS_STALLED;
190 			break;
191 		default:
192 			device->status = RAW_STATUS_FAILED;
193 			break;
194 	}
195 
196 	device->actual_length = actualLength;
197 	release_sem(device->notify);
198 }
199 
200 
201 static status_t
202 usb_raw_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
203 {
204 	TRACE((DRIVER_NAME": ioctl\n"));
205 	raw_device *device = (raw_device *)cookie;
206 	raw_command *command = (raw_command *)buffer;
207 
208 	if (device->device == 0)
209 		return B_DEV_NOT_READY;
210 
211 	switch (op) {
212 		case RAW_COMMAND_GET_VERSION: {
213 			command->version.status = DRIVER_VERSION;
214 			return B_OK;
215 		}
216 
217 		case RAW_COMMAND_GET_DEVICE_DESCRIPTOR: {
218 			const usb_device_descriptor *deviceDescriptor =
219 				gUSBModule->get_device_descriptor(device->device);
220 			if (!deviceDescriptor) {
221 				command->device.status = RAW_STATUS_ABORTED;
222 				return B_OK;
223 			}
224 
225 			memcpy(command->device.descriptor, deviceDescriptor,
226 				sizeof(usb_device_descriptor));
227 			command->device.status = RAW_STATUS_SUCCESS;
228 			return B_OK;
229 		}
230 
231 		case RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR: {
232 			const usb_configuration_info *configurationInfo =
233 				gUSBModule->get_nth_configuration(device->device,
234 				command->config.config_index);
235 			if (!configurationInfo) {
236 				command->config.status = RAW_STATUS_INVALID_CONFIGURATION;
237 				return B_OK;
238 			}
239 
240 			memcpy(command->config.descriptor, configurationInfo->descr,
241 				sizeof(usb_configuration_descriptor));
242 			command->config.status = RAW_STATUS_SUCCESS;
243 			return B_OK;
244 		}
245 
246 		case RAW_COMMAND_GET_INTERFACE_DESCRIPTOR: {
247 			const usb_configuration_info *configurationInfo =
248 				gUSBModule->get_nth_configuration(device->device,
249 				command->interface.config_index);
250 			if (!configurationInfo) {
251 				command->interface.status = RAW_STATUS_INVALID_CONFIGURATION;
252 				return B_OK;
253 			}
254 
255 			if (command->interface.interface_index >= configurationInfo->interface_count) {
256 				command->interface.status = RAW_STATUS_INVALID_INTERFACE;
257 				return B_OK;
258 			}
259 
260 			const usb_interface_info *interfaceInfo =
261 				configurationInfo->interface[command->endpoint.interface_index].active;
262 			if (!interfaceInfo) {
263 				command->interface.status = RAW_STATUS_ABORTED;
264 				return B_OK;
265 			}
266 
267 			memcpy(command->interface.descriptor, interfaceInfo->descr,
268 				sizeof(usb_interface_descriptor));
269 			command->interface.status = RAW_STATUS_SUCCESS;
270 			return B_OK;
271 		}
272 
273 		case RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR: {
274 			const usb_configuration_info *configurationInfo =
275 				gUSBModule->get_nth_configuration(device->device,
276 				command->endpoint.config_index);
277 			if (!configurationInfo) {
278 				command->endpoint.status = RAW_STATUS_INVALID_CONFIGURATION;
279 				return B_OK;
280 			}
281 
282 			if (command->endpoint.interface_index >= configurationInfo->interface_count) {
283 				command->endpoint.status = RAW_STATUS_INVALID_INTERFACE;
284 				return B_OK;
285 			}
286 
287 			const usb_interface_info *interfaceInfo =
288 				configurationInfo->interface[command->endpoint.interface_index].active;
289 			if (!interfaceInfo) {
290 				command->endpoint.status = RAW_STATUS_ABORTED;
291 				return B_OK;
292 			}
293 
294 			if (command->endpoint.endpoint_index >= interfaceInfo->endpoint_count) {
295 				command->endpoint.status = RAW_STATUS_INVALID_ENDPOINT;
296 				return B_OK;
297 			}
298 
299 			memcpy(command->endpoint.descriptor,
300 				interfaceInfo->endpoint[command->endpoint.endpoint_index].descr,
301 				sizeof(usb_endpoint_descriptor));
302 			command->endpoint.status = RAW_STATUS_SUCCESS;
303 			return B_OK;
304 		}
305 
306 		case RAW_COMMAND_GET_GENERIC_DESCRIPTOR: {
307 			const usb_configuration_info *configurationInfo =
308 				gUSBModule->get_nth_configuration(device->device,
309 				command->generic.config_index);
310 			if (!configurationInfo) {
311 				command->generic.status = RAW_STATUS_INVALID_CONFIGURATION;
312 				return B_OK;
313 			}
314 
315 			if (command->generic.interface_index >= configurationInfo->interface_count) {
316 				command->generic.status = RAW_STATUS_INVALID_INTERFACE;
317 				return B_OK;
318 			}
319 
320 			const usb_interface_info *interfaceInfo =
321 				configurationInfo->interface[command->generic.interface_index].active;
322 			if (!interfaceInfo) {
323 				command->generic.status = RAW_STATUS_ABORTED;
324 				return B_OK;
325 			}
326 
327 			if (command->generic.generic_index >= interfaceInfo->generic_count) {
328 				// ToDo: add RAW_STATUS_INVALID_GENERIC
329 				command->generic.status = RAW_STATUS_INVALID_ENDPOINT;
330 				return B_OK;
331 			}
332 
333 			usb_descriptor *descriptor = interfaceInfo->generic[command->generic.generic_index];
334 			if (!descriptor) {
335 				command->generic.status = RAW_STATUS_ABORTED;
336 				return B_OK;
337 			}
338 
339 			if (descriptor->generic.length > command->generic.length) {
340 				command->generic.status = RAW_STATUS_NO_MEMORY;
341 				return B_OK;
342 			}
343 
344 			memcpy(command->generic.descriptor, descriptor,
345 				descriptor->generic.length);
346 			command->generic.status = RAW_STATUS_SUCCESS;
347 			return B_OK;
348 		}
349 
350 		case RAW_COMMAND_GET_STRING_DESCRIPTOR: {
351 			size_t actualLength = 0;
352 			uint8 firstTwoBytes[2];
353 
354 			if (gUSBModule->get_descriptor(device->device,
355 				USB_DESCRIPTOR_STRING, command->string.string_index, 0,
356 				firstTwoBytes, 2, &actualLength) < B_OK
357 				|| actualLength != 2
358 				|| firstTwoBytes[1] != USB_DESCRIPTOR_STRING) {
359 				command->string.status = RAW_STATUS_ABORTED;
360 				command->string.length = 0;
361 				return B_OK;
362 			}
363 
364 			uint8 stringLength = MIN(firstTwoBytes[0], command->string.length);
365 			char *string = (char *)malloc(stringLength);
366 			if (!string) {
367 				command->string.status = RAW_STATUS_ABORTED;
368 				command->string.length = 0;
369 				return B_NO_MEMORY;
370 			}
371 
372 			if (gUSBModule->get_descriptor(device->device,
373 				USB_DESCRIPTOR_STRING, command->string.string_index, 0,
374 				string, stringLength, &actualLength) < B_OK
375 				|| actualLength != stringLength) {
376 				command->string.status = RAW_STATUS_ABORTED;
377 				command->string.length = 0;
378 				free(string);
379 				return B_OK;
380 			}
381 
382 			memcpy(command->string.descriptor, string, stringLength);
383 			command->string.status = RAW_STATUS_SUCCESS;
384 			command->string.length = stringLength;
385 			free(string);
386 			return B_OK;
387 		}
388 
389 		case RAW_COMMAND_GET_DESCRIPTOR: {
390 			size_t actualLength = 0;
391 			uint8 firstTwoBytes[2];
392 
393 			if (gUSBModule->get_descriptor(device->device,
394 				command->descriptor.type, command->descriptor.index,
395 				command->descriptor.language_id, firstTwoBytes, 2,
396 				&actualLength) < B_OK
397 				|| actualLength != 2
398 				|| firstTwoBytes[1] != command->descriptor.type) {
399 				command->descriptor.status = RAW_STATUS_ABORTED;
400 				command->descriptor.length = 0;
401 				return B_OK;
402 			}
403 
404 			uint8 length = MIN(firstTwoBytes[0], command->descriptor.length);
405 			uint8 *buffer = (uint8 *)malloc(length);
406 			if (!buffer) {
407 				command->descriptor.status = RAW_STATUS_ABORTED;
408 				command->descriptor.length = 0;
409 				return B_NO_MEMORY;
410 			}
411 
412 			if (gUSBModule->get_descriptor(device->device,
413 				command->descriptor.type, command->descriptor.index,
414 				command->descriptor.language_id, buffer, length,
415 				&actualLength) < B_OK
416 				|| actualLength != length) {
417 				command->descriptor.status = RAW_STATUS_ABORTED;
418 				command->descriptor.length = 0;
419 				free(buffer);
420 				return B_OK;
421 			}
422 
423 			memcpy(command->descriptor.data, buffer, length);
424 			command->descriptor.status = RAW_STATUS_SUCCESS;
425 			command->descriptor.length = length;
426 			free(buffer);
427 			return B_OK;
428 		}
429 
430 		case RAW_COMMAND_SET_CONFIGURATION: {
431 			const usb_configuration_info *configurationInfo =
432 				gUSBModule->get_nth_configuration(device->device,
433 				command->config.config_index);
434 			if (!configurationInfo) {
435 				command->config.status = RAW_STATUS_INVALID_CONFIGURATION;
436 				return B_OK;
437 			}
438 
439 			if (gUSBModule->set_configuration(device->device,
440 				configurationInfo) < B_OK) {
441 				command->config.status = RAW_STATUS_FAILED;
442 				return B_OK;
443 			}
444 
445 			command->config.status = RAW_STATUS_SUCCESS;
446 			return B_OK;
447 		}
448 
449 		case RAW_COMMAND_CONTROL_TRANSFER: {
450 			benaphore_lock(&device->lock);
451 			if (gUSBModule->queue_request(device->device,
452 				command->control.request_type, command->control.request,
453 				command->control.value, command->control.index,
454 				command->control.length, command->control.data,
455 				usb_raw_callback, device) < B_OK) {
456 				command->control.status = RAW_STATUS_FAILED;
457 				command->control.length = 0;
458 				benaphore_unlock(&device->lock);
459 				return B_OK;
460 			}
461 
462 			acquire_sem(device->notify);
463 			command->control.status = device->status;
464 			command->control.length = device->actual_length;
465 			benaphore_unlock(&device->lock);
466 			return B_OK;
467 		}
468 
469 		case RAW_COMMAND_INTERRUPT_TRANSFER:
470 		case RAW_COMMAND_BULK_TRANSFER:
471 		case RAW_COMMAND_ISOCHRONOUS_TRANSFER: {
472 			const usb_configuration_info *configurationInfo =
473 				gUSBModule->get_configuration(device->device);
474 			if (!configurationInfo) {
475 				command->transfer.status = RAW_STATUS_INVALID_CONFIGURATION;
476 				return B_OK;
477 			}
478 
479 			if (command->transfer.interface >= configurationInfo->interface_count) {
480 				command->transfer.status = RAW_STATUS_INVALID_INTERFACE;
481 				return B_OK;
482 			}
483 
484 			const usb_interface_info *interfaceInfo =
485 				configurationInfo->interface[command->transfer.interface].active;
486 			if (!interfaceInfo) {
487 				command->transfer.status = RAW_STATUS_ABORTED;
488 				return B_OK;
489 			}
490 
491 			if (command->transfer.endpoint >= interfaceInfo->endpoint_count) {
492 				command->transfer.status = RAW_STATUS_INVALID_ENDPOINT;
493 				return B_OK;
494 			}
495 
496 			const usb_endpoint_info *endpointInfo =
497 				&interfaceInfo->endpoint[command->transfer.endpoint];
498 			if (!endpointInfo->handle) {
499 				command->transfer.status = RAW_STATUS_INVALID_ENDPOINT;
500 				return B_OK;
501 			}
502 
503 			benaphore_lock(&device->lock);
504 
505 			status_t status;
506 			if (op == RAW_COMMAND_INTERRUPT_TRANSFER) {
507 				status = gUSBModule->queue_interrupt(endpointInfo->handle,
508 					command->transfer.data, command->transfer.length,
509 					usb_raw_callback, device);
510 			} else if (op == RAW_COMMAND_BULK_TRANSFER) {
511 				status = gUSBModule->queue_bulk(endpointInfo->handle,
512 					command->transfer.data, command->transfer.length,
513 					usb_raw_callback, device);
514 			} else {
515 				status = gUSBModule->queue_isochronous(endpointInfo->handle,
516 					command->isochronous.data, command->isochronous.length,
517 					command->isochronous.packet_descriptors,
518 					command->isochronous.packet_count, NULL, 0,
519 					usb_raw_callback, device);
520 			}
521 
522 			if (status < B_OK) {
523 				command->transfer.status = RAW_STATUS_FAILED;
524 				command->transfer.length = 0;
525 				benaphore_unlock(&device->lock);
526 				return B_OK;
527 			}
528 
529 			acquire_sem(device->notify);
530 			command->transfer.status = device->status;
531 			command->transfer.length = device->actual_length;
532 			benaphore_unlock(&device->lock);
533 			return B_OK;
534 		}
535 	}
536 
537 	return B_DEV_INVALID_IOCTL;
538 }
539 
540 
541 static status_t
542 usb_raw_read(void *cookie, off_t position, void *buffer, size_t *length)
543 {
544 	TRACE((DRIVER_NAME": read()\n"));
545 	*length = 0;
546 	return B_OK;
547 }
548 
549 
550 static status_t
551 usb_raw_write(void *cookie, off_t position, const void *buffer, size_t *length)
552 {
553 	TRACE((DRIVER_NAME": write()\n"));
554 	*length = 0;
555 	return B_OK;
556 }
557 
558 
559 //
560 //#pragma mark -
561 //
562 
563 
564 status_t
565 init_hardware()
566 {
567 	TRACE((DRIVER_NAME": init_hardware()\n"));
568 	return B_OK;
569 }
570 
571 
572 status_t
573 init_driver()
574 {
575 	TRACE((DRIVER_NAME": init_driver()\n"));
576 	static usb_notify_hooks notifyHooks = {
577 		&usb_raw_device_added,
578 		&usb_raw_device_removed
579 	};
580 
581 	gDeviceList = NULL;
582 	gDeviceCount = 0;
583 	status_t result = benaphore_init(&gDeviceListLock, "usb_raw device list lock");
584 	if (result < B_OK) {
585 		TRACE((DRIVER_NAME": failed to create device list lock\n"));
586 		return result;
587 	}
588 
589 	TRACE((DRIVER_NAME": trying module %s\n", B_USB_MODULE_NAME));
590 	result = get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule);
591 	if (result < B_OK) {
592 		TRACE((DRIVER_NAME": getting module failed 0x%08lx\n", result));
593 		benaphore_destroy(&gDeviceListLock);
594 		return result;
595 	}
596 
597 	gUSBModule->register_driver(DRIVER_NAME, NULL, 0, NULL);
598 	gUSBModule->install_notify(DRIVER_NAME, &notifyHooks);
599 	return B_OK;
600 }
601 
602 
603 void
604 uninit_driver()
605 {
606 	TRACE((DRIVER_NAME": uninit_driver()\n"));
607 	gUSBModule->uninstall_notify(DRIVER_NAME);
608 	benaphore_lock(&gDeviceListLock);
609 
610 	if (gDeviceNames) {
611 		for (int32 i = 1; gDeviceNames[i]; i++)
612 			free(gDeviceNames[i]);
613 		free(gDeviceNames);
614 		gDeviceNames = NULL;
615 	}
616 
617 	benaphore_destroy(&gDeviceListLock);
618 	put_module(B_USB_MODULE_NAME);
619 }
620 
621 
622 const char **
623 publish_devices()
624 {
625 	TRACE((DRIVER_NAME": publish_devices()\n"));
626 	if (gDeviceNames) {
627 		for (int32 i = 1; gDeviceNames[i]; i++)
628 			free(gDeviceNames[i]);
629 		free(gDeviceNames);
630 		gDeviceNames = NULL;
631 	}
632 
633 	int32 index = 0;
634 	gDeviceNames = (char **)malloc(sizeof(char *) * (gDeviceCount + 2));
635 	if (!gDeviceNames)
636 		return NULL;
637 
638 	gDeviceNames[index++] = DEVICE_NAME;
639 
640 	benaphore_lock(&gDeviceListLock);
641 	raw_device *element = gDeviceList;
642 	while (element) {
643 		gDeviceNames[index++] = strdup(element->name);
644 		element = (raw_device *)element->link;
645 	}
646 
647 	gDeviceNames[index++] = NULL;
648 	benaphore_unlock(&gDeviceListLock);
649 	return (const char **)gDeviceNames;
650 }
651 
652 
653 device_hooks *
654 find_device(const char *name)
655 {
656 	TRACE((DRIVER_NAME": find_device()\n"));
657 	static device_hooks hooks = {
658 		&usb_raw_open,
659 		&usb_raw_close,
660 		&usb_raw_free,
661 		&usb_raw_ioctl,
662 		&usb_raw_read,
663 		&usb_raw_write,
664 		NULL,
665 		NULL,
666 		NULL,
667 		NULL
668 	};
669 
670 	return &hooks;
671 }
672