📄 usbs_upd985xx.c
字号:
#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 0typedef 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*);typedef struct ep0_impl { usbs_control_endpoint common; cyg_bool rx_expecting_data; cyg_bool rx_indicator_valid; RxMailbox rx_indicator; cyg_bool tx_indicator_valid; TxMailbox tx_indicator; cyg_bool tx_needs_zero_transfer; cyg_uint32 tx_size;} ep0_impl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -