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 four for a Wacom tablet 117 size_t controlTransferLength; 118 int tryCount; 119 char repData[2] = { 0x02, 0x02 }; 120 char retData[2] = { 0x00, 0x00 }; 121 122 conf = usb->get_configuration(dev); 123 DPRINTF_INFO((ID "add_device(%ld, %p)\n", dev, conf)); 124 125 if ((num = get_number()) < 0) 126 return NULL; 127 128 udd = usb->get_device_descriptor(dev); 129 // only pick up wacom tablets 130 if (udd && udd->vendor_id == 0x056a) { 131 132 DPRINTF_ERR((ID "add_device() - wacom detected\n")); 133 134 // see if the device has been configured already 135 if (!conf) { 136 conf = usb->get_nth_configuration(dev, 0); 137 setConfiguration = true; 138 } 139 140 if (!conf) 141 goto fail; 142 143 for (ifc = 0; ifc < conf->interface_count; ifc++) { 144 DPRINTF_INFO((ID "add_device() - examining interface: %d\n", ifc)); 145 for (alt = 0; alt < conf->interface[ifc].alt_count; alt++) { 146 ii = &conf->interface[ifc].alt[alt]; 147 DPRINTF_INFO((ID "add_device() - examining alt interface: " 148 "%d\n", alt)); 149 150 151 // does it have the correct type of interface? 152 if (ii->descr->interface_class != 3) continue; 153 if (ii->descr->interface_subclass != 1) continue; 154 if (ii->endpoint_count != 1) continue; 155 156 // only accept input endpoints 157 if (ii->endpoint[0].descr->endpoint_address & 0x80) { 158 DPRINTF_INFO((ID "add_device() - found input endpoint\n")); 159 goto got_one; 160 } 161 } 162 } 163 } else 164 goto fail; 165 166 fail: 167 put_number(num); 168 if (device) { 169 free(device->data); 170 free(device); 171 } 172 return NULL; 173 174 got_one: 175 if ((device = (wacom_device *) malloc(sizeof(wacom_device))) == NULL) 176 goto fail; 177 178 device->dev = dev; 179 device->number = num; 180 device->open = 1; 181 device->notify_lock = -1; 182 device->data = NULL; 183 184 // if (setConfiguration) { 185 // the configuration has to be set yet (was not the current one) 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 275 // configure the rest of the wacom_device 276 device->pipe = ii->endpoint[0].handle; 277 //DPRINTF_INFO((ID "add_device() - pipe id = %ld\n", device->pipe)); 278 device->length = 0; 279 device->max_packet_size = ii->endpoint[0].descr->max_packet_size; 280 device->data = (char*)malloc(device->max_packet_size); 281 if (device->data == NULL) 282 goto fail; 283 //DPRINTF_INFO((ID "add_device() - max packet length = %ld\n", 284 // device->max_packet_size)); 285 device->status = 0;//B_USB_STATUS_SUCCESS; 286 device->vendor = udd->vendor_id; 287 device->product = udd->product_id; 288 289 DPRINTF_INFO((ID "add_device() - added %p (/dev/%s%d)\n", device, 290 kBasePublishPath, num)); 291 292 // add it to the list of devices so it will be published, etc 293 acquire_sem(sDeviceListLock); 294 device->next = sDeviceList; 295 sDeviceList = device; 296 sDeviceCount++; 297 release_sem(sDeviceListLock); 298 299 return device; 300 } 301 302 // remove_device 303 static void 304 remove_device(wacom_device *device) 305 { 306 put_number(device->number); 307 308 usb->cancel_queued_transfers(device->pipe); 309 310 delete_sem(device->notify_lock); 311 if (device->data) 312 free(device->data); 313 free(device); 314 } 315 316 // device_added 317 static status_t 318 device_added(usb_device dev, void** cookie) 319 { 320 wacom_device* device; 321 322 DPRINTF_INFO((ID "device_added(%ld,...)\n", dev)); 323 324 // first see, if this device is already added 325 acquire_sem(sDeviceListLock); 326 for (device = sDeviceList; device; device = device->next) { 327 DPRINTF_ERR((ID "device_added() - old device: %" B_PRIu32 "\n", 328 device->dev)); 329 if (device->dev == dev) { 330 DPRINTF_ERR((ID "device_added() - already added - done!\n")); 331 *cookie = (void*)device; 332 release_sem(sDeviceListLock); 333 return B_OK; 334 } 335 } 336 release_sem(sDeviceListLock); 337 338 if ((device = add_device(dev)) != NULL) { 339 *cookie = (void*)device; 340 DPRINTF_INFO((ID "device_added() - done!\n")); 341 return B_OK; 342 } else 343 DPRINTF_INFO((ID "device_added() - failed to add device!\n")); 344 345 return B_ERROR; 346 } 347 348 // device_removed 349 static status_t 350 device_removed(void *cookie) 351 { 352 wacom_device *device = (wacom_device *) cookie; 353 354 DPRINTF_INFO((ID "device_removed(%p)\n", device)); 355 356 if (device) { 357 358 acquire_sem(sDeviceListLock); 359 360 // remove it from the list of devices 361 if (device == sDeviceList) { 362 sDeviceList = device->next; 363 } else { 364 wacom_device *n; 365 for (n = sDeviceList; n; n = n->next) { 366 if (n->next == device) { 367 n->next = device->next; 368 break; 369 } 370 } 371 } 372 sDeviceCount--; 373 374 // tear it down if it's not open -- 375 // otherwise the last device_free() will handle it 376 377 device->open--; 378 379 DPRINTF_ERR((ID "device_removed() open: %d\n", device->open)); 380 381 if (device->open == 0) { 382 remove_device(device); 383 } else { 384 dprintf(ID "device /dev/%s%d still open -- marked for removal\n", 385 kBasePublishPath, device->number); 386 } 387 388 release_sem(sDeviceListLock); 389 } 390 391 return B_OK; 392 } 393 394 // #pragma mark - Device Hooks 395 // 396 // Here we implement the posixy driver hooks (open/close/read/write/ioctl) 397 398 // device_open 399 static status_t 400 device_open(const char *dname, uint32 flags, void** cookie) 401 { 402 wacom_device *device; 403 int n; 404 status_t ret = B_ERROR; 405 406 char controlDevicePath[1024]; 407 sprintf(controlDevicePath, "%s%s", kBasePublishPath, "control"); 408 if (strcmp(dname, controlDevicePath) == 0) { 409 dprintf(ID "device_open() -> refuse to open control device\n"); 410 return B_ERROR; 411 } 412 413 n = atoi(dname + strlen(kBasePublishPath)); 414 415 DPRINTF_INFO((ID "device_open(\"%s\",%d,...)\n", dname, flags)); 416 417 acquire_sem(sDeviceListLock); 418 for (device = sDeviceList; device; device = device->next) { 419 if (device->number == n) { 420 // if (device->open <= 1) { 421 device->open++; 422 *cookie = device; 423 DPRINTF_ERR((ID "device_open() open: %d\n", device->open)); 424 425 if (device->notify_lock < 0) { 426 device->notify_lock = create_sem(0, "notify_lock"); 427 if (device->notify_lock < 0) { 428 ret = device->notify_lock; 429 device->open--; 430 *cookie = NULL; 431 dprintf(ID "device_open() -> " 432 "create_sem() returns %" B_PRId32 "\n", ret); 433 } else { 434 ret = B_OK; 435 } 436 } 437 release_sem(sDeviceListLock); 438 return ret; 439 // } else { 440 // dprintf(ID "device_open() -> device is already open %ld\n", ret); 441 // release_sem(sDeviceListLock); 442 // return B_ERROR; 443 // } 444 } 445 } 446 release_sem(sDeviceListLock); 447 return ret; 448 } 449 450 // device_close 451 static status_t 452 device_close (void *cookie) 453 { 454 #if DEBUG_DRIVER 455 wacom_device *device = (wacom_device*) cookie; 456 DPRINTF_ERR((ID "device_close() name = \"%s%d\"\n", kBasePublishPath, 457 device->number)); 458 #endif 459 return B_OK; 460 } 461 462 // device_free 463 static status_t 464 device_free(void *cookie) 465 { 466 wacom_device *device = (wacom_device *)cookie; 467 468 DPRINTF_INFO((ID "device_free() name = \"%s%d\"\n", kBasePublishPath, 469 device->number)); 470 471 acquire_sem(sDeviceListLock); 472 473 device->open--; 474 475 DPRINTF_INFO((ID "device_free() open: %ld\n", device->open)); 476 477 if (device->open == 0) { 478 remove_device(device); 479 } 480 release_sem(sDeviceListLock); 481 482 return B_OK; 483 } 484 485 // device_interupt_callback 486 static void 487 device_interupt_callback(void* cookie, status_t status, void* data, 488 uint32 actualLength) 489 { 490 wacom_device* device = (wacom_device*)cookie; 491 uint32 length = min_c(actualLength, device->max_packet_size); 492 493 DPRINTF_INFO((ID "device_interupt_callback(%p) name = \"%s%d\" -> " 494 "status: %ld, length: %ld\n", cookie, kBasePublishPath, device->number, 495 status, actualLength)); 496 497 device->status = status; 498 if (device->notify_lock >= 0) { 499 if (status == B_OK) { 500 memcpy(device->data, data, length); 501 device->length = length; 502 } else { 503 device->length = 0; 504 } 505 release_sem(device->notify_lock); 506 } 507 508 DPRINTF_INFO((ID "device_interupt_callback() - done\n")); 509 } 510 511 // read_header 512 static void 513 read_header(const wacom_device* device, void* buffer) 514 { 515 uint16* ids = (uint16*)buffer; 516 uint32* size = (uint32*)buffer; 517 518 ids[0] = device->vendor; 519 ids[1] = device->product; 520 size[1] = device->max_packet_size; 521 } 522 523 // device_read 524 static status_t 525 device_read(void* cookie, off_t pos, void* buf, size_t* count) 526 { 527 wacom_device* device = (wacom_device*) cookie; 528 status_t ret = B_BAD_VALUE; 529 uint8* buffer = (uint8*)buf; 530 uint32 dataLength; 531 532 if (!device) 533 return ret; 534 535 ret = device->notify_lock; 536 537 DPRINTF_INFO((ID "device_read(%p,%Ld,0x%x,%d) name = \"%s%d\"\n", 538 cookie, pos, buf, *count, kBasePublishPath, device->number)); 539 540 if (ret >= B_OK) { 541 // what the client "reads" is decided depending on how much bytes are 542 // provided 8 bytes are needed to "read" vendor id, product id and max 543 // packet size in case the client wants to read more than 8 bytes, a usb 544 // interupt transfer is scheduled, and an error report is returned as 545 // appropriate 546 if (*count > 8) { 547 // queue the interrupt transfer 548 ret = usb->queue_interrupt(device->pipe, device->data, 549 device->max_packet_size, device_interupt_callback, device); 550 if (ret >= B_OK) { 551 // we will block here until the interrupt transfer has been done 552 ret = acquire_sem_etc(device->notify_lock, 1, 553 B_RELATIVE_TIMEOUT, 500 * 1000); 554 // handle time out 555 if (ret < B_OK) { 556 usb->cancel_queued_transfers(device->pipe); 557 acquire_sem(device->notify_lock); 558 // collect the sem released by the cancel 559 560 if (ret == B_TIMED_OUT) { 561 // a time_out is ok, since it only means that the device 562 // had nothing to report (ie mouse/pen was not moved) 563 // within the given time interval 564 DPRINTF_INFO((ID "device_read(%p) name = \"%s%d\" -> " 565 "B_TIMED_OUT\n", cookie, kBasePublishPath, 566 device->number)); 567 *count = 8; 568 read_header(device, buffer); 569 ret = B_OK; 570 } else { 571 // any other error trying to acquire the semaphore 572 *count = 0; 573 } 574 } else { 575 if (device->status == 0/*B_USBD_SUCCESS*/) { 576 DPRINTF_INFO((ID "interrupt transfer - success\n")); 577 // copy the data from the buffer 578 dataLength = min_c(device->length, *count - 8); 579 *count = dataLength + 8; 580 read_header(device, buffer); 581 memcpy(buffer + 8, device->data, dataLength); 582 } else { 583 // an error happened during the interrupt transfer 584 *count = 0; 585 dprintf(ID "interrupt transfer - " 586 "failure: %" B_PRIu32 "\n", device->status); 587 ret = B_ERROR; 588 } 589 } 590 } else { 591 *count = 0; 592 dprintf(ID "device_read(%p) name = \"%s%d\" -> error queuing " 593 "interrupt: %" B_PRId32 "\n", cookie, kBasePublishPath, 594 device->number, ret); 595 } 596 } else if (*count == 8) { 597 read_header(device, buffer); 598 ret = B_OK; 599 } else { 600 dprintf(ID "device_read(%p) name = \"%s%d\" -> buffer size must be " 601 "at least 8 bytes!\n", cookie, kBasePublishPath, 602 device->number); 603 *count = 0; 604 ret = B_BAD_VALUE; 605 } 606 } 607 608 return ret; 609 } 610 611 // device_write 612 static status_t 613 device_write(void *cookie, off_t pos, const void *buf, size_t *count) 614 { 615 return B_ERROR; 616 } 617 618 // device_control 619 static status_t 620 device_control (void *cookie, uint32 msg, void *arg1, size_t len) 621 { 622 return B_ERROR; 623 } 624 625 // #pragma mark - Driver Hooks 626 // 627 // These functions provide the glue used by DevFS to load/unload 628 // the driver and also handle registering with the USB bus manager 629 // to receive device added and removed events 630 631 static usb_notify_hooks notify_hooks = 632 { 633 &device_added, 634 &device_removed 635 }; 636 637 static const usb_support_descriptor kSupportedDevices[] = 638 { 639 { 3, 1, 2, 0, 0 } 640 }; 641 642 // init_hardware 643 status_t 644 init_hardware(void) 645 { 646 return B_OK; 647 } 648 649 // init_driver 650 status_t 651 init_driver(void) 652 { 653 DPRINTF_INFO((ID "init_driver(), built %s %s\n", __DATE__, __TIME__)); 654 655 #if DEBUG_DRIVER && !defined(__HAIKU__) 656 if (load_driver_symbols(kDriverName) == B_OK) { 657 DPRINTF_INFO((ID "loaded symbols\n")); 658 } else { 659 DPRINTF_ERR((ID "no driver symbols loaded!\n")); 660 } 661 #endif 662 663 if (get_module(B_USB_MODULE_NAME, (module_info**) &usb) != B_OK) { 664 DPRINTF_ERR((ID "cannot get module \"%s\"\n", B_USB_MODULE_NAME)); 665 return B_ERROR; 666 } 667 668 if ((sDeviceListLock = create_sem(1,"sDeviceListLock")) < 0) { 669 put_module(B_USB_MODULE_NAME); 670 return sDeviceListLock; 671 } 672 673 usb->register_driver(kDriverName, kSupportedDevices, 1, NULL); 674 usb->install_notify(kDriverName, ¬ify_hooks); 675 676 return B_OK; 677 } 678 679 // uninit_driver 680 void 681 uninit_driver(void) 682 { 683 int i; 684 685 DPRINTF_INFO((ID "uninit_driver()\n")); 686 687 usb->uninstall_notify(kDriverName); 688 689 delete_sem(sDeviceListLock); 690 691 put_module(B_USB_MODULE_NAME); 692 693 if (sDeviceNames) { 694 for (i = 0; sDeviceNames[i]; i++) 695 free(sDeviceNames[i]); 696 free(sDeviceNames); 697 } 698 699 DPRINTF_INFO((ID "uninit_driver() done\n")); 700 } 701 702 // publish_devices 703 const char** 704 publish_devices() 705 { 706 wacom_device *device; 707 int i; 708 709 DPRINTF_INFO((ID "publish_devices()\n")); 710 711 if (sDeviceNames) { 712 for (i = 0; sDeviceNames[i]; i++) 713 free((char *) sDeviceNames[i]); 714 free(sDeviceNames); 715 } 716 717 acquire_sem(sDeviceListLock); 718 sDeviceNames = (char**)malloc(sizeof(char*) * (sDeviceCount + 2)); 719 if (sDeviceNames) { 720 for (i = 0, device = sDeviceList; device; device = device->next) { 721 sDeviceNames[i] = (char*)malloc(strlen(kBasePublishPath) + 4); 722 if (sDeviceNames[i]) { 723 sprintf(sDeviceNames[i],"%s%d",kBasePublishPath,device->number); 724 DPRINTF_INFO((ID "publishing: \"/dev/%s\"\n",sDeviceNames[i])); 725 i++; 726 } 727 } 728 // publish the currently fake control device 729 sDeviceNames[i] = (char*)malloc(strlen(kBasePublishPath) + 8); 730 if (sDeviceNames[i]) 731 sprintf(sDeviceNames[i], "%s%s", kBasePublishPath, "control"); 732 733 sDeviceNames[i + 1] = 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