summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2021-03-10 17:10:49 +0700
committerhathach <[email protected]>2021-03-10 17:10:49 +0700
commit794083b647d1e591fcdba441da56b6f7646ae573 (patch)
tree040c54a46afd2f347fc8a474b17d881de3280eb7 /src
parentde1f36f2b02b00d8012748be304186e1eb78c728 (diff)
parentf9817da397d9e24801bb1b7e2b8ed0ddcef36d62 (diff)
Merge branch 'master' into edpt_ISO_xfer
Diffstat (limited to 'src')
-rw-r--r--src/class/cdc/cdc_device.c11
-rw-r--r--src/class/cdc/cdc_device.h3
-rw-r--r--src/class/midi/midi_device.c1
-rw-r--r--src/device/usbd.c41
-rw-r--r--src/device/usbd.h7
-rw-r--r--src/host/usbh.c2
-rw-r--r--src/osal/osal.h1
-rw-r--r--src/osal/osal_none.h9
-rw-r--r--src/osal/osal_pico.h4
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c103
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c21
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c40
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h24
13 files changed, 176 insertions, 91 deletions
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
index c679dc71e..18919c486 100644
--- a/src/class/cdc/cdc_device.c
+++ b/src/class/cdc/cdc_device.c
@@ -396,6 +396,17 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts);
}
break;
+ case CDC_REQUEST_SEND_BREAK:
+ if (stage == CONTROL_STAGE_SETUP)
+ {
+ tud_control_status(rhport, request);
+ }
+ else if (stage == CONTROL_STAGE_ACK)
+ {
+ TU_LOG2(" Send Break\r\n");
+ if ( tud_cdc_send_break_cb ) tud_cdc_send_break_cb(itf, request->wValue);
+ }
+ break;
default: return false; // stall unsupported request
}
diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h
index 62dcd3c0a..0885922c6 100644
--- a/src/class/cdc/cdc_device.h
+++ b/src/class/cdc/cdc_device.h
@@ -145,6 +145,9 @@ TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
// Invoked when line coding is change via SET_LINE_CODING
TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding);
+// Invoked when received send break
+TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms);
+
//--------------------------------------------------------------------+
// Inline Functions
//--------------------------------------------------------------------+
diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c
index c61bad17c..73536a8b0 100644
--- a/src/class/midi/midi_device.c
+++ b/src/class/midi/midi_device.c
@@ -387,6 +387,7 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint
p_midi->ep_out = ep_addr;
}
+ // Class Specific MIDI Stream endpoint descriptor
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
diff --git a/src/device/usbd.c b/src/device/usbd.c
index 1879729e8..8b126a9f6 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -699,13 +699,21 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// notable requests are: GET HID REPORT DESCRIPTOR, SET_INTERFACE, GET_INTERFACE
if ( !invoke_class_control(rhport, driver, p_request) )
{
- // For GET_INTERFACE, it is mandatory to respond even if the class
- // driver doesn't use alternate settings.
- TU_VERIFY( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type &&
- TUSB_REQ_GET_INTERFACE == p_request->bRequest);
+ // For GET_INTERFACE and SET_INTERFACE, it is mandatory to respond even if the class
+ // driver doesn't use alternate settings or implement this
+ TU_VERIFY(TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type);
- uint8_t alternate = 0;
- tud_control_xfer(rhport, p_request, &alternate, 1);
+ if (TUSB_REQ_GET_INTERFACE == p_request->bRequest)
+ {
+ uint8_t alternate = 0;
+ tud_control_xfer(rhport, p_request, &alternate, 1);
+ }else if (TUSB_REQ_SET_INTERFACE == p_request->bRequest)
+ {
+ tud_control_status(rhport, p_request);
+ } else
+ {
+ return false;
+ }
}
}
break;
@@ -992,11 +1000,15 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
switch (event->event_id)
{
case DCD_EVENT_UNPLUGGED:
- _usbd_dev.connected = 0;
- _usbd_dev.addressed = 0;
- _usbd_dev.cfg_num = 0;
- _usbd_dev.suspended = 0;
- osal_queue_send(_usbd_q, event, in_isr);
+ // UNPLUGGED event can be bouncing, only processing if we are currently connected
+ if ( _usbd_dev.connected )
+ {
+ _usbd_dev.connected = 0;
+ _usbd_dev.addressed = 0;
+ _usbd_dev.cfg_num = 0;
+ _usbd_dev.suspended = 0;
+ osal_queue_send(_usbd_q, event, in_isr);
+ }
break;
case DCD_EVENT_SOF:
@@ -1004,9 +1016,10 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
break;
case DCD_EVENT_SUSPEND:
- // NOTE: When plugging/unplugging device, the D+/D- state are unstable and can accidentally meet the
- // SUSPEND condition ( Idle for 3ms ). Some MCUs such as SAMD doesn't distinguish suspend vs disconnect as well.
- // We will skip handling SUSPEND/RESUME event if not currently connected
+ // NOTE: When plugging/unplugging device, the D+/D- state are unstable and
+ // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ).
+ // In addition, some MCUs such as SAMD or boards that haven no VBUS detection cannot distinguish
+ // suspended vs disconnected. We will skip handling SUSPEND/RESUME event if not currently connected
if ( _usbd_dev.connected )
{
_usbd_dev.suspended = 1;
diff --git a/src/device/usbd.h b/src/device/usbd.h
index b5f7dceba..56615b081 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -254,6 +254,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
//------------- MIDI -------------//
+// MIDI v1.0 is based on Audio v1.0
#define TUD_MIDI_DESC_HEAD_LEN (9 + 9 + 9 + 7)
#define TUD_MIDI_DESC_HEAD(_itfnum, _stridx, _numcables) \
@@ -289,10 +290,10 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* MS Out Jack (External), connected to In Jack Embedded */\
9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_OUT_EXT(_cablenum), 1, TUD_MIDI_JACKID_IN_EMB(_cablenum), 1, 0
-#define TUD_MIDI_DESC_EP_LEN(_numcables) (7 + 4 + (_numcables))
+#define TUD_MIDI_DESC_EP_LEN(_numcables) (9 + 4 + (_numcables))
#define TUD_MIDI_DESC_EP(_epout, _epsize, _numcables) \
- /* Endpoint */\
- 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+ /* Endpoint: Note Audio v1.0's endpoint has 9 bytes instead of 7 */\
+ 9, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0, 0, 0, \
/* MS Endpoint (connected to embedded jack) */\
(uint8_t)(4 + (_numcables)), TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, _numcables
diff --git a/src/host/usbh.c b/src/host/usbh.c
index 0bc6378b2..a4ee4cb5c 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -157,6 +157,7 @@ tusb_speed_t tuh_device_get_speed (uint8_t const dev_addr)
return (tusb_speed_t) _usbh_devices[dev_addr].speed;
}
+#if CFG_TUSB_OS == OPT_OS_NONE
void osal_task_delay(uint32_t msec)
{
(void) msec;
@@ -164,6 +165,7 @@ void osal_task_delay(uint32_t msec)
const uint32_t start = hcd_frame_number(TUH_OPT_RHPORT);
while ( ( hcd_frame_number(TUH_OPT_RHPORT) - start ) < msec ) {}
}
+#endif
//--------------------------------------------------------------------+
// CLASS-USBD API (don't require to verify parameters)
diff --git a/src/osal/osal.h b/src/osal/osal.h
index 02e3e0a06..28bdf479c 100644
--- a/src/osal/osal.h
+++ b/src/osal/osal.h
@@ -66,7 +66,6 @@ typedef void (*osal_task_func_t)( void * );
//--------------------------------------------------------------------+
// OSAL Porting API
//--------------------------------------------------------------------+
-//static inline void osal_task_delay(uint32_t msec);
//------------- Semaphore -------------//
static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h
index ea6818621..a1f997cf2 100644
--- a/src/osal/osal_none.h
+++ b/src/osal/osal_none.h
@@ -34,14 +34,7 @@
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
-//static inline void osal_task_delay(uint32_t msec)
-//{
-// (void) msec;
-// // TODO only used by Host stack, will implement using SOF
-//
-//// uint32_t start = tusb_hal_millis();
-//// while ( ( tusb_hal_millis() - start ) < msec ) {}
-//}
+
//--------------------------------------------------------------------+
// Binary Semaphore API
diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h
index de964a7a0..c277af271 100644
--- a/src/osal/osal_pico.h
+++ b/src/osal/osal_pico.h
@@ -39,12 +39,10 @@
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
-#ifndef RP2040_USB_HOST_MODE
static inline void osal_task_delay(uint32_t msec)
{
- sleep_ms(msec);
+ sleep_ms(msec);
}
-#endif
//--------------------------------------------------------------------+
// Binary Semaphore API
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index 95b0963a3..f844a0c65 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -48,23 +48,24 @@
// Init these in dcd_init
static uint8_t *next_buffer_ptr;
-// Endpoints 0-15, direction 0 for out and 1 for in.
-static struct hw_endpoint hw_endpoints[16][2] = {0};
+// USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
+static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2] = {0};
-static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, uint8_t in)
+static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
{
- return &hw_endpoints[num][in];
+ return &hw_endpoints[num][dir];
}
static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr)
{
uint8_t num = tu_edpt_number(ep_addr);
- uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0;
- return hw_endpoint_get_by_num(num, in);
+ tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ return hw_endpoint_get_by_num(num, dir);
}
+
static void _hw_endpoint_alloc(struct hw_endpoint *ep)
{
- uint size = TU_MIN(64, ep->wMaxPacketSize);
+ uint16_t size = tu_min16(64, ep->wMaxPacketSize);
// Assumes single buffered for now
ep->hw_data_buf = next_buffer_ptr;
@@ -99,15 +100,13 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep)
*ep->endpoint_control = reg;
}
-static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint wMaxPacketSize, uint8_t transfer_type)
+static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
{
- uint8_t num = tu_edpt_number(ep_addr);
- bool in = ep_addr & TUSB_DIR_IN_MASK;
+ const uint8_t num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
ep->ep_addr = ep_addr;
- ep->in = in;
// For device, IN is a tx transfer and OUT is an rx transfer
- ep->rx = in == false;
- ep->num = num;
+ ep->rx = (dir == TUSB_DIR_OUT);
// Response to a setup packet on EP0 starts with pid of 1
ep->next_pid = num == 0 ? 1u : 0u;
@@ -131,7 +130,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint wMax
ep->transfer_type = transfer_type;
// Every endpoint has a buffer control register in dpram
- if (ep->in)
+ if (dir == TUSB_DIR_IN)
{
ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
}
@@ -143,7 +142,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint wMax
// Clear existing buffer control state
*ep->buffer_control = 0;
- if (ep->num == 0)
+ if (num == 0)
{
// EP0 has no endpoint control register because
// the buffer offsets are fixed
@@ -155,7 +154,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint wMax
else
{
// Set the endpoint control register (starts at EP1, hence num-1)
- if (in)
+ if (dir == TUSB_DIR_IN)
{
ep->endpoint_control = &usb_dpram->ep_ctrl[num-1].in;
}
@@ -194,7 +193,7 @@ static void hw_endpoint_close(uint8_t ep_addr)
}
#endif
-static void hw_endpoint_init(uint8_t ep_addr, uint wMaxPacketSize, uint8_t bmAttributes)
+static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t bmAttributes)
{
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
_hw_endpoint_init(ep, ep_addr, wMaxPacketSize, bmAttributes);
@@ -259,10 +258,10 @@ static void ep0_0len_status(void)
static void _hw_endpoint_stall(struct hw_endpoint *ep)
{
assert(!ep->stalled);
- if (ep->num == 0)
+ if (tu_edpt_number(ep->ep_addr) == 0)
{
// A stall on EP0 has to be armed so it can be cleared on the next setup packet
- usb_hw_set->ep_stall_arm = ep->in ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
+ usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
}
_hw_endpoint_buffer_control_set_mask32(ep, USB_BUF_CTRL_STALL);
ep->stalled = true;
@@ -276,10 +275,10 @@ static void hw_endpoint_stall(uint8_t ep_addr)
static void _hw_endpoint_clear_stall(struct hw_endpoint *ep)
{
- if (ep->num == 0)
+ if (tu_edpt_number(ep->ep_addr) == 0)
{
// Probably already been cleared but no harm
- usb_hw_clear->ep_stall_arm = ep->in ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
+ usb_hw_clear->ep_stall_arm = (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
}
_hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL);
ep->stalled = false;
@@ -313,18 +312,67 @@ static void dcd_rp2040_irq(void)
hw_handle_buff_status();
}
+ // SE0 for 2 us or more, usually together with Bus Reset
+ if (status & USB_INTS_DEV_CONN_DIS_BITS)
+ {
+ handled |= USB_INTS_DEV_CONN_DIS_BITS;
+
+ if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS )
+ {
+ // Connected: nothing to do
+ }else
+ {
+ // Disconnected
+ dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
+ }
+
+ usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
+ }
+
+ // SE0 for 2.5 us or more
if (status & USB_INTS_BUS_RESET_BITS)
{
- pico_trace("BUS RESET (addr %d -> %d)\n", assigned_address, 0);
+ pico_trace("BUS RESET\n");
usb_hw->dev_addr_ctrl = 0;
handled |= USB_INTS_BUS_RESET_BITS;
- dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
+ dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
+
#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
- rp2040_usb_device_enumeration_fix();
+ // Only run enumeration walk-around if pull up is enabled
+ if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS )
+ {
+ rp2040_usb_device_enumeration_fix();
+ }
#endif
}
+#if 0
+ // TODO Enable SUSPEND & RESUME interrupt and test later on with/without VBUS detection
+
+ /* Note from pico datasheet 4.1.2.6.4 (v1.2)
+ * If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
+ * the device is first connected but the bus is idle. The bus can be idle for a few ms before
+ * the host begins sending start of frame packets. You will also see a suspend interrupt
+ * when the device is disconnected if you do not have a VBUS detect circuit connected. This is
+ * because without VBUS detection, it is impossible to tell the difference between
+ * being disconnected and suspended.
+ */
+ if (status & USB_INTS_DEV_SUSPEND_BITS)
+ {
+ handled |= USB_INTS_DEV_SUSPEND_BITS;
+ dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
+ usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
+ }
+
+ if (status & USB_INTS_DEV_RESUME_FROM_HOST_BITS)
+ {
+ handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
+ dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
+ usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
+ }
+#endif
+
if (status ^ handled)
{
panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
@@ -365,8 +413,10 @@ void dcd_init (uint8_t rhport)
// Enable individual controller IRQS here. Processor interrupt enable will be used
// for the global interrupt enable...
+ // TODO Enable SUSPEND & RESUME interrupt
usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS;
- usb_hw->inte = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS;
+ usb_hw->inte = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
+ USB_INTS_DEV_CONN_DIS_BITS /* | USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS */ ;
dcd_connect(rhport);
}
@@ -394,8 +444,9 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
void dcd_remote_wakeup(uint8_t rhport)
{
- pico_info("dcd_remote_wakeup %d is not supported yet\n", rhport);
+ pico_info("dcd_remote_wakeup %d\n", rhport);
assert(rhport == 0);
+ usb_hw_set->sie_ctrl = USB_SIE_CTRL_RESUME_BITS;
}
// disconnect by disabling internal pull-up resistor on D+/D-
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index efb2bd430..224f6ef21 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -291,14 +291,16 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
assert(ep->buffer_control);
assert(ep->hw_data_buf);
- uint8_t num = tu_edpt_number(ep_addr);
+ uint8_t const num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
+
bool in = ep_addr & TUSB_DIR_IN_MASK;
ep->ep_addr = ep_addr;
ep->dev_addr = dev_addr;
- ep->in = in;
+
// For host, IN to host == RX, anything else rx == false
- ep->rx = in == true;
- ep->num = num;
+ ep->rx = (dir == TUSB_DIR_IN);
+
// Response to a setup packet on EP0 starts with pid of 1
ep->next_pid = num == 0 ? 1u : 0u;
ep->wMaxPacketSize = wMaxPacketSize;
@@ -327,9 +329,9 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
// device address
// endpoint number / direction
// preamble
- uint32_t reg = dev_addr | (ep->num << USB_ADDR_ENDP1_ENDPOINT_LSB);
+ uint32_t reg = dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB);
// Assert the interrupt endpoint is IN_TO_HOST
- assert(ep->in);
+ assert(dir == TUSB_DIR_IN);
if (need_pre(dev_addr))
{
@@ -363,9 +365,10 @@ static void hw_endpoint_init(uint8_t dev_addr, const tusb_desc_endpoint_t *ep_de
//--------------------------------------------------------------------+
// HCD API
//--------------------------------------------------------------------+
-bool hcd_init(void)
+bool hcd_init(uint8_t rhport)
{
- pico_trace("hcd_init\n");
+ pico_trace("hcd_init %d\n", rhport);
+ assert(rhport == 0);
// Reset any previous state
rp2040_usb_init();
@@ -461,7 +464,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
if (ep == &epx) {
// That has set up buffer control, endpoint control etc
// for host we have to initiate the transfer
- usb_hw->dev_addr_ctrl = dev_addr | ep->num << USB_ADDR_ENDP_ENDPOINT_LSB;
+ usb_hw->dev_addr_ctrl = dev_addr | (tu_edpt_number(ep_addr) << USB_ADDR_ENDP_ENDPOINT_LSB);
uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | sie_ctrl_base;
flags |= ep->rx ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS;
// Set pre if we are a low speed device on full speed hub
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index 339297ad6..98ffea9a3 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -30,7 +30,6 @@
#include <stdlib.h>
#include "rp2040_usb.h"
-#include "hardware/clocks.h"
// Direction strings for debug
const char *ep_dir_string[] = {
@@ -44,10 +43,12 @@ static inline void _hw_endpoint_lock_update(struct hw_endpoint *ep, int delta) {
// sense to have worker and IRQ on same core, however I think using critsec is about equivalent.
}
+#if TUSB_OPT_HOST_ENABLED
static inline void _hw_endpoint_update_last_buf(struct hw_endpoint *ep)
{
ep->last_buf = ep->len + ep->transfer_size == ep->total_len;
}
+#endif
void rp2040_usb_init(void)
{
@@ -59,8 +60,11 @@ void rp2040_usb_init(void)
memset(usb_hw, 0, sizeof(*usb_hw));
memset(usb_dpram, 0, sizeof(*usb_dpram));
- // Mux to phy
+ // Mux the controller to the onboard usb phy
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
+
+ // Force VBUS detect so the device thinks it is plugged into a host
+ // TODO support VBUs detect
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
}
@@ -68,7 +72,9 @@ void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
{
ep->stalled = false;
ep->active = false;
+#if TUSB_OPT_HOST_ENABLED
ep->sent_setup = false;
+#endif
ep->total_len = 0;
ep->len = 0;
ep->transfer_size = 0;
@@ -84,12 +90,12 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m
value |= or_mask;
if (or_mask & USB_BUF_CTRL_AVAIL) {
if (*ep->buffer_control & USB_BUF_CTRL_AVAIL) {
- panic("ep %d %s was already available", ep->num, ep_dir_string[ep->in]);
+ panic("ep %d %s was already available", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
}
*ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL;
// 12 cycle delay.. (should be good for 48*12Mhz = 576Mhz)
// Don't need delay in host mode as host is in charge
-#ifndef RP2040_USB_HOST_MODE
+#if !TUSB_OPT_HOST_ENABLED
__asm volatile (
"b 1f\n"
"1: b 1f\n"
@@ -122,6 +128,7 @@ void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
val |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
ep->next_pid ^= 1u;
+#if TUSB_OPT_HOST_ENABLED
// Is this the last buffer? Only really matters for host mode. Will trigger
// the trans complete irq but also stop it polling. We only really care about
// trans complete for setup packets being sent
@@ -130,6 +137,7 @@ void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
pico_trace("Last buf (%d bytes left)\n", ep->transfer_size);
val |= USB_BUF_CTRL_LAST;
}
+#endif
// Finally, write to buffer_control which will trigger the transfer
// the next time the controller polls this dpram address
@@ -141,11 +149,11 @@ void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len)
{
_hw_endpoint_lock_update(ep, 1);
- pico_trace("Start transfer of total len %d on ep %d %s\n", total_len, ep->num, ep_dir_string[ep->in]);
+ pico_trace("Start transfer of total len %d on ep %d %s\n", total_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
if (ep->active)
{
// TODO: Is this acceptable for interrupt packets?
- pico_warn("WARN: starting new transfer on already active ep %d %s\n", ep->num, ep_dir_string[ep->in]);
+ pico_warn("WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
hw_endpoint_reset_transfer(ep);
}
@@ -153,12 +161,14 @@ void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t t
// Fill in info now that we're kicking off the hw
ep->total_len = total_len;
ep->len = 0;
- ep->transfer_size = tu_min32(total_len, ep->wMaxPacketSize);
+ ep->transfer_size = tu_min16(total_len, ep->wMaxPacketSize);
ep->active = true;
ep->user_buf = buffer;
+#if TUSB_OPT_HOST_ENABLED
// Recalculate if this is the last buffer
_hw_endpoint_update_last_buf(ep);
ep->buf_sel = 0;
+#endif
_hw_endpoint_start_next_buffer(ep);
_hw_endpoint_lock_update(ep, -1);
@@ -172,9 +182,9 @@ void _hw_endpoint_xfer_sync(struct hw_endpoint *ep)
// Get the buffer state and amount of bytes we have
// transferred
uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
- uint transferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
+ uint16_t transferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
-#ifdef RP2040_USB_HOST_MODE
+#if TUSB_OPT_HOST_ENABLED
// tag::host_buf_sel_fix[]
if (ep->buf_sel == 1)
{
@@ -223,16 +233,18 @@ bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep)
// Part way through a transfer
if (!ep->active)
{
- panic("Can't continue xfer on inactive ep %d %s", ep->num, ep_dir_string);
+ panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string);
}
// Update EP struct from hardware state
_hw_endpoint_xfer_sync(ep);
// Now we have synced our state with the hardware. Is there more data to transfer?
- uint remaining_bytes = ep->total_len - ep->len;
- ep->transfer_size = tu_min32(remaining_bytes, ep->wMaxPacketSize);
+ uint16_t remaining_bytes = ep->total_len - ep->len;
+ ep->transfer_size = tu_min16(remaining_bytes, ep->wMaxPacketSize);
+#if TUSB_OPT_HOST_ENABLED
_hw_endpoint_update_last_buf(ep);
+#endif
// Can happen because of programmer error so check for it
if (ep->len > ep->total_len)
@@ -244,7 +256,7 @@ bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep)
if (ep->len == ep->total_len)
{
pico_trace("Completed transfer of %d bytes on ep %d %s\n",
- ep->len, ep->num, ep_dir_string[ep->in]);
+ ep->len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
// Notify caller we are done so it can notify the tinyusb
// stack
_hw_endpoint_lock_update(ep, -1);
@@ -263,7 +275,7 @@ bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep)
void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start)
{
// Trace
- pico_trace("hw_endpoint_xfer ep %d %s", ep->num, ep_dir_string[ep->in]);
+ pico_trace("hw_endpoint_xfer ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
pico_trace(" total_len %d, start=%d\n", total_len, start);
assert(ep->configured);
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index 7c3234e8d..bb88d977f 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -42,10 +42,6 @@ struct hw_endpoint
{
// Is this a valid struct
bool configured;
- // EP direction
- bool in;
- // EP num (not including direction)
- uint8_t num;
// Transfer direction (i.e. IN is rx for host but tx for device)
// allows us to common up transfer functions
@@ -67,28 +63,30 @@ struct hw_endpoint
// Current transfer information
bool active;
- uint total_len;
- uint len;
+ uint16_t total_len;
+ uint16_t len;
// Amount of data with the hardware
- uint transfer_size;
- // Only needed for host mode
- bool last_buf;
- // HOST BUG. Host will incorrect write status to top half of buffer
- // control register when doing transfers > 1 packet
- uint8_t buf_sel;
+ uint16_t transfer_size;
// User buffer in main memory
uint8_t *user_buf;
// Data needed from EP descriptor
- uint wMaxPacketSize;
+ uint16_t wMaxPacketSize;
// Interrupt, bulk, etc
uint8_t transfer_type;
+#if TUSB_OPT_HOST_ENABLED
+ // Only needed for host mode
+ bool last_buf;
+ // HOST BUG. Host will incorrect write status to top half of buffer
+ // control register when doing transfers > 1 packet
+ uint8_t buf_sel;
// Only needed for host
uint8_t dev_addr;
bool sent_setup;
// If interrupt endpoint
uint8_t interrupt_num;
+#endif
};
void rp2040_usb_init(void);