xref: /haiku/src/add-ons/kernel/drivers/input/wacom/wacom.c (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
1 /*
2  * Copyright 2005-2008, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  *
8  * Portions of this code are based on Be Sample Code released under the
9  * Be Sample Code license. (USB sound device driver sample code IIRC.)
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include <Drivers.h>
17 #include <KernelExport.h>
18 #include <OS.h>
19 #include <USB3.h>
20 
21 int32 api_version = B_CUR_DRIVER_API_VERSION;
22 
23 #define DEBUG_DRIVER 0
24 
25 #if DEBUG_DRIVER
26 #	define DPRINTF_INFO(x) dprintf x;
27 #	define DPRINTF_ERR(x) dprintf x;
28 #else
29 #	define DPRINTF_INFO(x)
30 #	define DPRINTF_ERR(x) dprintf x;
31 #endif
32 
33 typedef struct wacom_device wacom_device;
34 
35 struct wacom_device {
36 	wacom_device*		next;
37 
38 	int					open;
39 	int					number;
40 
41 	usb_device			dev;
42 
43 	usb_pipe			pipe;
44 	char*				data;
45 	size_t				max_packet_size;
46 	size_t				length;
47 
48 	uint16				vendor;
49 	uint16				product;
50 
51 	sem_id				notify_lock;
52 	uint32				status;
53 };
54 
55 // handy strings for referring to ourself
56 #define ID "wacom: "
57 static const char* kDriverName = "wacom";
58 static const char* kBasePublishPath = "input/wacom/usb/";
59 
60 // list of device instances and names for publishing
61 static wacom_device* sDeviceList = NULL;
62 static sem_id sDeviceListLock = -1;
63 static int sDeviceCount = 0;
64 
65 static char** sDeviceNames = NULL;
66 
67 // handle for the USB bus manager
68 static usb_module_info* usb;
69 
70 // These rather inelegant routines are used to assign numbers to
71 // device instances so that they have unique names in devfs.
72 
73 static uint32 sDeviceNumbers = 0;
74 
75 // get_number
76 static int
77 get_number()
78 {
79 	int num;
80 
81 	for (num = 0; num < 32; num++) {
82 		if (!(sDeviceNumbers & (1 << num))) {
83 			sDeviceNumbers |= (1 << num);
84 			return num;
85 		}
86 	}
87 
88 	return -1;
89 }
90 
91 // put_number
92 static void
93 put_number(int num)
94 {
95 	sDeviceNumbers &= ~(1 << num);
96 }
97 
98 // #pragma mark - Device addition and removal
99 //
100 // add_device() and remove_device() are used to create and tear down
101 // device instances.  They are used from the callbacks device_added()
102 // and device_removed() which are invoked by the USB bus manager.
103 
104 // add_device
105 static wacom_device*
106 add_device(usb_device dev)
107 {
108 	wacom_device *device = NULL;
109 	int num, ifc, alt;
110 	const usb_interface_info *ii;
111 	status_t st;
112 	const usb_device_descriptor* udd;
113 	const usb_configuration_info *conf;
114 	bool setConfiguration = false;
115 
116 	// we need these two for a Wacom tablet
117 	size_t controlTransferLength;
118 	char repData[2] = { 0x02, 0x02 };
119 
120 	conf = usb->get_configuration(dev);
121 	DPRINTF_INFO((ID "add_device(%ld, %p)\n", dev, conf));
122 
123 	if ((num = get_number()) < 0)
124 		return NULL;
125 
126 	udd = usb->get_device_descriptor(dev);
127 	// only pick up wacom tablets
128 	if (udd && udd->vendor_id == 0x056a) {
129 
130 		DPRINTF_ERR((ID "add_device() - wacom detected\n"));
131 
132 		// see if the device has been configured already
133 		if (!conf) {
134 			conf = usb->get_nth_configuration(dev, 0);
135 			setConfiguration = true;
136 		}
137 
138 		if (!conf)
139 			goto fail;
140 
141 		for (ifc = 0; ifc < conf->interface_count; ifc++) {
142 			DPRINTF_INFO((ID "add_device() - examining interface: %d\n", ifc));
143 			for (alt = 0; alt < conf->interface[ifc].alt_count; alt++) {
144 				ii = &conf->interface[ifc].alt[alt];
145 				DPRINTF_INFO((ID "add_device() - examining alt interface: "
146 					"%d\n", alt));
147 
148 
149 				// does it have the correct type of interface?
150 				if (ii->descr->interface_class != 3) continue;
151 				if (ii->descr->interface_subclass != 1) continue;
152 				if (ii->endpoint_count != 1) continue;
153 
154 				// only accept input endpoints
155 				if (ii->endpoint[0].descr->endpoint_address & 0x80) {
156 					DPRINTF_INFO((ID "add_device() - found input endpoint\n"));
157 					goto got_one;
158 				}
159 			}
160 		}
161 	} else
162 		goto fail;
163 
164 fail:
165 	put_number(num);
166 	if (device) {
167 		free(device->data);
168 		free(device);
169 	}
170 	return NULL;
171 
172 got_one:
173 	if ((device = (wacom_device *) malloc(sizeof(wacom_device))) == NULL)
174 		goto fail;
175 
176 	device->dev = dev;
177 	device->number = num;
178 	device->open = 1;
179 	device->notify_lock = -1;
180 	device->data = NULL;
181 
182 //	if (setConfiguration) {
183 		// the configuration has to be set yet (was not the current one)
184 		DPRINTF_INFO((ID "add_device() - setting configuration...\n"));
185 		if ((st = usb->set_configuration(dev, conf)) != B_OK) {
186 			dprintf(ID "add_device() -> set_configuration() returns %ld\n", st);
187 			goto fail;
188 		} else
189 			DPRINTF_ERR((ID " ... success!\n"));
190 
191 		if (conf->interface[ifc].active != ii) {
192 			// the interface we found is not the active one and has to be set
193 			DPRINTF_INFO((ID "add_device() - setting interface: %p...\n", ii));
194 			if ((st = usb->set_alt_interface(dev, ii)) != B_OK) {
195 				dprintf(ID "add_device() -> set_alt_interface() returns %ld\n",
196 					st);
197 				goto fail;
198 			} else
199 				DPRINTF_ERR((ID " ... success!\n"));
200 		}
201 		// see if the device is a Wacom tablet and needs some special treatment
202 		// let's hope Wacom doesn't produce normal mice any time soon, or this
203 		// check will have to be more specific about product_id...hehe
204 		if (udd->vendor_id == 0x056a) {
205 			// do the control transfers to set up absolute mode (default is HID mode)
206 			controlTransferLength = 0;
207 			st = usb->send_request(dev, 0x21, 0x0b, 1, 0, 0, 0,
208 				&controlTransferLength);
209 
210 			if (st < B_OK) {
211 				dprintf(ID "add_device() - control transfer 1 failed: %ld\n",
212 					st);
213 			}
214 
215 			// "set interface" -> ?!?
216 			controlTransferLength = 2;
217 			st = usb->send_request(dev, 0x21, 0x09, (3 << 8) + 2, 1, 2, repData,
218 				&controlTransferLength);
219 
220 			if (st < B_OK) {
221 				dprintf(ID "add_device() - control transfer 2 failed: %ld\n",
222 					st);
223 			}
224 		}
225 //	}
226 
227 	// configure the rest of the wacom_device
228 	device->pipe = ii->endpoint[0].handle;
229 //DPRINTF_INFO((ID "add_device() - pipe id = %ld\n", device->pipe));
230 	device->length = 0;
231 	device->max_packet_size = ii->endpoint[0].descr->max_packet_size;
232 	device->data = (char*)malloc(device->max_packet_size);
233 	if (device->data == NULL)
234 		goto fail;
235 //DPRINTF_INFO((ID "add_device() - max packet length = %ld\n",
236 //	device->max_packet_size));
237 	device->status = 0;//B_USB_STATUS_SUCCESS;
238 	device->vendor = udd->vendor_id;
239 	device->product = udd->product_id;
240 
241 	DPRINTF_INFO((ID "add_device() - added %p (/dev/%s%d)\n", device,
242 		kBasePublishPath, num));
243 
244 	// add it to the list of devices so it will be published, etc
245 	acquire_sem(sDeviceListLock);
246 	device->next = sDeviceList;
247 	sDeviceList = device;
248 	sDeviceCount++;
249 	release_sem(sDeviceListLock);
250 
251 	return device;
252 }
253 
254 // remove_device
255 static void
256 remove_device(wacom_device *device)
257 {
258 	put_number(device->number);
259 
260 	usb->cancel_queued_transfers(device->pipe);
261 
262 	delete_sem(device->notify_lock);
263 	if (device->data)
264 		free(device->data);
265 	free(device);
266 }
267 
268 // device_added
269 static status_t
270 device_added(usb_device dev, void** cookie)
271 {
272 	wacom_device* device;
273 
274 	DPRINTF_INFO((ID "device_added(%ld,...)\n", dev));
275 
276 	// first see, if this device is already added
277 	acquire_sem(sDeviceListLock);
278 	for (device = sDeviceList; device; device = device->next) {
279 		DPRINTF_ERR((ID "device_added() - old device: %ld\n", device->dev));
280 		if (device->dev == dev) {
281 			DPRINTF_ERR((ID "device_added() - already added - done!\n"));
282 			*cookie = (void*)device;
283 			release_sem(sDeviceListLock);
284 			return B_OK;
285 		}
286 	}
287 	release_sem(sDeviceListLock);
288 
289 	if ((device = add_device(dev)) != NULL) {
290 		*cookie = (void*)device;
291 		DPRINTF_INFO((ID "device_added() - done!\n"));
292 		return B_OK;
293 	} else
294 		DPRINTF_INFO((ID "device_added() - failed to add device!\n"));
295 
296 	return B_ERROR;
297 }
298 
299 // device_removed
300 static status_t
301 device_removed(void *cookie)
302 {
303 	wacom_device *device = (wacom_device *) cookie;
304 
305 	DPRINTF_INFO((ID "device_removed(%p)\n", device));
306 
307 	if (device) {
308 
309 		acquire_sem(sDeviceListLock);
310 
311 		// remove it from the list of devices
312 		if (device == sDeviceList) {
313 			sDeviceList = device->next;
314 		} else {
315 			wacom_device *n;
316 			for (n = sDeviceList; n; n = n->next) {
317 				if (n->next == device) {
318 					n->next = device->next;
319 					break;
320 				}
321 			}
322 		}
323 		sDeviceCount--;
324 
325 		// tear it down if it's not open --
326 		// otherwise the last device_free() will handle it
327 
328 		device->open--;
329 
330 		DPRINTF_ERR((ID "device_removed() open: %d\n", device->open));
331 
332 		if (device->open == 0) {
333 			remove_device(device);
334 		} else {
335 			dprintf(ID "device /dev/%s%d still open -- marked for removal\n",
336 				kBasePublishPath, device->number);
337 		}
338 
339 		release_sem(sDeviceListLock);
340 	}
341 
342 	return B_OK;
343 }
344 
345 // #pragma mark - Device Hooks
346 //
347 // Here we implement the posixy driver hooks (open/close/read/write/ioctl)
348 
349 // device_open
350 static status_t
351 device_open(const char *dname, uint32 flags, void** cookie)
352 {
353 	wacom_device *device;
354 	int n;
355 	status_t ret = B_ERROR;
356 
357 	char controlDevicePath[1024];
358 	sprintf(controlDevicePath, "%s%s", kBasePublishPath, "control");
359 	if (strcmp(dname, controlDevicePath) == 0) {
360 		dprintf(ID "device_open() -> refuse to open control device\n");
361 		return B_ERROR;
362 	}
363 
364 	n = atoi(dname + strlen(kBasePublishPath));
365 
366 	DPRINTF_INFO((ID "device_open(\"%s\",%d,...)\n", dname, flags));
367 
368 	acquire_sem(sDeviceListLock);
369 	for (device = sDeviceList; device; device = device->next) {
370 		if (device->number == n) {
371 //			if (device->open <= 1) {
372 				device->open++;
373 				*cookie = device;
374 				DPRINTF_ERR((ID "device_open() open: %d\n", device->open));
375 
376 				if (device->notify_lock < 0) {
377 					device->notify_lock = create_sem(0, "notify_lock");
378 					if (device->notify_lock < 0) {
379 						ret = device->notify_lock;
380 						device->open--;
381 						*cookie = NULL;
382 						dprintf(ID "device_open() -> create_sem() returns %ld\n",
383 							ret);
384 					} else {
385 						ret = B_OK;
386 					}
387 				}
388 				release_sem(sDeviceListLock);
389 				return ret;
390 //			} else {
391 //				dprintf(ID "device_open() -> device is already open %ld\n", ret);
392 //				release_sem(sDeviceListLock);
393 //				return B_ERROR;
394 //			}
395 		}
396 	}
397 	release_sem(sDeviceListLock);
398 	return ret;
399 }
400 
401 // device_close
402 static status_t
403 device_close (void *cookie)
404 {
405 #if DEBUG_DRIVER
406 	wacom_device *device = (wacom_device*) cookie;
407 	DPRINTF_ERR((ID "device_close() name = \"%s%d\"\n", kBasePublishPath,
408 		device->number));
409 #endif
410 	return B_OK;
411 }
412 
413 // device_free
414 static status_t
415 device_free(void *cookie)
416 {
417 	wacom_device *device = (wacom_device *)cookie;
418 
419 	DPRINTF_INFO((ID "device_free() name = \"%s%d\"\n", kBasePublishPath,
420 		device->number));
421 
422 	acquire_sem(sDeviceListLock);
423 
424 	device->open--;
425 
426 	DPRINTF_INFO((ID "device_free() open: %ld\n", device->open));
427 
428 	if (device->open == 0) {
429 		remove_device(device);
430 	}
431 	release_sem(sDeviceListLock);
432 
433 	return B_OK;
434 }
435 
436 // device_interupt_callback
437 static void
438 device_interupt_callback(void* cookie, status_t status, void* data,
439 	uint32 actualLength)
440 {
441 	wacom_device* device = (wacom_device*)cookie;
442 	uint32 length = min_c(actualLength, device->max_packet_size);
443 
444 	DPRINTF_INFO((ID "device_interupt_callback(%p) name = \"%s%d\" -> "
445 		"status: %ld, length: %ld\n", cookie, kBasePublishPath, device->number,
446 		status, actualLength));
447 
448 	device->status = status;
449 	if (device->notify_lock >= 0) {
450 		if (status == B_OK) {
451 			memcpy(device->data, data, length);
452 			device->length = length;
453 		} else {
454 			device->length = 0;
455 		}
456 		release_sem(device->notify_lock);
457 	}
458 
459 	DPRINTF_INFO((ID "device_interupt_callback() - done\n"));
460 }
461 
462 // read_header
463 static void
464 read_header(const wacom_device* device, void* buffer)
465 {
466 	uint16* ids = (uint16*)buffer;
467 	uint32* size = (uint32*)buffer;
468 
469 	ids[0] = device->vendor;
470 	ids[1] = device->product;
471 	size[1] = device->max_packet_size;
472 }
473 
474 // device_read
475 static status_t
476 device_read(void* cookie, off_t pos, void* buf, size_t* count)
477 {
478 	wacom_device* device = (wacom_device*) cookie;
479 	status_t ret = B_BAD_VALUE;
480 	uint8* buffer = (uint8*)buf;
481 	uint32 dataLength;
482 
483 	if (!device)
484 		return ret;
485 
486 	ret = device->notify_lock;
487 
488 	DPRINTF_INFO((ID "device_read(%p,%Ld,0x%x,%d) name = \"%s%d\"\n",
489 			 cookie, pos, buf, *count, kBasePublishPath, device->number));
490 
491 	if (ret >= B_OK) {
492 		// what the client "reads" is decided depending on how much bytes are
493 		// provided 8 bytes are needed to "read" vendor id, product id and max
494 		// packet size in case the client wants to read more than 8 bytes, a usb
495 		// interupt transfer is scheduled, and an error report is returned as
496 		// appropriate
497 		if (*count > 8) {
498 			// queue the interrupt transfer
499 			ret = usb->queue_interrupt(device->pipe, device->data,
500 				device->max_packet_size, device_interupt_callback, device);
501 			if (ret >= B_OK) {
502 				// we will block here until the interrupt transfer has been done
503 				ret = acquire_sem_etc(device->notify_lock, 1,
504 					B_RELATIVE_TIMEOUT, 500 * 1000);
505 				// handle time out
506 				if (ret < B_OK) {
507 //					usb->cancel_queued_transfers(device->pipe);
508 					if (ret == B_TIMED_OUT) {
509 						// a time_out is ok, since it only means that the device
510 						// had nothing to report (ie mouse/pen was not moved)
511 						// within the given time interval
512 						DPRINTF_INFO((ID "device_read(%p) name = \"%s%d\" -> "
513 							"B_TIMED_OUT\n", cookie, kBasePublishPath,
514 							device->number));
515 						*count = 8;
516 						read_header(device, buffer);
517 						ret = B_OK;
518 					} else {
519 						// any other error trying to acquire the semaphore
520 						*count = 0;
521 					}
522 				} else {
523 					if (device->status == 0/*B_USBD_SUCCESS*/) {
524 						DPRINTF_INFO((ID "interrupt transfer - success\n"));
525 						// copy the data from the buffer
526 						dataLength = min_c(device->length, *count - 8);
527 						*count = dataLength + 8;
528 						read_header(device, buffer);
529 						memcpy(buffer + 8, device->data, dataLength);
530 					} else {
531 						// an error happened during the interrupt transfer
532 						*count = 0;
533 						dprintf(ID "interrupt transfer - failure: %ld\n",
534 							device->status);
535 						ret = B_ERROR;
536 					}
537 				}
538 			} else {
539 				*count = 0;
540 				dprintf(ID "device_read(%p) name = \"%s%d\" -> error queuing "
541 					"interrupt: %ld\n", cookie, kBasePublishPath,
542 					device->number, ret);
543 			}
544 		} else if (*count == 8) {
545 			read_header(device, buffer);
546 			ret = B_OK;
547 		} else {
548 			dprintf(ID "device_read(%p) name = \"%s%d\" -> buffer size must be "
549 				"at least 8 bytes!\n", cookie, kBasePublishPath,
550 				device->number);
551 			*count = 0;
552 			ret = B_BAD_VALUE;
553 		}
554 	}
555 
556 	return ret;
557 }
558 
559 // device_write
560 static status_t
561 device_write(void *cookie, off_t pos, const void *buf, size_t *count)
562 {
563 	return B_ERROR;
564 }
565 
566 // device_control
567 static status_t
568 device_control (void *cookie, uint32 msg, void *arg1, size_t len)
569 {
570 	return B_ERROR;
571 }
572 
573 // #pragma mark - Driver Hooks
574 //
575 // These functions provide the glue used by DevFS to load/unload
576 // the driver and also handle registering with the USB bus manager
577 // to receive device added and removed events
578 
579 static usb_notify_hooks notify_hooks =
580 {
581 	&device_added,
582 	&device_removed
583 };
584 
585 static const usb_support_descriptor kSupportedDevices[] =
586 {
587 	{ 3, 1, 2, 0, 0 }
588 };
589 
590 // init_hardware
591 status_t
592 init_hardware(void)
593 {
594 	return B_OK;
595 }
596 
597 // init_driver
598 status_t
599 init_driver(void)
600 {
601 	DPRINTF_INFO((ID "init_driver(), built %s %s\n", __DATE__, __TIME__));
602 
603 #if DEBUG_DRIVER && !defined(__HAIKU__)
604 	if (load_driver_symbols(kDriverName) == B_OK) {
605 		DPRINTF_INFO((ID "loaded symbols\n"));
606 	} else {
607 		DPRINTF_ERR((ID "no driver symbols loaded!\n"));
608 	}
609 #endif
610 
611 	if (get_module(B_USB_MODULE_NAME, (module_info**) &usb) != B_OK) {
612 		DPRINTF_ERR((ID "cannot get module \"%s\"\n", B_USB_MODULE_NAME));
613 		return B_ERROR;
614 	}
615 
616 	if ((sDeviceListLock = create_sem(1,"sDeviceListLock")) < 0) {
617 		put_module(B_USB_MODULE_NAME);
618 		return sDeviceListLock;
619 	}
620 
621 	usb->register_driver(kDriverName, kSupportedDevices, 1, NULL);
622 	usb->install_notify(kDriverName, &notify_hooks);
623 
624 	return B_OK;
625 }
626 
627 // uninit_driver
628 void
629 uninit_driver(void)
630 {
631 	int i;
632 
633 	DPRINTF_INFO((ID "uninit_driver()\n"));
634 
635 	usb->uninstall_notify(kDriverName);
636 
637 	delete_sem(sDeviceListLock);
638 
639 	put_module(B_USB_MODULE_NAME);
640 
641 	if (sDeviceNames) {
642 		for (i = 0; sDeviceNames[i]; i++)
643 			free(sDeviceNames[i]);
644 		free(sDeviceNames);
645 	}
646 
647 	DPRINTF_INFO((ID "uninit_driver() done\n"));
648 }
649 
650 // publish_devices
651 const char**
652 publish_devices()
653 {
654 	wacom_device *device;
655 	int i;
656 
657 	DPRINTF_INFO((ID "publish_devices()\n"));
658 
659 	if (sDeviceNames) {
660 		for (i = 0; sDeviceNames[i]; i++)
661 			free((char *) sDeviceNames[i]);
662 		free(sDeviceNames);
663 	}
664 
665 	acquire_sem(sDeviceListLock);
666 	sDeviceNames = (char**)malloc(sizeof(char*) * (sDeviceCount + 2));
667 	if (sDeviceNames) {
668 		for (i = 0, device = sDeviceList; device; device = device->next) {
669 			sDeviceNames[i] = (char*)malloc(strlen(kBasePublishPath) + 4);
670 			if (sDeviceNames[i]) {
671 				sprintf(sDeviceNames[i],"%s%d",kBasePublishPath,device->number);
672 				DPRINTF_INFO((ID "publishing: \"/dev/%s\"\n",sDeviceNames[i]));
673 				i++;
674 			}
675 		}
676 		// publish the currently fake control device
677 		sDeviceNames[i] = (char*)malloc(strlen(kBasePublishPath) + 8);
678 		if (sDeviceNames[i])
679 			sprintf(sDeviceNames[i], "%s%s", kBasePublishPath, "control");
680 
681 		sDeviceNames[i + 1] = NULL;
682 	}
683 
684 	release_sem(sDeviceListLock);
685 
686 	return (const char**)sDeviceNames;
687 }
688 
689 static device_hooks sDeviceHooks = {
690 	device_open,
691 	device_close,
692 	device_free,
693 	device_control,
694 	device_read,
695 	device_write
696 };
697 
698 // find_device
699 device_hooks*
700 find_device(const char* name)
701 {
702 	return &sDeviceHooks;
703 }
704