/*
 * reset and restart the SONIC.  Called in case of fatal
 * hardware/software errors.
 */
static void
snreset(struct sn_softc *sc)
{

	snstop(sc);
	sninit(sc);
}
static int
snioctl(struct ifnet *ifp, u_long cmd, void *data)
{
	struct ifaddr *ifa;
	struct sn_softc *sc = ifp->if_softc;
	int	s = splnet(), err = 0;
	int	temp;

	switch (cmd) {

	case SIOCINITIFADDR:
		ifa = (struct ifaddr *)data;
		ifp->if_flags |= IFF_UP;
		(void)sninit(sc);
		switch (ifa->ifa_addr->sa_family) {
#ifdef INET
		case AF_INET:
			arp_ifinit(ifp, ifa);
			break;
#endif
		default:
			break;
		}
		break;

	case SIOCSIFFLAGS:
		if ((err = ifioctl_common(ifp, cmd, data)) != 0)
			break;
		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.
			 */
			snstop(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.
			 */
			(void)sninit(sc);
		} else {
			/*
			 * reset the interface to pick up any other changes
			 * in flags
			 */
			temp = ifp->if_flags & IFF_UP;
			snreset(sc);
			ifp->if_flags |= temp;
			snstart(ifp);
		}
		break;

	case SIOCADDMULTI:
	case SIOCDELMULTI:
		if ((err = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
			/*
			 * Multicast list has changed; set the hardware
			 * filter accordingly. But remember UP flag!
			 */
			if (ifp->if_flags & IFF_RUNNING) {
				temp = ifp->if_flags & IFF_UP;
				snreset(sc);
				ifp->if_flags |= temp;
			}
			err = 0;
		}
		break;
	default:
		err = ether_ioctl(ifp, cmd, data);
		break;
	}
	splx(s);
	return err;
}
Exemple #3
0
int
sn_attach(device_t dev)
{
	struct sn_softc *sc = device_get_softc(dev);
	struct ifnet   *ifp = &sc->arpcom.ac_if;
	u_short         i;
	u_char         *p;
	int             rev;
	u_short         address;
	int		j;
	int		error;

	sn_activate(dev);

	snstop(sc);

	sc->dev = dev;
	sc->pages_wanted = -1;

	device_printf(dev, " ");

	SMC_SELECT_BANK(3);
	rev = inw(BASE + REVISION_REG_W);
	if (chip_ids[(rev >> 4) & 0xF])
		kprintf("%s ", chip_ids[(rev >> 4) & 0xF]);

	SMC_SELECT_BANK(1);
	i = inw(BASE + CONFIG_REG_W);
	kprintf("%s\n", i & CR_AUI_SELECT ? "AUI" : "UTP");

	if (sc->pccard_enaddr)
		for (j = 0; j < 3; j++) {
			u_short	w;

			w = (u_short)sc->arpcom.ac_enaddr[j * 2] | 
				(((u_short)sc->arpcom.ac_enaddr[j * 2 + 1]) << 8);
			outw(BASE + IAR_ADDR0_REG_W + j * 2, w);
		}

	/*
	 * Read the station address from the chip. The MAC address is bank 1,
	 * regs 4 - 9
	 */
	SMC_SELECT_BANK(1);
	p = (u_char *) & sc->arpcom.ac_enaddr;
	for (i = 0; i < 6; i += 2) {
		address = inw(BASE + IAR_ADDR0_REG_W + i);
		p[i + 1] = address >> 8;
		p[i] = address & 0xFF;
	}
	ifp->if_softc = sc;
	if_initname(ifp, "sn", device_get_unit(dev));
	ifp->if_mtu = ETHERMTU;
	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
	ifp->if_start = snstart;
	ifp->if_ioctl = snioctl;
	ifp->if_watchdog = snwatchdog;
	ifp->if_init = sninit;
	ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
	ifq_set_ready(&ifp->if_snd);
	ifp->if_timer = 0;

	ether_ifattach(ifp, sc->arpcom.ac_enaddr, NULL);

	ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->irq_res));

	error = bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE,
			       sn_intr, sc, &sc->intrhand,
			       ifp->if_serializer);
	if (error) {
		ether_ifdetach(ifp);
		sn_deactivate(dev);
		return error;
	}

	return 0;
}