Ejemplo n.º 1
0
/** Create DDF match ids from USB device descriptor.
 *
 * @param matches List of match ids to extend.
 * @param device_descriptor Device descriptor returned by given device.
 * @return Error code.
 */
int usb_device_create_match_ids_from_device_descriptor(
    const usb_standard_device_descriptor_t *device_descriptor,
    match_id_list_t *matches)
{
	/*
	 * Unless the vendor id is 0, the pair idVendor-idProduct
	 * quite uniquely describes the device.
	 */
	if (device_descriptor->vendor_id != 0) {
		/* First, with release number. */
		ADD_MATCHID_OR_RETURN(matches, 100,
		    "usb&vendor=0x%04x&product=0x%04x&release=" BCD_FMT,
		    (int) device_descriptor->vendor_id,
		    (int) device_descriptor->product_id,
		    BCD_ARGS(device_descriptor->device_version));
		
		/* Next, without release number. */
		ADD_MATCHID_OR_RETURN(matches, 90,
		    "usb&vendor=0x%04x&product=0x%04x",
		    (int) device_descriptor->vendor_id,
		    (int) device_descriptor->product_id);
	}

	/* Class match id */
	ADD_MATCHID_OR_RETURN(matches, 50, "usb&class=%s",
	    usb_str_class(device_descriptor->device_class));
	
	/* As a last resort, try fallback driver. */
	ADD_MATCHID_OR_RETURN(matches, 10, "usb&fallback");

	return EOK;
}
Ejemplo n.º 2
0
static void usb_dump_descriptor_interface(FILE *output,
    const char *line_prefix, const char *line_suffix,
    const uint8_t *descriptor, size_t descriptor_length)
{
	usb_standard_interface_descriptor_t *d
	    = (usb_standard_interface_descriptor_t *) descriptor;
	if (descriptor_length < sizeof(*d)) {
		return;
	}

	PRINTLINE("bLength = %d", d->length);
	PRINTLINE("bDescriptorType = 0x%02x", d->descriptor_type);
	PRINTLINE("bInterfaceNumber = %d", d->interface_number);
	PRINTLINE("bAlternateSetting = %d", d->alternate_setting);
	PRINTLINE("bNumEndpoints = %d", d->endpoint_count);
	PRINTLINE("bInterfaceClass = %s", d->interface_class == 0
	    ? "reserved (0)" : usb_str_class(d->interface_class));
	PRINTLINE("bInterfaceSubClass = %d", d->interface_subclass);
	PRINTLINE("bInterfaceProtocol = %d", d->interface_protocol);
	PRINTLINE("iInterface = %d", d->str_interface);
}
Ejemplo n.º 3
0
/** Polling fibril.
 *
 * @param arg Pointer to polling_data_t.
 * @return Always EOK.
 */
static int polling_fibril(void *arg)
{
	assert(arg);
	const polling_data_t *data = arg;
	/* Helper to reduce typing. */
	const usb_device_auto_polling_t *params = &data->auto_polling;

	usb_pipe_t *pipe
	    = &data->dev->pipes[data->pipe_index].pipe;

	if (params->debug > 0) {
		const usb_endpoint_mapping_t *mapping
		    = &data->dev->pipes[data->pipe_index];
		usb_log_debug("Poll%p: started polling of `%s' - " \
		    "interface %d (%s,%d,%d), %zuB/%zu.\n",
		    data, data->dev->ddf_dev->name,
		    (int) mapping->interface->interface_number,
		    usb_str_class(mapping->interface->interface_class),
		    (int) mapping->interface->interface_subclass,
		    (int) mapping->interface->interface_protocol,
		    data->request_size, pipe->max_packet_size);
	}

	usb_pipe_start_long_transfer(pipe);
	size_t failed_attempts = 0;
	while (failed_attempts <= params->max_failures) {
		size_t actual_size;
		const int rc = usb_pipe_read(pipe, data->buffer,
		    data->request_size, &actual_size);

		if (params->debug > 1) {
			if (rc == EOK) {
				usb_log_debug(
				    "Poll%p: received: '%s' (%zuB).\n",
				    data,
				    usb_debug_str_buffer(data->buffer,
				        actual_size, 16),
				    actual_size);
			} else {
				usb_log_debug(
				    "Poll%p: polling failed: %s.\n",
				    data, str_error(rc));
			}
		}

		/* If the pipe stalled, we can try to reset the stall. */
		if ((rc == ESTALL) && (params->auto_clear_halt)) {
			/*
			 * We ignore error here as this is usually a futile
			 * attempt anyway.
			 */
			usb_request_clear_endpoint_halt(
			    &data->dev->ctrl_pipe, pipe->endpoint_no);
		}

		if (rc != EOK) {
			++failed_attempts;
			const bool cont = (params->on_error == NULL) ? true :
			    params->on_error(data->dev, rc, params->arg);
			if (!cont) {
				failed_attempts = params->max_failures;
			}
			continue;
		}

		/* We have the data, execute the callback now. */
		assert(params->on_data);
		const bool carry_on = params->on_data(
		    data->dev, data->buffer, actual_size, params->arg);

		if (!carry_on) {
			/* This is user requested abort, erases failures. */
			failed_attempts = 0;
			break;
		}

		/* Reset as something might be only a temporary problem. */
		failed_attempts = 0;

		/* Take a rest before next request. */
		async_usleep(params->delay);
	}

	usb_pipe_end_long_transfer(pipe);

	const bool failed = failed_attempts > 0;

	if (params->on_polling_end != NULL) {
		params->on_polling_end(data->dev, failed, params->arg);
	}

	if (params->debug > 0) {
		if (failed) {
			usb_log_error("Polling of device `%s' terminated: "
			    "recurring failures.\n", data->dev->ddf_dev->name);
		} else {
			usb_log_debug("Polling of device `%s' terminated: "
			    "driver request.\n", data->dev->ddf_dev->name);
		}
	}

	/* Free the allocated memory. */
	free(data->buffer);
	free(data);

	return EOK;
}
Ejemplo n.º 4
0
/** Create device match ids based on its interface.
 *
 * @param[in] desc_device Device descriptor.
 * @param[in] desc_interface Interface descriptor.
 * @param[out] matches Initialized list of match ids.
 * @return Error code (the two mentioned are not the only ones).
 * @retval EINVAL Invalid input parameters (expects non NULL pointers).
 * @retval ENOENT Device class is not "use interface".
 */
int usb_device_create_match_ids_from_interface(
    const usb_standard_device_descriptor_t *desc_device,
    const usb_standard_interface_descriptor_t *desc_interface,
    match_id_list_t *matches)
{
	if (desc_interface == NULL || matches == NULL) {
		return EINVAL;
	}

	if (desc_interface->interface_class == USB_CLASS_USE_INTERFACE) {
		return ENOENT;
	}

	const char *classname = usb_str_class(desc_interface->interface_class);
	assert(classname != NULL);

#define IFACE_PROTOCOL_FMT "interface&class=%s&subclass=0x%02x&protocol=0x%02x"
#define IFACE_PROTOCOL_ARGS classname, desc_interface->interface_subclass, \
    desc_interface->interface_protocol

#define IFACE_SUBCLASS_FMT "interface&class=%s&subclass=0x%02x"
#define IFACE_SUBCLASS_ARGS classname, desc_interface->interface_subclass

#define IFACE_CLASS_FMT "interface&class=%s"
#define IFACE_CLASS_ARGS classname

#define VENDOR_RELEASE_FMT "vendor=0x%04x&product=0x%04x&release=" BCD_FMT
#define VENDOR_RELEASE_ARGS desc_device->vendor_id, desc_device->product_id, \
    BCD_ARGS(desc_device->device_version)

#define VENDOR_PRODUCT_FMT "vendor=0x%04x&product=0x%04x"
#define VENDOR_PRODUCT_ARGS desc_device->vendor_id, desc_device->product_id

#define VENDOR_ONLY_FMT "vendor=0x%04x"
#define VENDOR_ONLY_ARGS desc_device->vendor_id

	/*
	 * If the vendor is specified, create match ids with vendor with
	 * higher score.
	 * Then the same ones without the vendor part.
	 */
	if ((desc_device != NULL) && (desc_device->vendor_id != 0)) {
		/* First, interface matches with device release number. */
		ADD_MATCHID_OR_RETURN(matches, 250,
		    "usb&" VENDOR_RELEASE_FMT "&" IFACE_PROTOCOL_FMT,
		    VENDOR_RELEASE_ARGS, IFACE_PROTOCOL_ARGS);
		ADD_MATCHID_OR_RETURN(matches, 240,
		    "usb&" VENDOR_RELEASE_FMT "&" IFACE_SUBCLASS_FMT,
		    VENDOR_RELEASE_ARGS, IFACE_SUBCLASS_ARGS);
		ADD_MATCHID_OR_RETURN(matches, 230,
		    "usb&" VENDOR_RELEASE_FMT "&" IFACE_CLASS_FMT,
		    VENDOR_RELEASE_ARGS, IFACE_CLASS_ARGS);

		/* Next, interface matches without release number. */
		ADD_MATCHID_OR_RETURN(matches, 220,
		    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_PROTOCOL_FMT,
		    VENDOR_PRODUCT_ARGS, IFACE_PROTOCOL_ARGS);
		ADD_MATCHID_OR_RETURN(matches, 210,
		    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_SUBCLASS_FMT,
		    VENDOR_PRODUCT_ARGS, IFACE_SUBCLASS_ARGS);
		ADD_MATCHID_OR_RETURN(matches, 200,
		    "usb&" VENDOR_PRODUCT_FMT "&" IFACE_CLASS_FMT,
		    VENDOR_PRODUCT_ARGS, IFACE_CLASS_ARGS);

		/* Finally, interface matches with only vendor. */
		ADD_MATCHID_OR_RETURN(matches, 190,
		    "usb&" VENDOR_ONLY_FMT "&" IFACE_PROTOCOL_FMT,
		    VENDOR_ONLY_ARGS, IFACE_PROTOCOL_ARGS);
		ADD_MATCHID_OR_RETURN(matches, 180,
		    "usb&" VENDOR_ONLY_FMT "&" IFACE_SUBCLASS_FMT,
		    VENDOR_ONLY_ARGS, IFACE_SUBCLASS_ARGS);
		ADD_MATCHID_OR_RETURN(matches, 170,
		    "usb&" VENDOR_ONLY_FMT "&" IFACE_CLASS_FMT,
		    VENDOR_ONLY_ARGS, IFACE_CLASS_ARGS);
	}

	/* Now, the same but without any vendor specification. */
	ADD_MATCHID_OR_RETURN(matches, 160,
	    "usb&" IFACE_PROTOCOL_FMT,
	    IFACE_PROTOCOL_ARGS);
	ADD_MATCHID_OR_RETURN(matches, 150,
	    "usb&" IFACE_SUBCLASS_FMT,
	    IFACE_SUBCLASS_ARGS);
	ADD_MATCHID_OR_RETURN(matches, 140,
	    "usb&" IFACE_CLASS_FMT,
	    IFACE_CLASS_ARGS);

#undef IFACE_PROTOCOL_FMT
#undef IFACE_PROTOCOL_ARGS
#undef IFACE_SUBCLASS_FMT
#undef IFACE_SUBCLASS_ARGS
#undef IFACE_CLASS_FMT
#undef IFACE_CLASS_ARGS
#undef VENDOR_RELEASE_FMT
#undef VENDOR_RELEASE_ARGS
#undef VENDOR_PRODUCT_FMT
#undef VENDOR_PRODUCT_ARGS
#undef VENDOR_ONLY_FMT
#undef VENDOR_ONLY_ARGS

	/* As a last resort, try fallback driver. */
	ADD_MATCHID_OR_RETURN(matches, 10, "usb&interface&fallback");

	return EOK;
}