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