1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

usbus: Implement GET STATUS and SET/CLEAR FEATURE requests

This extends support for the GET STATUS requests to support endpoints
and interfaces as recipient. It also adds the SET and CLEAR FEATURE
requests for the endpoints with support to set and clear the halt
condition on an endpoint.
This commit is contained in:
Koen Zandberg 2021-10-31 21:18:14 +01:00
parent 13b4f8de2c
commit 7b2db7bf2b
No known key found for this signature in database
GPG Key ID: BA1718B37D79F51C
2 changed files with 67 additions and 4 deletions

View File

@ -58,6 +58,15 @@ extern "C" {
#define USB_TYPE_DESCRIPTOR_INTERFACE_ASSOC 0x0b /**< Interface association */
/** @} */
/**
* @name USB standard feature selectors
* @{
*/
#define USB_FEATURE_ENDPOINT_HALT 0x00 /**< Endpoint halt */
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 0x01 /**< Device remote wakeup */
#define USB_FEATURE_TEST_MODE 0x02 /**< Test mode feature */
/** @} */
/**
* @name USB configuration attributes
* @anchor USB_CONF_ATTR

View File

@ -105,13 +105,39 @@ static usbus_string_t *_get_descriptor(usbus_t *usbus, uint16_t idx)
static int _req_status(usbus_t *usbus)
{
uint8_t status[2];
memset(status, 0, sizeof(status));
usbus_control_slicer_put_bytes(usbus, status, sizeof(status));
/* Signal self powered */
uint16_t status = (CONFIG_USB_SELF_POWERED) ? 1 : 0;
usbus_control_slicer_put_bytes(usbus, (uint8_t*)&status, sizeof(status));
return sizeof(status);
}
static int _req_iface_status(usbus_t *usbus)
{
uint16_t status = 0; /* always zero */
usbus_control_slicer_put_bytes(usbus, (uint8_t*)&status, sizeof(status));
return sizeof(status);
}
static int _req_endpoint_status(usbus_t *usbus, usbus_endpoint_t *ep)
{
uint16_t status = ep->halted ? 1 : 0;
usbus_control_slicer_put_bytes(usbus, (uint8_t*)&status, sizeof(status));
return sizeof(status);
}
static int _req_endpoint_feature(usbus_endpoint_t *ep, uint16_t feature, bool enable)
{
switch (feature) {
case USB_FEATURE_ENDPOINT_HALT:
enable ? usbus_endpoint_halt(ep) : usbus_endpoint_clear_halt(ep);
break;
default:
DEBUG("usbus: unknown endpoint feature request: %u\n", feature);
return -1;
}
return 1;
}
static int _req_str(usbus_t *usbus, uint16_t idx)
{
/* Return an error condition by default */
@ -238,6 +264,11 @@ static int _recv_interface_setup(usbus_t *usbus, usb_setup_t *pkt)
(usbus_control_handler_t *)usbus->control;
uint16_t destination = pkt->index & 0x0f;
/* Globally handle the iface get status request */
if (pkt->request == USB_SETUP_REQ_GET_STATUS) {
return _req_iface_status(usbus);
}
/* Find interface handler */
for (usbus_interface_t *iface = usbus->iface; iface; iface = iface->next) {
if (destination == iface->idx &&
@ -251,6 +282,26 @@ static int _recv_interface_setup(usbus_t *usbus, usb_setup_t *pkt)
return -1;
}
static int _recv_endpoint_setup(usbus_t *usbus, usb_setup_t *pkt)
{
uint8_t destination = pkt->index & 0x0f;
bool in = pkt->index & (1 << 7); /* Bit seven is 1 for IN, 0 for OUT */
usbus_endpoint_t *ep = in ? &usbus->ep_in[destination] :
&usbus->ep_out[destination];
switch (pkt->request) {
case USB_SETUP_REQ_GET_STATUS:
return _req_endpoint_status(usbus, ep);
case USB_SETUP_REQ_SET_FEATURE:
return _req_endpoint_feature(ep, pkt->value, true);
case USB_SETUP_REQ_CLEAR_FEATURE:
return _req_endpoint_feature(ep, pkt->value, false);
default:
DEBUG("usbus: Unknown endpoint request %u\n", pkt->request);
return -1;
}
}
static void _recv_setup(usbus_t *usbus, usbus_control_handler_t *handler)
{
usb_setup_t *pkt = &handler->setup;
@ -272,6 +323,9 @@ static void _recv_setup(usbus_t *usbus, usbus_control_handler_t *handler)
case USB_SETUP_REQUEST_RECIPIENT_INTERFACE:
res = _recv_interface_setup(usbus, pkt);
break;
case USB_SETUP_REQUEST_RECIPIENT_ENDPOINT:
res = _recv_endpoint_setup(usbus, pkt);
break;
default:
DEBUG("usbus_control: Unhandled setup request\n");
}