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

📄 usbs_upd985xx.c

📁 NEC的USB接口驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
        result          = false;        *which          = true;    } else {        result          = true;        tx_in_progress  = true;    }    cyg_drv_dsr_unlock();    return result;}// Invoked only from dsr context.static voidtx_unlock(void){    tx_in_progress  = false;    if (ep0_tx_pending) {        ep0_tx_pending  = false;        ep0_start_tx();        return;    }# ifdef CYGPKG_DEVS_USB_UPD985XX_EP3    if (ep3_tx_pending) {        ep3_tx_pending  = false;        ep35_start_tx(&ep3);        return;    }# endif# ifdef CYGPKG_DEVS_USB_UPD985XX_EP5    if (ep5_tx_pending) {        ep5_tx_pending  = false;        ep35_start_tx(&ep5);        return;    }# endif}# define TX_TRY_LOCK(_x_)   tx_try_lock(_x_)# define TX_UNLOCK()        tx_unlock()#else# define TX_TRY_LOCK(_x_)   1# define TX_UNLOCK()        CYG_EMPTY_STATEMENT#endif// ----------------------------------------------------------------------------// Endpoint 0//// As usual, control messages are more complicated than the rest.//// 1) during initialization a receive is initiated into the common//    eight-byte buffer, used for the standard header of the control//    packet. Until that header has been received and analysed,//    there is no way of knowing whether or not the host will be//    sending any more data.//// 2) the control packet may indicate that the host will be sending//    more data. A higher-level handler for the control message should//    have provided a suitable buffer, so a receive can be started//    into that buffer. A flag indicates whether we are currently//    receiving a new control packet or additional data.//// 3) the host may decide to cancel that extra data and send a new//    control message instead. There is a flag to indicate that//    the transfer included a SETUP token.//// 4) transmits only happen when the control packet involves returning//    data. Unfortunately there is a problem in that, with eCos, the//    return data will generally not be in a single contiguous buffer.//    Discontinuous data could be handled by having a separate buffer//    descriptor for each bit of data, but it is not known in advance//    how many buffer descriptors might be needed so allocating//    those statically presents a problem as well. Instead a single//    static buffer is used, and data from higher-level code is copied//    there. This introduces a new problem: how big should that buffer//    be? A configuration option is used for that.//// If endpoint 6 is in use as well then things get more complicated// because a single receive pool will be shared between endpoints 0// and 6, and when adding a buffer to a pool there is no way of// specifying the endpoint. Hence it will be necessary to receive// into a static buffer and then copy into either an endpoint 0 or// and endpoint 6 buffer.// Fill the transmit buffer by repeatedly invoking the refill function// and copying into the ep0 tx buffer. The relevant fields in the// ep0 structure are cleared immediately and the completion function// is called, even though the data has not actually gone out. That avoids// a possible race condition where the host sends a new control packet// immediately, before the transmit-complete has been processed// (unlikely in practice, not least because ep0_tx_dsr() will get called// before ep0_rx_dsr()).static intep0_fill_txbuffer(void){    int filled  = 0;    while (filled < CYGNUM_DEVS_USB_UPD985XX_EP0_TXBUFSIZE) {        if (0 != ep0.common.buffer_size) {            if ((filled + ep0.common.buffer_size) < CYGNUM_DEVS_USB_UPD985XX_EP0_TXBUFSIZE) {                memcpy(&(uncached->ep0_tx_buffer[filled]), ep0.common.buffer, ep0.common.buffer_size);                filled += ep0.common.buffer_size;                ep0.common.buffer_size = 0;            } else {                break;            }        } else if ((void (*)(usbs_control_endpoint*))0 != ep0.common.fill_buffer_fn) {            (*ep0.common.fill_buffer_fn)(&ep0.common);        } else {            break;        }    }    CYG_ASSERT((0 == ep0.common.buffer_size) && ((void (*)(usbs_control_endpoint*))0 == ep0.common.fill_buffer_fn), \               "Endpoint 0 transmit buffer overflow");    if ((usbs_control_return (*)(usbs_control_endpoint*, int))0 != ep0.common.complete_fn) {        (*ep0.common.complete_fn)(&ep0.common, 0);    }    ep0.common.buffer           = (unsigned char*) 0;    ep0.common.buffer_size      = 0;    ep0.common.fill_buffer_fn   = 0;    ep0.common.complete_fn      = 0;        return filled;}// Start a new receive operation on endpoint 0. This needs to happen// from a number of places, including from initialization.//// IMHO the hardware is somewhat overengineered here. All that is// needed is to receive a single eight-byte control packet, or a// small amount of additional control data. That could be achieved// by using a single buffer descriptor in the uncached structure,// plus a suitably-sized static uncached ep0_rx_buffer.//// But no, buffer descriptors must be linked and new buffers must// be added to the end. When a control packet arrives, the// receive pool continues to point at the old buffer descriptor.// So we need two buffer descriptors plus two links, switching// between them as appropriate.//// It is not at all clear what would happen if another packet// started to happen while things were being updated. There is// also potential confusion between endpoint 0 and endpoint 6// receives.static voidep0_start_rx(cyg_uint32 size){    // The buffer descriptor to be added. This will be either    // ep0_rxbufdescs[0] or ep0_rxbufdescs[2];    RxBufferDescriptor* desc = &(uncached->ep0_rx_bufdescs[0]);        CYG_ASSERTC(size > 0);    // Block interrupts for the duration. This does not prevent    // problems if the hardware sees another packet and starts    // doing things, but should prevent some software race    // conditions.    cyg_drv_isr_lock();    // We are about to start a new rx operation, so the    // current indicator may get invalidated.    ep0.rx_indicator_valid = false;    // Start by looking at the current pool0 status. There are    // three possibilities: during init or after reset, the pool    // will be empty; otherwise the pool should point at either    // rx_bufdescs[0] or rx_bufdescs[2], corresponding to the    // last received packet.    if (0 == (*USBS_RP0IR & USBS_RPxIR_RNOD_MASK)) {        // Nothing currently in the pool. Use ep0_rx_bufdescs[0],        // and no need to update a link.    } else if (desc == *USBS_RP0AR) {        // The pool already points at bufdescs[0], switch to bufdescs[2],        // and link from bufdescs[1].        desc    = &(uncached->ep0_rx_bufdescs[2]);        uncached->ep0_rx_bufdescs[1].buffer     = (void*) desc;    } else {        // The pool should point at bufdescs[2], stick with bufdescs[0]        CYG_ASSERT(&(uncached->ep0_rx_bufdescs[2]) == *USBS_RP0AR, "Endpoint 0 rx buffer confusion");        uncached->ep0_rx_bufdescs[3].buffer     = (void*) desc;    }    // Now fill in the buffer directory being added    desc[0].control     = RXBUFDESC_CTRL_LAST | RXBUFDESC_CTRL_BUFDESC_BUFDESC | size;    desc[0].buffer      = (void*) uncached->ep0_rx_buffer;    desc[1].control     = RXBUFDESC_CTRL_BUFDESC_LINK;    desc[1].buffer      = 0;        while (0 != (*USBS_CMR & IBUS_SWAP32(USBS_CMR_BUSY))) {        // Do nothing: this situation should be short-lived.    }    *USBS_CA    = IBUS_SWAPPTR(void, desc);                     FLUSH_IBUS();    *USBS_CMR   = IBUS_SWAP32(USBS_CMR_COMMAND_ADD_POOL0 | 1);  FLUSH_IBUS();    cyg_drv_isr_unlock();}// Ditto for transmits. The data is assumed to be in// uncached->ep0_tx_buffer already. A size of 0 indicates// a need to send a terminating packet explicitly.static voidep0_start_tx(void){    if (!TX_TRY_LOCK(&ep0_tx_pending)) {        return;    }        uncached->ep0_tx_bufdesc.buffer     = uncached->ep0_tx_buffer;    uncached->ep0_tx_bufdesc.control    = TXBUFDESC_CTRL_LAST | TXBUFDESC_CTRL_BUFDESC_BUFDESC | ep0.tx_size;    cyg_drv_isr_lock();    while (0 != (*USBS_CMR & IBUS_SWAP32(USBS_CMR_BUSY))) {        // Do nothing: this situation should be short-lived.    }    *USBS_CA    = IBUS_SWAPPTR(void, &(uncached->ep0_tx_bufdesc));      FLUSH_IBUS();    *USBS_CMR   = IBUS_SWAP32(USBS_CMR_COMMAND_TX_EP0 | ep0.tx_size);   FLUSH_IBUS();    cyg_drv_isr_unlock();}// An endpoint 0 transmission has completed. Usually the only action// that is needed is to drain the tx mailbox entry, otherwise it is// possible that we could end up with ep0 transmits using up all// available slots. The endpoint 0 hardware requires no further// attention, and as far as higher-level code is concerned the// transmission completed a long time ago when ep0_fill_txbuffer()// called the completion function.//// There is one special case. If the host asked for e.g. a string// descriptor and asked for 255 bytes, but the string was only// e.g. 32 bytes, then there is a problem. With a default value// for CYGNUM_DEVS_USB_UPD985XX_EP0_PKTSIZE, the data will be// transferred as four 8-byte packets, but it is necessary to// terminate the transfer with a 0-byte packet. Endpoint 0 always// operates in NZLP mode so the hardware will never generate// this last packet. Instead it is necessary to set up an// additional transfer of zero bytes. That could be done at the// same time as the main data transfer, but then it would be// necessary to poll the hardware and wait until it has finished// processing that initial transfer.static voidep0_tx_dsr(void){    if (!ep0.tx_indicator_valid) {        drain_tx_mailbox();        if (!ep0.tx_indicator_valid) {            // A transmit interrupt when there does not appear to be            // any data?            CYG_FAIL("EP0 tx DSR invoked when there is no valid tx indicator");            return;        }    }    // There is not actually anything worth looking at in the status.    ep0.tx_indicator_valid      = false;    if (ep0.tx_needs_zero_transfer) {        ep0.tx_needs_zero_transfer = false;        uncached->ep0_tx_bufdesc.buffer     = uncached->ep0_tx_buffer;        uncached->ep0_tx_bufdesc.control    = TXBUFDESC_CTRL_LAST | TXBUFDESC_CTRL_BUFDESC_BUFDESC | 0;        cyg_drv_isr_lock();        while (0 != (*USBS_CMR & IBUS_SWAP32(USBS_CMR_BUSY))) {            // Do nothing: this situation should be short-lived.        }        *USBS_CA    = IBUS_SWAPPTR(void, &(uncached->ep0_tx_bufdesc));          FLUSH_IBUS();        *USBS_CMR   = IBUS_SWAP32(USBS_CMR_COMMAND_TX_EP0 | 0);   FLUSH_IBUS();        cyg_drv_isr_unlock();            } else {        TX_UNLOCK();    }}// An endpoint 0 receive has completed. This could be a new control// message. Or it could be the data for a previous control message. Or// it could be a new control message when expecting the data from// a previous one. The ep0.rx_expecting_data field indicates// whether or not a new control message is expected.//// At times an interrupt triggers and there is an rx indication for a// zero-byte transfer. Such a transfer may be followed immediately by// a real transfer. It is not understood why the zero-byte transfer// occurs. They are ignored by the drain_rx_mailbox() code, to make// sure that there is at most one valid rx indicator at a time.static voidep0_rx_dsr(void){    // Start by checking the rx indicator to make sure that a packet    // really has been received.    if (!ep0.rx_indicator_valid) {        drain_rx_mailbox();        if (!ep0.rx_indicator_valid) {            // Do not assert, in case of a spurious interrupt for a            // zero-byte transfer.

⌨️ 快捷键说明

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