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