mirror of
https://github.com/hathach/tinyusb.git
synced 2025-03-30 22:20:17 +00:00
portable: fomu: get msc to enumerate
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
ba889eeb9e
commit
32bb68409e
@ -41,105 +41,130 @@ void mputln(const char *str);
|
|||||||
// SIE Command
|
// SIE Command
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
static uint8_t volatile out_buffer_length[16];
|
#define EP_SIZE 64
|
||||||
static uint8_t volatile * out_buffer[16];
|
|
||||||
static uint8_t volatile out_buffer_max[16];
|
static uint16_t volatile rx_buffer_length[16];
|
||||||
|
static uint8_t volatile * rx_buffer[16];
|
||||||
|
static uint16_t volatile rx_buffer_max[16];
|
||||||
|
|
||||||
static volatile bool tx_in_progress;
|
static volatile bool tx_in_progress;
|
||||||
static volatile uint8_t tx_ep;
|
static volatile uint8_t tx_ep;
|
||||||
static volatile uint16_t tx_len;
|
static volatile uint16_t tx_len;
|
||||||
|
static uint8_t volatile * tx_buffer;
|
||||||
|
static volatile uint16_t tx_offset;
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// PIPE HELPER
|
// PIPE HELPER
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
static void finish_tx(void) {
|
static void finish_tx(void) {
|
||||||
// // Don't allow requeueing -- only queue more data if the system is idle.
|
// Don't send empty data
|
||||||
// if (!(usb_in_status_read() & 2)) {
|
if (!tx_in_progress) {
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Don't send empty data
|
|
||||||
if (!tx_in_progress) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
tx_offset += EP_SIZE;
|
||||||
|
if (tx_offset >= tx_len) {
|
||||||
tx_in_progress = 0;
|
tx_in_progress = 0;
|
||||||
|
tx_buffer = NULL;
|
||||||
dcd_event_xfer_complete(0, tx_ep, tx_len, XFER_RESULT_SUCCESS, true);
|
dcd_event_xfer_complete(0, tx_ep, tx_len, XFER_RESULT_SUCCESS, true);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send more data
|
||||||
|
uint8_t added_bytes;
|
||||||
|
for (added_bytes = 0; (added_bytes < EP_SIZE) && (added_bytes + tx_offset < tx_len); added_bytes++) {
|
||||||
|
usb_in_data_write(tx_buffer[added_bytes + tx_offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updating the epno queues the data
|
||||||
|
usb_in_ctrl_write(tu_edpt_number(tx_ep) & 0xf);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_rx(bool in_isr) {
|
static void process_rx(bool in_isr) {
|
||||||
// If there isn't any data in the FIFO, don't do anything.
|
// If there isn't any data in the FIFO, don't do anything.
|
||||||
if (!(usb_out_status_read() & 1))
|
if (!(usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
uint8_t out_ep = (usb_out_status_read() >> CSR_USB_OUT_STATUS_EPNO_OFFSET) & 0xf;
|
||||||
|
|
||||||
|
// If the destination buffer doesn't exist, don't drain the hardware
|
||||||
|
// fifo. Note that this can cause deadlocks if the host is waiting
|
||||||
|
// on some other endpoint's data!
|
||||||
|
if (rx_buffer[out_ep] == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
uint8_t out_ep = (usb_out_status_read() >> 2) & 0xf;
|
|
||||||
uint32_t total_read = 0;
|
uint32_t total_read = 0;
|
||||||
uint32_t current_offset = out_buffer_length[out_ep];
|
uint32_t current_offset = rx_buffer_length[out_ep];
|
||||||
while (usb_out_status_read() & 1) {
|
while (usb_out_status_read() & (1 << CSR_USB_OUT_STATUS_HAVE_OFFSET)) {
|
||||||
uint8_t c = usb_out_data_read();
|
uint8_t c = usb_out_data_read();
|
||||||
total_read++;
|
total_read++;
|
||||||
if (out_buffer_length[out_ep] < out_buffer_max[out_ep])
|
if (rx_buffer_length[out_ep] < rx_buffer_max[out_ep])
|
||||||
out_buffer[out_ep][current_offset++] = c;
|
rx_buffer[out_ep][current_offset++] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip off the CRC16
|
// Strip off the CRC16
|
||||||
total_read -= 2;
|
rx_buffer_length[out_ep] += (total_read - 2);
|
||||||
out_buffer_length[out_ep] += total_read;
|
if (rx_buffer_length[out_ep] > rx_buffer_max[out_ep])
|
||||||
if (out_buffer_length[out_ep] > out_buffer_max[out_ep])
|
rx_buffer_length[out_ep] = rx_buffer_max[out_ep];
|
||||||
out_buffer_length[out_ep] = out_buffer_max[out_ep];
|
|
||||||
|
|
||||||
if (out_buffer_max[out_ep] == out_buffer_length[out_ep]) {
|
if (rx_buffer_max[out_ep] == rx_buffer_length[out_ep]) {
|
||||||
out_buffer[out_ep] = NULL;
|
rx_buffer[out_ep] = NULL;
|
||||||
dcd_event_xfer_complete(0, tu_edpt_addr(out_ep, TUSB_DIR_OUT), out_buffer_length[out_ep], XFER_RESULT_SUCCESS, in_isr);
|
uint16_t len = rx_buffer_length[out_ep];
|
||||||
|
dcd_event_xfer_complete(0, tu_edpt_addr(out_ep, TUSB_DIR_OUT), len, XFER_RESULT_SUCCESS, in_isr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acknowledge having received the data
|
// Acknowledge having received the data, and re-enable data reception
|
||||||
usb_out_ctrl_write(2);
|
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// CONTROLLER API
|
// CONTROLLER API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
static void dcd_reset(void)
|
||||||
|
{
|
||||||
|
usb_address_write(0);
|
||||||
|
|
||||||
|
// Reset all three FIFO handlers
|
||||||
|
usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_RESET_OFFSET);
|
||||||
|
usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET);
|
||||||
|
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET);
|
||||||
|
|
||||||
|
// Accept incoming data by default.
|
||||||
|
usb_out_ctrl_write(CSR_USB_OUT_CTRL_ENABLE_OFFSET);
|
||||||
|
|
||||||
|
memset(rx_buffer, 0, sizeof(rx_buffer));
|
||||||
|
tx_in_progress = 0;
|
||||||
|
tx_len = 0;
|
||||||
|
tx_buffer = NULL;
|
||||||
|
tx_offset = 0;
|
||||||
|
|
||||||
|
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
|
||||||
|
}
|
||||||
|
|
||||||
// Initializes the USB peripheral for device mode and enables it.
|
// Initializes the USB peripheral for device mode and enables it.
|
||||||
void dcd_init(uint8_t rhport)
|
void dcd_init(uint8_t rhport)
|
||||||
{
|
{
|
||||||
(void) rhport;
|
(void) rhport;
|
||||||
|
|
||||||
usb_pullup_out_write(0);
|
usb_pullup_out_write(0);
|
||||||
usb_address_write(0);
|
|
||||||
usb_out_ctrl_write(0);
|
|
||||||
|
|
||||||
usb_setup_ev_enable_write(0);
|
usb_setup_ev_enable_write(0);
|
||||||
usb_in_ev_enable_write(0);
|
usb_in_ev_enable_write(0);
|
||||||
usb_out_ev_enable_write(0);
|
usb_out_ev_enable_write(0);
|
||||||
|
|
||||||
// Reset the IN handler
|
|
||||||
usb_in_ctrl_write(0x20);
|
|
||||||
|
|
||||||
// Reset the SETUP handler
|
|
||||||
usb_setup_ctrl_write(0x04);
|
|
||||||
|
|
||||||
// Reset the OUT handler
|
|
||||||
usb_out_ctrl_write(0x04);
|
|
||||||
|
|
||||||
// Enable all event handlers and clear their contents
|
// Enable all event handlers and clear their contents
|
||||||
usb_setup_ev_pending_write(usb_setup_ev_pending_read());
|
usb_setup_ev_pending_write(usb_setup_ev_pending_read());
|
||||||
usb_in_ev_pending_write(usb_in_ev_pending_read());
|
usb_in_ev_pending_write(usb_in_ev_pending_read());
|
||||||
usb_out_ev_pending_write(usb_out_ev_pending_read());
|
usb_out_ev_pending_write(usb_out_ev_pending_read());
|
||||||
usb_setup_ev_enable_write(3);
|
|
||||||
usb_in_ev_enable_write(1);
|
usb_in_ev_enable_write(1);
|
||||||
usb_out_ev_enable_write(1);
|
usb_out_ev_enable_write(1);
|
||||||
|
usb_setup_ev_enable_write(3);
|
||||||
// Accept incoming data by default.
|
|
||||||
usb_out_ctrl_write(2);
|
|
||||||
|
|
||||||
// Turn on the external pullup
|
// Turn on the external pullup
|
||||||
usb_pullup_out_write(1);
|
usb_pullup_out_write(1);
|
||||||
|
|
||||||
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enables or disables the USB device interrupt(s). May be used to
|
// Enables or disables the USB device interrupt(s). May be used to
|
||||||
@ -222,36 +247,45 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t
|
|||||||
{
|
{
|
||||||
(void)rhport;
|
(void)rhport;
|
||||||
|
|
||||||
|
// These sorts of transfers are handled in hardware
|
||||||
|
if ((tu_edpt_number(ep_addr) == 0) && (total_bytes == 0) && (buffer == NULL)) {
|
||||||
|
dcd_event_xfer_complete(0, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false);
|
||||||
|
|
||||||
|
// An IN packet is sent to acknowledge an OUT token. Re-enable OUT after this.
|
||||||
|
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN)
|
||||||
|
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_ENABLE_OFFSET);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
|
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
|
||||||
// These sorts of transfers are handled in hardware
|
|
||||||
if ((tu_edpt_number(ep_addr) == 0) && (total_bytes == 0) && (buffer == 0)) {
|
|
||||||
dcd_event_xfer_complete(0, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
|
|
||||||
// Wait for the tx pipe to free up
|
// Wait for the tx pipe to free up
|
||||||
while (tx_in_progress)
|
while (tx_in_progress)
|
||||||
;
|
;
|
||||||
tx_in_progress = 1;
|
tx_in_progress = 1;
|
||||||
tx_ep = ep_addr;
|
tx_ep = ep_addr;
|
||||||
tx_len = total_bytes;
|
tx_len = total_bytes;
|
||||||
|
tx_buffer = buffer;
|
||||||
|
tx_offset = 0;
|
||||||
|
|
||||||
for (offset = 0; offset < total_bytes; offset++) {
|
for (offset = 0; (offset < EP_SIZE) && (offset < total_bytes); offset++) {
|
||||||
usb_in_data_write(buffer[offset]);
|
usb_in_data_write(buffer[offset]);
|
||||||
}
|
}
|
||||||
// Updating the epno queues the data
|
// Updating the epno queues the data
|
||||||
usb_in_ctrl_write(tu_edpt_number(ep_addr) & 0xf);
|
usb_in_ctrl_write(tu_edpt_number(ep_addr) & 0xf);
|
||||||
last_tx_buffer = buffer;
|
|
||||||
last_tx_bytes = total_bytes;
|
|
||||||
}
|
}
|
||||||
else if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) {
|
else if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) {
|
||||||
|
TU_ASSERT(rx_buffer[tu_edpt_number(ep_addr)] == NULL);
|
||||||
|
|
||||||
// Wait for the rx pipe to free up
|
rx_buffer_length[tu_edpt_number(ep_addr)] = 0;
|
||||||
while (out_buffer[tu_edpt_number(ep_addr)])
|
rx_buffer_max[tu_edpt_number(ep_addr)] = total_bytes;
|
||||||
;
|
rx_buffer[tu_edpt_number(ep_addr)] = buffer;
|
||||||
out_buffer_max[tu_edpt_number(ep_addr)] = total_bytes;
|
|
||||||
out_buffer[tu_edpt_number(ep_addr)] = buffer;
|
// If there's data in the buffer already, we'll try draining it
|
||||||
out_buffer_length[tu_edpt_number(ep_addr)] = 0;
|
// into the current fifo immediately. Note that since this
|
||||||
|
// bit is set, an interrupt won't fire again, so there is
|
||||||
|
// no need for a lock here.
|
||||||
process_rx(false);
|
process_rx(false);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -273,11 +307,7 @@ void hal_dcd_isr(uint8_t rhport)
|
|||||||
// This event means a bus reset occurred. Reset everything, and
|
// This event means a bus reset occurred. Reset everything, and
|
||||||
// abandon any further processing.
|
// abandon any further processing.
|
||||||
if (setup_pending & 2) {
|
if (setup_pending & 2) {
|
||||||
usb_setup_ctrl_write(1 << CSR_USB_SETUP_CTRL_RESET_OFFSET);
|
dcd_reset();
|
||||||
usb_in_ctrl_write(1 << CSR_USB_IN_CTRL_RESET_OFFSET);
|
|
||||||
usb_out_ctrl_write(1 << CSR_USB_OUT_CTRL_RESET_OFFSET);
|
|
||||||
|
|
||||||
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user