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