static status_t usb_hid_free(void *cookie) { TRACE("free(%p)\n", cookie); mutex_lock(&sDriverLock); HIDDevice *device = ((ProtocolHandler *)cookie)->Device(); if (device->IsOpen()) { // another handler of this device is still open so we can't free it } else if (device->IsRemoved()) { // the parent device is removed already and none of its handlers are // open anymore so we can free it here for (uint32 i = 0;; i++) { ProtocolHandler *handler = device->ProtocolHandlerAt(i); if (handler == NULL) break; gDeviceList->RemoveDevice(NULL, handler); } delete device; } mutex_unlock(&sDriverLock); return B_OK; }
status_t usb_hid_device_removed(void *cookie) { mutex_lock(&sDriverLock); int32 parentCookie = (int32)cookie; TRACE("device_removed(%ld)\n", parentCookie); for (int32 i = 0; i < gDeviceList->CountDevices(); i++) { ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->DeviceAt(i); if (!handler) continue; HIDDevice *device = handler->Device(); if (device->ParentCookie() != parentCookie) continue; // this handler's device belongs to the one removed if (device->IsOpen()) { // the device and it's handlers will be deleted in the free hook device->Removed(); break; } // remove all the handlers for (uint32 i = 0;; i++) { handler = device->ProtocolHandlerAt(i); if (handler == NULL) break; gDeviceList->RemoveDevice(NULL, handler); } delete device; break; } mutex_unlock(&sDriverLock); return B_OK; }
status_t usb_hid_device_added(usb_device device, void **cookie) { TRACE("device_added()\n"); const usb_device_descriptor *deviceDescriptor = gUSBModule->get_device_descriptor(device); TRACE("vendor id: 0x%04x; product id: 0x%04x\n", deviceDescriptor->vendor_id, deviceDescriptor->product_id); // wacom devices are handled by the dedicated wacom driver if (deviceDescriptor->vendor_id == USB_VENDOR_WACOM) return B_ERROR; const usb_configuration_info *config = gUSBModule->get_nth_configuration(device, USB_DEFAULT_CONFIGURATION); if (config == NULL) { TRACE_ALWAYS("cannot get default configuration\n"); return B_ERROR; } // ensure default configuration is set status_t result = gUSBModule->set_configuration(device, config); if (result != B_OK) { TRACE_ALWAYS("set_configuration() failed 0x%08lx\n", result); return result; } // refresh config config = gUSBModule->get_configuration(device); if (config == NULL) { TRACE_ALWAYS("cannot get current configuration\n"); return B_ERROR; } bool devicesFound = false; int32 parentCookie = atomic_add(&sParentCookie, 1); for (size_t i = 0; i < config->interface_count; i++) { const usb_interface_info *interface = config->interface[i].active; uint8 interfaceClass = interface->descr->interface_class; TRACE("interface %lu: class: %u; subclass: %u; protocol: %u\n", i, interfaceClass, interface->descr->interface_subclass, interface->descr->interface_protocol); if (interfaceClass == USB_INTERFACE_CLASS_HID) { mutex_lock(&sDriverLock); HIDDevice *hidDevice = new(std::nothrow) HIDDevice(device, config, i); if (hidDevice != NULL && hidDevice->InitCheck() == B_OK) { hidDevice->SetParentCookie(parentCookie); for (uint32 i = 0;; i++) { ProtocolHandler *handler = hidDevice->ProtocolHandlerAt(i); if (handler == NULL) break; // As devices can be un- and replugged at will, we cannot // simply rely on a device count. If there is just one // keyboard, this does not mean that it uses the 0 name. // There might have been two keyboards and the one using 0 // might have been unplugged. So we just generate names // until we find one that is not currently in use. int32 index = 0; char pathBuffer[128]; const char *basePath = handler->BasePath(); while (true) { sprintf(pathBuffer, "%s%ld", basePath, index++); if (gDeviceList->FindDevice(pathBuffer) == NULL) { // this name is still free, use it handler->SetPublishPath(strdup(pathBuffer)); break; } } gDeviceList->AddDevice(handler->PublishPath(), handler); devicesFound = true; } } else delete hidDevice; mutex_unlock(&sDriverLock); } } if (!devicesFound) return B_ERROR; *cookie = (void *)parentCookie; return B_OK; }
status_t usb_hid_device_added(usb_device device, void **cookie) { TRACE("device_added()\n"); const usb_device_descriptor *deviceDescriptor = gUSBModule->get_device_descriptor(device); TRACE("vendor id: 0x%04x; product id: 0x%04x\n", deviceDescriptor->vendor_id, deviceDescriptor->product_id); for (int32 i = 0; i < gBlackListedDeviceCount; i++) { usb_support_descriptor &entry = gBlackListedDevices[i]; if ((entry.vendor != 0 && deviceDescriptor->vendor_id != entry.vendor) || (entry.product != 0 && deviceDescriptor->product_id != entry.product)) { continue; } return B_ERROR; } const usb_configuration_info *config = gUSBModule->get_nth_configuration(device, USB_DEFAULT_CONFIGURATION); if (config == NULL) { TRACE_ALWAYS("cannot get default configuration\n"); return B_ERROR; } // ensure default configuration is set status_t result = gUSBModule->set_configuration(device, config); if (result != B_OK) { TRACE_ALWAYS("set_configuration() failed 0x%08" B_PRIx32 "\n", result); return result; } // refresh config config = gUSBModule->get_configuration(device); if (config == NULL) { TRACE_ALWAYS("cannot get current configuration\n"); return B_ERROR; } bool devicesFound = false; int32 parentCookie = atomic_add(&sParentCookie, 1); for (size_t i = 0; i < config->interface_count; i++) { const usb_interface_info *interface = config->interface[i].active; uint8 interfaceClass = interface->descr->interface_class; TRACE("interface %" B_PRIuSIZE ": class: %u; subclass: %u; protocol: " "%u\n", i, interfaceClass, interface->descr->interface_subclass, interface->descr->interface_protocol); // check for quirky devices first int32 quirkyIndex = -1; for (int32 j = 0; j < gQuirkyDeviceCount; j++) { usb_hid_quirky_device &quirky = gQuirkyDevices[j]; if ((quirky.vendor_id != 0 && deviceDescriptor->vendor_id != quirky.vendor_id) || (quirky.product_id != 0 && deviceDescriptor->product_id != quirky.product_id) || (quirky.device_class != 0 && interfaceClass != quirky.device_class) || (quirky.device_subclass != 0 && interface->descr->interface_subclass != quirky.device_subclass) || (quirky.device_protocol != 0 && interface->descr->interface_protocol != quirky.device_protocol)) { continue; } quirkyIndex = j; break; } if (quirkyIndex >= 0 || interfaceClass == USB_INTERFACE_CLASS_HID) { mutex_lock(&sDriverLock); HIDDevice *hidDevice = new(std::nothrow) HIDDevice(device, config, i, quirkyIndex); if (hidDevice != NULL && hidDevice->InitCheck() == B_OK) { hidDevice->SetParentCookie(parentCookie); for (uint32 i = 0;; i++) { ProtocolHandler *handler = hidDevice->ProtocolHandlerAt(i); if (handler == NULL) break; // As devices can be un- and replugged at will, we cannot // simply rely on a device count. If there is just one // keyboard, this does not mean that it uses the 0 name. // There might have been two keyboards and the one using 0 // might have been unplugged. So we just generate names // until we find one that is not currently in use. int32 index = 0; char pathBuffer[128]; const char *basePath = handler->BasePath(); while (true) { sprintf(pathBuffer, "%s%" B_PRId32, basePath, index++); if (gDeviceList->FindDevice(pathBuffer) == NULL) { // this name is still free, use it handler->SetPublishPath(strdup(pathBuffer)); break; } } gDeviceList->AddDevice(handler->PublishPath(), handler); devicesFound = true; } } else delete hidDevice; mutex_unlock(&sDriverLock); } } if (!devicesFound) return B_ERROR; *cookie = (void *)(addr_t)parentCookie; return B_OK; }