rp2040: Add helper functions to usbserial.c

Add helper functions for manipulating the buffer memory and packet
control registers.  This is in preparation for double buffer support.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2023-09-24 01:22:31 -04:00
parent cd8d57c2c6
commit 83eecae028
1 changed files with 56 additions and 20 deletions

View File

@ -26,29 +26,67 @@
#define DPBUF_SIZE 64 #define DPBUF_SIZE 64
// Get the offset of a given endpoint's base buffer
static uint32_t static uint32_t
usb_buf_offset(uint32_t ep) usb_buf_offset(uint32_t ep)
{ {
return 0x100 + ep * DPBUF_SIZE * 2; return 0x100 + ep * DPBUF_SIZE * 2;
} }
// Obtain a pointer to an endpoint buffer
static void*
usb_buf_addr(uint32_t ep, int bufnum)
{
return (void*)usb_dpram + usb_buf_offset(ep) + bufnum * DPBUF_SIZE;
}
// Return a pointer to the ep_buf_ctrl register for an endpoint
static volatile uint16_t *
lookup_epbufctrl(uint32_t ep, int is_rx, int bufnum)
{
volatile uint16_t *epbp;
if (is_rx)
epbp = (void*)&usb_dpram->ep_buf_ctrl[ep].out;
else
epbp = (void*)&usb_dpram->ep_buf_ctrl[ep].in;
return &epbp[bufnum];
}
// Determine the next transfer PID id from the last PID
static uint32_t
next_data_pid(uint32_t epb)
{
return (epb ^ USB_BUF_CTRL_DATA1_PID) & USB_BUF_CTRL_DATA1_PID;
}
// Extract the number of bytes in an rx buffer
static uint32_t
get_rx_count(uint32_t epb, uint32_t max_len)
{
uint32_t c = epb & USB_BUF_CTRL_LEN_MASK;
if (c > max_len)
c = max_len;
return c;
}
static int_fast8_t static int_fast8_t
usb_write_packet(uint32_t ep, const void *data, uint_fast8_t len) usb_write_packet(uint32_t ep, const void *data, uint_fast8_t len)
{ {
// Check if there is room for this packet // Check if there is room for this packet
uint32_t epb = usb_dpram->ep_buf_ctrl[ep].in; volatile uint16_t *epbp = lookup_epbufctrl(ep, 0, 0);
uint32_t epb = *epbp;
if (epb & (USB_BUF_CTRL_AVAIL|USB_BUF_CTRL_FULL)) if (epb & (USB_BUF_CTRL_AVAIL|USB_BUF_CTRL_FULL))
return -1; return -1;
uint32_t pid = (epb ^ USB_BUF_CTRL_DATA1_PID) & USB_BUF_CTRL_DATA1_PID; // Determine the next packet header
uint32_t pid = next_data_pid(epb);
uint32_t new_epb = USB_BUF_CTRL_FULL | USB_BUF_CTRL_LAST | pid | len; uint32_t new_epb = USB_BUF_CTRL_FULL | USB_BUF_CTRL_LAST | pid | len;
usb_dpram->ep_buf_ctrl[ep].in = new_epb; *epbp = new_epb;
barrier();
// Copy the packet to the hw buffer // Copy the packet to the hw buffer
void *addr = (void*)usb_dpram + usb_buf_offset(ep); memcpy(usb_buf_addr(ep, 0), data, len);
barrier();
memcpy(addr, data, len);
barrier();
// Inform the USB hardware of the available packet // Inform the USB hardware of the available packet
usb_dpram->ep_buf_ctrl[ep].in = new_epb | USB_BUF_CTRL_AVAIL; barrier();
*epbp = new_epb | USB_BUF_CTRL_AVAIL;
return len; return len;
} }
@ -56,22 +94,20 @@ static int_fast8_t
usb_read_packet(uint32_t ep, void *data, uint_fast8_t max_len) usb_read_packet(uint32_t ep, void *data, uint_fast8_t max_len)
{ {
// Check if there is a packet ready // Check if there is a packet ready
uint32_t epb = usb_dpram->ep_buf_ctrl[ep].out; volatile uint16_t *epbp = lookup_epbufctrl(ep, 1, 0);
uint32_t epb = *epbp;
if ((epb & (USB_BUF_CTRL_AVAIL|USB_BUF_CTRL_FULL)) != USB_BUF_CTRL_FULL) if ((epb & (USB_BUF_CTRL_AVAIL|USB_BUF_CTRL_FULL)) != USB_BUF_CTRL_FULL)
return -1; return -1;
// Determine the next packet header
uint32_t new_epb = USB_BUF_CTRL_LAST | next_data_pid(epb) | DPBUF_SIZE;
*epbp = new_epb;
barrier();
// Copy the packet to the given buffer // Copy the packet to the given buffer
uint32_t pid = (epb ^ USB_BUF_CTRL_DATA1_PID) & USB_BUF_CTRL_DATA1_PID; uint32_t c = get_rx_count(epb, max_len);
uint32_t new_epb = USB_BUF_CTRL_LAST | pid | DPBUF_SIZE; memcpy(data, usb_buf_addr(ep, 0), c);
usb_dpram->ep_buf_ctrl[ep].out = new_epb;
uint32_t c = epb & USB_BUF_CTRL_LEN_MASK;
if (c > max_len)
c = max_len;
void *addr = (void*)usb_dpram + usb_buf_offset(ep);
barrier();
memcpy(data, addr, c);
barrier();
// Notify the USB hardware that the space is now available // Notify the USB hardware that the space is now available
usb_dpram->ep_buf_ctrl[ep].out = new_epb | USB_BUF_CTRL_AVAIL; barrier();
*epbp = new_epb | USB_BUF_CTRL_AVAIL;
return c; return c;
} }