/* Watchdog timer handler. */
void
bce_watchdog(struct ifnet *ifp)
{
	struct bce_softc *sc = ifp->if_softc;

	printf("%s: device timeout\n", sc->bce_dev.dv_xname);
	ifp->if_oerrors++;

	(void) bce_init(ifp);

	/* Try to get more packets going. */
	bce_start(ifp);
}
/* Watchdog timer handler. */
static void
bce_watchdog(struct ifnet *ifp)
{
	struct bce_softc *sc = ifp->if_softc;

	aprint_error_dev(sc->bce_dev, "device timeout\n");
	ifp->if_oerrors++;

	(void) bce_init(ifp);

	/* Try to get more packets going. */
	bce_start(ifp);
}
/* handle media, and ethernet requests */
static int
bce_ioctl(struct ifnet *ifp, u_long cmd, void *data)
{
	int		s, error;

	s = splnet();
	error = ether_ioctl(ifp, cmd, data);
	if (error == ENETRESET) {
		/* change multicast list */
		error = 0;
	}

	/* Try to get more packets going. */
	bce_start(ifp);

	splx(s);
	return error;
}
int
bce_intr(void *xsc)
{
	struct bce_softc *sc;
	struct ifnet   *ifp;
	u_int32_t intstatus;
	int             wantinit;
	int             handled = 0;

	sc = xsc;
	ifp = &sc->bce_ac.ac_if;


	for (wantinit = 0; wantinit == 0;) {
		intstatus = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
		    BCE_INT_STS);

		/* ignore if not ours, or unsolicited interrupts */
		intstatus &= sc->bce_intmask;
		if (intstatus == 0)
			break;

		handled = 1;

		/* Ack interrupt */
		bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_INT_STS,
		    intstatus);

		/* Receive interrupts. */
		if (intstatus & I_RI)
			bce_rxintr(sc);
		/* Transmit interrupts. */
		if (intstatus & I_XI)
			bce_txintr(sc);
		/* Error interrupts */
		if (intstatus & ~(I_RI | I_XI)) {
			if (intstatus & I_XU)
				printf("%s: transmit fifo underflow\n",
				    sc->bce_dev.dv_xname);
			if (intstatus & I_RO) {
				printf("%s: receive fifo overflow\n",
				    sc->bce_dev.dv_xname);
				ifp->if_ierrors++;
			}
			if (intstatus & I_RU)
				printf("%s: receive descriptor underflow\n",
				       sc->bce_dev.dv_xname);
			if (intstatus & I_DE)
				printf("%s: descriptor protocol error\n",
				       sc->bce_dev.dv_xname);
			if (intstatus & I_PD)
				printf("%s: data error\n",
				    sc->bce_dev.dv_xname);
			if (intstatus & I_PC)
				printf("%s: descriptor error\n",
				    sc->bce_dev.dv_xname);
			if (intstatus & I_TO)
				printf("%s: general purpose timeout\n",
				    sc->bce_dev.dv_xname);
			wantinit = 1;
		}
	}

	if (handled) {
		if (wantinit)
			bce_init(ifp);
		/* Try to get more packets going. */
		bce_start(ifp);
	}
	return (handled);
}
/* handle media, and ethernet requests */
int
bce_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
	struct bce_softc *sc = ifp->if_softc;
	struct ifreq   *ifr = (struct ifreq *) data;
	struct ifaddr *ifa = (struct ifaddr *)data;
	int             s, error = 0;

	s = splnet();

	if ((error = ether_ioctl(ifp, &sc->bce_ac, cmd, data)) > 0) {
		splx(s);
		return (error);
	}

	switch (cmd) {
	case SIOCSIFADDR:
		ifp->if_flags |= IFF_UP;

		switch (ifa->ifa_addr->sa_family) {
#ifdef INET
		case AF_INET:
			bce_init(ifp);
			arp_ifinit(&sc->bce_ac, ifa);
			break;
#endif /* INET */
		default:
			bce_init(ifp);
			break;
		}
		break;
	case SIOCSIFMTU:
		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU)
			error = EINVAL;
		else if (ifp->if_mtu != ifr->ifr_mtu)
			ifp->if_mtu = ifr->ifr_mtu;
		break;
	case SIOCSIFFLAGS:
		if(ifp->if_flags & IFF_UP)
			if(ifp->if_flags & IFF_RUNNING)
				bce_set_filter(ifp);
			else
				bce_init(ifp);
		else if(ifp->if_flags & IFF_RUNNING)
			bce_stop(ifp, 0);

		break;
	case SIOCADDMULTI:
	case SIOCDELMULTI:
		error = (cmd == SIOCADDMULTI) ?
		    ether_addmulti(ifr, &sc->bce_ac) :
		    ether_delmulti(ifr, &sc->bce_ac);

		if (error == ENETRESET) {
			/*
			 * Multicast list has changed; set the hardware
			 * filter accordingly.
			 */
			if (ifp->if_flags & IFF_RUNNING)
				bce_set_filter(ifp);
			error = 0;
		}
		break;
	case SIOCSIFMEDIA:
	case SIOCGIFMEDIA:
		error = ifmedia_ioctl(ifp, ifr, &sc->bce_mii.mii_media, cmd);
		break;
	default:
		error = ENOTTY;
		break;
	}

	if (error == 0) {
		/* Try to get more packets going. */
		bce_start(ifp);
	}

	splx(s);
	return error;
}
int
bce_intr(void *xsc)
{
	struct bce_softc *sc;
	struct ifnet   *ifp;
	uint32_t	intstatus;
	int		wantinit;
	int		handled = 0;

	sc = xsc;
	ifp = &sc->ethercom.ec_if;

	for (wantinit = 0; wantinit == 0;) {
		intstatus = bus_space_read_4(sc->bce_btag, sc->bce_bhandle,
		    BCE_INT_STS);

		/* ignore if not ours, or unsolicited interrupts */
		intstatus &= sc->bce_intmask;
		if (intstatus == 0)
			break;

		handled = 1;

		/* Ack interrupt */
		bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_INT_STS,
		    intstatus);

		/* Receive interrupts. */
		if (intstatus & I_RI)
			bce_rxintr(sc);
		/* Transmit interrupts. */
		if (intstatus & I_XI)
			bce_txintr(sc);
		/* Error interrupts */
		if (intstatus & ~(I_RI | I_XI)) {
			const char *msg = NULL;
			if (intstatus & I_XU)
				msg = "transmit fifo underflow";
			if (intstatus & I_RO) {
				msg = "receive fifo overflow";
				ifp->if_ierrors++;
			}
			if (intstatus & I_RU)
				msg = "receive descriptor underflow";
			if (intstatus & I_DE)
				msg = "descriptor protocol error";
			if (intstatus & I_PD)
				msg = "data error";
			if (intstatus & I_PC)
				msg = "descriptor error";
			if (intstatus & I_TO)
				msg = "general purpose timeout";
			if (msg != NULL)
				aprint_error_dev(sc->bce_dev, "%s\n", msg);
			wantinit = 1;
		}
	}

	if (handled) {
		if (wantinit)
			bce_init(ifp);
		rnd_add_uint32(&sc->rnd_source, intstatus);
		/* Try to get more packets going. */
		bce_start(ifp);
	}
	return (handled);
}