From 5b477918b6d954ffc7f9f8a2acf02172d6a2ddfc Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Tue, 17 Sep 2019 19:48:09 +0200 Subject: [PATCH] usbus: Rework handling of set control requests --- sys/include/usb/usbus/control.h | 17 ++++++++ sys/usb/usbus/usbus_control.c | 72 +++++++++++++++++++-------------- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/sys/include/usb/usbus/control.h b/sys/include/usb/usbus/control.h index f1293ebed8..8032b22bac 100644 --- a/sys/include/usb/usbus/control.h +++ b/sys/include/usb/usbus/control.h @@ -64,6 +64,11 @@ typedef struct { */ usbus_control_slicer_t slicer; + /** + * @brief Received bytes for set requests + */ + size_t received_len; + /** * @brief EP0 OUT endpoint */ @@ -123,6 +128,18 @@ void usbus_control_slicer_ready(usbus_t *usbus); */ int usbus_control_slicer_nextslice(usbus_t *usbus); +/** + * @brief Retrieve the data from the OUT pipe of the control endpoint + * + * @pre usbus->state == USBUS_CONTROL_REQUEST_STATE_OUTDATA + * + * @param[in] usbus USBUS context + * @param[out] len Length of the data part + * + * @return pointer to the data buffer + */ +uint8_t *usbus_control_get_out_data(usbus_t *usbus, size_t *len); + #ifdef __cplusplus } #endif diff --git a/sys/usb/usbus/usbus_control.c b/sys/usb/usbus/usbus_control.c index 17574cf137..4c12bf4f22 100644 --- a/sys/usb/usbus/usbus_control.c +++ b/sys/usb/usbus/usbus_control.c @@ -192,7 +192,6 @@ static int _req_descriptor(usbus_t *usbus, usb_setup_t *pkt) static int _recv_dev_setup(usbus_t *usbus, usb_setup_t *pkt) { - usbus_control_handler_t *ep0 = (usbus_control_handler_t *)usbus->control; int res = -1; if (usb_setup_is_read(pkt)) { @@ -213,21 +212,19 @@ static int _recv_dev_setup(usbus_t *usbus, usb_setup_t *pkt) case USB_SETUP_REQ_SET_ADDRESS: DEBUG("usbus_control: Setting address\n"); usbus->addr = (uint8_t)pkt->value; - res = 0; + res = 1; break; case USB_SETUP_REQ_SET_CONFIGURATION: /* Nothing configuration dependent to do here, only one * configuration supported */ usbus->state = USBUS_STATE_CONFIGURED; _activate_endpoints(usbus); - res = 0; + res = 1; break; default: DEBUG("usbus: Unknown write request %u\n", pkt->request); break; } - /* Signal zero-length packet */ - usbdev_ep_ready(ep0->in, 0); } return res; } @@ -257,19 +254,7 @@ static void _recv_setup(usbus_t *usbus, usbus_control_handler_t *handler) DEBUG("usbus_control: Received setup %x %x @ %d\n", pkt->type, pkt->request, pkt->length); - if (usb_setup_is_read(pkt)) { - handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_INDATA; - } - else { - if (pkt->length) { - handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_OUTDATA; - usbdev_ep_ready(handler->out, 0); - } - else { - handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_INACK; - usbdev_ep_ready(handler->in, 0); - } - } + uint8_t destination = pkt->type & USB_SETUP_REQUEST_RECIPIENT_MASK; int res = 0; switch (destination) { @@ -290,7 +275,22 @@ static void _recv_setup(usbus_t *usbus, usbus_control_handler_t *handler) handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_READY; } else if (res) { - usbus_control_slicer_ready(usbus); + if (usb_setup_is_read(pkt)) { + handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_INDATA; + usbus_control_slicer_ready(usbus); + } + else { + /* Signal ready for new data in case there is more */ + if (handler->received_len < pkt->length) { + handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_OUTDATA; + usbdev_ep_ready(handler->out, 1); + } + else { + handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_INACK; + usbdev_ep_ready(handler->in, 0); + } + } + } } @@ -307,6 +307,19 @@ static void _usbus_config_ep0(usbus_control_handler_t *ep0_handler) usbdev_ep_ready(ep0_handler->out, 0); } +uint8_t *usbus_control_get_out_data(usbus_t *usbus, size_t *len) +{ + usbus_control_handler_t *handler = (usbus_control_handler_t*)usbus->control; + + assert(len); + assert(handler->control_request_state == USBUS_CONTROL_REQUEST_STATE_OUTDATA); + + usbdev_ep_t *ep_out = handler->out; + usbdev_ep_get(ep_out, USBOPT_EP_AVAILABLE, + len, sizeof(size_t)); + return ep_out->buf; +} + static void _init(usbus_t *usbus, usbus_handler_t *handler) { DEBUG("usbus_control: Initializing EP0\n"); @@ -334,12 +347,15 @@ static int _handle_tr_complete(usbus_t *usbus, usbus->state = USBUS_STATE_ADDR; } ep0_handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_READY; + /* Ready for new control request */ + usbdev_ep_ready(ep0_handler->out, 0); } break; case USBUS_CONTROL_REQUEST_STATE_OUTACK: if (ep->dir == USB_EP_DIR_OUT) { - memset(&ep0_handler->slicer, 0, sizeof(usbus_control_slicer_t)); ep0_handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_READY; + /* Ready for new control request */ + usbdev_ep_ready(ep0_handler->out, 0); } break; case USBUS_CONTROL_REQUEST_STATE_INDATA: @@ -357,18 +373,11 @@ static int _handle_tr_complete(usbus_t *usbus, break; case USBUS_CONTROL_REQUEST_STATE_OUTDATA: if (ep->dir == USB_EP_DIR_OUT) { - /* Ready in ZLP */ - ep0_handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_INACK; size_t len = 0; - usbdev_ep_get(ep, USBOPT_EP_AVAILABLE, &len, sizeof(size_t)); - DEBUG("Expected len: %d, received: %d\n", - ep0_handler->setup.length, len); - if (ep0_handler->setup.length == len) { - DEBUG("DATA complete\n"); - usbdev_ep_ready(ep0_handler->in, 0); - } - /* Flush OUT buffer */ - usbdev_ep_ready(ep0_handler->out, 0); + usbdev_ep_get(ep0_handler->out, USBOPT_EP_AVAILABLE, + &len, sizeof(size_t)); + ep0_handler->received_len += len; + _recv_setup(usbus, ep0_handler); } else { DEBUG("usbus_control: Invalid state OUTDATA with IN request\n"); @@ -379,6 +388,7 @@ static int _handle_tr_complete(usbus_t *usbus, memset(&ep0_handler->slicer, 0, sizeof(usbus_control_slicer_t)); memcpy(&ep0_handler->setup, ep0_handler->out->buf, sizeof(usb_setup_t)); + ep0_handler->received_len = 0; ep0_handler->slicer.reqlen = ep0_handler->setup.length; _recv_setup(usbus, ep0_handler); }