diff options
| author | hathach <[email protected]> | 2021-03-10 17:10:49 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2021-03-10 17:10:49 +0700 |
| commit | 794083b647d1e591fcdba441da56b6f7646ae573 (patch) | |
| tree | 040c54a46afd2f347fc8a474b17d881de3280eb7 /src | |
| parent | de1f36f2b02b00d8012748be304186e1eb78c728 (diff) | |
| parent | f9817da397d9e24801bb1b7e2b8ed0ddcef36d62 (diff) | |
Merge branch 'master' into edpt_ISO_xfer
Diffstat (limited to 'src')
| -rw-r--r-- | src/class/cdc/cdc_device.c | 11 | ||||
| -rw-r--r-- | src/class/cdc/cdc_device.h | 3 | ||||
| -rw-r--r-- | src/class/midi/midi_device.c | 1 | ||||
| -rw-r--r-- | src/device/usbd.c | 41 | ||||
| -rw-r--r-- | src/device/usbd.h | 7 | ||||
| -rw-r--r-- | src/host/usbh.c | 2 | ||||
| -rw-r--r-- | src/osal/osal.h | 1 | ||||
| -rw-r--r-- | src/osal/osal_none.h | 9 | ||||
| -rw-r--r-- | src/osal/osal_pico.h | 4 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/dcd_rp2040.c | 103 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/hcd_rp2040.c | 21 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/rp2040_usb.c | 40 | ||||
| -rw-r--r-- | src/portable/raspberrypi/rp2040/rp2040_usb.h | 24 |
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); |
