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() -> set_configuration() returns %ld\n", st); 189 goto fail; 190 } else 191 DPRINTF_ERR((ID " ... success!\n")); 192 193 if (conf->interface[ifc].active != ii) { 194 // the interface we found is not the active one and has to be set 195 DPRINTF_INFO((ID "add_device() - setting interface: %p...\n", ii)); 196 if ((st = usb->set_alt_interface(dev, ii)) != B_OK) { 197 dprintf(ID "add_device() -> set_alt_interface() returns %ld\n", 198 st); 199 goto fail; 200 } else 201 DPRINTF_ERR((ID " ... success!\n")); 202 } 203 // see if the device is a Wacom tablet and needs some special treatment 204 // let's hope Wacom doesn't produce normal mice any time soon, or this 205 // check will have to be more specific about product_id...hehe 206 if (udd->vendor_id == 0x056a) { 207 // do the control transfers to set up absolute mode (default is HID 208 // mode) 209 210 // see 'Device Class Definition for HID 1.11' (HID1_11.pdf), 211 // par. 7.2 (available at www.usb.org/developers/hidpage) 212 213 // set protocol mode to 'report' (instead of 'boot') 214 controlTransferLength = 0; 215 // HID Class-Specific Request, Host to device (=0x21): 216 // SET_PROTOCOL (=0x0b) to Report Protocol (=1) 217 // of Interface #0 (=0) 218 st = usb->send_request(dev, 0x21, 0x0b, 1, 0, 0, 0, 219 &controlTransferLength); 220 221 if (st < B_OK) { 222 dprintf(ID "add_device() - control transfer 1 failed: %ld\n", 223 st); 224 } 225 226 // try up to five times to set the tablet to 'Wacom'-mode (enabling 227 // absolute mode, pressure data, etc.) 228 controlTransferLength = 2; 229 230 for (tryCount = 0; tryCount < 5; tryCount++) { 231 // HID Class-Specific Request, Host to device (=0x21): 232 // SET_REPORT (=0x09) type Feature (=3) with ID 2 (=2) of 233 // Interface #0 (=0) to repData (== { 0x02, 0x02 }) 234 st = usb->send_request(dev, 0x21, 0x09, (3 << 8) + 2, 0, 2, 235 repData, &controlTransferLength); 236 237 if (st < B_OK) { 238 dprintf(ID "add_device() - control transfer 2 failed: %ld" 239 "\n", st); 240 } 241 242 // check if registers are set correctly 243 244 // HID Class-Specific Request, Device to host (=0xA1): 245 // GET_REPORT (=0x01) type Feature (=3) with ID 2 (=2) of 246 // Interface #0 (=0) to retData 247 st = usb->send_request(dev, 0xA1, 0x01, (3 << 8) + 2, 0, 2, 248 retData, &controlTransferLength); 249 250 if (st < B_OK) { 251 dprintf(ID "add_device() - control transfer 3 failed: %ld" 252 "\n", st); 253 } 254 255 DPRINTF_INFO((ID "add_device() - retData: %u - %u\n", 256 retData[0], retData[1])); 257 258 if (retData[0] == repData[0] && retData[1] == repData[1]) { 259 DPRINTF_INFO((ID "add_device() - successfully set " 260 "'Wacom'-mode\n")); 261 break; 262 } 263 } 264 265 DPRINTF_INFO((ID "add_device() - number of tries: %u\n", 266 tryCount + 1)); 267 268 if (tryCount > 4) { 269 dprintf(ID "add_device() - set 'Wacom'-mode failed\n"); 270 } 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: %ld\n", device->dev)); 327 if (device->dev == dev) { 328 DPRINTF_ERR((ID "device_added() - already added - done!\n")); 329 *cookie = (void*)device; 330 release_sem(sDeviceListLock); 331 return B_OK; 332 } 333 } 334 release_sem(sDeviceListLock); 335 336 if ((device = add_device(dev)) != NULL) { 337 *cookie = (void*)device; 338 DPRINTF_INFO((ID "device_added() - done!\n")); 339 return B_OK; 340 } else 341 DPRINTF_INFO((ID "device_added() - failed to add device!\n")); 342 343 return B_ERROR; 344 } 345 346 // device_removed 347 static status_t 348 device_removed(void *cookie) 349 { 350 wacom_device *device = (wacom_device *) cookie; 351 352 DPRINTF_INFO((ID "device_removed(%p)\n", device)); 353 354 if (device) { 355 356 acquire_sem(sDeviceListLock); 357 358 // remove it from the list of devices 359 if (device == sDeviceList) { 360 sDeviceList = device->next; 361 } else { 362 wacom_device *n; 363 for (n = sDeviceList; n; n = n->next) { 364 if (n->next == device) { 365 n->next = device->next; 366 break; 367 } 368 } 369 } 370 sDeviceCount--; 371 372 // tear it down if it's not open -- 373 // otherwise the last device_free() will handle it 374 375 device->open--; 376 377 DPRINTF_ERR((ID "device_removed() open: %d\n", device->open)); 378 379 if (device->open == 0) { 380 remove_device(device); 381 } else { 382 dprintf(ID "device /dev/%s%d still open -- marked for removal\n", 383 kBasePublishPath, device->number); 384 } 385 386 release_sem(sDeviceListLock); 387 } 388 389 return B_OK; 390 } 391 392 // #pragma mark - Device Hooks 393 // 394 // Here we implement the posixy driver hooks (open/close/read/write/ioctl) 395 396 // device_open 397 static status_t 398 device_open(const char *dname, uint32 flags, void** cookie) 399 { 400 wacom_device *device; 401 int n; 402 status_t ret = B_ERROR; 403 404 char controlDevicePath[1024]; 405 sprintf(controlDevicePath, "%s%s", kBasePublishPath, "control"); 406 if (strcmp(dname, controlDevicePath) == 0) { 407 dprintf(ID "device_open() -> refuse to open control device\n"); 408 return B_ERROR; 409 } 410 411 n = atoi(dname + strlen(kBasePublishPath)); 412 413 DPRINTF_INFO((ID "device_open(\"%s\",%d,...)\n", dname, flags)); 414 415 acquire_sem(sDeviceListLock); 416 for (device = sDeviceList; device; device = device->next) { 417 if (device->number == n) { 418 // if (device->open <= 1) { 419 device->open++; 420 *cookie = device; 421 DPRINTF_ERR((ID "device_open() open: %d\n", device->open)); 422 423 if (device->notify_lock < 0) { 424 device->notify_lock = create_sem(0, "notify_lock"); 425 if (device->notify_lock < 0) { 426 ret = device->notify_lock; 427 device->open--; 428 *cookie = NULL; 429 dprintf(ID "device_open() -> create_sem() returns %ld\n", 430 ret); 431 } else { 432 ret = B_OK; 433 } 434 } 435 release_sem(sDeviceListLock); 436 return ret; 437 // } else { 438 // dprintf(ID "device_open() -> device is already open %ld\n", ret); 439 // release_sem(sDeviceListLock); 440 // return B_ERROR; 441 // } 442 } 443 } 444 release_sem(sDeviceListLock); 445 return ret; 446 } 447 448 // device_close 449 static status_t 450 device_close (void *cookie) 451 { 452 #if DEBUG_DRIVER 453 wacom_device *device = (wacom_device*) cookie; 454 DPRINTF_ERR((ID "device_close() name = \"%s%d\"\n", kBasePublishPath, 455 device->number)); 456 #endif 457 return B_OK; 458 } 459 460 // device_free 461 static status_t 462 device_free(void *cookie) 463 { 464 wacom_device *device = (wacom_device *)cookie; 465 466 DPRINTF_INFO((ID "device_free() name = \"%s%d\"\n", kBasePublishPath, 467 device->number)); 468 469 acquire_sem(sDeviceListLock); 470 471 device->open--; 472 473 DPRINTF_INFO((ID "device_free() open: %ld\n", device->open)); 474 475 if (device->open == 0) { 476 remove_device(device); 477 } 478 release_sem(sDeviceListLock); 479 480 return B_OK; 481 } 482 483 // device_interupt_callback 484 static void 485 device_interupt_callback(void* cookie, status_t status, void* data, 486 uint32 actualLength) 487 { 488 wacom_device* device = (wacom_device*)cookie; 489 uint32 length = min_c(actualLength, device->max_packet_size); 490 491 DPRINTF_INFO((ID "device_interupt_callback(%p) name = \"%s%d\" -> " 492 "status: %ld, length: %ld\n", cookie, kBasePublishPath, device->number, 493 status, actualLength)); 494 495 device->status = status; 496 if (device->notify_lock >= 0) { 497 if (status == B_OK) { 498 memcpy(device->data, data, length); 499 device->length = length; 500 } else { 501 device->length = 0; 502 } 503 release_sem(device->notify_lock); 504 } 505 506 DPRINTF_INFO((ID "device_interupt_callback() - done\n")); 507 } 508 509 // read_header 510 static void 511 read_header(const wacom_device* device, void* buffer) 512 { 513 uint16* ids = (uint16*)buffer; 514 uint32* size = (uint32*)buffer; 515 516 ids[0] = device->vendor; 517 ids[1] = device->product; 518 size[1] = device->max_packet_size; 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 8 bytes are needed to "read" vendor id, product id and max 541 // packet size in case the client wants to read more than 8 bytes, a usb 542 // interupt transfer is scheduled, and an error report is returned as 543 // appropriate 544 if (*count > 8) { 545 // queue the interrupt transfer 546 ret = usb->queue_interrupt(device->pipe, device->data, 547 device->max_packet_size, device_interupt_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 = 8; 566 read_header(device, buffer); 567 ret = B_OK; 568 } else { 569 // any other error trying to acquire the semaphore 570 *count = 0; 571 } 572 } else { 573 if (device->status == 0/*B_USBD_SUCCESS*/) { 574 DPRINTF_INFO((ID "interrupt transfer - success\n")); 575 // copy the data from the buffer 576 dataLength = min_c(device->length, *count - 8); 577 *count = dataLength + 8; 578 read_header(device, buffer); 579 memcpy(buffer + 8, device->data, dataLength); 580 } else { 581 // an error happened during the interrupt transfer 582 *count = 0; 583 dprintf(ID "interrupt transfer - failure: %ld\n", 584 device->status); 585 ret = B_ERROR; 586 } 587 } 588 } else { 589 *count = 0; 590 dprintf(ID "device_read(%p) name = \"%s%d\" -> error queuing " 591 "interrupt: %ld\n", cookie, kBasePublishPath, 592 device->number, ret); 593 } 594 } else if (*count == 8) { 595 read_header(device, buffer); 596 ret = B_OK; 597 } else { 598 dprintf(ID "device_read(%p) name = \"%s%d\" -> buffer size must be " 599 "at least 8 bytes!\n", cookie, kBasePublishPath, 600 device->number); 601 *count = 0; 602 ret = B_BAD_VALUE; 603 } 604 } 605 606 return ret; 607 } 608 609 // device_write 610 static status_t 611 device_write(void *cookie, off_t pos, const void *buf, size_t *count) 612 { 613 return B_ERROR; 614 } 615 616 // device_control 617 static status_t 618 device_control (void *cookie, uint32 msg, void *arg1, size_t len) 619 { 620 return B_ERROR; 621 } 622 623 // #pragma mark - Driver Hooks 624 // 625 // These functions provide the glue used by DevFS to load/unload 626 // the driver and also handle registering with the USB bus manager 627 // to receive device added and removed events 628 629 static usb_notify_hooks notify_hooks = 630 { 631 &device_added, 632 &device_removed 633 }; 634 635 static const usb_support_descriptor kSupportedDevices[] = 636 { 637 { 3, 1, 2, 0, 0 } 638 }; 639 640 // init_hardware 641 status_t 642 init_hardware(void) 643 { 644 return B_OK; 645 } 646 647 // init_driver 648 status_t 649 init_driver(void) 650 { 651 DPRINTF_INFO((ID "init_driver(), built %s %s\n", __DATE__, __TIME__)); 652 653 #if DEBUG_DRIVER && !defined(__HAIKU__) 654 if (load_driver_symbols(kDriverName) == B_OK) { 655 DPRINTF_INFO((ID "loaded symbols\n")); 656 } else { 657 DPRINTF_ERR((ID "no driver symbols loaded!\n")); 658 } 659 #endif 660 661 if (get_module(B_USB_MODULE_NAME, (module_info**) &usb) != B_OK) { 662 DPRINTF_ERR((ID "cannot get module \"%s\"\n", B_USB_MODULE_NAME)); 663 return B_ERROR; 664 } 665 666 if ((sDeviceListLock = create_sem(1,"sDeviceListLock")) < 0) { 667 put_module(B_USB_MODULE_NAME); 668 return sDeviceListLock; 669 } 670 671 usb->register_driver(kDriverName, kSupportedDevices, 1, NULL); 672 usb->install_notify(kDriverName, ¬ify_hooks); 673 674 return B_OK; 675 } 676 677 // uninit_driver 678 void 679 uninit_driver(void) 680 { 681 int i; 682 683 DPRINTF_INFO((ID "uninit_driver()\n")); 684 685 usb->uninstall_notify(kDriverName); 686 687 delete_sem(sDeviceListLock); 688 689 put_module(B_USB_MODULE_NAME); 690 691 if (sDeviceNames) { 692 for (i = 0; sDeviceNames[i]; i++) 693 free(sDeviceNames[i]); 694 free(sDeviceNames); 695 } 696 697 DPRINTF_INFO((ID "uninit_driver() done\n")); 698 } 699 700 // publish_devices 701 const char** 702 publish_devices() 703 { 704 wacom_device *device; 705 int i; 706 707 DPRINTF_INFO((ID "publish_devices()\n")); 708 709 if (sDeviceNames) { 710 for (i = 0; sDeviceNames[i]; i++) 711 free((char *) sDeviceNames[i]); 712 free(sDeviceNames); 713 } 714 715 acquire_sem(sDeviceListLock); 716 sDeviceNames = (char**)malloc(sizeof(char*) * (sDeviceCount + 2)); 717 if (sDeviceNames) { 718 for (i = 0, device = sDeviceList; device; device = device->next) { 719 sDeviceNames[i] = (char*)malloc(strlen(kBasePublishPath) + 4); 720 if (sDeviceNames[i]) { 721 sprintf(sDeviceNames[i],"%s%d",kBasePublishPath,device->number); 722 DPRINTF_INFO((ID "publishing: \"/dev/%s\"\n",sDeviceNames[i])); 723 i++; 724 } 725 } 726 // publish the currently fake control device 727 sDeviceNames[i] = (char*)malloc(strlen(kBasePublishPath) + 8); 728 if (sDeviceNames[i]) 729 sprintf(sDeviceNames[i], "%s%s", kBasePublishPath, "control"); 730 731 sDeviceNames[i + 1] = NULL; 732 } 733 734 release_sem(sDeviceListLock); 735 736 return (const char**)sDeviceNames; 737 } 738 739 static device_hooks sDeviceHooks = { 740 device_open, 741 device_close, 742 device_free, 743 device_control, 744 device_read, 745 device_write 746 }; 747 748 // find_device 749 device_hooks* 750 find_device(const char* name) 751 { 752 return &sDeviceHooks; 753 } 754