Exemplo n.º 1
0
/** Count number of alternate settings of a interface.
 *
 * @param config_descr Full configuration descriptor.
 * @param config_descr_size Size of @p config_descr in bytes.
 * @param interface_no Interface number.
 * @return Number of alternate interfaces for @p interface_no interface.
 */
size_t usb_interface_count_alternates(const uint8_t *config_descr,
    size_t config_descr_size, uint8_t interface_no)
{
	assert(config_descr != NULL);
	assert(config_descr_size > 0);

	const usb_dp_parser_t dp_parser = {
		.nesting = usb_dp_standard_descriptor_nesting
	};
	const usb_dp_parser_data_t dp_data = {
		.data = config_descr,
		.size = config_descr_size,
		.arg = NULL
	};

	size_t alternate_count = 0;

	const void *iface_ptr =
	    usb_dp_get_nested_descriptor(&dp_parser, &dp_data, config_descr);
	while (iface_ptr != NULL) {
		const usb_standard_interface_descriptor_t *iface = iface_ptr;
		if (iface->descriptor_type == USB_DESCTYPE_INTERFACE
		    && iface->interface_number == interface_no) {
			++alternate_count;
		}
		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
		    config_descr, iface_ptr);
	}

	return alternate_count;
}
Exemplo n.º 2
0
static void browse_descriptor_tree_internal(usb_dp_parser_t *parser,
    usb_dp_parser_data_t *data, const uint8_t *root, size_t depth,
    dump_descriptor_in_tree_t callback, void *arg)
{
	if (root == NULL) {
		return;
	}
	callback(root, depth, arg);
	const uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
	do {
		browse_descriptor_tree_internal(parser, data, child, depth + 1,
		    callback, arg);
		child = usb_dp_get_sibling_descriptor(parser, data,
		    root, child);
	} while (child != NULL);
}
Exemplo n.º 3
0
/** Browser of the descriptor tree.
 *
 * @see usb_dp_walk_simple
 *
 * @param parser Descriptor parser.
 * @param data Data for descriptor parser.
 * @param root Pointer to current root of the tree.
 * @param depth Current nesting depth.
 * @param callback Callback for each found descriptor.
 * @param arg Custom (user) argument.
 */
static void usb_dp_browse_simple_internal(const usb_dp_parser_t *parser,
    const usb_dp_parser_data_t *data, const uint8_t *root, size_t depth,
    void (*callback)(const uint8_t *, size_t, void *), void *arg)
{
	if (root == NULL) {
		return;
	}
	callback(root, depth, arg);
	const uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
	do {
		usb_dp_browse_simple_internal(parser, data, child, depth + 1,
		    callback, arg);
		child = usb_dp_get_sibling_descriptor(parser, data,
		    root, child);
	} while (child != NULL);
}
Exemplo n.º 4
0
/** Skip all nested descriptors.
 *
 * @param parser Parser.
 * @param data Parser data.
 * @param parent Pointer to the beginning of parent descriptor.
 * @return Pointer to first non-child descriptor.
 * @retval NULL No next descriptor.
 * @retval NULL Invalid input.
 */
static const uint8_t *skip_nested_descriptors(const usb_dp_parser_t *parser,
    const usb_dp_parser_data_t *data, const uint8_t *parent)
{
	const uint8_t *child =
	    usb_dp_get_nested_descriptor(parser, data, parent);
	if (child == NULL) {
		return get_next_descriptor(data, parent);
	}
	const uint8_t *next_child =
	    skip_nested_descriptors(parser, data, child);
	while (is_nested_descriptor(parser, data, next_child, parent)) {
		next_child = skip_nested_descriptors(parser, data, next_child);
	}

	return next_child;
}
Exemplo n.º 5
0
/** Process endpoint descriptor.
 *
 * @param mapping Endpoint mapping list.
 * @param mapping_count Number of endpoint mappings in @p mapping.
 * @param interface Interface descriptor under which belongs the @p endpoint.
 * @param endpoint Endpoint descriptor.
 * @return Error code.
 */
static int process_endpoint(
    usb_endpoint_mapping_t *mapping, size_t mapping_count,
    usb_standard_interface_descriptor_t *interface,
    usb_standard_endpoint_descriptor_t *endpoint_desc,
    usb_dev_session_t *bus_session)
{

	/*
	 * Get endpoint characteristics.
	 */

	/* Actual endpoint number is in bits 0..3 */
	const usb_endpoint_t ep_no = endpoint_desc->endpoint_address & 0x0F;

	const usb_endpoint_description_t description = {
		/* Endpoint direction is set by bit 7 */
		.direction = (endpoint_desc->endpoint_address & 128)
		    ? USB_DIRECTION_IN : USB_DIRECTION_OUT,
		/* Transfer type is in bits 0..2 and
		 * the enum values corresponds 1:1 */
		.transfer_type = endpoint_desc->attributes & 3,

		/* Get interface characteristics. */
		.interface_class = interface->interface_class,
		.interface_subclass = interface->interface_subclass,
		.interface_protocol = interface->interface_protocol,
	};

	/*
	 * Find the most fitting mapping and initialize the pipe.
	 */
	usb_endpoint_mapping_t *ep_mapping = find_endpoint_mapping(mapping,
	    mapping_count, &description,
	    interface->interface_number, interface->alternate_setting);
	if (ep_mapping == NULL) {
		return ENOENT;
	}

	if (ep_mapping->present) {
		return EEXIST;
	}

	int rc = usb_pipe_initialize(&ep_mapping->pipe,
	    ep_no, description.transfer_type,
	    ED_MPS_PACKET_SIZE_GET(
	        uint16_usb2host(endpoint_desc->max_packet_size)),
	    description.direction,
	    ED_MPS_TRANS_OPPORTUNITIES_GET(
	        uint16_usb2host(endpoint_desc->max_packet_size)), bus_session);
	if (rc != EOK) {
		return rc;
	}

	ep_mapping->present = true;
	ep_mapping->descriptor = endpoint_desc;
	ep_mapping->interface = interface;

	return EOK;
}

/** Process whole USB interface.
 *
 * @param mapping Endpoint mapping list.
 * @param mapping_count Number of endpoint mappings in @p mapping.
 * @param parser Descriptor parser.
 * @param parser_data Descriptor parser data.
 * @param interface_descriptor Interface descriptor.
 * @return Error code.
 */
static int process_interface(
    usb_endpoint_mapping_t *mapping, size_t mapping_count,
    const usb_dp_parser_t *parser, const usb_dp_parser_data_t *parser_data,
    const uint8_t *interface_descriptor, usb_dev_session_t *bus_session)
{
	const uint8_t *descriptor = usb_dp_get_nested_descriptor(parser,
	    parser_data, interface_descriptor);

	if (descriptor == NULL) {
		return ENOENT;
	}

	do {
		if (is_endpoint_descriptor(descriptor)) {
			(void) process_endpoint(mapping, mapping_count,
			    (usb_standard_interface_descriptor_t *)
			        interface_descriptor,
			    (usb_standard_endpoint_descriptor_t *)
			        descriptor,
			    bus_session);
		}

		descriptor = usb_dp_get_sibling_descriptor(parser, parser_data,
		    interface_descriptor, descriptor);
	} while (descriptor != NULL);

	return EOK;
}

/** Initialize endpoint pipes from configuration descriptor.
 *
 * The mapping array is expected to conform to following rules:
 * - @c pipe must be uninitialized pipe
 * - @c description must point to prepared endpoint description
 * - @c descriptor does not need to be initialized (will be overwritten)
 * - @c interface does not need to be initialized (will be overwritten)
 * - @c present does not need to be initialized (will be overwritten)
 *
 * After processing the configuration descriptor, the mapping is updated
 * in the following fashion:
 * - @c present will be set to @c true when the endpoint was found in the
 *   configuration
 * - @c descriptor will point inside the configuration descriptor to endpoint
 *   corresponding to given description (or NULL for not found descriptor)
 * - @c interface will point inside the configuration descriptor to interface
 *   descriptor the endpoint @c descriptor belongs to (or NULL for not found
 *   descriptor)
 * - @c pipe will be initialized when found, otherwise left untouched
 * - @c description will be untouched under all circumstances
 *
 * @param mapping Endpoint mapping list.
 * @param mapping_count Number of endpoint mappings in @p mapping.
 * @param configuration_descriptor Full configuration descriptor (is expected
 *	to be in USB endianness: i.e. as-is after being retrieved from
 *	the device).
 * @param configuration_descriptor_size Size of @p configuration_descriptor
 *	in bytes.
 * @param connection Connection backing the endpoint pipes.
 * @return Error code.
 */
int usb_pipe_initialize_from_configuration(
    usb_endpoint_mapping_t *mapping, size_t mapping_count,
    const uint8_t *config_descriptor, size_t config_descriptor_size,
    usb_dev_session_t *bus_session)
{
	if (config_descriptor == NULL)
		return EBADMEM;
	
	if (config_descriptor_size <
	    sizeof(usb_standard_configuration_descriptor_t)) {
		return ERANGE;
	}

	/* Go through the mapping and set all endpoints to not present. */
	for (size_t i = 0; i < mapping_count; i++) {
		mapping[i].present = false;
		mapping[i].descriptor = NULL;
		mapping[i].interface = NULL;
	}

	/* Prepare the descriptor parser. */
	const usb_dp_parser_t dp_parser = {
		.nesting = descriptor_nesting
	};
	const usb_dp_parser_data_t dp_data = {
		.data = config_descriptor,
		.size = config_descriptor_size,
	};

	/*
	 * Iterate through all interfaces.
	 */
	const uint8_t *interface = usb_dp_get_nested_descriptor(&dp_parser,
	    &dp_data, config_descriptor);
	if (interface == NULL) {
		return ENOENT;
	}
	do {
		(void) process_interface(mapping, mapping_count,
		    &dp_parser, &dp_data, interface, bus_session);
		interface = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
		    config_descriptor, interface);
	} while (interface != NULL);

	return EOK;
}

/** Probe default control pipe for max packet size.
 *
 * The function tries to get the correct value of max packet size several
 * time before giving up.
 *
 * The session on the pipe shall not be started.
 *
 * @param pipe Default control pipe.
 * @return Error code.
 */
int usb_pipe_probe_default_control(usb_pipe_t *pipe)
{
	assert(pipe);
	static_assert(DEV_DESCR_MAX_PACKET_SIZE_OFFSET < CTRL_PIPE_MIN_PACKET_SIZE);

	if ((pipe->direction != USB_DIRECTION_BOTH) ||
	    (pipe->transfer_type != USB_TRANSFER_CONTROL) ||
	    (pipe->endpoint_no != 0)) {
		return EINVAL;
	}

	uint8_t dev_descr_start[CTRL_PIPE_MIN_PACKET_SIZE];
	size_t transferred_size;
	int rc;
	for (size_t attempt_var = 0; attempt_var < 3; ++attempt_var) {
		rc = usb_request_get_descriptor(pipe, USB_REQUEST_TYPE_STANDARD,
		    USB_REQUEST_RECIPIENT_DEVICE, USB_DESCTYPE_DEVICE,
		    0, 0, dev_descr_start, CTRL_PIPE_MIN_PACKET_SIZE,
		    &transferred_size);
		if (rc == EOK) {
			if (transferred_size != CTRL_PIPE_MIN_PACKET_SIZE) {
				rc = ELIMIT;
				continue;
			}
			break;
		}
	}
	if (rc != EOK) {
		return rc;
	}

	pipe->max_packet_size
	    = dev_descr_start[DEV_DESCR_MAX_PACKET_SIZE_OFFSET];

	return EOK;
}
Exemplo n.º 6
0
/** Initialize alternate interface representation structure.
 *
 * @param[in] alternates Pointer to allocated structure.
 * @param[in] config_descr Configuration descriptor.
 * @param[in] config_descr_size Size of configuration descriptor.
 * @param[in] interface_number Interface number.
 * @return Error code.
 */
int usb_alternate_interfaces_init(usb_alternate_interfaces_t *alternates,
    const uint8_t *config_descr, size_t config_descr_size, int interface_number)
{
	assert(alternates != NULL);
	assert(config_descr != NULL);
	assert(config_descr_size > 0);

	alternates->alternatives = NULL;
	alternates->alternative_count = 0;
	alternates->current = 0;

	/* No interfaces. */
	if (interface_number < 0) {
		return EOK;
	}

	alternates->alternative_count
	    = usb_interface_count_alternates(config_descr, config_descr_size,
	        interface_number);

	if (alternates->alternative_count == 0) {
		return ENOENT;
	}

	alternates->alternatives = calloc(alternates->alternative_count,
	    sizeof(usb_alternate_interface_descriptors_t));
	if (alternates->alternatives == NULL) {
		return ENOMEM;
	}

	const usb_dp_parser_t dp_parser = {
		.nesting = usb_dp_standard_descriptor_nesting
	};
	const usb_dp_parser_data_t dp_data = {
		.data = config_descr,
		.size = config_descr_size,
		.arg = NULL
	};

	usb_alternate_interface_descriptors_t *iterator
	    = &alternates->alternatives[0];

	const usb_alternate_interface_descriptors_t *end
	    = &alternates->alternatives[alternates->alternative_count];

	const void *iface_ptr =
	    usb_dp_get_nested_descriptor(&dp_parser, &dp_data, dp_data.data);

	while (iface_ptr != NULL && iterator < end) {
		const usb_standard_interface_descriptor_t *iface = iface_ptr;

		if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE)
		    || (iface->interface_number != interface_number)) {
			/* This is not a valid alternate interface descriptor
			 * for interface with number == interface_number. */
			iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser,
			    &dp_data, dp_data.data, iface_ptr);
			continue;
		}

		iterator->interface = iface;
		iterator->nested_descriptors = iface_ptr + sizeof(*iface);

		/* Find next interface to count size of nested descriptors. */
		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
		    dp_data.data, iface_ptr);

		const uint8_t *next = (iface_ptr == NULL) ?
		    dp_data.data + dp_data.size : iface_ptr;

		iterator->nested_descriptors_size
		    = next - iterator->nested_descriptors;

		++iterator;
	}

	return EOK;
}