usb: short control IN might need a ZLP

Control transfers can transfer less than was requested by the host in the
wLength field.  if this short transfer is a multiple of the endpoint's packet
size, a zero length packet must be sent.

Adds tests for a range of control transfer IN requests, and properly supports
this in the core.  Based heavily on work by Kuldeep Dhaka.

See https://github.com/libopencm3/libopencm3/pull/505
and https://github.com/libopencm3/libopencm3/pull/194 for original discussion.

Tested with stm32f4, stm32f103 and stm32l053.
This commit is contained in:
Karl Palsson
2015-10-11 01:17:24 +00:00
parent 5270c11a09
commit 3ed12b6fd9
4 changed files with 146 additions and 3 deletions

View File

@@ -44,6 +44,7 @@
* USB Vendor:Interface control requests.
*/
#define GZ_REQ_SET_PATTERN 1
#define GZ_REQ_PRODUCE 2
#define INTEL_COMPLIANCE_WRITE 0x5b
#define INTEL_COMPLIANCE_READ 0x5c
@@ -168,7 +169,7 @@ static const char * usb_strings[] = {
};
/* Buffer to be used for control requests. */
static uint8_t usbd_control_buffer[128];
static uint8_t usbd_control_buffer[5*64];
static usbd_device *our_dev;
/* Private global for state */
@@ -253,6 +254,21 @@ static int gadget0_control_request(usbd_device *usbd_dev,
case INTEL_COMPLIANCE_READ:
ER_DPRINTF("unimplemented!");
return USBD_REQ_NOTSUPP;
case GZ_REQ_PRODUCE:
ER_DPRINTF("fake loopback of %d\n", req->wValue);
if (req->wValue > sizeof(usbd_control_buffer)) {
ER_DPRINTF("Can't write more than out control buffer! %d > %d\n",
req->wValue, sizeof(usbd_control_buffer));
return USBD_REQ_NOTSUPP;
}
/* Don't produce more than asked for! */
if (req->wValue > req->wLength) {
ER_DPRINTF("Truncating reply to match wLen\n");
*len = req->wLength;
} else {
*len = req->wValue;
}
return USBD_REQ_HANDLED;
}
return USBD_REQ_NEXT_CALLBACK;
}