/** 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; }
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); }
/** 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; }
/** 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; }