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