📄 usbs_sa11x0.c
字号:
#define DMA_CONTROL_CLEAR_ALL (DMA_CONTROL_RUN | DMA_CONTROL_INTR_ENABLE | DMA_STATUS_ERROR | \
DMA_STATUS_DONE_A | DMA_CONTROL_START_A | DMA_STATUS_DONE_B | DMA_CONTROL_START_B)
// The DMA engines operate eight-bytes at a time. This affects issues
// such as alignment.
#define DMA_BURST_SIZE 8
// The DMA engines bypass the cache and MMU, accessing physical
// memory directly. Newer HALS should provide appropriate macros.
#ifndef HAL_VIRT_TO_PHYS_ADDRESS
# error HAL macros for translating between virtual and physical memory are required.
#endif
// Make absolutely sure that the two endpoints use different
// DMA channels. Right now this check cannot be done easily
// at the CDL level.
# if defined(CYGNUM_DEVS_USB_SA11X0_EP1_DMA_CHANNEL) && defined(CYGNUM_DEVS_USB_SA11X0_EP2_DMA_CHANNEL)
# if (CYGNUM_DEVS_USB_SA11X0_EP1_DMA_CHANNEL == CYGNUM_DEVS_USB_SA11X0_EP2_DMA_CHANNEL)
# error Different DMA channels must be selected for the two endpoints.
# endif
# endif
# ifdef CYGNUM_DEVS_USB_SA11X0_EP1_DMA_CHANNEL
static usbs_sa11x0_dma* const ep1_dma_base = (usbs_sa11x0_dma* const)(0xB0000000 | (0x20 * CYGNUM_DEVS_USB_SA11X0_EP1_DMA_CHANNEL));
# define EP1_DMA_ADDRESS (&(ep1_dma_base->address))
# define EP1_DMA_CONTROL_SET (&(ep1_dma_base->control_set))
# define EP1_DMA_CONTROL_CLEAR (&(ep1_dma_base->control_clear))
# define EP1_DMA_STATUS (&(ep1_dma_base->status))
# define EP1_DMA_BUF_A_ADDRESS (&(ep1_dma_base->buf_a_address))
# define EP1_DMA_BUF_A_SIZE (&(ep1_dma_base->buf_a_size))
# define EP1_DMA_BUF_B_ADDRESS (&(ep1_dma_base->buf_b_address))
# define EP1_DMA_BUF_B_SIZE (&(ep1_dma_base->buf_b_size))
// The correct value for the DMA address register is fixed for USB transfers
// See table 11.6 of the SA1110 Advanced Developer's Manual
// Device datum width == 1 byte
// Device burst size == 8 bytes
// Device transfer direction == read (device->memory)
// Endianness is controlled by the ARM architectural HAL package
# ifdef CYGHWR_HAL_ARM_BIGENDIAN
# define EP1_DMA_ADDRESS_VALUE (0x80000A00 | 0x10 | 0x0 | 0x4 | 0x2 | 0x1)
# else
# define EP1_DMA_ADDRESS_VALUE (0x80000A00 | 0x10 | 0x0 | 0x4 | 0x0 | 0x1)
# endif
# endif // EP1_DMA
# ifdef CYGNUM_DEVS_USB_SA11X0_EP2_DMA_CHANNEL
static usbs_sa11x0_dma* const ep2_dma_base = (usbs_sa11x0_dma* const)(0xB0000000 | (0x20 * CYGNUM_DEVS_USB_SA11X0_EP2_DMA_CHANNEL));
# define EP2_DMA_ADDRESS (&(ep2_dma_base->address))
# define EP2_DMA_CONTROL_SET (&(ep2_dma_base->control_set))
# define EP2_DMA_CONTROL_CLEAR (&(ep2_dma_base->control_clear))
# define EP2_DMA_STATUS (&(ep2_dma_base->status))
# define EP2_DMA_BUF_A_ADDRESS (&(ep2_dma_base->buf_a_address))
# define EP2_DMA_BUF_A_SIZE (&(ep2_dma_base->buf_a_size))
# define EP2_DMA_BUF_B_ADDRESS (&(ep2_dma_base->buf_b_address))
# define EP2_DMA_BUF_B_SIZE (&(ep2_dma_base->buf_b_size))
# ifdef CYGHWR_HAL_ARM_BIGENDIAN
# define EP2_DMA_ADDRESS_VALUE (0x80000A00 | 0x00 | 0x0 | 0x4 | 0x2 | 0x0)
# else
# define EP2_DMA_ADDRESS_VALUE (0x80000A00 | 0x00 | 0x0 | 0x4 | 0x0 | 0x0)
# endif
# endif // EP2_DMA
#endif // EP1_DMA || EP2_DMA
// ----------------------------------------------------------------------------
// Static data. There is a data structure for each endpoint. The
// implementation is essentially a private class that inherits from
// common classes for control and data endpoints, but device drivers
// are supposed to be written in C so some ugliness is required.
//
// Devtab entries are defined in usbs_sa11x0_data.cxx to make sure
// that the linker does not garbage-collect them.
// Support for the interrupt handling code.
static cyg_interrupt usbs_sa11x0_intr_data;
static cyg_handle_t usbs_sa11x0_intr_handle;
static volatile int isr_status_bits = 0;
// Endpoint 0 is always present, this module would not get compiled
// otherwise.
static void usbs_sa11x0_ep0_start(usbs_control_endpoint*);
static void usbs_sa11x0_poll(usbs_control_endpoint*);
typedef enum ep0_state {
EP0_STATE_IDLE = 0,
EP0_STATE_IN = 1,
EP0_STATE_OUT = 2
} ep0_state;
typedef struct ep0_impl {
usbs_control_endpoint common;
ep0_state ep_state;
int length;
int transmitted;
} ep0_impl;
static ep0_impl ep0 = {
common:
{
state: USBS_STATE_POWERED, // The hardware does not distinguish between detached, attached and powered.
enumeration_data: (usbs_enumeration_data*) 0,
start_fn: &usbs_sa11x0_ep0_start,
poll_fn: &usbs_sa11x0_poll,
interrupt_vector: SA11X0_IRQ_USB_SERVICE_REQUEST,
control_buffer: { 0, 0, 0, 0, 0, 0, 0, 0 },
state_change_fn: (void (*)(usbs_control_endpoint*, void*, usbs_state_change, int)) 0,
state_change_data: (void*) 0,
standard_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0,
standard_control_data: (void*) 0,
class_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0,
class_control_data: (void*) 0,
vendor_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0,
vendor_control_data: (void*) 0,
reserved_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0,
reserved_control_data: (void*) 0,
buffer: (unsigned char*) 0,
buffer_size: 0,
fill_buffer_fn: (void (*)(usbs_control_endpoint*)) 0,
fill_data: (void*) 0,
fill_index: 0,
complete_fn: (usbs_control_return (*)(usbs_control_endpoint*, int)) 0
},
ep_state: EP0_STATE_IDLE,
length: 0,
transmitted: 0
};
extern usbs_control_endpoint usbs_sa11x0_ep0 __attribute__((alias ("ep0")));
// Endpoint 1 is optional. If the application only involves control
// messages or only slave->host transfers then the endpoint 1
// support can be disabled.
#ifdef CYGPKG_DEVS_USB_SA11X0_EP1
typedef struct ep1_impl {
usbs_rx_endpoint common;
int fetched;
cyg_bool using_buf_a;
} ep1_impl;
static void ep1_start_rx(usbs_rx_endpoint*);
static void ep1_set_halted(usbs_rx_endpoint*, cyg_bool);
static ep1_impl ep1 = {
common: {
start_rx_fn: &ep1_start_rx,
set_halted_fn: &ep1_set_halted,
complete_fn: (void (*)(void*, int)) 0,
complete_data: (void*) 0,
buffer: (unsigned char*) 0,
buffer_size: 0,
halted: 0,
},
fetched: 0,
using_buf_a: 0
};
extern usbs_rx_endpoint usbs_sa11x0_ep1 __attribute__((alias ("ep1")));
#endif
// Endpoint 2 is optional. If the application only involves control
// messages or only host->slave transfers then the endpoint 2 support
// can be disabled.
#ifdef CYGPKG_DEVS_USB_SA11X0_EP2
typedef struct ep2_impl {
usbs_tx_endpoint common;
int transmitted;
int pkt_size;
} ep2_impl;
static void ep2_start_tx(usbs_tx_endpoint*);
static void ep2_set_halted(usbs_tx_endpoint*, cyg_bool);
static ep2_impl ep2 = {
common: {
start_tx_fn: &ep2_start_tx,
set_halted_fn: &ep2_set_halted,
complete_fn: (void (*)(void*, int)) 0,
complete_data: (void*) 0,
buffer: (const unsigned char*) 0,
buffer_size: 0,
halted: 0,
},
transmitted: 0,
pkt_size: 0
};
extern usbs_tx_endpoint usbs_sa11x0_ep2 __attribute__ ((alias ("ep2")));
#endif
// ----------------------------------------------------------------------------
// Hardware problem: experiments indicate that manipulating the USB
// controller registers does not always work as expected. The control
// fifo is especially badly affected, with e.g. writes just being lost
// completely. It is necessary to work around these problems using
// retry loops. MAX_RETRIES controls the total number of attempts to
// access a register. MAX_CHECKS controls the number of times a
// register is checked to determine whether or not the attempt has
// been succesful. These constants are used to access the data fifo,
// so MAX_RETRIES has to be > 20 bytes.
#define MAX_RETRIES 32
#define MAX_CHECKS 8
// Write one or more bits to a register. This should result in some
// bits ending up set and other bits ending up clear. Some register
// bits are write-1-to-clear or may have side effects.
static cyg_bool
usbs_sa11x0_poke(volatile int* addr, int value, int should_be_set, int should_be_clear)
{
cyg_bool result = false;
int retries, checks;
for (retries = 0; !result && (retries < MAX_RETRIES); retries++) {
*addr = value;
(void) *addr; // The first read is always invalid.
for (checks = 0; !result && (checks < MAX_CHECKS); checks++) {
int current_value = *addr;
if (should_be_set != (should_be_set & current_value)) {
continue;
}
if ((0 != should_be_clear) && (0 != (should_be_clear & current_value))) {
continue;
}
result = true;
}
}
if (!result) {
DBG(("usbs_sa11x0_poke failed: addr %x, value %x, should_be_set %x, should_be_clear %x, actual %x\n", \
(int) addr, value, should_be_set, should_be_clear, *addr));
}
return result;
}
// Write a whole value to a register, rather than just manipulating
// individual bits.
static cyg_bool
usbs_sa11x0_poke_value(volatile int* addr, int value)
{
cyg_bool result = false;
int retries, checks;
for (retries = 0; !result && (retries < MAX_RETRIES); retries++) {
*addr = value;
(void) *addr; // The first read is always invalid.
for (checks = 0; !result && (checks < MAX_CHECKS); checks++) {
if (value == *addr) {
result = true;
}
}
}
if (!result) {
DBG(("usbs_sa11x0_poke_value failed: addr %x, value %x, actual %x\n", (int) addr, value, *addr));
}
return result;
}
// ----------------------------------------------------------------------------
// Control transfers
//
// Endpoint 0 is rather more complicated than the others. This is
// partly due to the nature of the control protocol, for example it is
// bidirectional and transfer sizes are unpredictable.
//
// The USB standard imposes some timing constraints on endpoint 0, see
// section 9.2.6 of the spec. For example the set-address operation is
// supposed to take at most 50ms. In general the timings are reasonably
// generous so no special action is taken here. There could be problems
// when debugging, but that is pretty much inevitable.
//
// It is necessary to maintain a state for the control endpoint, the
// default state being idle. Control operations involve roughly the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -