Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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;
}