1 /* 2 * Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch> 3 * Distributed under the terms of the MIT license. 4 */ 5 6 7 //! Driver for USB Human Interface Devices. 8 9 10 #include "DeviceList.h" 11 #include "Driver.h" 12 #include "HIDDevice.h" 13 #include "ProtocolHandler.h" 14 #include "QuirkyDevices.h" 15 16 #include <lock.h> 17 #include <util/AutoLock.h> 18 19 #include <new> 20 #include <stdio.h> 21 #include <string.h> 22 23 24 struct device_cookie { 25 ProtocolHandler* handler; 26 uint32 cookie; 27 }; 28 29 30 int32 api_version = B_CUR_DRIVER_API_VERSION; 31 usb_module_info *gUSBModule = NULL; 32 DeviceList *gDeviceList = NULL; 33 static int32 sParentCookie = 0; 34 static mutex sDriverLock; 35 static usb_support_descriptor *sSupportDescriptors; 36 37 38 usb_support_descriptor gBlackListedDevices[] = { 39 { 40 // temperature sensor which declares itself as a usb hid device 41 0, 0, 0, 0x0c45, 0x7401 42 }, 43 { 44 // Silicon Labs EC3 JTAG/C2 probe, declares itself as usb hid 45 0, 0, 0, 0x10c4, 0x8044 46 }, 47 { 48 // wacom devices are handled by the dedicated wacom driver 49 0, 0, 0, USB_VENDOR_WACOM, 0 50 } 51 52 }; 53 54 int32 gBlackListedDeviceCount 55 = sizeof(gBlackListedDevices) / sizeof(gBlackListedDevices[0]); 56 57 58 // #pragma mark - notify hooks 59 60 61 status_t 62 usb_hid_device_added(usb_device device, void **cookie) 63 { 64 TRACE("device_added()\n"); 65 const usb_device_descriptor *deviceDescriptor 66 = gUSBModule->get_device_descriptor(device); 67 68 TRACE("vendor id: 0x%04x; product id: 0x%04x\n", 69 deviceDescriptor->vendor_id, deviceDescriptor->product_id); 70 71 for (int32 i = 0; i < gBlackListedDeviceCount; i++) { 72 usb_support_descriptor &entry = gBlackListedDevices[i]; 73 if ((entry.vendor != 0 74 && deviceDescriptor->vendor_id != entry.vendor) 75 || (entry.product != 0 76 && deviceDescriptor->product_id != entry.product)) { 77 continue; 78 } 79 80 return B_ERROR; 81 } 82 83 const usb_configuration_info *config 84 = gUSBModule->get_nth_configuration(device, USB_DEFAULT_CONFIGURATION); 85 if (config == NULL) { 86 TRACE_ALWAYS("cannot get default configuration\n"); 87 return B_ERROR; 88 } 89 90 // ensure default configuration is set 91 status_t result = gUSBModule->set_configuration(device, config); 92 if (result != B_OK) { 93 TRACE_ALWAYS("set_configuration() failed 0x%08" B_PRIx32 "\n", result); 94 return result; 95 } 96 97 // refresh config 98 config = gUSBModule->get_configuration(device); 99 if (config == NULL) { 100 TRACE_ALWAYS("cannot get current configuration\n"); 101 return B_ERROR; 102 } 103 104 bool devicesFound = false; 105 int32 parentCookie = atomic_add(&sParentCookie, 1); 106 for (size_t i = 0; i < config->interface_count; i++) { 107 const usb_interface_info *interface = config->interface[i].active; 108 if (interface == NULL || interface->descr == NULL) 109 continue; 110 111 uint8 interfaceClass = interface->descr->interface_class; 112 TRACE("interface %" B_PRIuSIZE ": class: %u; subclass: %u; protocol: " 113 "%u\n", i, interfaceClass, interface->descr->interface_subclass, 114 interface->descr->interface_protocol); 115 116 // check for quirky devices first 117 int32 quirkyIndex = -1; 118 for (int32 j = 0; j < gQuirkyDeviceCount; j++) { 119 usb_hid_quirky_device &quirky = gQuirkyDevices[j]; 120 if ((quirky.vendor_id != 0 121 && deviceDescriptor->vendor_id != quirky.vendor_id) 122 || (quirky.product_id != 0 123 && deviceDescriptor->product_id != quirky.product_id) 124 || (quirky.device_class != 0 125 && interfaceClass != quirky.device_class) 126 || (quirky.device_subclass != 0 127 && interface->descr->interface_subclass 128 != quirky.device_subclass) 129 || (quirky.device_protocol != 0 130 && interface->descr->interface_protocol 131 != quirky.device_protocol)) { 132 continue; 133 } 134 135 quirkyIndex = j; 136 break; 137 } 138 139 if (quirkyIndex >= 0 || interfaceClass == USB_INTERFACE_CLASS_HID) { 140 mutex_lock(&sDriverLock); 141 HIDDevice *hidDevice 142 = new(std::nothrow) HIDDevice(device, config, i, quirkyIndex); 143 144 if (hidDevice != NULL && hidDevice->InitCheck() == B_OK) { 145 hidDevice->SetParentCookie(parentCookie); 146 147 for (uint32 i = 0;; i++) { 148 ProtocolHandler *handler = hidDevice->ProtocolHandlerAt(i); 149 if (handler == NULL) 150 break; 151 152 // As devices can be un- and replugged at will, we cannot 153 // simply rely on a device count. If there is just one 154 // keyboard, this does not mean that it uses the 0 name. 155 // There might have been two keyboards and the one using 0 156 // might have been unplugged. So we just generate names 157 // until we find one that is not currently in use. 158 int32 index = 0; 159 char pathBuffer[128]; 160 const char *basePath = handler->BasePath(); 161 while (true) { 162 sprintf(pathBuffer, "%s%" B_PRId32, basePath, index++); 163 if (gDeviceList->FindDevice(pathBuffer) == NULL) { 164 // this name is still free, use it 165 handler->SetPublishPath(strdup(pathBuffer)); 166 break; 167 } 168 } 169 170 gDeviceList->AddDevice(handler->PublishPath(), handler); 171 devicesFound = true; 172 } 173 } else 174 delete hidDevice; 175 176 mutex_unlock(&sDriverLock); 177 } 178 } 179 180 if (!devicesFound) 181 return B_ERROR; 182 183 *cookie = (void *)(addr_t)parentCookie; 184 return B_OK; 185 } 186 187 188 status_t 189 usb_hid_device_removed(void *cookie) 190 { 191 mutex_lock(&sDriverLock); 192 int32 parentCookie = (int32)(addr_t)cookie; 193 TRACE("device_removed(%" B_PRId32 ")\n", parentCookie); 194 195 // removed device may contain multiple HID devices on multiple interfaces 196 // we must go through all published devices and remove all that belong to this parent 197 for (int32 i = 0; i < gDeviceList->CountDevices(); i++) { 198 ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->DeviceAt(i); 199 if (!handler) 200 continue; 201 202 HIDDevice *device = handler->Device(); 203 if (device->ParentCookie() != parentCookie) 204 continue; 205 206 // remove all the handlers 207 for (uint32 j = 0;; j++) { 208 handler = device->ProtocolHandlerAt(j); 209 if (handler == NULL) 210 break; 211 212 gDeviceList->RemoveDevice(NULL, handler); 213 i--; // device count changed, adjust index 214 } 215 216 // this handler's device belongs to the one removed 217 if (device->IsOpen()) { 218 // the device and it's handlers will be deleted in the free hook 219 device->Removed(); 220 } else 221 delete device; 222 } 223 224 mutex_unlock(&sDriverLock); 225 return B_OK; 226 } 227 228 229 // #pragma mark - driver hooks 230 231 232 static status_t 233 usb_hid_open(const char *name, uint32 flags, void **_cookie) 234 { 235 TRACE("open(%s, %" B_PRIu32 ", %p)\n", name, flags, _cookie); 236 237 device_cookie *cookie = new(std::nothrow) device_cookie(); 238 if (cookie == NULL) 239 return B_NO_MEMORY; 240 241 MutexLocker locker(sDriverLock); 242 243 ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->FindDevice(name); 244 TRACE(" name %s: handler %p\n", name, handler); 245 246 cookie->handler = handler; 247 cookie->cookie = 0; 248 249 status_t result = handler == NULL ? B_ENTRY_NOT_FOUND : B_OK; 250 if (result == B_OK) 251 result = handler->Open(flags, &cookie->cookie); 252 253 if (result != B_OK) { 254 delete cookie; 255 return result; 256 } 257 258 *_cookie = cookie; 259 260 return B_OK; 261 } 262 263 264 static status_t 265 usb_hid_read(void *_cookie, off_t position, void *buffer, size_t *numBytes) 266 { 267 device_cookie *cookie = (device_cookie *)_cookie; 268 269 TRACE("read(%p, %" B_PRIu64 ", %p, %p (%lu)\n", cookie, position, buffer, 270 numBytes, numBytes != NULL ? *numBytes : 0); 271 return cookie->handler->Read(&cookie->cookie, position, buffer, numBytes); 272 } 273 274 275 static status_t 276 usb_hid_write(void *_cookie, off_t position, const void *buffer, 277 size_t *numBytes) 278 { 279 device_cookie *cookie = (device_cookie *)_cookie; 280 281 TRACE("write(%p, %" B_PRIu64 ", %p, %p (%lu)\n", cookie, position, buffer, numBytes, 282 numBytes != NULL ? *numBytes : 0); 283 return cookie->handler->Write(&cookie->cookie, position, buffer, numBytes); 284 } 285 286 287 static status_t 288 usb_hid_control(void *_cookie, uint32 op, void *buffer, size_t length) 289 { 290 device_cookie *cookie = (device_cookie *)_cookie; 291 292 TRACE("control(%p, %" B_PRIu32 ", %p, %" B_PRIuSIZE ")\n", cookie, op, 293 buffer, length); 294 return cookie->handler->Control(&cookie->cookie, op, buffer, length); 295 } 296 297 298 static status_t 299 usb_hid_close(void *_cookie) 300 { 301 device_cookie *cookie = (device_cookie *)_cookie; 302 303 TRACE("close(%p)\n", cookie); 304 return cookie->handler->Close(&cookie->cookie); 305 } 306 307 308 static status_t 309 usb_hid_free(void *_cookie) 310 { 311 device_cookie *cookie = (device_cookie *)_cookie; 312 TRACE("free(%p)\n", cookie); 313 314 mutex_lock(&sDriverLock); 315 316 HIDDevice *device = cookie->handler->Device(); 317 if (device->IsOpen()) { 318 // another handler of this device is still open so we can't free it 319 } else if (device->IsRemoved()) { 320 // the parent device is removed already and none of its handlers are 321 // open anymore so we can free it here 322 delete device; 323 } 324 325 mutex_unlock(&sDriverLock); 326 327 delete cookie; 328 return B_OK; 329 } 330 331 332 // #pragma mark - driver API 333 334 335 status_t 336 init_hardware() 337 { 338 TRACE("init_hardware() " __DATE__ " " __TIME__ "\n"); 339 return B_OK; 340 } 341 342 343 status_t 344 init_driver() 345 { 346 TRACE("init_driver() " __DATE__ " " __TIME__ "\n"); 347 if (get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule) != B_OK) 348 return B_ERROR; 349 350 gDeviceList = new(std::nothrow) DeviceList(); 351 if (gDeviceList == NULL) { 352 put_module(B_USB_MODULE_NAME); 353 return B_NO_MEMORY; 354 } 355 356 mutex_init(&sDriverLock, "usb hid driver lock"); 357 358 static usb_notify_hooks notifyHooks = { 359 &usb_hid_device_added, 360 &usb_hid_device_removed 361 }; 362 363 static usb_support_descriptor genericHIDSupportDescriptor = { 364 USB_INTERFACE_CLASS_HID, 0, 0, 0, 0 365 }; 366 367 int32 supportDescriptorCount = 1 + gQuirkyDeviceCount; 368 sSupportDescriptors 369 = new(std::nothrow) usb_support_descriptor[supportDescriptorCount]; 370 if (sSupportDescriptors != NULL) { 371 sSupportDescriptors[0] = genericHIDSupportDescriptor; 372 for (int32 i = 0; i < gQuirkyDeviceCount; i++) { 373 usb_support_descriptor &descriptor = sSupportDescriptors[i + 1]; 374 descriptor.dev_class = gQuirkyDevices[i].device_class; 375 descriptor.dev_subclass = gQuirkyDevices[i].device_subclass; 376 descriptor.dev_protocol = gQuirkyDevices[i].device_protocol; 377 descriptor.vendor = gQuirkyDevices[i].vendor_id; 378 descriptor.product = gQuirkyDevices[i].product_id; 379 } 380 381 gUSBModule->register_driver(DRIVER_NAME, sSupportDescriptors, 382 supportDescriptorCount, NULL); 383 } else { 384 // no memory for quirky devices, at least support proper HID 385 gUSBModule->register_driver(DRIVER_NAME, &genericHIDSupportDescriptor, 386 1, NULL); 387 } 388 389 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 390 TRACE("init_driver() OK\n"); 391 return B_OK; 392 } 393 394 395 void 396 uninit_driver() 397 { 398 TRACE("uninit_driver()\n"); 399 gUSBModule->uninstall_notify(DRIVER_NAME); 400 put_module(B_USB_MODULE_NAME); 401 delete[] sSupportDescriptors; 402 sSupportDescriptors = NULL; 403 delete gDeviceList; 404 gDeviceList = NULL; 405 mutex_destroy(&sDriverLock); 406 } 407 408 409 const char ** 410 publish_devices() 411 { 412 TRACE("publish_devices()\n"); 413 const char **publishList = gDeviceList->PublishDevices(); 414 415 int32 index = 0; 416 while (publishList[index] != NULL) { 417 TRACE("publishing %s\n", publishList[index]); 418 index++; 419 } 420 421 return publishList; 422 } 423 424 425 device_hooks * 426 find_device(const char *name) 427 { 428 static device_hooks hooks = { 429 usb_hid_open, 430 usb_hid_close, 431 usb_hid_free, 432 usb_hid_control, 433 usb_hid_read, 434 usb_hid_write, 435 NULL, /* select */ 436 NULL /* deselect */ 437 }; 438 439 TRACE("find_device(%s)\n", name); 440 if (gDeviceList->FindDevice(name) == NULL) { 441 TRACE_ALWAYS("didn't find device %s\n", name); 442 return NULL; 443 } 444 445 return &hooks; 446 } 447