Skeleton, and initial stm32fsdev implementation (that leaks memory)

This commit is contained in:
Nathan Conrad 2020-04-12 21:07:17 -04:00
parent 2ff3f765db
commit 0eeaccaf46
5 changed files with 111 additions and 2 deletions

View File

@ -119,6 +119,13 @@ Opening an endpoint is done for all non-control endpoints once the host picks a
Also make sure to enable endpoint specific interrupts.
##### dcd_edpt_close
Close an endpoint. After calling this, the device should not respond to any packets directed towards this endpoint. Implementation is optional, and is to be called from USBD in a non-interrupt context.
This function is used for implementing alternate settings.
When called, this function need to abort any transfers in progress through this endpoint, before returning.
##### dcd_edpt_xfer
`dcd_edpt_xfer` is responsible for configuring the peripheral to send or receive data from the host. "xfer" is short for "transfer". **This is one of the core methods you must implement for TinyUSB to work (one other is the interrupt handler).** Data from the host is the OUT direction and data to the host is IN. It is used for all endpoints including the control endpoint 0. Make sure to handle the zero-length packet STATUS packet on endpoint 0 correctly. It may be a special transaction to the peripheral.

View File

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

View File

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

View File

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

View File

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