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

📄 usbs_sa11x0.c

📁 基于ecos的redboot
💻 C
📖 第 1 页 / 共 5 页
字号:
#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 + -