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

📄 usbs_upd985xx.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:

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;

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_EP3
static 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_EP5
static 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 void
drain_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 void
drain_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_TRANSMITS
static 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*);

⌨️ 快捷键说明

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