Skip to content

Commit

Permalink
usbus: Implement GET STATUS and SET/CLEAR FEATURE requests
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bergzand committed Apr 11, 2023
1 parent 44c5c9e commit 5fd5618
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 3 deletions.
9 changes: 9 additions & 0 deletions sys/include/usb/descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ extern "C" {
#define USB_TYPE_DESCRIPTOR_INTERFACE_ASSOC 0x0b /**< Interface association */
/** @} */

/**
* @name USB standard feature selectors
* {
*/
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 0x01 /**< Device remote wakeup */
#define USB_FEATURE_ENDPOINT_HALT 0x00 /**< Endpoint halt */
#define USB_FEATURE_TEST_MODE 0x02 /**< Test mode feature */
/** @} */

/**
* @name USB configuration attributes
* @anchor USB_CONF_ATTR
Expand Down
60 changes: 57 additions & 3 deletions sys/usb/usbus/usbus_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
/* 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);
}

memset(status, 0, sizeof(status));
usbus_control_slicer_put_bytes(usbus, status, 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 */
Expand Down Expand Up @@ -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 &&
Expand All @@ -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;
Expand All @@ -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");
}
Expand Down

0 comments on commit 5fd5618

Please sign in to comment.