diff --git a/include/libopencm3/usb/usbd.h b/include/libopencm3/usb/usbd.h index b50c65d2..a884f9ce 100644 --- a/include/libopencm3/usb/usbd.h +++ b/include/libopencm3/usb/usbd.h @@ -89,6 +89,9 @@ extern int usbd_register_control_callback(usbd_device *usbd_dev, uint8_t type, extern int usbd_register_set_config_callback(usbd_device *usbd_dev, void (*callback)(usbd_device *usbd_dev, uint16_t wValue)); +extern void usbd_register_set_altsetting_callback(usbd_device *usbd_dev, + void (*callback)(usbd_device *usbd_dev, uint16_t wIndex, uint16_t wValue)); + /* Functions to be provided by the hardware abstraction layer */ extern void usbd_poll(usbd_device *usbd_dev); extern void usbd_disconnect(usbd_device *usbd_dev, bool disconnected); diff --git a/include/libopencm3/usb/usbstd.h b/include/libopencm3/usb/usbstd.h index 0b5cb213..1927690a 100644 --- a/include/libopencm3/usb/usbstd.h +++ b/include/libopencm3/usb/usbstd.h @@ -163,7 +163,8 @@ struct usb_config_descriptor { /* Descriptor ends here. The following are used internally: */ const struct usb_interface { - int num_altsetting; + uint8_t *cur_altsetting; + uint8_t num_altsetting; const struct usb_iface_assoc_descriptor *iface_assoc; const struct usb_interface_descriptor *altsetting; } *interface; diff --git a/lib/usb/usb_private.h b/lib/usb/usb_private.h index 81466dfa..4d8f7ed4 100644 --- a/lib/usb/usb_private.h +++ b/lib/usb/usb_private.h @@ -89,6 +89,9 @@ struct _usbd_device { void (*user_callback_set_config[MAX_USER_SET_CONFIG_CALLBACK]) (usbd_device *usbd_dev, uint16_t wValue); + void (*user_callback_set_altsetting)(usbd_device *usbd_dev, + uint16_t wIndex, uint16_t wValue); + const struct _usbd_driver *driver; /* private driver data */ diff --git a/lib/usb/usb_standard.c b/lib/usb/usb_standard.c index 885f077b..8bdc5c9d 100644 --- a/lib/usb/usb_standard.c +++ b/lib/usb/usb_standard.c @@ -56,6 +56,13 @@ int usbd_register_set_config_callback(usbd_device *usbd_dev, return -1; } +void usbd_register_set_altsetting_callback(usbd_device *usbd_dev, + void (*callback)(usbd_device *usbd_dev, + uint16_t wIndex, uint16_t wValue)) +{ + usbd_dev->user_callback_set_altsetting = callback; +} + static uint16_t build_config_descriptor(usbd_device *usbd_dev, uint8_t index, uint8_t *buf, uint16_t len) { @@ -294,32 +301,53 @@ static int usb_standard_set_interface(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len) { - (void)usbd_dev; - (void)req; + const struct usb_config_descriptor *cfx = &usbd_dev->config[usbd_dev->current_config - 1]; + const struct usb_interface *iface; + (void)buf; - /* FIXME: Adapt if we have more than one interface. */ - if (req->wValue != 0) { - return 0; + if (req->wIndex >= cfx->bNumInterfaces) { + return USBD_REQ_NOTSUPP; } + + iface = &cfx->interface[req->wIndex]; + + if (req->wValue >= iface->num_altsetting) { + return USBD_REQ_NOTSUPP; + } + + if (iface->cur_altsetting) { + *iface->cur_altsetting = req->wValue; + } else if (req->wValue > 0) { + return USBD_REQ_NOTSUPP; + } + + if (usbd_dev->user_callback_set_altsetting) { + usbd_dev->user_callback_set_altsetting(usbd_dev, + req->wIndex, req->wValue); + } + *len = 0; - return 1; + return USBD_REQ_HANDLED; } static int usb_standard_get_interface(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len) { - (void)usbd_dev; - (void)req; - (void)buf; + uint8_t *cur_altsetting; + const struct usb_config_descriptor *cfx = &usbd_dev->config[usbd_dev->current_config - 1]; + + if (req->wIndex >= cfx->bNumInterfaces) { + return USBD_REQ_NOTSUPP; + } - /* FIXME: Adapt if we have more than one interface. */ *len = 1; - (*buf)[0] = 0; + cur_altsetting = cfx->interface[req->wIndex].cur_altsetting; + (*buf)[0] = (cur_altsetting) ? *cur_altsetting : 0; - return 1; + return USBD_REQ_HANDLED; } static int usb_standard_device_get_status(usbd_device *usbd_dev,