mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-29 13:48:21 +00:00
kernel: initial xhci and usb implementation
This commit is contained in:
@@ -0,0 +1,477 @@
|
||||
#include <kernel/usb.h>
|
||||
#include <logging.h>
|
||||
#include <kernel/alloc.h>
|
||||
|
||||
// TODO support using other configurations (for simplicity, we will just pick the first one for now)
|
||||
|
||||
extern usb_class_driver_t *usb_class_drivers;
|
||||
extern usb_class_driver_t *usb_class_drivers_end;
|
||||
|
||||
static void endpoint_configured(usb_device_t *dev, void *ctx, usb_status_t status, size_t transferred);
|
||||
|
||||
static bool endpoint_desc_valid(usb_device_t *dev, usb_endpoint_desc_t *desc) {
|
||||
uint8_t ep_num = desc->bEndpointAddress & USB_ENDPOINT_ADDRESS_NUM_MASK;
|
||||
uint8_t ep_type = desc->bmAttributes & USB_ENDPOINT_ATTRIB_TYPE_MASK;
|
||||
uint16_t max_packet_size = usb_endpoint_max_packet_size(desc);
|
||||
uint8_t high_speed_transactions = (desc->wMaxPacketSize >> 11) & 0x3;
|
||||
|
||||
if (ep_num == 0)
|
||||
return false;
|
||||
|
||||
if (max_packet_size == 0)
|
||||
return false;
|
||||
|
||||
if (ep_type == USB_ENDPOINT_ATTRIB_TYPE_BULK) {
|
||||
if (dev->speed == USB_SPEED_LOW)
|
||||
return false;
|
||||
if (dev->speed == USB_SPEED_HIGH && high_speed_transactions != 0)
|
||||
return false;
|
||||
} else if (ep_type == USB_ENDPOINT_ATTRIB_TYPE_INTR) {
|
||||
if (desc->bInterval == 0)
|
||||
return false;
|
||||
if ((dev->speed == USB_SPEED_HIGH ||
|
||||
dev->speed == USB_SPEED_SUPER ||
|
||||
dev->speed == USB_SPEED_SUPER_PLUS) &&
|
||||
desc->bInterval > 16)
|
||||
return false;
|
||||
if (dev->speed == USB_SPEED_HIGH && high_speed_transactions == 3)
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool endpoint_requires_ss_companion(usb_device_t *dev, usb_endpoint_t *endpoint) {
|
||||
if (dev->speed != USB_SPEED_SUPER && dev->speed != USB_SPEED_SUPER_PLUS)
|
||||
return false;
|
||||
|
||||
return (endpoint->desc->bmAttributes & USB_ENDPOINT_ATTRIB_TYPE_MASK) != USB_ENDPOINT_ATTRIB_TYPE_CONTROL;
|
||||
}
|
||||
|
||||
static bool device_port_stale(usb_device_t *dev) {
|
||||
return dev->hub->ports[dev->port_number].generation != dev->port_generation;
|
||||
}
|
||||
|
||||
static int attach_interface_to_driver(usb_device_t *device, usb_interface_t *interface) {
|
||||
int best_score = 0;
|
||||
usb_class_driver_t *best_driver = NULL;
|
||||
|
||||
for (usb_class_driver_t **it = &usb_class_drivers; it < &usb_class_drivers_end; ++it) {
|
||||
usb_class_driver_t *driver = *it;
|
||||
int score = driver->probe(device, interface);
|
||||
|
||||
if (score > best_score) {
|
||||
best_score = score;
|
||||
best_driver = driver;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_driver == NULL) {
|
||||
printf("usb: no driver found for interface %u\n", interface->desc->bInterfaceNumber);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (best_driver->attach(device, interface)) {
|
||||
printf("usb: attaching %s port %u addr %u interface %u to driver '%s' failed\n",
|
||||
device->hub->name,
|
||||
device->port_number + 1,
|
||||
device->address,
|
||||
interface->desc->bInterfaceNumber,
|
||||
best_driver->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
interface->driver = best_driver;
|
||||
printf("usb: %s port %u addr %u device %04x:%04x interface %u attached to driver '%s' (score: %d)\n",
|
||||
device->hub->name,
|
||||
device->port_number + 1,
|
||||
device->address,
|
||||
device->desc.idVendor,
|
||||
device->desc.idProduct,
|
||||
interface->desc->bInterfaceNumber,
|
||||
best_driver->name,
|
||||
best_score);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// device plug ininitialization is complete, pass control for each interface to a driver
|
||||
static int attach_to_drivers(usb_device_t *device) {
|
||||
if (device_port_stale(device))
|
||||
return ENODEV;
|
||||
|
||||
device->hub->ports[device->port_number].device = device;
|
||||
|
||||
for (int i = 0; i < device->config_desc->bNumInterfaces; ++i) {
|
||||
usb_interface_t *interface = &device->interfaces[i];
|
||||
|
||||
if (interface->desc == NULL)
|
||||
return EINVAL;
|
||||
|
||||
if (attach_interface_to_driver(device, interface))
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int configure_next_endpoint(usb_device_t *dev, uint8_t interface_idx, uint8_t endpoint_idx) {
|
||||
if (device_port_stale(dev))
|
||||
return ENODEV;
|
||||
|
||||
for (; interface_idx < dev->config_desc->bNumInterfaces; interface_idx++, endpoint_idx = 0) {
|
||||
usb_interface_t *interface = &dev->interfaces[interface_idx];
|
||||
if (interface->desc == NULL)
|
||||
return EINVAL;
|
||||
|
||||
if (endpoint_idx < interface->desc->bNumEndpoints) {
|
||||
usb_endpoint_t *endpoint = &interface->endpoints[endpoint_idx];
|
||||
if (endpoint->desc == NULL)
|
||||
return EINVAL;
|
||||
|
||||
uintptr_t id = endpoint_idx | (interface_idx << 8);
|
||||
return dev->hub->ctrl->ops->configure_ep(dev->hub->ctrl, dev, endpoint, endpoint_configured, (void *)id);
|
||||
}
|
||||
}
|
||||
|
||||
return attach_to_drivers(dev);
|
||||
}
|
||||
|
||||
static void post_config_cleanup(usb_device_t *dev) {
|
||||
for (int i = 0; i < dev->config_desc->bNumInterfaces; ++i) {
|
||||
if (dev->interfaces[i].endpoints)
|
||||
free(dev->interfaces[i].endpoints);
|
||||
}
|
||||
|
||||
free(dev->interfaces);
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
}
|
||||
|
||||
// configure all the endpoints and attach to driver if the last endpoint was configured
|
||||
static void endpoint_configured(usb_device_t *dev, void *ctx, usb_status_t status, size_t transferred) {
|
||||
if (status != USB_STATUS_SUCCESS)
|
||||
goto error;
|
||||
|
||||
if (device_port_stale(dev))
|
||||
goto error;
|
||||
|
||||
uintptr_t id = (uintptr_t)ctx;
|
||||
uint8_t endpoint_idx = (id & 0xff) + 1;
|
||||
uint8_t interface_idx = (id >> 8) & 0xff;
|
||||
|
||||
if (configure_next_endpoint(dev, interface_idx, endpoint_idx) == 0)
|
||||
return; // success, wait for endpoint to be configured.
|
||||
|
||||
error:
|
||||
printf("usb: endpoint config failed\n");
|
||||
post_config_cleanup(dev);
|
||||
}
|
||||
|
||||
// allocate and populate interface and endpoint datastructures, then start configuring endpoints
|
||||
static void set_configuration_done(usb_device_t *dev, void *, usb_status_t status, size_t transferred) {
|
||||
if (status != USB_STATUS_SUCCESS) {
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
printf("usb: failed to set configuration\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (device_port_stale(dev)) {
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->interfaces = alloc(dev->config_desc->bNumInterfaces * sizeof(usb_interface_t));
|
||||
if (dev->interfaces == NULL) {
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
printf("usb: out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// set up interface data
|
||||
usb_for_each_descriptor(dev->config_desc, desc) {
|
||||
// since this is the first pass over the configure descriptor,
|
||||
// we will verify if it is valid and fail the enumeration if not
|
||||
USB_FOR_EACH_DESCRIPTOR_CHECK(dev->config_desc, desc) {
|
||||
printf("usb: malformed config description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
if (desc->bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE)
|
||||
continue;
|
||||
|
||||
if (desc->bLength < sizeof(usb_interface_desc_t)) {
|
||||
printf("usb: malformed interface description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
usb_interface_desc_t *interface_desc = (usb_interface_desc_t *)desc;
|
||||
if (interface_desc->bAlternateSetting)
|
||||
continue;
|
||||
|
||||
if (interface_desc->bInterfaceNumber >= dev->config_desc->bNumInterfaces) {
|
||||
printf("usb: malformed interface description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
usb_interface_t *interface = &dev->interfaces[interface_desc->bInterfaceNumber];
|
||||
if (interface->desc != NULL) {
|
||||
printf("usb: duplicate interface description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
interface->desc = interface_desc;
|
||||
if (interface_desc->bNumEndpoints > 0) {
|
||||
interface->endpoints = alloc(interface_desc->bNumEndpoints * sizeof(usb_endpoint_t));
|
||||
if (interface->endpoints == NULL) {
|
||||
printf("usb: out of memory\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for missing interfaces
|
||||
for (int i = 0; i < dev->config_desc->bNumInterfaces; ++i) {
|
||||
if (dev->interfaces[i].desc == NULL) {
|
||||
printf("usb: missing interface description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
}
|
||||
|
||||
// set up endpoint data
|
||||
usb_interface_t *current_interface = NULL;
|
||||
size_t current_endpoint = 0;
|
||||
usb_for_each_descriptor(dev->config_desc, desc) {
|
||||
USB_FOR_EACH_DESCRIPTOR_CHECK(dev->config_desc, desc) {
|
||||
printf("usb: malformed config description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE) {
|
||||
if (desc->bLength < sizeof(usb_interface_desc_t)) {
|
||||
printf("usb: malformed interface description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
usb_interface_desc_t *interface_desc = (usb_interface_desc_t *)desc;
|
||||
if (interface_desc->bInterfaceNumber >= dev->config_desc->bNumInterfaces) {
|
||||
printf("usb: malformed interface description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
if (interface_desc->bAlternateSetting) {
|
||||
current_endpoint = 0;
|
||||
current_interface = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
current_endpoint = 0;
|
||||
current_interface = &dev->interfaces[interface_desc->bInterfaceNumber];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE_ENDPOINT) {
|
||||
// skip any endpoints on an alternate setting
|
||||
if (current_interface == NULL)
|
||||
continue;
|
||||
|
||||
if (desc->bLength < sizeof(usb_endpoint_desc_t)) {
|
||||
printf("usb: malformed endpoint description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
if (current_endpoint >= current_interface->desc->bNumEndpoints) {
|
||||
printf("usb: malformed interface description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
usb_endpoint_desc_t *endpoint_desc = (usb_endpoint_desc_t *)desc;
|
||||
if (!endpoint_desc_valid(dev, endpoint_desc)) {
|
||||
printf("usb: malformed endpoint description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
current_interface->endpoints[current_endpoint++].desc = endpoint_desc;
|
||||
} else if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE_SS_EP_COMPANION) {
|
||||
if (current_interface == NULL || current_endpoint == 0 || desc->bLength < sizeof(usb_ss_ep_companion_desc_t)) {
|
||||
printf("usb: malformed endpoint companion description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
current_interface->endpoints[current_endpoint - 1].ss_companion = (usb_ss_ep_companion_desc_t *)desc;
|
||||
}
|
||||
}
|
||||
|
||||
// verify if we got all advertised endpoints
|
||||
for (int i = 0; i < dev->config_desc->bNumInterfaces; ++i) {
|
||||
usb_interface_t *interface = &dev->interfaces[i];
|
||||
for (int j = 0; j < interface->desc->bNumEndpoints; ++j) {
|
||||
if (interface->endpoints[j].desc == NULL) {
|
||||
printf("usb: missing endpoint description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
|
||||
if (endpoint_requires_ss_companion(dev, &interface->endpoints[j]) && interface->endpoints[j].ss_companion == NULL) {
|
||||
printf("usb: missing endpoint companion description\n");
|
||||
goto interface_setup_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (configure_next_endpoint(dev, 0, 0) == 0)
|
||||
return; // success, wait for endpoint to be configured.
|
||||
|
||||
interface_setup_error:
|
||||
post_config_cleanup(dev);
|
||||
}
|
||||
|
||||
// set default configuration
|
||||
static void get_configuration_done(usb_device_t *dev, void *, usb_status_t status, size_t transferred) {
|
||||
if (status != USB_STATUS_SUCCESS) {
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
printf("usb: failed to get config descriptor\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (device_port_stale(dev)) {
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (usb_set_configuration(dev, dev->config_desc->bConfigurationValue, set_configuration_done)) {
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
printf("usb: usb_set_configuration failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
static bool config_desc_header_valid(usb_config_desc_t *desc, size_t transferred) {
|
||||
if (transferred < sizeof(usb_config_desc_t))
|
||||
return false;
|
||||
|
||||
if (desc->bLength != sizeof(usb_config_desc_t))
|
||||
return false;
|
||||
|
||||
if (desc->bDescriptorType != USB_DESCRIPTOR_TYPE_CONFIG)
|
||||
return false;
|
||||
|
||||
if (desc->wTotalLength < desc->bLength)
|
||||
return false;
|
||||
|
||||
if (desc->wTotalLength > USB_MAX_CONFIG_DESC_SIZE)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// get the rest of configuration
|
||||
static void get_configuration_header_done(usb_device_t *dev, void *, usb_status_t status, size_t transferred) {
|
||||
if (status != USB_STATUS_SUCCESS) {
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
printf("usb: usb_set_configuration failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (device_port_stale(dev)) {
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!config_desc_header_valid(dev->config_desc, transferred)) {
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
printf("usb: malformed config descriptor header\n");
|
||||
return;
|
||||
}
|
||||
|
||||
void *p = realloc(dev->config_desc, dev->config_desc->wTotalLength);
|
||||
if (p == NULL) {
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
printf("usb: out of memory to get configuration\n");
|
||||
return;
|
||||
}
|
||||
dev->config_desc = p;
|
||||
|
||||
if (usb_get_device_descriptor(dev, USB_DESCRIPTOR_TYPE_CONFIG, 0, dev->config_desc, dev->config_desc->wTotalLength, get_configuration_done, NULL)) {
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
printf("usb: usb_get_device_descriptor failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
// get configuration descriptor size
|
||||
static void address_done(usb_hub_t *hub, uint8_t port, usb_device_t *dev) {
|
||||
if (dev == NULL) {
|
||||
printf("usb: failed to address device in plug-in path\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (device_port_stale(dev)) {
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->config_desc = alloc(sizeof(usb_config_desc_t));
|
||||
if (dev->config_desc == NULL) {
|
||||
printf("usb: out of memory to get configuration\n");
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (usb_get_device_descriptor(dev, USB_DESCRIPTOR_TYPE_CONFIG, 0, dev->config_desc, sizeof(usb_config_desc_t), get_configuration_header_done, NULL)) {
|
||||
printf("usb: usb_get_device_descriptor failed\n");
|
||||
free(dev->config_desc);
|
||||
dev->hub->ctrl->ops->deaddress_device(dev->hub->ctrl, dev);
|
||||
}
|
||||
}
|
||||
|
||||
// address device
|
||||
void usb_hub_event_reset(usb_hub_t *hub, int port) {
|
||||
if (hub->ctrl->ops->address_device(hub->ctrl, hub, port, address_done)) {
|
||||
printf("usb_hub %s: failed to address device\n", hub->name);
|
||||
}
|
||||
}
|
||||
|
||||
// reset device
|
||||
void usb_hub_event_connect(usb_hub_t *hub, int port) {
|
||||
__assert(port < hub->port_count);
|
||||
hub->ports[port].generation++;
|
||||
|
||||
if (hub->ops->set_port_feature(hub, port, USB_HUB_FEATURE_PORT_RESET)) {
|
||||
printf("usb_hub %s: port reset failed\n", hub->name);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_hub_event_disconnect(usb_hub_t* hub, int port) {
|
||||
__assert(port < hub->port_count);
|
||||
hub->ports[port].generation++;
|
||||
|
||||
usb_device_t *device = hub->ports[port].device;
|
||||
if (device == NULL) {
|
||||
printf("usb: unplugged device during device init\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hub->ports[port].device = NULL;
|
||||
|
||||
// TODO in the case of a hub driver this would also cause a sort of "recursive disconnect" from there
|
||||
for (int i = 0; i < device->config_desc->bNumInterfaces; ++i) {
|
||||
usb_interface_t *interface = &device->interfaces[i];
|
||||
if (interface->driver && interface->driver->detach)
|
||||
interface->driver->detach(device, interface);
|
||||
}
|
||||
|
||||
// TODO block new transfers
|
||||
// TODO stop transfers
|
||||
|
||||
post_config_cleanup(device);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#include <kernel/alloc.h>
|
||||
#include <kernel/pmm.h>
|
||||
#include <kernel/usb.h>
|
||||
#include <logging.h>
|
||||
|
||||
extern usb_class_driver_t *usb_class_drivers;
|
||||
extern usb_class_driver_t *usb_class_drivers_end;
|
||||
|
||||
int usb_submit_xfer(usb_device_t *dev, usb_xfer_t *xfer) {
|
||||
usb_ctrl_t *ctrl = dev->hub->ctrl;
|
||||
xfer->device = dev;
|
||||
return ctrl->ops->xfer(ctrl, dev, xfer);
|
||||
}
|
||||
|
||||
int usb_control_xfer(usb_device_t *dev, usb_setup_t *setup, void *buffer, usb_completion_callback_t callback, void *ctx) {
|
||||
usb_xfer_t xfer = {0};
|
||||
xfer.flags = (setup->bmRequestType & USB_REQUEST_DIR_TO_HOST) ? USB_XFER_FLAG_TO_HOST : USB_XFER_FLAG_TO_DEVICE;
|
||||
xfer.type = USB_XFER_TYPE_CONTROL;
|
||||
xfer.setup = setup;
|
||||
xfer.data = buffer;
|
||||
xfer.data_length = setup->wLength;
|
||||
xfer.completion = callback;
|
||||
xfer.completion_ctx = ctx;
|
||||
|
||||
return usb_submit_xfer(dev, &xfer);
|
||||
}
|
||||
|
||||
static int usb_get_descriptor_for_recipient(usb_device_t *dev, uint8_t recipient, uint16_t index, uint8_t desc_type, uint8_t desc_index, void *buffer, uint16_t length, usb_completion_callback_t callback, void *callback_ctx) {
|
||||
usb_setup_t setup = {0};
|
||||
setup.bmRequestType = recipient | USB_REQUEST_STANDARD | USB_REQUEST_DIR_TO_HOST;
|
||||
setup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
|
||||
setup.wValue = ((uint16_t)desc_type << 8) | desc_index;
|
||||
setup.wIndex = index;
|
||||
setup.wLength = length;
|
||||
|
||||
return usb_control_xfer(dev, &setup, buffer, callback, callback_ctx ? callback_ctx : buffer);
|
||||
}
|
||||
|
||||
int usb_get_device_descriptor(usb_device_t *dev, uint8_t desc_type, uint8_t desc_index, void *buffer, uint16_t length, usb_completion_callback_t callback, void *callback_ctx) {
|
||||
return usb_get_descriptor_for_recipient(dev, USB_REQUEST_RECIP_DEVICE, 0, desc_type, desc_index, buffer, length, callback, callback_ctx);
|
||||
}
|
||||
|
||||
int usb_get_interface_descriptor(usb_device_t *dev, uint16_t interface_number, uint8_t desc_type, uint8_t desc_index, void *buffer, uint16_t length, usb_completion_callback_t callback, void *callback_ctx) {
|
||||
return usb_get_descriptor_for_recipient(dev, USB_REQUEST_RECIP_INTERFACE, interface_number, desc_type, desc_index, buffer, length, callback, callback_ctx);
|
||||
}
|
||||
|
||||
int usb_get_endpoint_descriptor(usb_device_t *dev, uint16_t endpoint_address, uint8_t desc_type, uint8_t desc_index, void *buffer, uint16_t length, usb_completion_callback_t callback, void *callback_ctx) {
|
||||
return usb_get_descriptor_for_recipient(dev, USB_REQUEST_RECIP_ENDPOINT, endpoint_address, desc_type, desc_index, buffer, length, callback, callback_ctx);
|
||||
}
|
||||
|
||||
int usb_set_configuration(usb_device_t *dev, uint8_t config_value, usb_completion_callback_t callback) {
|
||||
usb_setup_t setup = {0};
|
||||
setup.bmRequestType = USB_REQUEST_RECIP_DEVICE | USB_REQUEST_STANDARD | USB_REQUEST_DIR_TO_DEVICE;
|
||||
setup.bRequest = USB_REQUEST_SET_CONFIGURATION;
|
||||
setup.wValue = config_value;
|
||||
setup.wIndex = 0;
|
||||
setup.wLength = 0;
|
||||
|
||||
return usb_control_xfer(dev, &setup, NULL, callback, NULL);
|
||||
}
|
||||
Reference in New Issue
Block a user