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 for (int32 i = 0; i < gDeviceList->CountDevices(); i++) { 196 ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->DeviceAt(i); 197 if (!handler) 198 continue; 199 200 HIDDevice *device = handler->Device(); 201 if (device->ParentCookie() != parentCookie) 202 continue; 203 204 // remove all the handlers 205 for (uint32 i = 0;; i++) { 206 handler = device->ProtocolHandlerAt(i); 207 if (handler == NULL) 208 break; 209 210 gDeviceList->RemoveDevice(NULL, handler); 211 } 212 213 // this handler's device belongs to the one removed 214 if (device->IsOpen()) { 215 // the device and it's handlers will be deleted in the free hook 216 device->Removed(); 217 } else 218 delete device; 219 220 break; 221 } 222 223 mutex_unlock(&sDriverLock); 224 return B_OK; 225 } 226 227 228 // #pragma mark - driver hooks 229 230 231 static status_t 232 usb_hid_open(const char *name, uint32 flags, void **_cookie) 233 { 234 TRACE("open(%s, %" B_PRIu32 ", %p)\n", name, flags, _cookie); 235 236 device_cookie *cookie = new(std::nothrow) device_cookie(); 237 if (cookie == NULL) 238 return B_NO_MEMORY; 239 240 MutexLocker locker(sDriverLock); 241 242 ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->FindDevice(name); 243 TRACE(" name %s: handler %p\n", name, handler); 244 245 cookie->handler = handler; 246 cookie->cookie = 0; 247 248 status_t result = handler == NULL ? B_ENTRY_NOT_FOUND : B_OK; 249 if (result == B_OK) 250 result = handler->Open(flags, &cookie->cookie); 251 252 if (result != B_OK) { 253 delete cookie; 254 return result; 255 } 256 257 *_cookie = cookie; 258 259 return B_OK; 260 } 261 262 263 static status_t 264 usb_hid_read(void *_cookie, off_t position, void *buffer, size_t *numBytes) 265 { 266 device_cookie *cookie = (device_cookie *)_cookie; 267 268 TRACE("read(%p, %" B_PRIu64 ", %p, %p (%lu)\n", cookie, position, buffer, 269 numBytes, numBytes != NULL ? *numBytes : 0); 270 return cookie->handler->Read(&cookie->cookie, position, buffer, numBytes); 271 } 272 273 274 static status_t 275 usb_hid_write(void *_cookie, off_t position, const void *buffer, 276 size_t *numBytes) 277 { 278 device_cookie *cookie = (device_cookie *)_cookie; 279 280 TRACE("write(%p, %" B_PRIu64 ", %p, %p (%lu)\n", cookie, position, buffer, numBytes, 281 numBytes != NULL ? *numBytes : 0); 282 return cookie->handler->Write(&cookie->cookie, position, buffer, numBytes); 283 } 284 285 286 static status_t 287 usb_hid_control(void *_cookie, uint32 op, void *buffer, size_t length) 288 { 289 device_cookie *cookie = (device_cookie *)_cookie; 290 291 TRACE("control(%p, %" B_PRIu32 ", %p, %" B_PRIuSIZE ")\n", cookie, op, 292 buffer, length); 293 return cookie->handler->Control(&cookie->cookie, op, buffer, length); 294 } 295 296 297 static status_t 298 usb_hid_close(void *_cookie) 299 { 300 device_cookie *cookie = (device_cookie *)_cookie; 301 302 TRACE("close(%p)\n", cookie); 303 return cookie->handler->Close(&cookie->cookie); 304 } 305 306 307 static status_t 308 usb_hid_free(void *_cookie) 309 { 310 device_cookie *cookie = (device_cookie *)_cookie; 311 TRACE("free(%p)\n", cookie); 312 313 mutex_lock(&sDriverLock); 314 315 HIDDevice *device = cookie->handler->Device(); 316 if (device->IsOpen()) { 317 // another handler of this device is still open so we can't free it 318 } else if (device->IsRemoved()) { 319 // the parent device is removed already and none of its handlers are 320 // open anymore so we can free it here 321 delete device; 322 } 323 324 mutex_unlock(&sDriverLock); 325 326 delete cookie; 327 return B_OK; 328 } 329 330 331 // #pragma mark - driver API 332 333 334 status_t 335 init_hardware() 336 { 337 TRACE("init_hardware() " __DATE__ " " __TIME__ "\n"); 338 return B_OK; 339 } 340 341 342 status_t 343 init_driver() 344 { 345 TRACE("init_driver() " __DATE__ " " __TIME__ "\n"); 346 if (get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule) != B_OK) 347 return B_ERROR; 348 349 gDeviceList = new(std::nothrow) DeviceList(); 350 if (gDeviceList == NULL) { 351 put_module(B_USB_MODULE_NAME); 352 return B_NO_MEMORY; 353 } 354 355 mutex_init(&sDriverLock, "usb hid driver lock"); 356 357 static usb_notify_hooks notifyHooks = { 358 &usb_hid_device_added, 359 &usb_hid_device_removed 360 }; 361 362 static usb_support_descriptor genericHIDSupportDescriptor = { 363 USB_INTERFACE_CLASS_HID, 0, 0, 0, 0 364 }; 365 366 int32 supportDescriptorCount = 1 + gQuirkyDeviceCount; 367 sSupportDescriptors 368 = new(std::nothrow) usb_support_descriptor[supportDescriptorCount]; 369 if (sSupportDescriptors != NULL) { 370 sSupportDescriptors[0] = genericHIDSupportDescriptor; 371 for (int32 i = 0; i < gQuirkyDeviceCount; i++) { 372 usb_support_descriptor &descriptor = sSupportDescriptors[i + 1]; 373 descriptor.dev_class = gQuirkyDevices[i].device_class; 374 descriptor.dev_subclass = gQuirkyDevices[i].device_subclass; 375 descriptor.dev_protocol = gQuirkyDevices[i].device_protocol; 376 descriptor.vendor = gQuirkyDevices[i].vendor_id; 377 descriptor.product = gQuirkyDevices[i].product_id; 378 } 379 380 gUSBModule->register_driver(DRIVER_NAME, sSupportDescriptors, 381 supportDescriptorCount, NULL); 382 } else { 383 // no memory for quirky devices, at least support proper HID 384 gUSBModule->register_driver(DRIVER_NAME, &genericHIDSupportDescriptor, 385 1, NULL); 386 } 387 388 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 389 TRACE("init_driver() OK\n"); 390 return B_OK; 391 } 392 393 394 void 395 uninit_driver() 396 { 397 TRACE("uninit_driver()\n"); 398 gUSBModule->uninstall_notify(DRIVER_NAME); 399 put_module(B_USB_MODULE_NAME); 400 delete[] sSupportDescriptors; 401 sSupportDescriptors = NULL; 402 delete gDeviceList; 403 gDeviceList = NULL; 404 mutex_destroy(&sDriverLock); 405 } 406 407 408 const char ** 409 publish_devices() 410 { 411 TRACE("publish_devices()\n"); 412 const char **publishList = gDeviceList->PublishDevices(); 413 414 int32 index = 0; 415 while (publishList[index] != NULL) { 416 TRACE("publishing %s\n", publishList[index]); 417 index++; 418 } 419 420 return publishList; 421 } 422 423 424 device_hooks * 425 find_device(const char *name) 426 { 427 static device_hooks hooks = { 428 usb_hid_open, 429 usb_hid_close, 430 usb_hid_free, 431 usb_hid_control, 432 usb_hid_read, 433 usb_hid_write, 434 NULL, /* select */ 435 NULL /* deselect */ 436 }; 437 438 TRACE("find_device(%s)\n", name); 439 if (gDeviceList->FindDevice(name) == NULL) { 440 TRACE_ALWAYS("didn't find device %s\n", name); 441 return NULL; 442 } 443 444 return &hooks; 445 } 446