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