summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNathan Conrad <[email protected]>2020-04-12 21:07:17 -0400
committerNathan Conrad <[email protected]>2020-04-12 21:27:27 -0400
commit0eeaccaf46c28444cc0830895559652cf5638c60 (patch)
tree2a31a54dd03a0ff7a413427e3cee6a9036bd85e4 /src
parent2ff3f765db7e62201d0491093111b0d649446046 (diff)
Skeleton, and initial stm32fsdev implementation (that leaks memory)
Diffstat (limited to 'src')
-rw-r--r--src/device/dcd.h6
-rw-r--r--src/device/usbd.c61
-rw-r--r--src/device/usbd.h2
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c37
4 files changed, 104 insertions, 2 deletions
diff --git a/src/device/dcd.h b/src/device/dcd.h
index 487ddb3b6..f48530227 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -66,7 +66,7 @@ typedef struct TU_ATTR_ALIGNED(4)
// USBD_EVT_XFER_COMPLETE
struct {
- uint8_t ep_addr;
+ uint8_t ep_addr; ///< 0xFF signifies that the transfer was aborted.
uint8_t result;
uint32_t len;
}xfer_complete;
@@ -123,6 +123,10 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re
// Configure endpoint's registers according to descriptor
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
+// Close an endpoint.
+// Since it is weak, caller must TU_ASSERT this function's existence before calling it.
+void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK;
+
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
diff --git a/src/device/usbd.c b/src/device/usbd.c
index 397a681ed..e46532567 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -420,6 +420,11 @@ void tud_task (void)
uint8_t const ep_addr = event.xfer_complete.ep_addr;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const ep_dir = tu_edpt_dir(ep_addr);
+
+ if(ep_addr == 0xFF) // aborted transfer
+ {
+ break;
+ }
TU_LOG2(" Endpoint: 0x%02X, Bytes: %u\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
@@ -1036,4 +1041,60 @@ bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr)
return _usbd_dev.ep_status[epnum][dir].stalled;
}
+/**
+ * Remove queued xfer complete messages from event queue,
+ * for a particular ep.
+ */
+static void usbd_abort_transfers(uint8_t rhport, uint8_t ep_addr)
+{
+ dcd_event_t ev_sentinal =
+ {
+ .event_id = DCD_EVENT_COUNT, ///< This is an invalid event ID.
+ };
+ dcd_event_t event;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const ep_dir = tu_edpt_dir(ep_addr);
+
+ dcd_int_disable(rhport);
+ // Queue sentinal element
+ TU_ASSERT(osal_queue_send(_usbd_q, &ev_sentinal, true), /**/);
+
+ TU_ASSERT(osal_queue_receive(_usbd_q, &event), /**/);
+
+ while(event.event_id != DCD_EVENT_COUNT)
+ {
+ if((event.rhport == rhport) && (event.event_id == DCD_EVENT_XFER_COMPLETE)
+ && (event.xfer_complete.ep_addr == ep_addr))
+ {
+ _usbd_dev.ep_status[epnum][ep_dir].busy = false;
+ event.xfer_complete.ep_addr = 0xFF; // Mark transfer as invalid
+ }
+ TU_ASSERT(osal_queue_send(_usbd_q, &event, true), /**/);
+ TU_ASSERT(osal_queue_receive(_usbd_q, &event), /**/);
+ }
+
+ dcd_int_enable(rhport);
+}
+
+/**
+ * tud_edpt_close will disable an endpoint, and clear all pending transfers
+ * through the particular endpoint.
+ *
+ * It must be called from the usb task (i.e. from the control request
+ * handler while handling SET_ALTERNATE).
+ */
+void tud_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+
+ TU_ASSERT(dcd_edpt_close, /**/);
+ TU_LOG2(" CLOSING Endpoint: 0x%02X\r\n", ep_addr);
+
+ dcd_edpt_close(rhport, ep_addr);
+
+ /* Now, in progress transfers have to be expunged */
+ usbd_abort_transfers(rhport, ep_addr);
+
+ return;
+}
+
#endif
diff --git a/src/device/usbd.h b/src/device/usbd.h
index 817af20e3..2447c2082 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -79,6 +79,8 @@ static inline bool tud_connect(void)
return true;
}
+void tud_edpt_close(uint8_t rhport, uint8_t ep_addr);
+
// Carry out Data and Status stage of control transfer
// - If len = 0, it is equivalent to sending status only
// - If len > wLength : it will be truncated
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index f962a4bee..fa044e2d6 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -69,7 +69,6 @@
* - Endpoint index is the ID of the endpoint
* - This means that priority is given to endpoints with lower ID numbers
* - Code is mixing up EP IX with EP ID. Everywhere.
- * - No way to close endpoints; Can a device be reconfigured without a reset?
* - Packet buffer memory is copied in the interrupt.
* - This is better for performance, but means interrupts are disabled for longer
* - DMA may be the best choice, but it could also be pushed to the USBD task.
@@ -623,6 +622,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc
if(dir == TUSB_DIR_IN)
{
+ // FIXME: use pma_alloc to allocate memory dynamically
*pcd_ep_tx_address_ptr(USB, epnum) = ep_buf_ptr;
pcd_set_ep_tx_cnt(USB, epnum, p_endpoint_desc->wMaxPacketSize.size);
pcd_clear_tx_dtog(USB, epnum);
@@ -630,6 +630,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc
}
else
{
+ // FIXME: use pma_alloc to allocate memory dynamically
*pcd_ep_rx_address_ptr(USB, epnum) = ep_buf_ptr;
pcd_set_ep_rx_cnt(USB, epnum, p_endpoint_desc->wMaxPacketSize.size);
pcd_clear_rx_dtog(USB, epnum);
@@ -642,6 +643,40 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc
return true;
}
+/**
+ * Close an endpoint.
+ *
+ * This function should be called with interrupts enabled, though
+ * this implementation should be valid with them disabled, too.
+ * This also clears transfers in progress, should there be any.
+ */
+void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
+{
+ (void)rhport;
+ uint32_t const epnum = tu_edpt_number(ep_addr);
+ uint32_t const dir = tu_edpt_dir(ep_addr);
+
+#ifndef NDEBUG
+ TU_ASSERT(epnum < MAX_EP_COUNT, /**/);
+#endif
+
+ //uint16_t memptr;
+
+ if(dir == TUSB_DIR_IN)
+ {
+ pcd_set_ep_tx_status(USB,epnum,USB_EP_TX_DIS);
+ //memptr = *pcd_ep_tx_address_ptr(USB, epnum);
+ }
+ else
+ {
+ pcd_set_ep_rx_status(USB, epnum, USB_EP_RX_DIS);
+ //memptr = *pcd_ep_rx_address_ptr(USB, epnum);
+ }
+
+ // FIXME: Free memory
+ // pma_free(memptr);
+}
+
// Currently, single-buffered, and only 64 bytes at a time (max)
static void dcd_transmit_packet(xfer_ctl_t * xfer, uint16_t ep_ix)