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

📄 usbs_upd985xx.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
// endpoint control registers, thus avoiding unnecessary code
// duplication. These will not work for the isochronous endpoints
// because those are just too special.
#define EPtx_CR_EpxEN                   (0x01 << 31)
#define EPtx_CR_SSx                     (0x01 << 18)
#define EPtx_CR_NAKx                    (0x01 << 16)
#define EPtx_CR_MAXPx_MASK              (0x7F << 0)
#define EPtx_CR_MAXPx_SHIFT             0

#define EPrx_CR_EPxEN                   (0x01 << 31)
#define EPrx_CR_SSx                     (0x01 << 18)
#define EPrx_CR_NHSKx                   (0x01 << 17)
#define EPrx_CR_NAKx                    (0x01 << 16)
#define EPrx_CR_MAXPx_MASK              (0x7F << 0)
#define EPrx_CR_MAXPx_SHIFT             0

// USB command register
#define USBS_CMR_BUSY                   (0x01 << 31)
#define USBS_CMR_COMMAND_MASK           (0x07 << 24)
#define USBS_CMR_COMMAND_SHIFT          24
#define USBS_CMR_COMMAND_TX_EP0         (0x00 << 24)
#define USBS_CMR_COMMAND_TX_EP1         (0x01 << 24)
#define USBS_CMR_COMMAND_TX_EP3         (0x02 << 24)
#define USBS_CMR_COMMAND_TX_EP5         (0x03 << 24)
#define USBS_CMR_COMMAND_ADD_POOL0      (0x04 << 24)
#define USBS_CMR_COMMAND_ADD_POOL1      (0x05 << 24)
#define USBS_CMR_COMMAND_ADD_POOL2      (0x06 << 24)
#define USBS_CMR_SIZE_MASK              (0x0FFFF << 0)
#define USBS_CMR_SIZE_SHIFT             0

// TX Endpoint status
#define USBS_TEPSR_EP5TS_MASK           (0x03 << 24)
#define USBS_TEPSR_EP5TS_SHIFT          24
#define USBS_TEPSR_EP5TS_IDLE           (0x00 << 24)
#define USBS_TEPSR_EP5TS_ONE            (0x01 << 24)
#define USBS_TEPSR_EP5TS_TWO            (0x02 << 24)
#define USBS_TEPSR_EP3TS_MASK           (0x03 << 16)
#define USBS_TEPSR_EP3TS_SHIFT          16
#define USBS_TEPSR_EP3TS_IDLE           (0x00 << 16)
#define USBS_TEPSR_EP3TS_ONE            (0x01 << 16)
#define USBS_TEPSR_EP3TS_TWO            (0x02 << 16)
#define USBS_TEPSR_EP1TS_MASK           (0x03 << 8)
#define USBS_TEPSR_EP1TS_SHIFT          8
#define USBS_TEPSR_EP1TS_IDLE           (0x00 << 8)
#define USBS_TEPSR_EP1TS_ONE            (0x01 << 8)
#define USBS_TEPSR_EP1TS_TWO            (0x02 << 8)
#define USBS_TEPSR_EP0TS_MASK           (0x03 << 0)
#define USBS_TEPSR_EP0TS_SHIFT          0
#define USBS_TEPSR_EP0TS_IDLE           (0x00 << 0)
#define USBS_TEPSR_EP0TS_ONE            (0x01 << 0)
#define USBS_TEPSR_EP0TS_TWO            (0x02 << 0)

// Receive pools. The RP0IR, RP1IR and RP2IR registers
// all use the same bits.
#define USBS_RPxIR_AL_MASK              (0x07 << 28)
#define USBS_RPxIR_AL_SHIFT             28
#define USBS_RPxIR_AL_NONE              (0 << 28)
#define USBS_RPxIR_RNOD_MASK            (0x0FFFF << 0)
#define USBS_RPxIR_RNOD_SHIFT           0

// The other registers do not have special bits.

// Data transfers involve buffer descriptors and mailboxes. The
// relevant data structures and fields need to be defined. For now
// assume 32-bit mode of operation, i.e. there will be no padding
// between two successive 32-bit entities

// A transmit packet directory consists of up to 255 buffer
// descriptors. Each buffer descriptor specifies a buffer and a size
// of up to 64K. 

typedef struct TxBufferDescriptor {
    cyg_uint32  control;
    void*       buffer;
} TxBufferDescriptor;

#define TXBUFDESC_CTRL_LAST                     (0x01 << 31)
#define TXBUFDESC_CTRL_BUFDESC_MASK             (0x01 << 30)
#define TXBUFDESC_CTRL_BUFDESC_SHIFT            30
#define TXBUFDESC_CTRL_BUFDESC_LINK             (0x00 << 30)
#define TXBUFDESC_CTRL_BUFDESC_BUFDESC          (0x01 << 30)
#define TXBUFDESC_CTRL_SIZE_MASK                (0x0FFFF << 0)
#define TXBUFDESC_CTRL_SIZE_SHIFT               0

// The result of a transmit operation gets written to a mailbox
// structure in memory.
typedef struct TxMailbox {
    cyg_uint32  status;
} TxMailbox;

#define TXMBOX_STATUS_IBUS_ERROR                (0x01 << 10)
#define TXMBOX_STATUS_UNDERRUN                  (0x01 << 9)
#define TXMBOX_STATUS_MODE_MASK                 (0x01 << 8)
#define TXMBOX_STATUS_MODE_SHIFT                8
#define TXMBOX_STATUS_MODE_SZLP                 (0x00 << 8)
#define TXMBOX_STATUS_MODE_NZLP                 (0x01 << 8)
#define TXMBOX_STATUS_EPN_MASK                  (0x07 << 0)
#define TXMBOX_STATUS_EPN_SHIFT                 0
#define TXMBOX_STATUS_EPN_EP0                   (0x00 << 0)
#define TXMBOX_STATUS_EPN_EP1                   (0x02 << 0)
#define TXMBOX_STATUS_EPN_EP3                   (0x04 << 0)
#define TXMBOX_STATUS_EPN_EP5                   (0x06 << 0)

// Now for receive operations. This involves adding buffer descriptors
// to one of three pools. The pools are managed by registers.
typedef struct RxBufferDescriptor {
    cyg_uint32          control;
    void*               buffer;
} RxBufferDescriptor;

#define RXBUFDESC_CTRL_LAST                     (0x01 << 31)
#define RXBUFDESC_CTRL_BUFDESC_MASK             (0x01 << 30)
#define RXBUFDESC_CTRL_BUFDESC_SHIFT            30
#define RXBUFDESC_CTRL_BUFDESC_LINK             (0x00 << 30)
#define RXBUFDESC_CTRL_BUFDESC_BUFDESC          (0x01 << 30)
#define RXBUFDESC_CTRL_SIZE_MASK                (0x0FFFF << 0)
#define RXBUFDESC_CTRL_SIZE_SHIFT               0

typedef struct RxMailbox {
    cyg_uint32          status;
    void*               address;
} RxMailbox;

#define RXMBOX_STATUS_EPN_MASK                  (0x07 << 29)
#define RXMBOX_STATUS_EPN_SHIFT                 29
#define RXMBOX_STATUS_EPN_EP0                   (0x01 << 29)
#define RXMBOX_STATUS_EPN_EP2                   (0x03 << 29)
#define RXMBOX_STATUS_EPN_EP4                   (0x05 << 29)
#define RXMBOX_STATUS_EPN_EP6                   (0x07 << 29)
#define RXMBOX_STATUS_CORRUPTION                (0x01 << 25)
#define RXMBOX_STATUS_IBUS_ERROR                (0x01 << 24)
#define RXMBOX_STATUS_SETUP_MASK                (0x01 << 23)
#define RXMBOX_STATUS_SETUP_SHIFT               23
#define RXMBOX_STATUS_SETUP_NORMAL              (0x00 << 23)
#define RXMBOX_STATUS_SETUP_SETUP               (0x01 << 23)
#define RXMBOX_STATUS_OVERRUN                   (0x01 << 22)
#define RXMBOX_STATUS_DATA_TOGGLE               (0x01 << 21)
#define RXMBOX_STATUS_CRC                       (0x01 << 20)
#define RXMBOX_STATUS_BIT_STUFFING              (0x01 << 19)
#define RXMBOX_STATUS_64K                       (0x01 << 18)
#define RXMBOX_STATUS_MODE_MASK                 (0x03 << 16)
#define RXMBOX_STATUS_MODE_SHIFT                16
#define RXMBOX_STATUS_MODE_NORMAL               (0x00 << 16)
#define RXMBOX_STATUS_MODE_NORMAL2              (0x01 << 16)
#define RXMBOX_STATUS_MODE_ASSEMBLE             (0x02 << 16)
#define RXMBOX_STATUS_MODE_SEPARATE             (0x03 << 16)
#define RXMBOX_STATUS_SIZE_MASK                 (0x0FFFF << 0)
#define RXMBOX_STATUS_SIZE_SHIFT                0


// ----------------------------------------------------------------------------
// Hardware work around - see NEC erratum S1, CPU to IBUS write restriction.
// Reading back from the USB device after every write prevents any problems.
// Strictly speaking it is only necessary to do this after every three
// writes, but if there is concurrent ethernet activity then doing it
// after eveyr write is safer. The frame number/version register seems
// like a good one to read back from.

#ifdef CYGIMP_DEVS_USB_UPD985XX_IBUS_WRITE_LIMIT
# define FLUSH_IBUS()   \
      CYG_MACRO_START   \
      (void)*USBS_VER;  \
      CYG_MACRO_END

#else
# define FLUSH_IBUS()       CYG_EMPTY_STATEMENT
#endif

// ----------------------------------------------------------------------------
// 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_upd985xx_data.cxx to make sure
// that the linker does not garbage-collect them.

// Support for the interrupt handling code.
static cyg_interrupt usbs_upd985xx_intr_data;
static cyg_handle_t  usbs_upd985xx_intr_handle;

// The various bits in the two interrupt status registers are read-once,
// i.e. reading the register clears the bits. Since much of the processing
// is deferred to DSR level, it is necessary to keep track of pending
// interrupts in separate variables. If another interrupt happens during
// DSR processing, these variables will be updated. The main DSR loops
// until there are no interesting bits left. Interrupts have to be
// disabled briefly when clearing bits.
static volatile cyg_uint32 usbs_upd985xx_gsr1   = 0;
static volatile cyg_uint32 usbs_upd985xx_gsr2   = 0;

// Many of the interrupt bits are of no interest and it is convenient
// to mask them out in the ISR, thus avoiding unnecessary dsr
// invocations.
static cyg_uint32 usbs_upd985xx_gsr1_mask       = 0;
static cyg_uint32 usbs_upd985xx_gsr2_mask       = 0;

// Sizes for the receive and transmit mboxes.
// NOTE: it is not clear what the optimal size for these
// mailboxes is. For receives maybe one per rx endpoint,
// plus a spare. For transmits maybe just two, since only
// one transmit at a time is supported. Mailboxes are
// relatively small, so for now four each should be ok.
#define RXMBOX_COUNT    4
#define TXMBOX_COUNT    4

// There is one instance of this data structure. It is allocated
// in kseg0 cached memory, but during initialization a separate
// pointer value is set to the kseg1 uncached equivalent. This
// makes it easier to point the hardware at uncached memory without
// having to worry about cache line boundaries everywhere.

typedef struct uncached_data {
    // This partial cacheline does not actually store any data.
    // However it ensures that the data does not share a cacheline
    // with some other static, with updates to that other static
    // causing funny side effects on the uncached data. There is a
    // memory optimisation of subtracting sizeof(RxMailbox.status),
    // i.e. exploit knowledge of alignment.
    unsigned char       cacheline_start[HAL_DCACHE_LINE_SIZE - sizeof(cyg_uint32)];

    RxMailbox           rx_mboxes[RXMBOX_COUNT];
    TxMailbox           tx_mboxes[TXMBOX_COUNT];

    // For transmits a single buffer descriptor per endpoint suffices.
    // If transmit locking is enabled then actually a single buffer
    // descriptor for the whole system would suffice.
    TxBufferDescriptor  ep0_tx_bufdesc;
#ifdef CYGPKG_DEVS_USB_UPD985XX_EP3
    TxBufferDescriptor  ep3_tx_bufdesc;
#endif
#ifdef CYGPKG_DEVS_USB_UPD985XX_EP5
    TxBufferDescriptor  ep5_tx_bufdesc;
#endif
    
    
    // More buffer descriptors are needed than might be expected, see
    // the start_rx routines. 
    RxBufferDescriptor  ep0_rx_bufdescs[4];
#ifdef CYGPKG_DEVS_USB_UPD985XX_EP4
    RxBufferDescriptor  ep4_rx_bufdescs[8];
#endif    

    
#ifdef CYGPKG_DEVS_USB_UPD985XX_EP4
    // Space for the start and end of a transfer, avoiding problems
    // with invalidating partial cache lines.
    unsigned char       ep4_head[HAL_DCACHE_LINE_SIZE];
    unsigned char       ep4_tail[HAL_DCACHE_LINE_SIZE];
#endif
    
    // The "big" buffers come last, reducing the offsets for the previous
    // structures. It is not clear this really matters for MIPS.
    //
    // Endpoint 0 receive and transmit buffers. A transmit buffer is
    // convenient because the hardware pretty much expects all of the
    // data to be in contiguous memory, as opposed to the normal eCos
    // USB driver model with refill buffers etc. An alternative
    // implementation would keep the data in separate areas but would
    // require lots of TxBufferDescriptors, so in memory terms the
    // overheads of a single transmit buffer are not as big as might
    // seem. It might be possible to get things working eight bytes
    // at a time since the hardware appears to depend on zero-byte
    // terminating packets in places, but that has not been attempted.
    //
    // A separate receive buffer is useful because it can be placed in
    // uncached memory, avoiding the need for invalidation and
    // worrying about other data in the cache lines. Note that this
    // buffer may also get used for endpoint 6 interrupt receives
    // because the two endpoints share a single pool.
    unsigned char       ep0_rx_buffer[CYGNUM_DEVS_USB_UPD985XX_EP0_RXBUFSIZE];
    unsigned char       ep0_tx_buffer[CYGNUM_DEVS_USB_UPD985XX_EP0_TXBUFSIZE];

    // Another cacheline to prevent overlap with other statics.
    // This has to be full-sized since the previous field is only byte-aligned.
    unsigned char       cacheline_end[HAL_DCACHE_LINE_SIZE];
} uncached_data;

// This data structure is quite large so making it all uninitialized
// means a potentially big saving in ROM-booting systems. This
// requires additional effort by the endpoint initialization routines.
static uncached_data    cached_copy;

static uncached_data*   uncached        = (uncached_data*)0;

// Endpoint 0. See the description below.

static void usbs_upd985xx_ep0_start(usbs_control_endpoint*);
static void usbs_upd985xx_poll(usbs_control_endpoint*);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -