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: %d\n", alt)); 146 147 148 // does it have the correct type of interface? 149 if (ii->descr->interface_class != 3) continue; 150 if (ii->descr->interface_subclass != 1) continue; 151 if (ii->endpoint_count != 1) continue; 152 153 // only accept input endpoints 154 if (ii->endpoint[0].descr->endpoint_address & 0x80) { 155 DPRINTF_INFO((ID "add_device() - found input endpoint\n")); 156 goto got_one; 157 } 158 } 159 } 160 } else 161 goto fail; 162 163 fail: 164 put_number(num); 165 if (device) { 166 free(device->data); 167 free(device); 168 } 169 return NULL; 170 171 got_one: 172 if ((device = (wacom_device *) malloc(sizeof(wacom_device))) == NULL) 173 goto fail; 174 175 device->dev = dev; 176 device->number = num; 177 device->open = 1; 178 device->notify_lock = -1; 179 device->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 device->pipe = ii->endpoint[0].handle; 223 //DPRINTF_INFO((ID "add_device() - pipe id = %ld\n", device->pipe)); 224 device->length = 0; 225 device->max_packet_size = ii->endpoint[0].descr->max_packet_size; 226 device->data = (char*)malloc(device->max_packet_size); 227 if (device->data == NULL) 228 goto fail; 229 //DPRINTF_INFO((ID "add_device() - max packet length = %ld\n", device->max_packet_size)); 230 device->status = 0;//B_USB_STATUS_SUCCESS; 231 device->vendor = udd->vendor_id; 232 device->product = udd->product_id; 233 234 DPRINTF_INFO((ID "add_device() - added %p (/dev/%s%d)\n", device, kBasePublishPath, num)); 235 236 // add it to the list of devices so it will be published, etc 237 acquire_sem(sDeviceListLock); 238 device->next = sDeviceList; 239 sDeviceList = device; 240 sDeviceCount++; 241 release_sem(sDeviceListLock); 242 243 return device; 244 } 245 246 // remove_device 247 static void 248 remove_device(wacom_device *device) 249 { 250 put_number(device->number); 251 252 usb->cancel_queued_transfers(device->pipe); 253 254 delete_sem(device->notify_lock); 255 if (device->data) 256 free(device->data); 257 free(device); 258 } 259 260 // device_added 261 static status_t 262 device_added(usb_device dev, void** cookie) 263 { 264 wacom_device* device; 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 (device = sDeviceList; device; device = device->next) { 271 DPRINTF_ERR((ID "device_added() - old device: %ld\n", device->dev)); 272 if (device->dev == dev) { 273 DPRINTF_ERR((ID "device_added() - already added - done!\n")); 274 *cookie = (void*)device; 275 release_sem(sDeviceListLock); 276 return B_OK; 277 } 278 } 279 release_sem(sDeviceListLock); 280 281 if ((device = add_device(dev)) != NULL) { 282 *cookie = (void*)device; 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 *device = (wacom_device *) cookie; 296 297 DPRINTF_INFO((ID "device_removed(%p)\n", device)); 298 299 if (device) { 300 301 acquire_sem(sDeviceListLock); 302 303 // remove it from the list of devices 304 if (device == sDeviceList) { 305 sDeviceList = device->next; 306 } else { 307 wacom_device *n; 308 for (n = sDeviceList; n; n = n->next) { 309 if (n->next == device) { 310 n->next = device->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 device->open--; 321 322 DPRINTF_ERR((ID "device_removed() open: %d\n", device->open)); 323 324 if (device->open == 0) { 325 remove_device(device); 326 } else { 327 dprintf(ID "device /dev/%s%d still open -- marked for removal\n", 328 kBasePublishPath, device->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 *device; 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 (device = sDeviceList; device; device = device->next) { 362 if (device->number == n) { 363 // if (device->open <= 1) { 364 device->open++; 365 *cookie = device; 366 DPRINTF_ERR((ID "device_open() open: %d\n", device->open)); 367 368 if (device->notify_lock < 0) { 369 if ((device->notify_lock = create_sem(0, "notify_lock")) < 0) { 370 ret = device->notify_lock; 371 device->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 *device = (wacom_device*) cookie; 397 DPRINTF_ERR((ID "device_close() name = \"%s%d\"\n", kBasePublishPath, device->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 *device = (wacom_device *)cookie; 407 408 DPRINTF_INFO((ID "device_free() name = \"%s%d\"\n", kBasePublishPath, device->number)); 409 410 acquire_sem(sDeviceListLock); 411 412 device->open--; 413 414 DPRINTF_INFO((ID "device_free() open: %ld\n", device->open)); 415 416 if (device->open == 0) { 417 remove_device(device); 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 actualLength) 428 { 429 wacom_device* device = (wacom_device*)cookie; 430 uint32 length = min_c(actualLength, device->max_packet_size); 431 432 DPRINTF_INFO((ID "device_interupt_callback(%p) name = \"%s%d\" -> " 433 "status: %ld, length: %ld\n", cookie, kBasePublishPath, device->number, 434 status, actualLength)); 435 436 device->status = status; 437 if (device->notify_lock >= 0) { 438 if (status == 0/*B_USB_STATUS_SUCCESS*/) { 439 memcpy(device->data, data, length); 440 device->length = length; 441 } else { 442 device->length = 0; 443 } 444 release_sem(device->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* device, void* buffer) 453 { 454 uint16* ids = (uint16*)buffer; 455 uint32* size = (uint32*)buffer; 456 457 ids[0] = device->vendor; 458 ids[1] = device->product; 459 size[1] = device->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* device = (wacom_device*) cookie; 467 status_t ret = B_BAD_VALUE; 468 uint8* buffer = (uint8*)buf; 469 uint32 dataLength; 470 471 if (!device) 472 return ret; 473 474 ret = device->notify_lock; 475 476 DPRINTF_INFO((ID "device_read(%p,%Ld,0x%x,%d) name = \"%s%d\"\n", 477 cookie, pos, buf, *count, kBasePublishPath, device->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(device->pipe, device->data, device->max_packet_size, 487 device_interupt_callback, device); 488 if (ret >= B_OK) { 489 // we will block here until the interrupt transfer has been done 490 ret = acquire_sem_etc(device->notify_lock, 1, B_RELATIVE_TIMEOUT, 500 * 1000); 491 // handle time out 492 if (ret < B_OK) { 493 // usb->cancel_queued_transfers(device->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, device->number)); 500 *count = 8; 501 read_header(device, buffer); 502 ret = B_OK; 503 } else { 504 // any other error trying to acquire the semaphore 505 *count = 0; 506 } 507 } else { 508 if (device->status == 0/*B_USBD_SUCCESS*/) { 509 DPRINTF_INFO((ID "interrupt transfer - success\n")); 510 // copy the data from the buffer 511 dataLength = min_c(device->length, *count - 8); 512 *count = dataLength + 8; 513 read_header(device, buffer); 514 memcpy(buffer + 8, device->data, dataLength); 515 } else { 516 // an error happened during the interrupt transfer 517 *count = 0; 518 dprintf(ID "interrupt transfer - failure: %ld\n", device->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, device->number, ret); 526 } 527 } else if (*count == 8) { 528 read_header(device, 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, device->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 *device; 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, device = sDeviceList; device; device = device->next) { 651 if ((sDeviceNames[i] = (char *) malloc(strlen(kBasePublishPath) + 4))) { 652 sprintf(sDeviceNames[i],"%s%d",kBasePublishPath,device->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