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; 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 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 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 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 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 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 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 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 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 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,%Ld,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 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 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 649 init_hardware(void) 650 { 651 return B_OK; 652 } 653 654 // init_driver 655 status_t 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 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** 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* 752 find_device(const char* name) 753 { 754 return &sDeviceHooks; 755 } 756