usbus: Rework handling of set control requests

This commit is contained in:
Koen Zandberg 2019-09-17 19:48:09 +02:00
parent 00131b3ba3
commit 5b477918b6
No known key found for this signature in database
GPG Key ID: 0895A893E6D2985B
2 changed files with 58 additions and 31 deletions

View File

@ -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

View File

@ -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,8 +275,23 @@ static void _recv_setup(usbus_t *usbus, usbus_control_handler_t *handler)
handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_READY;
}
else if (res) {
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);
}
}
}
}
static void _usbus_config_ep0(usbus_control_handler_t *ep0_handler)
@ -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);
}