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