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