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