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

📄 eth_drv.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
    ifp->if_softc = sc;
    ifp->if_start = eth_drv_send;
    ifp->if_ioctl = eth_drv_ioctl;
    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
#ifdef IFF_NOTRAILERS
    ifp->if_flags |= IFF_NOTRAILERS;
#endif
#ifdef CYGPKG_NET_FREEBSD_STACK
    ifp->if_name = xp = ifp->if_xname;
    np = (char *)sc->dev_name;
    unit = 0;
    while (*np && !((*np >= '0') && (*np <= '9'))) *xp++ = *np++;
    if (*np) {
        *xp = '\0';
        while (*np) {
            unit = (unit * 10) + (*np++ - '0');
        }
        ifp->if_unit = unit;
    }
    ifp->if_init = (void_fun *)eth_drv_start;
    ifp->if_output = ether_output;
#else
    bcopy((void *)sc->dev_name, ifp->if_xname, IFNAMSIZ);
#endif
    sc->state = 0;

    // Attach the interface
#ifdef CYGPKG_NET_FREEBSD_STACK
    ether_ifattach(ifp, 0);
#else
    if_attach(ifp);
    ether_ifattach(ifp);
#endif

#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
// Set up interfaces so debug environment can share this device
    {
        void *dbg = CYGACC_CALL_IF_DBG_DATA();
        if (!dbg) {
            CYGACC_CALL_IF_DBG_DATA_SET((void *)sc);
        }
    }
#endif
}

//
// This [internal] function will be called to stop activity on an interface.
//
static void
eth_drv_stop(struct eth_drv_sc *sc)
{
    (sc->funs->stop)(sc);
    sc->state &= ~ETH_DRV_STATE_ACTIVE;
}

//
// This [internal] function will be called to start activity on an interface.
//
static void
eth_drv_start(struct eth_drv_sc *sc)
{
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;

    // Perform any hardware initialization
    (sc->funs->start)(sc, (unsigned char *)&sc->sc_arpcom.ac_enaddr, 0);
#ifdef CYGPKG_NET_FREEBSD_STACK
    // resend multicast addresses if present
    if(ifp->if_multiaddrs.lh_first && ifp->if_ioctl) {
        int s = splimp();
	ifp->if_ioctl(ifp, SIOCADDMULTI, 0);
	splx(s);
    }
#endif
    // Set 'running' flag, and clear output active flag.
    ifp->if_flags |= IFF_RUNNING;
    ifp->if_flags &= ~IFF_OACTIVE;
    sc->state |= ETH_DRV_STATE_ACTIVE;
    eth_drv_send(ifp);  // Try and start up transmit
}

//
// This function supports "I/O control" operations on an interface.
//
static int  
eth_drv_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
    struct eth_drv_sc *sc = ifp->if_softc;
#ifndef CYGPKG_NET_FREEBSD_STACK
    struct ifaddr *ifa = (struct ifaddr *) data;
#endif
    struct ifreq *ifr = (struct ifreq *)data;
    int     s, error = 0;

// DEBUG
#ifdef CYGPKG_NET_FREEBSD_STACK
    log(LOG_IOCTL, "%s: cmd: %s, data:\n", __FUNCTION__, _ioctl_name(cmd));
    log_dump(LOG_IOCTL, data, 32);
#endif
// DEBUG

    s = splnet();

#ifdef CYGPKG_NET_FREEBSD_STACK
    if ((error = ether_ioctl(ifp, cmd, data)) > 0) {
#else
    if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
#endif
        splx(s);
        return error;
    }

    switch (cmd) {

    case SIOCSIFADDR:
#ifndef CYGPKG_NET_FREEBSD_STACK // Now in if_ethersubr.c
        ifp->if_flags |= IFF_UP;

        switch (ifa->ifa_addr->sa_family) {
#ifdef INET
        case AF_INET:
            eth_drv_start(sc);
            arp_ifinit(&sc->sc_arpcom, ifa);
            break;
#endif
        default:
            eth_drv_start(sc);
            break;
        }
#endif // CYGPKG_NET_FREEBSD_STACK
        break;

    case SIOCGIFHWADDR:
        // Get hardware (MAC) address
        ifr->ifr_hwaddr.sa_family = AF_INET;
        bcopy(&sc->sc_arpcom.ac_enaddr, &ifr->ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
        break;

    case SIOCSIFHWADDR:
        // Set hardware (MAC) address
        bcopy(&ifr->ifr_hwaddr.sa_data, &sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
        if ((sc->funs->control)(sc, ETH_DRV_SET_MAC_ADDRESS,
                                &sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN)) {
            error = EINVAL;
        }
        break;

#ifdef SIOCGIFSTATS
    case SIOCGIFSTATS:
#ifdef SIOCGIFSTATSUD
    case SIOCGIFSTATSUD:
#endif
        // Get interface statistics:
        if ((sc->funs->control)(sc, (cmd == SIOCGIFSTATS)
                                ? ETH_DRV_GET_IF_STATS
                                : ETH_DRV_GET_IF_STATS_UD,
                                data, 0 ) ) {
            error = EINVAL;
        }
        break;
#endif // SIOCGIFSTATS

    case SIOCSIFFLAGS:
        if ((ifp->if_flags & IFF_UP) == 0 &&
            (ifp->if_flags & IFF_RUNNING) != 0) {
            /*
             * If interface is marked down and it is running, then
             * stop it.
             */
            eth_drv_stop(sc);
            ifp->if_flags &= ~IFF_RUNNING;
        } else
            if ((ifp->if_flags & IFF_UP) != 0 &&
                (ifp->if_flags & IFF_RUNNING) == 0) {
                /*
                 * If interface is marked up and it is stopped, then
                 * start it.
                 */
                eth_drv_start(sc);
            } else {
                /*
                 * Reset the interface to pick up changes in any other
                 * flags that affect hardware registers.
                 */
                eth_drv_stop(sc);
                eth_drv_start(sc);
            }
        break;

#ifdef CYGPKG_NET_FREEBSD_STACK
    case SIOCADDMULTI:
    case SIOCDELMULTI:
    {
	struct ifmultiaddr *ifma;
        struct eth_drv_mc_list mc_list;
        int mode = (ifp->if_flags & IFF_ALLMULTI) ? ETH_DRV_SET_MC_ALL :
                                                    ETH_DRV_SET_MC_LIST;

#ifdef DEBUG
        log(LOG_ADDR, "%s Multi\n",(cmd == SIOCADDMULTI) ? "Add" : "Del");
#endif
        mc_list.len = 0;
        LIST_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) {
  	    if (ifma->ifma_addr->sa_family != AF_LINK) {
	      continue;
	    }
#ifdef DEBUG
            log_dump(LOG_ADDR, LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 6);
#endif
            if ((LLADDR((struct sockaddr_dl *)ifma->ifma_addr)[0] & 0x01) == 0) {
#ifdef DEBUG
                log(LOG_ADDR, "** Not a multicast address - ignored\n");
#endif
                continue;
            }
            if (mc_list.len < ETH_DRV_MAX_MC) {
                bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
                      mc_list.addrs[mc_list.len], ETHER_ADDR_LEN);
                mc_list.len++;
            } else {
                mode = ETH_DRV_SET_MC_ALL;
            }
        }
        // Note: drivers may behave like IFF_ALLMULTI if the list is 
        // more than their hardware can handle, e.g. some can only handle 1.
        if ((sc->funs->control)(sc, mode, &mc_list, sizeof(mc_list))) {
            diag_printf( "[%s] Warning: Driver can't set multi-cast mode\n",
                         __FUNCTION__ );
            error = EINVAL;
        }
        break;
    }
#endif

    default:
        error = EINVAL;
        break;
    }

    splx(s);
    return (error);
}

//
// Control whether any special locking needs to take place if we intend to
// cooperate with a ROM monitor (e.g. RedBoot) using this hardware.  
//
#if defined(CYGSEM_HAL_USE_ROM_MONITOR) && \    defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG) && \   !defined(CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_COMMS)

// Indicate that special locking precautions are warranted.
#define _LOCK_WITH_ROM_MONITOR

// This defines the [well known] channel that RedBoot will use when it is
// using the network hardware for the debug channel.
#define RedBoot_TCP_CHANNEL CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS

// Define this if you ever need to call 'diag_printf()' from interrupt level
// code (ISR) and the debug channel might be using the network hardware. If
// this is not the case, then disabling interrupts here is over-kill.
//#define _LOCK_USING_INTERRUPTS
#endif

//
// This routine is called to start transmitting if there is data
// available.
//
static void 
eth_drv_send(struct ifnet *ifp)
{
    struct eth_drv_sc *sc = ifp->if_softc;
#if MAX_ETH_DRV_SG > 64
    static  // Avoid large stack requirements
#endif
    struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
    int sg_len;
    struct mbuf *m0, *m;
    int len, total_len;
    unsigned char *data;
#ifdef _LOCK_WITH_ROM_MONITOR
#ifdef _LOCK_USING_INTERRUPTS
    cyg_uint32 ints;
#endif
    bool need_lock = false;
    int debug_chan;
#endif // _LOCK_WITH_ROM_MONITOR

    // This is now only called from network threads, so no guarding is
    // required; locking is in place via the splfoo() mechanism already.

    if ((ifp->if_flags & IFF_RUNNING) != IFF_RUNNING) {
         return;
    }

    // If nothing on the queue, no need to bother hardware
    if (IF_IS_EMPTY(&ifp->if_snd)) {
        return;
    }

    while ((sc->funs->can_send)(sc) > 0) {
        IF_DEQUEUE(&ifp->if_snd, m0);
        if (m0 == 0) {
            break;
        }

#ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATED_FAILURES
        if ( simulate_fail( sc, SIMULATE_FAIL_SEND ) ) {
            // must free the mbufs
            m_freem(m0);
            continue; // next packet to send
        }
#endif

#ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
        if (cyg_io_eth_net_debug) {
            START_CONSOLE();
            diag_printf("Sending %d bytes\n", m0->m_pkthdr.len);
            END_CONSOLE();
        }
#endif

        /* We need to use m->m_pkthdr.len, so require the header */
        if ((m0->m_flags & M_PKTHDR) == 0)
            panic("eth_drv_send: no header mbuf");

#if NBPFILTER > 0
        /* Tap off here if there is a BPF listener. */
        if (ifp->if_bpf)
            bpf_mtap(ifp->if_bpf, m0);
#endif

        // Extract data pointers (don't actually move data here)
        sg_len = 0;  total_len = 0;
        for (m = m0; m ; m = m->m_next) {
            data = mtod(m, u_char *);
            len = m->m_len;
            total_len += len;
            sg_list[sg_len].buf = (CYG_ADDRESS)data;
            sg_list[sg_len].len = len;
            if ( len )
                sg_len++;
#ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
            if (cyg_io_eth_net_debug) {
                START_CONSOLE();
                diag_printf("xmit %d bytes at %x sg[%d]\n", len, data, sg_len);
                if ( cyg_io_eth_net_debug > 1)
                    diag_dump_buf(data, len);
                END_CONSOLE();
            }
#endif
            if ( MAX_ETH_DRV_SG < sg_len ) {
#ifdef CYGPKG_IO_ETH_DRIVERS_WARN_NO_MBUFS
                int needed = 0;
                struct mbuf *m1;
                for (m1 = m0; m1 ; m1 = m1->m_next) needed++;

⌨️ 快捷键说明

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