📄 usbs_sa11x0.c
字号:
#define DMA_STATUS_DONE_B (1 << 5)#define DMA_CONTROL_START_B (1 << 6)#define DMA_STATUS_BUFFER_IN_USE (1 << 7)// All the bits that are useful to clear. BUFFER_IN_USE is read-only.#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_CHANNELstatic 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_CHANNELstatic 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_EP1typedef 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_EP2typedef 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_boolusbs_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_boolusbs_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// following sequence of events:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -