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

📄 usbsethdrv.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
        } else if (real_size > CYGNUM_USBS_ETH_MAX_FRAME_SIZE) {            INCR_STAT(eth->rx_too_long_frames);        } else {            // The packet appears to be valid. Inform higher level            // code and mark the buffer as in use.            resubmit            = false;            eth->rx_buffer_full = true;            eth->rx_active      = false;            eth_drv_dsr(0, 0, (cyg_addrword_t) sc);        }    }        if (resubmit) {        eth->rx_active = true;        usbs_eth_start_rx(eth, eth->rx_bufptr, &usbs_ethdrv_recv_callback, callback_data);    }}// Another callback, used to wait while an endpoint is halted.static voidusbs_ethdrv_halted_callback(void* callback_data, int size){    struct eth_drv_sc* sc = (struct eth_drv_sc*) callback_data;    usbs_ethdrv_recv_callback((usbs_eth*) sc->driver_private, callback_data, 0);}// Start a receive operation. It is not possible to abort an existing// rx operation, so a valid sequence of events is: start, rx ongoing,// stop, restart. The rx_active field is used to keep track of whether// or not there is still a receive in progress. The receive callback// will just discard incoming data if the eCos stack is not currently// running.static voidusbs_ethdrv_start_recv(struct eth_drv_sc* sc, usbs_eth* eth){    cyg_drv_dsr_lock();    if (!eth->rx_active) {        eth->rx_active = true;        usbs_eth_start_rx(eth, eth->rx_bufptr, &usbs_ethdrv_recv_callback, (void*) sc);    }    cyg_drv_dsr_unlock();}// This is invoked from the delivery thread when a valid buffer// has been received. The buffer should be scattered into the// supplied list, then another receive should be started.static voidusbs_ethdrv_recv(struct eth_drv_sc* sc,                 struct eth_drv_sg* sg_list, int sg_len){    usbs_eth* eth = (usbs_eth*)(sc->driver_private);    CYG_ASSERT( eth->rx_buffer_full, "This function should only be called when there is a buffer available");    (void) scatter(eth->rx_bufptr, sg_list, sg_len);    eth->rx_buffer_full = false;    eth->rx_active      = true;    usbs_eth_start_rx(eth, eth->rx_bufptr, &usbs_ethdrv_recv_callback, (void*) sc);}// ----------------------------------------------------------------------------// Now for the transmit process.//// When an application thread writes down a socket the data gets moved// into mbufs, and then passed to the appropriate device driver - which// may or may not be able to process it immediately. There is also a// timeout thread within the TCP/IP to handle retransmits etc.//// The stack will start by calling usbs_ethdrv_can_send() to determine// whether or not the driver can accept the packet. For the purposes// of the USB-ethernet driver this is true provided both host// and target are up and there is a spare buffer available.//// If the usbs_eth_can_send() returns true then there will be a call// to usbs_ethdrv_send(). This gathers the data into a single// buffer. If there is no transmit in progress yet then one is started.//// At some point the packet will have been transmitted and a callback// gets invoked. This needs to call eth_drv_dsr(), waking up the// delivery thread. The deliver() function can then check which// transmissions have completed and inform the higher level code// via sc->funs->eth_drv->tx_done(). The buffer can be re-used at// that point.static voidusbs_ethdrv_send_callback(usbs_eth* eth, void* callback_data, int size){    struct eth_drv_sc* sc = (struct eth_drv_sc*) callback_data;    CYG_ASSERT( eth == (usbs_eth*)(sc->driver_private), "USB and TCP/IP worlds need to be consistent");    INCR_STAT(eth->interrupts);    // There are a variety of possible error codes. -EAGAIN indicates    // that the endpoint is stalled. -EPIPE indicates that the    // connection to the host has been lost. These are not really    // particularly interesting. Whatever happens the buffer    // must be cleared and higher-level code informed so that    // the mbufs can be released.    if (size > 0) {        INCR_STAT(eth->tx_count);    }    eth->tx_done = true;    eth_drv_dsr(0, 0, (cyg_addrword_t) sc);}// Is it possible to send an ethernet frame? This requires// an empty buffer, i.e. there should be no existing// transmit in progress. It also requires that the host// is connected and that the endpoint is not currently halted.static intusbs_ethdrv_can_send(struct eth_drv_sc* sc){    usbs_eth* eth = (usbs_eth*)(sc->driver_private);    return eth->host_up && !eth->tx_buffer_full && !eth->tx_endpoint->halted;}// Actually start a packet transmission. This means collecting// all the data into a single buffer and then invoking the// lower-level code. The latter may discard the packet immediately// if the MAC is not appropriate: it would be more efficient to// catch that here, especially for large packets, but the check// has to happen inside the lower-level code anyway in case// that is being invoked directly rather than via the driver.//// There is a possible recursion problem,// send->start_tx->tx_done->can_send->send, which is guarded// against using the tx_in_send flag.static voidusbs_ethdrv_send(struct eth_drv_sc* sc,              struct eth_drv_sg* sgl_list, int sg_len, int total_len,              unsigned long key){    usbs_eth* eth = (usbs_eth*)(sc->driver_private);        CYG_ASSERT( 0 == eth->tx_in_send, "send() should not be invoked recursively");    CYG_ASSERT( total_len <= CYGNUM_USBS_ETH_MAX_FRAME_SIZE, "ethernet maximum frame size should be observed");    CYG_ASSERT( CYGNUM_USBS_ETH_MIN_FRAME_SIZE <= total_len, "ethernet minimum frame size should be observed");    eth->tx_in_send = true;    CYG_ASSERT( !eth->tx_buffer_full, "the transmit buffer should be empty");    gather(eth->tx_buffer, CYGNUM_USBS_ETH_MAX_FRAME_SIZE, sgl_list, sg_len);    eth->tx_buffer_full = true;    eth->tx_done        = false;    eth->tx_key         = key;    usbs_eth_start_tx(eth, eth->tx_buffer, &usbs_ethdrv_send_callback, (void*) sc);    eth->tx_in_send = false;}// ----------------------------------------------------------------------------// Deliver needs to take into account both receive and transmit buffers.static voidusbs_ethdrv_deliver(struct eth_drv_sc* sc){    usbs_eth* eth = (usbs_eth*)(sc->driver_private);    if (eth->rx_buffer_full) {        int size = eth->rx_bufptr[0] + (eth->rx_bufptr[1] << 8);        (*sc->funs->eth_drv->recv)(sc, size);    }    if (eth->tx_done) {        unsigned long key   = eth->tx_key;        eth->tx_buffer_full = false;        eth->tx_done        = false;        (*sc->funs->eth_drv->tx_done)(sc, key, 1);    }}// ----------------------------------------------------------------------------// usbs_ethdrv_start()//// This gets called by the TCP/IP stack later on during// initialization, when the stack is ready to send and receive// packets. It may get called multiple times while the stack// is running, with different flags values.//// As far as transmits are concerned, nothing needs to be done. If no// transmit is in progress then everything is fine anyway. If a// transmit is already in progress then it must be allowed to complete// via the usual route. Receives should however be restarted, the// start function has appropriate safeguards.//// Invoked in: thread context only// ----------------------------------------------------------------------------static voidusbs_ethdrv_start(struct eth_drv_sc* sc, unsigned char* enaddr, int flags){    usbs_eth* eth = (usbs_eth*)(sc->driver_private);    if (!eth->ecos_up) {        eth->ecos_up = true;        usbs_ethdrv_start_recv(sc, eth);    }}// ----------------------------------------------------------------------------// usbs_ethdrv_stop()//// Similarly this gets called by the TCP/IP stack to bring the network// interface down. Nothing should happen for any packets currently// being transmitted or received, that would cause confusion everywhere.// The receive callback checks the ecos_up flag and does the right// thing. The TCP/IP stack should not call can_send() after taking// the interface down so no new transmits will be initiated.//// Invoked in: thread context only// ----------------------------------------------------------------------------static voidusbs_ethdrv_stop(struct eth_drv_sc* sc){    usbs_eth* eth = (usbs_eth*)(sc->driver_private);    eth->ecos_up = false;}// ----------------------------------------------------------------------------// usbs_eth_ioctl()//// The operations to worry about here are:////    SET_MAC_ADDRESS,via the SIOCSIFHWADDR ioctl////    GET_IF_STATS and GET_IF_STATS_UD, to report gathered statistics.//// Invoked in: thread context only// ----------------------------------------------------------------------------static intusbs_ethdrv_ioctl(struct eth_drv_sc* sc, unsigned long key, void* data, int data_length){    usbs_eth* eth = (usbs_eth*)(sc->driver_private);    int       result = EINVAL;        switch(key) {      case ETH_DRV_SET_MAC_ADDRESS:        {            if (6 == data_length) {                memcpy(eth->ecos_MAC, data, 6);                result = 0;            }        }        break;#if defined(CYGFUN_USBS_ETHDRV_STATISTICS) && defined(ETH_DRV_GET_IF_STATS_UD)      case ETH_DRV_GET_IF_STATS_UD:      case ETH_DRV_GET_IF_STATS:        {            static unsigned char my_chipset[] = { 0, 0 };            struct ether_drv_stats *p = (struct ether_drv_stats*) data;            int    i;            strcpy(p->description, CYGDAT_USBS_ETHDRV_DESCRIPTION);            for ( i = 0; i < SNMP_CHIPSET_LEN; i++ ) {                if ( 0 == (p->snmp_chipset[i] = my_chipset[i]) ) {                    break;                }            }            p->duplex               = 3;        // 3 == duplex            p->operational          = (eth->host_up && eth->ecos_up) ? 3 : 2;   // 3 == up, 2 == down            p->speed                = 10 * 1000000;            p->supports_dot3        = 1;            p->rx_too_long_frames   = eth->rx_too_long_frames;            p->rx_short_frames      = eth->rx_short_frames;            p->interrupts           = eth->interrupts;            p->rx_count             = eth->rx_count;            p->tx_count             = eth->tx_count;            p->tx_queue_len         = 1;            result=0;        }        break;#endif              default:        break;    }    return result;}                 // ----------------------------------------------------------------------------// usbs_ethdrv_poll()//// On real ethernet hardware this is used by RedBoot once the// application has started running, so that the network device can be// used for debugging purposes as well as for the application's own// needs. The lower-level USB device may supply a poll function as well.// ----------------------------------------------------------------------------static voidusbs_ethdrv_poll(struct eth_drv_sc* sc){    usbs_eth*   eth = (usbs_eth*)(sc->driver_private);    (*eth->control_endpoint->poll_fn)(eth->control_endpoint);}// ----------------------------------------------------------------------------// usbs_ethdrv_intvector()//// See usbs_eth_poll().// ----------------------------------------------------------------------------static intusbs_ethdrv_intvector(struct eth_drv_sc* sc){    usbs_eth*   eth = (usbs_eth*)(sc->driver_private);    return eth->control_endpoint->interrupt_vector;}

⌨️ 快捷键说明

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