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 uint8 interfaceClass = interface->descr->interface_class; 109 TRACE("interface %" B_PRIuSIZE ": class: %u; subclass: %u; protocol: " 110 "%u\n", i, interfaceClass, interface->descr->interface_subclass, 111 interface->descr->interface_protocol); 112 113 // check for quirky devices first 114 int32 quirkyIndex = -1; 115 for (int32 j = 0; j < gQuirkyDeviceCount; j++) { 116 usb_hid_quirky_device &quirky = gQuirkyDevices[j]; 117 if ((quirky.vendor_id != 0 118 && deviceDescriptor->vendor_id != quirky.vendor_id) 119 || (quirky.product_id != 0 120 && deviceDescriptor->product_id != quirky.product_id) 121 || (quirky.device_class != 0 122 && interfaceClass != quirky.device_class) 123 || (quirky.device_subclass != 0 124 && interface->descr->interface_subclass 125 != quirky.device_subclass) 126 || (quirky.device_protocol != 0 127 && interface->descr->interface_protocol 128 != quirky.device_protocol)) { 129 continue; 130 } 131 132 quirkyIndex = j; 133 break; 134 } 135 136 if (quirkyIndex >= 0 || interfaceClass == USB_INTERFACE_CLASS_HID) { 137 mutex_lock(&sDriverLock); 138 HIDDevice *hidDevice 139 = new(std::nothrow) HIDDevice(device, config, i, quirkyIndex); 140 141 if (hidDevice != NULL && hidDevice->InitCheck() == B_OK) { 142 hidDevice->SetParentCookie(parentCookie); 143 144 for (uint32 i = 0;; i++) { 145 ProtocolHandler *handler = hidDevice->ProtocolHandlerAt(i); 146 if (handler == NULL) 147 break; 148 149 // As devices can be un- and replugged at will, we cannot 150 // simply rely on a device count. If there is just one 151 // keyboard, this does not mean that it uses the 0 name. 152 // There might have been two keyboards and the one using 0 153 // might have been unplugged. So we just generate names 154 // until we find one that is not currently in use. 155 int32 index = 0; 156 char pathBuffer[128]; 157 const char *basePath = handler->BasePath(); 158 while (true) { 159 sprintf(pathBuffer, "%s%" B_PRId32, basePath, index++); 160 if (gDeviceList->FindDevice(pathBuffer) == NULL) { 161 // this name is still free, use it 162 handler->SetPublishPath(strdup(pathBuffer)); 163 break; 164 } 165 } 166 167 gDeviceList->AddDevice(handler->PublishPath(), handler); 168 devicesFound = true; 169 } 170 } else 171 delete hidDevice; 172 173 mutex_unlock(&sDriverLock); 174 } 175 } 176 177 if (!devicesFound) 178 return B_ERROR; 179 180 *cookie = (void *)(addr_t)parentCookie; 181 return B_OK; 182 } 183 184 185 status_t 186 usb_hid_device_removed(void *cookie) 187 { 188 mutex_lock(&sDriverLock); 189 int32 parentCookie = (int32)(addr_t)cookie; 190 TRACE("device_removed(%" B_PRId32 ")\n", parentCookie); 191 192 for (int32 i = 0; i < gDeviceList->CountDevices(); i++) { 193 ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->DeviceAt(i); 194 if (!handler) 195 continue; 196 197 HIDDevice *device = handler->Device(); 198 if (device->ParentCookie() != parentCookie) 199 continue; 200 201 // remove all the handlers 202 for (uint32 i = 0;; i++) { 203 handler = device->ProtocolHandlerAt(i); 204 if (handler == NULL) 205 break; 206 207 gDeviceList->RemoveDevice(NULL, handler); 208 } 209 210 // this handler's device belongs to the one removed 211 if (device->IsOpen()) { 212 // the device and it's handlers will be deleted in the free hook 213 device->Removed(); 214 } else 215 delete device; 216 217 break; 218 } 219 220 mutex_unlock(&sDriverLock); 221 return B_OK; 222 } 223 224 225 // #pragma mark - driver hooks 226 227 228 static status_t 229 usb_hid_open(const char *name, uint32 flags, void **_cookie) 230 { 231 TRACE("open(%s, %" B_PRIu32 ", %p)\n", name, flags, _cookie); 232 233 device_cookie *cookie = new(std::nothrow) device_cookie(); 234 if (cookie == NULL) 235 return B_NO_MEMORY; 236 237 MutexLocker locker(sDriverLock); 238 239 ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->FindDevice(name); 240 TRACE(" name %s: handler %p\n", name, handler); 241 242 cookie->handler = handler; 243 cookie->cookie = 0; 244 245 status_t result = handler == NULL ? B_ENTRY_NOT_FOUND : B_OK; 246 if (result == B_OK) 247 result = handler->Open(flags, &cookie->cookie); 248 249 if (result != B_OK) { 250 delete cookie; 251 return result; 252 } 253 254 *_cookie = cookie; 255 256 return B_OK; 257 } 258 259 260 static status_t 261 usb_hid_read(void *_cookie, off_t position, void *buffer, size_t *numBytes) 262 { 263 device_cookie *cookie = (device_cookie *)_cookie; 264 265 TRACE("read(%p, %" B_PRIu64 ", %p, %p (%lu)\n", cookie, position, buffer, 266 numBytes, numBytes != NULL ? *numBytes : 0); 267 return cookie->handler->Read(&cookie->cookie, position, buffer, numBytes); 268 } 269 270 271 static status_t 272 usb_hid_write(void *_cookie, off_t position, const void *buffer, 273 size_t *numBytes) 274 { 275 device_cookie *cookie = (device_cookie *)_cookie; 276 277 TRACE("write(%p, %" B_PRIu64 ", %p, %p (%lu)\n", cookie, position, buffer, numBytes, 278 numBytes != NULL ? *numBytes : 0); 279 return cookie->handler->Write(&cookie->cookie, position, buffer, numBytes); 280 } 281 282 283 static status_t 284 usb_hid_control(void *_cookie, uint32 op, void *buffer, size_t length) 285 { 286 device_cookie *cookie = (device_cookie *)_cookie; 287 288 TRACE("control(%p, %" B_PRIu32 ", %p, %" B_PRIuSIZE ")\n", cookie, op, 289 buffer, length); 290 return cookie->handler->Control(&cookie->cookie, op, buffer, length); 291 } 292 293 294 static status_t 295 usb_hid_close(void *_cookie) 296 { 297 device_cookie *cookie = (device_cookie *)_cookie; 298 299 TRACE("close(%p)\n", cookie); 300 return cookie->handler->Close(&cookie->cookie); 301 } 302 303 304 static status_t 305 usb_hid_free(void *_cookie) 306 { 307 device_cookie *cookie = (device_cookie *)_cookie; 308 TRACE("free(%p)\n", cookie); 309 310 mutex_lock(&sDriverLock); 311 312 HIDDevice *device = cookie->handler->Device(); 313 if (device->IsOpen()) { 314 // another handler of this device is still open so we can't free it 315 } else if (device->IsRemoved()) { 316 // the parent device is removed already and none of its handlers are 317 // open anymore so we can free it here 318 delete device; 319 } 320 321 mutex_unlock(&sDriverLock); 322 323 delete cookie; 324 return B_OK; 325 } 326 327 328 // #pragma mark - driver API 329 330 331 status_t 332 init_hardware() 333 { 334 TRACE("init_hardware() " __DATE__ " " __TIME__ "\n"); 335 return B_OK; 336 } 337 338 339 status_t 340 init_driver() 341 { 342 TRACE("init_driver() " __DATE__ " " __TIME__ "\n"); 343 if (get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule) != B_OK) 344 return B_ERROR; 345 346 gDeviceList = new(std::nothrow) DeviceList(); 347 if (gDeviceList == NULL) { 348 put_module(B_USB_MODULE_NAME); 349 return B_NO_MEMORY; 350 } 351 352 mutex_init(&sDriverLock, "usb hid driver lock"); 353 354 static usb_notify_hooks notifyHooks = { 355 &usb_hid_device_added, 356 &usb_hid_device_removed 357 }; 358 359 static usb_support_descriptor genericHIDSupportDescriptor = { 360 USB_INTERFACE_CLASS_HID, 0, 0, 0, 0 361 }; 362 363 int32 supportDescriptorCount = 1 + gQuirkyDeviceCount; 364 sSupportDescriptors 365 = new(std::nothrow) usb_support_descriptor[supportDescriptorCount]; 366 if (sSupportDescriptors != NULL) { 367 sSupportDescriptors[0] = genericHIDSupportDescriptor; 368 for (int32 i = 0; i < gQuirkyDeviceCount; i++) { 369 usb_support_descriptor &descriptor = sSupportDescriptors[i + 1]; 370 descriptor.dev_class = gQuirkyDevices[i].device_class; 371 descriptor.dev_subclass = gQuirkyDevices[i].device_subclass; 372 descriptor.dev_protocol = gQuirkyDevices[i].device_protocol; 373 descriptor.vendor = gQuirkyDevices[i].vendor_id; 374 descriptor.product = gQuirkyDevices[i].product_id; 375 } 376 377 gUSBModule->register_driver(DRIVER_NAME, sSupportDescriptors, 378 supportDescriptorCount, NULL); 379 } else { 380 // no memory for quirky devices, at least support proper HID 381 gUSBModule->register_driver(DRIVER_NAME, &genericHIDSupportDescriptor, 382 1, NULL); 383 } 384 385 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 386 TRACE("init_driver() OK\n"); 387 return B_OK; 388 } 389 390 391 void 392 uninit_driver() 393 { 394 TRACE("uninit_driver()\n"); 395 gUSBModule->uninstall_notify(DRIVER_NAME); 396 put_module(B_USB_MODULE_NAME); 397 delete[] sSupportDescriptors; 398 sSupportDescriptors = NULL; 399 delete gDeviceList; 400 gDeviceList = NULL; 401 mutex_destroy(&sDriverLock); 402 } 403 404 405 const char ** 406 publish_devices() 407 { 408 TRACE("publish_devices()\n"); 409 const char **publishList = gDeviceList->PublishDevices(); 410 411 int32 index = 0; 412 while (publishList[index] != NULL) { 413 TRACE("publishing %s\n", publishList[index]); 414 index++; 415 } 416 417 return publishList; 418 } 419 420 421 device_hooks * 422 find_device(const char *name) 423 { 424 static device_hooks hooks = { 425 usb_hid_open, 426 usb_hid_close, 427 usb_hid_free, 428 usb_hid_control, 429 usb_hid_read, 430 usb_hid_write, 431 NULL, /* select */ 432 NULL /* deselect */ 433 }; 434 435 TRACE("find_device(%s)\n", name); 436 if (gDeviceList->FindDevice(name) == NULL) { 437 TRACE_ALWAYS("didn't find device %s\n", name); 438 return NULL; 439 } 440 441 return &hooks; 442 } 443