📄 usbs_upd985xx.c
字号:
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_upd985xx_ep0_start, poll_fn: &usbs_upd985xx_poll, interrupt_vector: CYGNUM_HAL_INTERRUPT_USB, 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 }, rx_expecting_data: false, rx_indicator_valid: false, rx_indicator: { 0, (void*) 0 }, tx_indicator_valid: false, tx_indicator: { 0 }, tx_needs_zero_transfer: 0};extern usbs_control_endpoint usbs_upd985xx_ep0 __attribute__((alias ("ep0")));// Endpoint 1, isochronous transmits. This endpoint is not yet// supported. Although the interface for bulk transmits should be// mostly re-usable, there are some additional error conditions if// either the host or the target fails to achieve the desired// throughput.// Endpoint 2, isochronous receives. Not yet supported for now, just// like endpoint 1.// Endpoints 3 and 5 can share some code.#if defined(CYGPKG_DEVS_USB_UPD985XX_EP3) || defined(CYGPKG_DEVS_USB_UPD985XX_EP5)// Endpoint 3, bulk transmits, and endpoint 5, either interrupt transmits// or emulation of bulk transmits. The hardware does most// of the work.typedef struct ep35_impl { usbs_tx_endpoint common; cyg_bool tx_indicator_valid; TxMailbox tx_indicator; int send_command; volatile cyg_uint32* cr; TxBufferDescriptor* tx_bufdesc;} ep35_impl;# ifdef CYGPKG_DEVS_USB_UPD985XX_EP3static void ep3_start_tx(usbs_tx_endpoint*);static void ep3_set_halted(usbs_tx_endpoint*, cyg_bool);static ep35_impl ep3 = { common: { start_tx_fn: &ep3_start_tx, set_halted_fn: &ep3_set_halted, complete_fn: (void (*)(void*, int)) 0, complete_data: (void*) 0, buffer: (const unsigned char*) 0, buffer_size: 0, halted: 0, }, tx_indicator_valid: false, tx_indicator: { 0 }, send_command: USBS_CMR_COMMAND_TX_EP3, cr: EP3_CR, tx_bufdesc: 0 // Needs run-time initialization};extern usbs_tx_endpoint usbs_upd985xx_ep3 __attribute__ ((alias ("ep3")));# endif# ifdef CYGPKG_DEVS_USB_UPD985XX_EP5static void ep5_start_tx(usbs_tx_endpoint*);static void ep5_set_halted(usbs_tx_endpoint*, cyg_bool);static ep35_impl ep5 = { common: { start_tx_fn: &ep5_start_tx, set_halted_fn: &ep5_set_halted, complete_fn: (void (*)(void*, int)) 0, complete_data: (void*) 0, buffer: (const unsigned char*) 0, buffer_size: 0, halted: 0, }, tx_indicator_valid: false, tx_indicator: { 0 }, send_command: USBS_CMR_COMMAND_TX_EP5, cr: EP5_CR, tx_bufdesc: 0 // Needs run-time initialization};extern usbs_tx_endpoint usbs_upd985xx_ep5 __attribute__ ((alias ("ep5")));# endif#endif#ifdef CYGPKG_DEVS_USB_UPD985XX_EP4// Endpoint 4, bulk receives. Again the hardware does the hard work.// Receive pool 2 is reserved for this endpoint.typedef struct ep4_impl { usbs_rx_endpoint common; cyg_uint32 head_size; cyg_uint32 direct_size; cyg_uint32 tail_size; cyg_bool rx_indicator_valid; RxMailbox rx_indicator; cyg_int32 tail_index;} ep4_impl;static void ep4_start_rx(usbs_rx_endpoint*);static void ep4_set_halted(usbs_rx_endpoint*, cyg_bool);static ep4_impl ep4 = { common: { start_rx_fn: &ep4_start_rx, set_halted_fn: &ep4_set_halted, complete_fn: (void (*)(void*, int)) 0, complete_data: (void*) 0, buffer: (unsigned char*) 0, buffer_size: 0, halted: 0, }, rx_indicator_valid: false, rx_indicator: { 0, (void*) 0 }, tail_index: -1};extern usbs_rx_endpoint usbs_upd985xx_ep4 __attribute__((alias ("ep4")));#endif// Endpoint 6, interrupt receives. Not yet implemented. There may// be conflicts because the hardware is shared with endpoint 0.// ----------------------------------------------------------------------------// Mailbox support.//// The transmit and receive mailboxes are shared between the// appropriate endpoints. This causes some complications if e.g.// transmits on several endpoints complete at the same time. For// example the tx mailbox might contain send indicators for endpoints// 3 and 0, but the DSR code will process endpoint 0 before endpoint// 3.//// This device driver works on the basis that there can be only one// transmit and/or receive in progress for any given endpoint, so the// relevant information can be extracted from the mailbox and put into// the per-endpoint structures. The routines below can be used to// move data from the mailboxes. They will be called in DSR context// so there is no need to worry about locking.static voiddrain_tx_mailbox(void){ TxMailbox* tmra = IBUS_SWAPPTR(TxMailbox, *USBS_TMRA); TxMailbox* tmwa = IBUS_SWAPPTR(TxMailbox, *USBS_TMWA); if (tmra != tmwa) { do { TxMailbox mbox = *tmra; tmra++; if (tmra == &(uncached->tx_mboxes[TXMBOX_COUNT])) { tmra = &(uncached->tx_mboxes[0]); } switch(mbox.status & TXMBOX_STATUS_EPN_MASK) { case TXMBOX_STATUS_EPN_EP0: CYG_ASSERT(false == ep0.tx_indicator_valid, "Only one ep0 transmit should be in progress at a time"); ep0.tx_indicator = mbox; ep0.tx_indicator_valid = true; break;#ifdef CYGPKG_DEVS_USB_UPD985XX_EP3 case TXMBOX_STATUS_EPN_EP3: CYG_ASSERT(false == ep3.tx_indicator_valid, "Only one ep3 transmit should be in progress at a time"); ep3.tx_indicator = mbox; ep3.tx_indicator_valid = true; break;#endif #ifdef CYGPKG_DEVS_USB_UPD985XX_EP5 case TXMBOX_STATUS_EPN_EP5: CYG_ASSERT(false == ep5.tx_indicator_valid, "Only one ep5 transmit should be in progress at a time"); ep5.tx_indicator = mbox; ep5.tx_indicator_valid = true; break;#endif default: break; } } while (tmra != tmwa); *USBS_TMRA = IBUS_SWAPPTR(TxMailbox, tmra); FLUSH_IBUS(); }}static voiddrain_rx_mailbox(void){ RxMailbox* rmra = IBUS_SWAPPTR(RxMailbox, *USBS_RMRA); RxMailbox* rmwa = IBUS_SWAPPTR(RxMailbox, *USBS_RMWA); if (rmra != rmwa) { do { RxMailbox mbox = *rmra; rmra++; if (rmra == &(uncached->rx_mboxes[RXMBOX_COUNT])) { rmra = &(uncached->rx_mboxes[0]); } switch(mbox.status & RXMBOX_STATUS_EPN_MASK) { case RXMBOX_STATUS_EPN_EP0: // Ignore zero-byte transfers. It is not clear why // these happen, but they have been observed. if (0 != (mbox.status & RXMBOX_STATUS_SIZE_MASK)) { CYG_ASSERT(false == ep0.rx_indicator_valid, "Only one ep0 receive should be in progress at a time"); ep0.rx_indicator = mbox; ep0.rx_indicator_valid = true; } break;#ifdef CYGPKG_DEVS_USB_UPD985XX_EP4 case RXMBOX_STATUS_EPN_EP4: // If an error occurs then the hardware may report // multiple rx completions, each with an IBUS error // indicator. For now only the last rx indicator is // taken into account, which means we could lose // a successful receive that happens to be followed // by an error. // NOTE: any possibility of improving on this?#if 1 CYG_ASSERT(false == ep4.rx_indicator_valid, "Only one ep4 receive should be in progress at a time");#endif ep4.rx_indicator = mbox; ep4.rx_indicator_valid = true; break;#endif default: break; } } while (rmra != rmwa); *USBS_RMRA = IBUS_SWAPPTR(RxMailbox, rmra); FLUSH_IBUS(); }}// ----------------------------------------------------------------------------// Transmit locking.//// According to NEC errata U3 and U4 the hardware may exhibit// undesirable behaviour if there are concurrent transmissions. There// are various ways of resolving this, but the simplest is to perform// locking in software so that at most one transmit endpoint is in use// at any one time. This approach works fine if transmissions only// involve one tx endpoint plus the control endpoint because the// control endpoint generally only gets used during initialization and// the other endpoint only gets used after initialization. If multiple// transmit endpoints are used then locking in software becomes less// acceptable, especially if isochronous transfers are used because// timing is important for those.//// There is a theoretical problem if e.g. there is a very large bulk// transfer on a busy bus and it is necessary to respond to a control// message. The control reply would be delayed, possibly causing a// violation of the USB standard and a timeout on the host.#ifdef CYGIMP_DEVS_USB_UPD985XX_SERIALIZE_TRANSMITSstatic void ep0_start_tx(void);# if defined(CYGPKG_DEVS_USB_UPD985XX_EP3) || defined(CYGPKG_DEVS_USB_UPD985XX_EP5)static void ep35_start_tx(ep35_impl*);# endifstatic cyg_bool tx_in_progress = false;static cyg_bool ep0_tx_pending = false;# ifdef CYGPKG_DEVS_USB_UPD985XX_EP3static cyg_bool ep3_tx_pending = false;# endif# ifdef CYGPKG_DEVS_USB_UPD985XX_EP5static cyg_bool ep5_tx_pending = false;# endif// Invoked from ep?_start_tx(). Scheduling may or may not be locked.static cyg_booltx_try_lock(cyg_bool* which){ cyg_bool result; cyg_drv_dsr_lock(); if (tx_in_progress) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -