2021-01-20 02:52:07 +01:00
/*
* The MIT License ( MIT )
*
* Copyright ( c ) 2020 Raspberry Pi ( Trading ) Ltd .
2021-06-11 13:26:41 +02:00
* Copyright ( c ) 2021 Ha Thach ( tinyusb . org ) for Double Buffered
2021-01-20 02:52:07 +01:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*
* This file is part of the TinyUSB stack .
*/
# include "tusb_option.h"
2022-03-02 06:22:20 +01:00
# if CFG_TUH_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUH_RPI_PIO_USB
2021-01-20 02:52:07 +01:00
# include "pico.h"
# include "rp2040_usb.h"
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
# include "osal/osal.h"
# include "host/hcd.h"
# include "host/usbh.h"
2022-03-01 17:55:53 +01:00
// port 0 is native USB port, other is counted as software PIO
# define RHPORT_NATIVE 0
2021-01-20 02:52:07 +01:00
//--------------------------------------------------------------------+
// Low level rp2040 controller functions
//--------------------------------------------------------------------+
# ifndef PICO_USB_HOST_INTERRUPT_ENDPOINTS
# define PICO_USB_HOST_INTERRUPT_ENDPOINTS (USB_MAX_ENDPOINTS - 1)
# endif
static_assert ( PICO_USB_HOST_INTERRUPT_ENDPOINTS < = USB_MAX_ENDPOINTS , " " ) ;
// Host mode uses one shared endpoint register for non-interrupt endpoint
2021-06-10 17:00:59 +02:00
static struct hw_endpoint ep_pool [ 1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS ] ;
# define epx (ep_pool[0])
2021-01-20 02:52:07 +01:00
2021-06-10 17:00:59 +02:00
# define usb_hw_set hw_set_alias(usb_hw)
2021-01-20 02:52:07 +01:00
# define usb_hw_clear hw_clear_alias(usb_hw)
// Flags we set by default in sie_ctrl (we add other bits on top)
2021-06-10 17:00:59 +02:00
enum {
2021-08-11 15:06:57 +02:00
SIE_CTRL_BASE = USB_SIE_CTRL_SOF_EN_BITS | USB_SIE_CTRL_KEEP_ALIVE_EN_BITS |
USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS
2021-06-10 17:00:59 +02:00
} ;
2021-01-20 02:52:07 +01:00
static struct hw_endpoint * get_dev_ep ( uint8_t dev_addr , uint8_t ep_addr )
{
2021-06-13 08:18:32 +02:00
uint8_t num = tu_edpt_number ( ep_addr ) ;
if ( num = = 0 ) return & epx ;
2021-06-10 17:00:59 +02:00
2021-06-13 08:18:32 +02:00
for ( uint32_t i = 1 ; i < TU_ARRAY_SIZE ( ep_pool ) ; i + + )
{
struct hw_endpoint * ep = & ep_pool [ i ] ;
if ( ep - > configured & & ( ep - > dev_addr = = dev_addr ) & & ( ep - > ep_addr = = ep_addr ) ) return ep ;
}
2021-06-10 17:00:59 +02:00
2021-06-13 08:18:32 +02:00
return NULL ;
2021-01-20 02:52:07 +01:00
}
static inline uint8_t dev_speed ( void )
{
return ( usb_hw - > sie_status & USB_SIE_STATUS_SPEED_BITS ) > > USB_SIE_STATUS_SPEED_LSB ;
}
static bool need_pre ( uint8_t dev_addr )
{
// If this device is different to the speed of the root device
// (i.e. is a low speed device on a full speed hub) then need pre
2021-08-24 07:30:57 +02:00
return hcd_port_speed_get ( 0 ) ! = tuh_speed_get ( dev_addr ) ;
2021-01-20 02:52:07 +01:00
}
static void hw_xfer_complete ( struct hw_endpoint * ep , xfer_result_t xfer_result )
{
// Mark transfer as done before we tell the tinyusb stack
uint8_t dev_addr = ep - > dev_addr ;
uint8_t ep_addr = ep - > ep_addr ;
2021-06-11 12:58:29 +02:00
uint xferred_len = ep - > xferred_len ;
2021-01-20 02:52:07 +01:00
hw_endpoint_reset_transfer ( ep ) ;
2021-06-11 12:05:49 +02:00
hcd_event_xfer_complete ( dev_addr , ep_addr , xferred_len , xfer_result , true ) ;
2021-01-20 02:52:07 +01:00
}
static void _handle_buff_status_bit ( uint bit , struct hw_endpoint * ep )
{
usb_hw_clear - > buf_status = bit ;
2021-06-11 12:34:51 +02:00
bool done = hw_endpoint_xfer_continue ( ep ) ;
2021-01-20 02:52:07 +01:00
if ( done )
{
hw_xfer_complete ( ep , XFER_RESULT_SUCCESS ) ;
}
}
static void hw_handle_buff_status ( void )
{
uint32_t remaining_buffers = usb_hw - > buf_status ;
pico_trace ( " buf_status 0x%08x \n " , remaining_buffers ) ;
// Check EPX first
uint bit = 0 b1 ;
if ( remaining_buffers & bit )
{
remaining_buffers & = ~ bit ;
struct hw_endpoint * ep = & epx ;
2021-06-11 12:05:49 +02:00
uint32_t ep_ctrl = * ep - > endpoint_control ;
if ( ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS )
{
2021-06-11 13:53:56 +02:00
TU_LOG ( 3 , " Double Buffered: " ) ;
2021-06-11 12:05:49 +02:00
} else
{
2021-06-11 13:53:56 +02:00
TU_LOG ( 3 , " Single Buffered: " ) ;
2021-06-11 12:05:49 +02:00
}
2021-06-11 13:53:56 +02:00
TU_LOG_HEX ( 3 , ep_ctrl ) ;
2021-06-11 12:05:49 +02:00
2021-01-20 02:52:07 +01:00
_handle_buff_status_bit ( bit , ep ) ;
}
// Check interrupt endpoints
for ( uint i = 1 ; i < = USB_HOST_INTERRUPT_ENDPOINTS & & remaining_buffers ; i + + )
{
// EPX is bit 0
// IEP1 is bit 2
// IEP2 is bit 4
// IEP3 is bit 6
// etc
bit = 1 < < ( i * 2 ) ;
if ( remaining_buffers & bit )
{
remaining_buffers & = ~ bit ;
2021-06-10 17:00:59 +02:00
_handle_buff_status_bit ( bit , & ep_pool [ i ] ) ;
2021-01-20 02:52:07 +01:00
}
}
if ( remaining_buffers )
{
panic ( " Unhandled buffer %d \n " , remaining_buffers ) ;
}
}
static void hw_trans_complete ( void )
{
2021-06-13 10:27:20 +02:00
if ( usb_hw - > sie_ctrl & USB_SIE_CTRL_SEND_SETUP_BITS )
{
pico_trace ( " Sent setup packet \n " ) ;
2021-11-05 10:39:31 +01:00
struct hw_endpoint * ep = & epx ;
assert ( ep - > active ) ;
2021-06-13 10:27:20 +02:00
hw_xfer_complete ( ep , XFER_RESULT_SUCCESS ) ;
}
else
{
// Don't care. Will handle this in buff status
return ;
}
2021-01-20 02:52:07 +01:00
}
static void hcd_rp2040_irq ( void )
{
uint32_t status = usb_hw - > ints ;
uint32_t handled = 0 ;
if ( status & USB_INTS_HOST_CONN_DIS_BITS )
{
handled | = USB_INTS_HOST_CONN_DIS_BITS ;
if ( dev_speed ( ) )
{
2022-03-01 17:55:53 +01:00
hcd_event_device_attach ( RHPORT_NATIVE , true ) ;
2021-01-20 02:52:07 +01:00
}
else
{
2022-03-01 17:55:53 +01:00
hcd_event_device_remove ( RHPORT_NATIVE , true ) ;
2021-01-20 02:52:07 +01:00
}
// Clear speed change interrupt
usb_hw_clear - > sie_status = USB_SIE_STATUS_SPEED_BITS ;
}
2021-06-11 13:26:41 +02:00
if ( status & USB_INTS_BUFF_STATUS_BITS )
{
handled | = USB_INTS_BUFF_STATUS_BITS ;
TU_LOG ( 2 , " Buffer complete \n " ) ;
hw_handle_buff_status ( ) ;
}
2021-01-20 02:52:07 +01:00
if ( status & USB_INTS_TRANS_COMPLETE_BITS )
{
handled | = USB_INTS_TRANS_COMPLETE_BITS ;
usb_hw_clear - > sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS ;
2021-06-10 17:00:59 +02:00
TU_LOG ( 2 , " Transfer complete \n " ) ;
2021-01-20 02:52:07 +01:00
hw_trans_complete ( ) ;
}
if ( status & USB_INTS_STALL_BITS )
{
// We have rx'd a stall from the device
pico_trace ( " Stall REC \n " ) ;
handled | = USB_INTS_STALL_BITS ;
usb_hw_clear - > sie_status = USB_SIE_STATUS_STALL_REC_BITS ;
hw_xfer_complete ( & epx , XFER_RESULT_STALLED ) ;
}
if ( status & USB_INTS_ERROR_RX_TIMEOUT_BITS )
{
handled | = USB_INTS_ERROR_RX_TIMEOUT_BITS ;
usb_hw_clear - > sie_status = USB_SIE_STATUS_RX_TIMEOUT_BITS ;
}
if ( status & USB_INTS_ERROR_DATA_SEQ_BITS )
{
usb_hw_clear - > sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS ;
2021-09-01 11:52:27 +02:00
TU_LOG ( 3 , " Seq Error: [0] = 0x%04u [1] = 0x%04x \r \n " , tu_u32_low16 ( * epx . buffer_control ) , tu_u32_high16 ( * epx . buffer_control ) ) ;
2021-01-20 02:52:07 +01:00
panic ( " Data Seq Error \n " ) ;
}
if ( status ^ handled )
{
panic ( " Unhandled IRQ 0x%x \n " , ( uint ) ( status ^ handled ) ) ;
}
}
static struct hw_endpoint * _next_free_interrupt_ep ( void )
{
struct hw_endpoint * ep = NULL ;
2021-06-10 17:00:59 +02:00
for ( uint i = 1 ; i < TU_ARRAY_SIZE ( ep_pool ) ; i + + )
2021-01-20 02:52:07 +01:00
{
2021-06-10 17:00:59 +02:00
ep = & ep_pool [ i ] ;
2021-01-20 02:52:07 +01:00
if ( ! ep - > configured )
{
// Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
ep - > interrupt_num = i - 1 ;
return ep ;
}
}
return ep ;
}
static struct hw_endpoint * _hw_endpoint_allocate ( uint8_t transfer_type )
{
struct hw_endpoint * ep = NULL ;
2021-06-10 17:00:59 +02:00
2021-01-20 02:52:07 +01:00
if ( transfer_type = = TUSB_XFER_INTERRUPT )
{
ep = _next_free_interrupt_ep ( ) ;
pico_info ( " Allocate interrupt ep %d \n " , ep - > interrupt_num ) ;
assert ( ep ) ;
ep - > buffer_control = & usbh_dpram - > int_ep_buffer_ctrl [ ep - > interrupt_num ] . ctrl ;
ep - > endpoint_control = & usbh_dpram - > int_ep_ctrl [ ep - > interrupt_num ] . ctrl ;
2021-06-11 12:05:49 +02:00
// 0 for epx (double buffered): TODO increase to 1024 for ISO
// 2x64 for intep0
// 3x64 for intep1
2021-01-20 02:52:07 +01:00
// etc
2021-06-11 12:05:49 +02:00
ep - > hw_data_buf = & usbh_dpram - > epx_data [ 64 * ( ep - > interrupt_num + 2 ) ] ;
2021-01-20 02:52:07 +01:00
}
else
{
ep = & epx ;
ep - > buffer_control = & usbh_dpram - > epx_buf_ctrl ;
ep - > endpoint_control = & usbh_dpram - > epx_ctrl ;
ep - > hw_data_buf = & usbh_dpram - > epx_data [ 0 ] ;
}
2021-06-10 17:00:59 +02:00
2021-01-20 02:52:07 +01:00
return ep ;
}
static void _hw_endpoint_init ( struct hw_endpoint * ep , uint8_t dev_addr , uint8_t ep_addr , uint wMaxPacketSize , uint8_t transfer_type , uint8_t bmInterval )
{
// Already has data buffer, endpoint control, and buffer control allocated at this point
assert ( ep - > endpoint_control ) ;
assert ( ep - > buffer_control ) ;
assert ( ep - > hw_data_buf ) ;
2021-03-02 08:54:12 +01:00
uint8_t const num = tu_edpt_number ( ep_addr ) ;
tusb_dir_t const dir = tu_edpt_dir ( ep_addr ) ;
2021-01-20 02:52:07 +01:00
ep - > ep_addr = ep_addr ;
ep - > dev_addr = dev_addr ;
2021-03-02 08:54:12 +01:00
2021-01-20 02:52:07 +01:00
// For host, IN to host == RX, anything else rx == false
2021-03-02 08:54:12 +01:00
ep - > rx = ( dir = = TUSB_DIR_IN ) ;
2021-01-20 02:52:07 +01:00
// Response to a setup packet on EP0 starts with pid of 1
2021-06-11 12:05:49 +02:00
ep - > next_pid = ( num = = 0 ? 1u : 0u ) ;
2021-01-20 02:52:07 +01:00
ep - > wMaxPacketSize = wMaxPacketSize ;
ep - > transfer_type = transfer_type ;
2021-05-10 16:09:09 +02:00
pico_trace ( " hw_endpoint_init dev %d ep %d %s xfer %d \n " , ep - > dev_addr , tu_edpt_number ( ep - > ep_addr ) , ep_dir_string [ tu_edpt_dir ( ep - > ep_addr ) ] , ep - > transfer_type ) ;
pico_trace ( " dev %d ep %d %s setup buffer @ 0x%p \n " , ep - > dev_addr , tu_edpt_number ( ep - > ep_addr ) , ep_dir_string [ tu_edpt_dir ( ep - > ep_addr ) ] , ep - > hw_data_buf ) ;
2021-01-20 02:52:07 +01:00
uint dpram_offset = hw_data_offset ( ep - > hw_data_buf ) ;
// Bits 0-5 should be 0
assert ( ! ( dpram_offset & 0 b111111 ) ) ;
// Fill in endpoint control register with buffer offset
uint32_t ep_reg = EP_CTRL_ENABLE_BITS
| EP_CTRL_INTERRUPT_PER_BUFFER
| ( ep - > transfer_type < < EP_CTRL_BUFFER_TYPE_LSB )
| dpram_offset ;
ep_reg | = bmInterval ? ( bmInterval - 1 ) < < EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB : 0 ;
* ep - > endpoint_control = ep_reg ;
pico_trace ( " endpoint control (0x%p) <- 0x%x \n " , ep - > endpoint_control , ep_reg ) ;
ep - > configured = true ;
if ( bmInterval )
{
// This is an interrupt endpoint
// so need to set up interrupt endpoint address control register with:
// device address
// endpoint number / direction
// preamble
2021-03-02 08:54:12 +01:00
uint32_t reg = dev_addr | ( num < < USB_ADDR_ENDP1_ENDPOINT_LSB ) ;
2022-02-23 13:25:01 +01:00
if ( dir = = TUSB_DIR_OUT )
{
reg | = USB_ADDR_ENDP1_INTEP_DIR_BITS ;
}
2021-01-20 02:52:07 +01:00
if ( need_pre ( dev_addr ) )
{
reg | = USB_ADDR_ENDP1_INTEP_PREAMBLE_BITS ;
}
usb_hw - > int_ep_addr_ctrl [ ep - > interrupt_num ] = reg ;
// Finally, enable interrupt that endpoint
usb_hw_set - > int_ep_ctrl = 1 < < ( ep - > interrupt_num + 1 ) ;
// If it's an interrupt endpoint we need to set up the buffer control
// register
}
}
//--------------------------------------------------------------------+
// HCD API
//--------------------------------------------------------------------+
2021-02-25 16:48:19 +01:00
bool hcd_init ( uint8_t rhport )
2021-01-20 02:52:07 +01:00
{
2021-02-25 16:48:19 +01:00
pico_trace ( " hcd_init %d \n " , rhport ) ;
assert ( rhport = = 0 ) ;
2021-01-20 02:52:07 +01:00
// Reset any previous state
rp2040_usb_init ( ) ;
2021-08-11 15:06:57 +02:00
// Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
usb_hw - > pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS ;
2021-01-20 02:52:07 +01:00
irq_set_exclusive_handler ( USBCTRL_IRQ , hcd_rp2040_irq ) ;
// clear epx and interrupt eps
2021-06-10 17:00:59 +02:00
memset ( & ep_pool , 0 , sizeof ( ep_pool ) ) ;
2021-01-20 02:52:07 +01:00
// Enable in host mode with SOF / Keep alive on
usb_hw - > main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS ;
2021-06-13 08:18:32 +02:00
usb_hw - > sie_ctrl = SIE_CTRL_BASE ;
2021-01-20 02:52:07 +01:00
usb_hw - > inte = USB_INTE_BUFF_STATUS_BITS |
USB_INTE_HOST_CONN_DIS_BITS |
USB_INTE_HOST_RESUME_BITS |
USB_INTE_STALL_BITS |
USB_INTE_TRANS_COMPLETE_BITS |
USB_INTE_ERROR_RX_TIMEOUT_BITS |
USB_INTE_ERROR_DATA_SEQ_BITS ;
return true ;
}
void hcd_port_reset ( uint8_t rhport )
{
pico_trace ( " hcd_port_reset \n " ) ;
assert ( rhport = = 0 ) ;
// TODO: Nothing to do here yet. Perhaps need to reset some state?
}
2022-03-02 06:33:47 +01:00
void hcd_port_reset_end ( uint8_t rhport )
{
( void ) rhport ;
}
2021-01-20 02:52:07 +01:00
bool hcd_port_connect_status ( uint8_t rhport )
{
pico_trace ( " hcd_port_connect_status \n " ) ;
assert ( rhport = = 0 ) ;
return usb_hw - > sie_status & USB_SIE_STATUS_SPEED_BITS ;
}
tusb_speed_t hcd_port_speed_get ( uint8_t rhport )
{
assert ( rhport = = 0 ) ;
// TODO: Should enumval this register
switch ( dev_speed ( ) )
{
case 1 :
return TUSB_SPEED_LOW ;
case 2 :
return TUSB_SPEED_FULL ;
default :
panic ( " Invalid speed \n " ) ;
2021-06-10 17:00:59 +02:00
return TUSB_SPEED_INVALID ;
2021-01-20 02:52:07 +01:00
}
}
// Close all opened endpoint belong to this device
void hcd_device_close ( uint8_t rhport , uint8_t dev_addr )
{
2021-11-30 11:36:52 +01:00
pico_trace ( " hcd_device_close %d \n " , dev_addr ) ;
( void ) rhport ;
2021-06-10 18:29:02 +02:00
2021-11-30 11:36:52 +01:00
if ( dev_addr = = 0 ) return ;
for ( size_t i = 1 ; i < TU_ARRAY_SIZE ( ep_pool ) ; i + + )
{
hw_endpoint_t * ep = & ep_pool [ i ] ;
if ( ep - > dev_addr = = dev_addr & & ep - > configured )
2021-11-12 23:58:51 +01:00
{
2021-11-30 11:36:52 +01:00
// in case it is an interrupt endpoint, disable it
usb_hw_clear - > int_ep_ctrl = ( 1 < < ( ep - > interrupt_num + 1 ) ) ;
usb_hw - > int_ep_addr_ctrl [ ep - > interrupt_num ] = 0 ;
// unconfigure the endpoint
ep - > configured = false ;
* ep - > endpoint_control = 0 ;
* ep - > buffer_control = 0 ;
hw_endpoint_reset_transfer ( ep ) ;
2021-11-12 23:58:51 +01:00
}
2021-11-30 11:36:52 +01:00
}
2021-01-20 02:52:07 +01:00
}
2021-06-10 18:29:02 +02:00
uint32_t hcd_frame_number ( uint8_t rhport )
{
( void ) rhport ;
return usb_hw - > sof_rd ;
}
2021-01-20 02:52:07 +01:00
void hcd_int_enable ( uint8_t rhport )
{
assert ( rhport = = 0 ) ;
irq_set_enabled ( USBCTRL_IRQ , true ) ;
}
void hcd_int_disable ( uint8_t rhport )
{
// todo we should check this is disabling from the correct core; note currently this is never called
assert ( rhport = = 0 ) ;
irq_set_enabled ( USBCTRL_IRQ , false ) ;
}
2021-06-11 12:05:49 +02:00
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
2021-06-10 18:29:02 +02:00
bool hcd_edpt_open ( uint8_t rhport , uint8_t dev_addr , tusb_desc_endpoint_t const * ep_desc )
{
( void ) rhport ;
pico_trace ( " hcd_edpt_open dev_addr %d, ep_addr %d \n " , dev_addr , ep_desc - > bEndpointAddress ) ;
// Allocated differently based on if it's an interrupt endpoint or not
struct hw_endpoint * ep = _hw_endpoint_allocate ( ep_desc - > bmAttributes . xfer ) ;
_hw_endpoint_init ( ep ,
dev_addr ,
ep_desc - > bEndpointAddress ,
2021-10-24 08:11:21 +02:00
tu_edpt_packet_size ( ep_desc ) ,
2021-06-10 18:29:02 +02:00
ep_desc - > bmAttributes . xfer ,
ep_desc - > bInterval ) ;
return true ;
}
2021-01-20 02:52:07 +01:00
bool hcd_edpt_xfer ( uint8_t rhport , uint8_t dev_addr , uint8_t ep_addr , uint8_t * buffer , uint16_t buflen )
{
2021-06-10 18:29:02 +02:00
( void ) rhport ;
2021-06-10 17:00:59 +02:00
pico_trace ( " hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d \n " , dev_addr , ep_addr , buflen ) ;
2021-01-20 02:52:07 +01:00
2021-06-10 18:29:02 +02:00
uint8_t const ep_num = tu_edpt_number ( ep_addr ) ;
tusb_dir_t const ep_dir = tu_edpt_dir ( ep_addr ) ;
2021-01-20 02:52:07 +01:00
// Get appropriate ep. Either EPX or interrupt endpoint
struct hw_endpoint * ep = get_dev_ep ( dev_addr , ep_addr ) ;
2021-01-24 03:19:10 +01:00
assert ( ep ) ;
2021-01-20 02:52:07 +01:00
2021-06-13 10:27:20 +02:00
// Control endpoint can change direction 0x00 <-> 0x80
if ( ep_addr ! = ep - > ep_addr )
2021-01-20 02:52:07 +01:00
{
2021-06-13 10:27:20 +02:00
assert ( ep_num = = 0 ) ;
// Direction has flipped on endpoint control so re init it but with same properties
_hw_endpoint_init ( ep , dev_addr , ep_addr , ep - > wMaxPacketSize , ep - > transfer_type , 0 ) ;
2021-01-20 02:52:07 +01:00
}
// If a normal transfer (non-interrupt) then initiate using
// sie ctrl registers. Otherwise interrupt ep registers should
// already be configured
if ( ep = = & epx ) {
2021-06-11 12:34:51 +02:00
hw_endpoint_xfer_start ( ep , buffer , buflen ) ;
2021-06-11 12:05:49 +02:00
2021-01-20 02:52:07 +01:00
// That has set up buffer control, endpoint control etc
// for host we have to initiate the transfer
2021-06-10 18:29:02 +02:00
usb_hw - > dev_addr_ctrl = dev_addr | ( ep_num < < USB_ADDR_ENDP_ENDPOINT_LSB ) ;
2021-06-13 08:18:32 +02:00
uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | SIE_CTRL_BASE |
2021-06-10 18:29:02 +02:00
( ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS ) ;
2021-01-20 02:52:07 +01:00
// Set pre if we are a low speed device on full speed hub
flags | = need_pre ( dev_addr ) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0 ;
2021-06-10 18:29:02 +02:00
2021-01-20 02:52:07 +01:00
usb_hw - > sie_ctrl = flags ;
2021-06-11 12:05:49 +02:00
} else
{
2021-06-11 12:34:51 +02:00
hw_endpoint_xfer_start ( ep , buffer , buflen ) ;
2021-01-20 02:52:07 +01:00
}
return true ;
}
bool hcd_setup_send ( uint8_t rhport , uint8_t dev_addr , uint8_t const setup_packet [ 8 ] )
{
2021-06-10 18:29:02 +02:00
( void ) rhport ;
2021-01-20 02:52:07 +01:00
// Copy data into setup packet buffer
2022-05-21 00:25:30 +02:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Warray-bounds"
# pragma GCC diagnostic ignored "-Wstringop-overflow"
2021-01-20 02:52:07 +01:00
memcpy ( ( void * ) & usbh_dpram - > setup_packet [ 0 ] , setup_packet , 8 ) ;
2022-05-21 00:25:30 +02:00
# pragma GCC diagnostic pop
2021-01-20 02:52:07 +01:00
// Configure EP0 struct with setup info for the trans complete
struct hw_endpoint * ep = _hw_endpoint_allocate ( 0 ) ;
2021-06-10 17:00:59 +02:00
2021-01-20 02:52:07 +01:00
// EP0 out
_hw_endpoint_init ( ep , dev_addr , 0x00 , ep - > wMaxPacketSize , 0 , 0 ) ;
assert ( ep - > configured ) ;
2021-06-10 17:00:59 +02:00
2021-06-11 12:58:29 +02:00
ep - > remaining_len = 8 ;
2021-06-10 17:00:59 +02:00
ep - > active = true ;
2021-01-20 02:52:07 +01:00
// Set device address
usb_hw - > dev_addr_ctrl = dev_addr ;
2021-06-10 17:00:59 +02:00
2021-01-20 02:52:07 +01:00
// Set pre if we are a low speed device on full speed hub
2021-06-13 08:18:32 +02:00
uint32_t const flags = SIE_CTRL_BASE | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS |
2021-06-10 17:00:59 +02:00
( need_pre ( dev_addr ) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0 ) ;
2021-01-20 02:52:07 +01:00
usb_hw - > sie_ctrl = flags ;
2021-06-10 17:00:59 +02:00
2021-01-20 02:52:07 +01:00
return true ;
}
2021-06-10 12:19:21 +02:00
//bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
//{
// // EPX is shared, so multiple device addresses and endpoint addresses share that
// // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own
// // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint
// // on that device
// pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\n", dev_addr, ep_addr);
// struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
// assert(ep);
// bool busy = ep->active;
// pico_trace("busy == %d\n", busy);
// return busy;
//}
2021-01-20 02:52:07 +01:00
bool hcd_edpt_clear_stall ( uint8_t dev_addr , uint8_t ep_addr )
{
2021-06-10 18:29:02 +02:00
( void ) dev_addr ;
2021-06-11 12:05:49 +02:00
( void ) ep_addr ;
2021-06-10 18:29:02 +02:00
2021-01-20 02:52:07 +01:00
panic ( " hcd_clear_stall " ) ;
return true ;
}
# endif