⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbs_sa11x0.c

📁 Sa11的USB驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
#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 + -