xref: /haiku/src/add-ons/kernel/drivers/bus/usb/usb_raw.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
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 			const usb_configuration_info *configurationInfo =
472 				gUSBModule->get_configuration(device->device);
473 			if (!configurationInfo) {
474 				command->transfer.status = RAW_STATUS_INVALID_CONFIGURATION;
475 				return B_OK;
476 			}
477 
478 			if (command->transfer.interface >= configurationInfo->interface_count) {
479 				command->transfer.status = RAW_STATUS_INVALID_INTERFACE;
480 				return B_OK;
481 			}
482 
483 			const usb_interface_info *interfaceInfo =
484 				configurationInfo->interface[command->transfer.interface].active;
485 			if (!interfaceInfo) {
486 				command->transfer.status = RAW_STATUS_ABORTED;
487 				return B_OK;
488 			}
489 
490 			if (command->transfer.endpoint >= interfaceInfo->endpoint_count) {
491 				command->transfer.status = RAW_STATUS_INVALID_ENDPOINT;
492 				return B_OK;
493 			}
494 
495 			const usb_endpoint_info *endpointInfo =
496 				&interfaceInfo->endpoint[command->transfer.endpoint];
497 			if (!endpointInfo->handle) {
498 				command->transfer.status = RAW_STATUS_INVALID_ENDPOINT;
499 				return B_OK;
500 			}
501 
502 			benaphore_lock(&device->lock);
503 
504 			status_t status;
505 			if (op == RAW_COMMAND_INTERRUPT_TRANSFER) {
506 				status = gUSBModule->queue_interrupt(endpointInfo->handle,
507 					command->transfer.data, command->transfer.length,
508 					usb_raw_callback, device);
509 			} else {
510 				status = gUSBModule->queue_bulk(endpointInfo->handle,
511 					command->transfer.data, command->transfer.length,
512 					usb_raw_callback, device);
513 			}
514 
515 			if (status < B_OK) {
516 				command->transfer.status = RAW_STATUS_FAILED;
517 				command->transfer.length = 0;
518 				benaphore_unlock(&device->lock);
519 				return B_OK;
520 			}
521 
522 			acquire_sem(device->notify);
523 			command->transfer.status = device->status;
524 			command->transfer.length = device->actual_length;
525 			benaphore_unlock(&device->lock);
526 			return B_OK;
527 		}
528 	}
529 
530 	return B_DEV_INVALID_IOCTL;
531 }
532 
533 
534 static status_t
535 usb_raw_read(void *cookie, off_t position, void *buffer, size_t *length)
536 {
537 	TRACE((DRIVER_NAME": read()\n"));
538 	*length = 0;
539 	return B_OK;
540 }
541 
542 
543 static status_t
544 usb_raw_write(void *cookie, off_t position, const void *buffer, size_t *length)
545 {
546 	TRACE((DRIVER_NAME": write()\n"));
547 	*length = 0;
548 	return B_OK;
549 }
550 
551 
552 //
553 //#pragma mark -
554 //
555 
556 
557 status_t
558 init_hardware()
559 {
560 	TRACE((DRIVER_NAME": init_hardware()\n"));
561 	return B_OK;
562 }
563 
564 
565 status_t
566 init_driver()
567 {
568 	TRACE((DRIVER_NAME": init_driver()\n"));
569 	static usb_notify_hooks notifyHooks = {
570 		&usb_raw_device_added,
571 		&usb_raw_device_removed
572 	};
573 
574 	gDeviceList = NULL;
575 	gDeviceCount = 0;
576 	status_t result = benaphore_init(&gDeviceListLock, "usb_raw device list lock");
577 	if (result < B_OK) {
578 		TRACE((DRIVER_NAME": failed to create device list lock\n"));
579 		return result;
580 	}
581 
582 	TRACE((DRIVER_NAME": trying module %s\n", B_USB_MODULE_NAME));
583 	result = get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule);
584 	if (result < B_OK) {
585 		TRACE((DRIVER_NAME": getting module failed 0x%08lx\n", result));
586 		return result;
587 	}
588 
589 	gUSBModule->register_driver(DRIVER_NAME, NULL, 0, NULL);
590 	gUSBModule->install_notify(DRIVER_NAME, &notifyHooks);
591 	return B_OK;
592 }
593 
594 
595 void
596 uninit_driver()
597 {
598 	TRACE((DRIVER_NAME": uninit_driver()\n"));
599 	gUSBModule->uninstall_notify(DRIVER_NAME);
600 	benaphore_lock(&gDeviceListLock);
601 
602 	if (gDeviceNames) {
603 		for (int32 i = 1; gDeviceNames[i]; i++)
604 			free(gDeviceNames[i]);
605 		free(gDeviceNames);
606 	}
607 
608 	benaphore_destroy(&gDeviceListLock);
609 	put_module(B_USB_MODULE_NAME);
610 }
611 
612 
613 const char **
614 publish_devices()
615 {
616 	TRACE((DRIVER_NAME": publish_devices()\n"));
617 	if (gDeviceNames) {
618 		for (int32 i = 1; gDeviceNames[i]; i++)
619 			free(gDeviceNames[i]);
620 		free(gDeviceNames);
621 	}
622 
623 	int32 index = 0;
624 	gDeviceNames = (char **)malloc(sizeof(char *) * (gDeviceCount + 2));
625 	gDeviceNames[index++] = DEVICE_NAME;
626 
627 	benaphore_lock(&gDeviceListLock);
628 	raw_device *element = gDeviceList;
629 	while (element) {
630 		gDeviceNames[index++] = strdup(element->name);
631 		element = (raw_device *)element->link;
632 	}
633 
634 	gDeviceNames[index++] = NULL;
635 	benaphore_unlock(&gDeviceListLock);
636 	return (const char **)gDeviceNames;
637 }
638 
639 
640 device_hooks *
641 find_device(const char *name)
642 {
643 	TRACE((DRIVER_NAME": find_device()\n"));
644 	static device_hooks hooks = {
645 		&usb_raw_open,
646 		&usb_raw_close,
647 		&usb_raw_free,
648 		&usb_raw_ioctl,
649 		&usb_raw_read,
650 		&usb_raw_write,
651 		NULL,
652 		NULL,
653 		NULL,
654 		NULL
655 	};
656 
657 	return &hooks;
658 }
659