host_communication: Send zero-length-packet on wMaxPacketSize
We need to send zero-length packets on bulk endpoints whenever the
transfer size is exactly a multiple of the wMaxPacketSize.
See USB 2.0 Specification Section 5.8.3 titled "Bulk Transfer Packet
Size constraints."
Change-Id: Ice3842399d5a5c4a18383860f81074497c6e7c9b
Closes: OS#4331
diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c
index 0eccc65..ac2595c 100644
--- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c
+++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c
@@ -1077,6 +1077,14 @@
* Exported functions
*---------------------------------------------------------------------------*/
+
+uint16_t USBD_GetEndpointSize(uint8_t bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ return pEndpoint->size;
+}
+
/**
* USBD (UDP) interrupt handler
* Manages device resume, suspend, end of bus reset.
diff --git a/firmware/atmel_softpack_libraries/usb/include/USBD.h b/firmware/atmel_softpack_libraries/usb/include/USBD.h
index 15a6859..6fc931f 100644
--- a/firmware/atmel_softpack_libraries/usb/include/USBD.h
+++ b/firmware/atmel_softpack_libraries/usb/include/USBD.h
@@ -214,6 +214,8 @@
* Exported functions
*------------------------------------------------------------------------------*/
+extern uint16_t USBD_GetEndpointSize(uint8_t bEndpoint);
+
//extern void USBD_IrqHandler(void);
extern void USBD_Init(void);
diff --git a/firmware/libcommon/source/host_communication.c b/firmware/libcommon/source/host_communication.c
index 0e496c5..9a6e5b3 100644
--- a/firmware/libcommon/source/host_communication.c
+++ b/firmware/libcommon/source/host_communication.c
@@ -33,10 +33,18 @@
{
struct msgb *msg = (struct msgb *) arg;
struct usb_buffered_ep *bep = msg->dst;
+ uint16_t ep_size = USBD_GetEndpointSize(bep->ep);
unsigned long x;
TRACE_DEBUG("%s (EP=0x%02x)\r\n", __func__, bep->ep);
+ if (((msgb_length(msg) % ep_size) == 0) && (transferred == ep_size)) {
+ /* terminate with ZLP; pass in 'msg' again as 'arg' so we get
+ * called the second time and proceed with usb_buf_free below */
+ USBD_Write(bep->ep, 0, 0, (TransferCallback) &usb_write_cb, msg);
+ return;
+ }
+
local_irq_save(x);
bep->in_progress--;
local_irq_restore(x);