Subject: Re: wi driver: pcmcia_function_{enable,disable}
To: None <port-i386@netbsd.org>
From: enami tsugutomo <enami@sm.sony.co.jp>
List: port-i386
Date: 02/15/2000 19:22:38
chopps@merit.edu (Christian E. Hopps) writes:

> Right, I believe this is the correct behavoir.  Just save the
> information in the softc and then whenever the card is enabled it should 
> be intitialized as the user has requested.

Fortunately, wi driver already have such members in softc (I'm not
sure if they are enough).

Anyway, here is wi driver I'm using.  Could someone try this?  (Sorry,
it includes not so important cosmetic changes, but I can't live with
them ;-).

- If device isn't enabled, information is just set into/got from
softc.
- Don't modify IFF_* flags in enable/disable.  With this, I believe we
no longer necessary special handling of IFF_RUNNING in wi_init.
- Don't specially handle IFF_PROMISC in wi_ioctl.  Probably we need to
call wi_setmulti in addition to setting register.
- Some minor bug fix; disestablish shutdown hook on detach and
disestablish intrrupt on enable failure.

enami.
Index: if_wi.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pcmcia/if_wi.c,v
retrieving revision 1.7
diff -c -r1.7 if_wi.c
*** if_wi.c	2000/02/13 06:17:58	1.7
--- if_wi.c	2000/02/15 10:09:33
***************
*** 131,137 ****
  
  static void wi_reset		__P((struct wi_softc *));
  static int wi_ioctl		__P((struct ifnet *, u_long, caddr_t));
! static void wi_init		__P((void *));
  static void wi_start		__P((struct ifnet *));
  static void wi_stop		__P((struct wi_softc *));
  static void wi_watchdog		__P((struct ifnet *));
--- 131,137 ----
  
  static void wi_reset		__P((struct wi_softc *));
  static int wi_ioctl		__P((struct ifnet *, u_long, caddr_t));
! static void wi_init		__P((struct wi_softc *));
  static void wi_start		__P((struct ifnet *));
  static void wi_stop		__P((struct wi_softc *));
  static void wi_watchdog		__P((struct ifnet *));
***************
*** 150,165 ****
  static int wi_seek		__P((struct wi_softc *, int, int, int));
  static int wi_alloc_nicmem	__P((struct wi_softc *, int, int *));
  static void wi_inquire		__P((void *));
! static void wi_setdef		__P((struct wi_softc *, struct wi_req *));
  static int wi_mgmt_xmit		__P((struct wi_softc *, caddr_t, int));
  static void wi_shutdown		__P((void *));
  
  static int wi_enable __P((struct wi_softc *));
! static int wi_disable __P((struct wi_softc *));
  
! 
! struct cfattach wi_ca =
! {
  	sizeof(struct wi_softc), wi_match, wi_attach, wi_detach, wi_activate
  };
  
--- 150,164 ----
  static int wi_seek		__P((struct wi_softc *, int, int, int));
  static int wi_alloc_nicmem	__P((struct wi_softc *, int, int *));
  static void wi_inquire		__P((void *));
! static int wi_setdef		__P((struct wi_softc *, struct wi_req *));
! static int wi_getdef		__P((struct wi_softc *, struct wi_req *));
  static int wi_mgmt_xmit		__P((struct wi_softc *, caddr_t, int));
  static void wi_shutdown		__P((void *));
  
  static int wi_enable __P((struct wi_softc *));
! static void wi_disable __P((struct wi_softc *));
  
! struct cfattach wi_ca = {
  	sizeof(struct wi_softc), wi_match, wi_attach, wi_detach, wi_activate
  };
  
***************
*** 179,185 ****
  wi_enable(sc)
  	struct wi_softc *sc;
  {
! 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  
  	sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, wi_intr, sc);
  	if (sc->sc_ih == NULL) {
--- 178,186 ----
  wi_enable(sc)
  	struct wi_softc *sc;
  {
! 
! 	if (sc->sc_enabled != 0)
! 		return (0);
  
  	sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, wi_intr, sc);
  	if (sc->sc_ih == NULL) {
***************
*** 189,218 ****
  	}
  	if (pcmcia_function_enable(sc->sc_pf) != 0) {
  		printf("%s: couldn't enable card\n", sc->sc_dev.dv_xname);
  		return (EIO);
  	}
  
! 	wi_init(sc);
! 	ifp->if_flags |= IFF_RUNNING;
! 	return 0;
  }
  
! int
  wi_disable(sc)
  	struct wi_softc *sc;
  {
- 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  
! 	if (ifp->if_flags & IFF_RUNNING) {
! 		wi_stop(sc);
! 		pcmcia_function_disable(sc->sc_pf);
! 		pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
! 	}
! 	ifp->if_flags &= ~IFF_RUNNING;
! 	ifp->if_timer = 0;
  
! 	/* XXX */;
! 	return 0;
  }
  
  
--- 190,215 ----
  	}
  	if (pcmcia_function_enable(sc->sc_pf) != 0) {
  		printf("%s: couldn't enable card\n", sc->sc_dev.dv_xname);
+ 		pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
  		return (EIO);
  	}
  
! 	sc->sc_enabled = 1;
! 	return (0);
  }
  
! void
  wi_disable(sc)
  	struct wi_softc *sc;
  {
  
! 	if (sc->sc_enabled == 0)
! 		return;
  
! 	pcmcia_function_disable(sc->sc_pf);
! 	pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
! 	sc->sc_enabled = 0;
! 	return;
  }
  
  
***************
*** 340,348 ****
  	wi_read_record(sc, &gen);
  	sc->wi_has_wep = gen.wi_val;
  
- 	wi_init(sc);
- 	wi_stop(sc);
- 
  	/*
  	 * Call MI attach routines.
  	 */
--- 337,342 ----
***************
*** 915,921 ****
  #if 0
  		/* Punt on ranges. */
  		if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
! 			 sizeof(enm->enm_addrlo)) != 0)
  			break;
  #endif
  		bcopy(enm->enm_addrlo,
--- 909,915 ----
  #if 0
  		/* Punt on ranges. */
  		if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
! 		    sizeof(enm->enm_addrlo)) != 0)
  			break;
  #endif
  		bcopy(enm->enm_addrlo,
***************
*** 930,941 ****
  	return;
  }
  
! static void wi_setdef(sc, wreq)
  	struct wi_softc		*sc;
  	struct wi_req		*wreq;
  {
  	struct sockaddr_dl	*sdl;
  	struct ifnet		*ifp;
  
  	ifp = &sc->sc_ethercom.ec_if;
  
--- 924,937 ----
  	return;
  }
  
! static int
! wi_setdef(sc, wreq)
  	struct wi_softc		*sc;
  	struct wi_req		*wreq;
  {
  	struct sockaddr_dl	*sdl;
  	struct ifnet		*ifp;
+ 	int error = 0;
  
  	ifp = &sc->sc_ethercom.ec_if;
  
***************
*** 943,949 ****
  	case WI_RID_MAC_NODE:
  		sdl = (struct sockaddr_dl *)ifp->if_sadl;
  		bcopy((char *)&wreq->wi_val, (char *)&sc->sc_macaddr,
! 		   ETHER_ADDR_LEN);
  		bcopy((char *)&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN);
  		break;
  	case WI_RID_PORTTYPE:
--- 939,945 ----
  	case WI_RID_MAC_NODE:
  		sdl = (struct sockaddr_dl *)ifp->if_sadl;
  		bcopy((char *)&wreq->wi_val, (char *)&sc->sc_macaddr,
! 		    ETHER_ADDR_LEN);
  		bcopy((char *)&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN);
  		break;
  	case WI_RID_PORTTYPE:
***************
*** 993,1008 ****
  		break;
  	case WI_RID_DEFLT_CRYPT_KEYS:
  		bcopy((char *)wreq, (char *)&sc->wi_keys,
! 		      sizeof(struct wi_ltv_keys));
  		break;
  	default:
  		break;
  	}
  
! 	/* Reinitialize WaveLAN. */
! 	wi_init(sc);
  
! 	return;
  }
  
  static int wi_ioctl(ifp, command, data)
--- 989,1091 ----
  		break;
  	case WI_RID_DEFLT_CRYPT_KEYS:
  		bcopy((char *)wreq, (char *)&sc->wi_keys,
! 		    sizeof(struct wi_ltv_keys));
  		break;
  	default:
+ 		error = EINVAL;
  		break;
  	}
  
! 	return (error);
! }
  
! static int
! wi_getdef(sc, wreq)
! 	struct wi_softc		*sc;
! 	struct wi_req		*wreq;
! {
! 	struct sockaddr_dl	*sdl;
! 	struct ifnet		*ifp;
! 	int error = 0;
! 
! 	ifp = &sc->sc_ethercom.ec_if;
! 
! 	wreq->wi_len = 2;			/* XXX */
! 	switch (wreq->wi_type) {
! 	case WI_RID_MAC_NODE:
! 		wreq->wi_len += ETHER_ADDR_LEN / 2 - 1;
! 		sdl = (struct sockaddr_dl *)ifp->if_sadl;
! 		bcopy(&sc->sc_macaddr, &wreq->wi_val, ETHER_ADDR_LEN);
! 		bcopy(LLADDR(sdl), &wreq->wi_val, ETHER_ADDR_LEN);
! 		break;
! 	case WI_RID_PORTTYPE:
! 		wreq->wi_val[0] = sc->wi_ptype;
! 		break;
! 	case WI_RID_TX_RATE:
! 		wreq->wi_val[0] = sc->wi_tx_rate;
! 		break;
! 	case WI_RID_MAX_DATALEN:
! 		wreq->wi_val[0] = sc->wi_max_data_len;
! 		break;
! 	case WI_RID_RTS_THRESH:
! 		wreq->wi_val[0] = sc->wi_rts_thresh;
! 		break;
! 	case WI_RID_SYSTEM_SCALE:
! 		wreq->wi_val[0] = sc->wi_ap_density;
! 		break;
! 	case WI_RID_CREATE_IBSS:
! 		wreq->wi_val[0] = sc->wi_create_ibss;
! 		break;
! 	case WI_RID_OWN_CHNL:
! 		wreq->wi_val[0] = sc->wi_channel;
! 		break;
! 	case WI_RID_NODENAME:
! 		bzero(&wreq->wi_val[0], sizeof(wreq->wi_val));
! 		wreq->wi_val[0] = strlen(sc->wi_node_name);
! 		wreq->wi_len += roundup(wreq->wi_val[0], 2) / 2 - 1;
! 		bcopy(sc->wi_node_name, &wreq->wi_val[1], 30);
! 		break;
! 	case WI_RID_DESIRED_SSID:
! 		bzero(&wreq->wi_val[0], sizeof(wreq->wi_val));
! 		wreq->wi_val[0] = strlen(sc->wi_net_name);
! 		wreq->wi_len += roundup(wreq->wi_val[0], 2) / 2 - 1;
! 		bcopy(sc->wi_net_name, &wreq->wi_val[1], 30);
! 		break;
! 	case WI_RID_OWN_SSID:
! 		bzero(&wreq->wi_val[0], sizeof(wreq->wi_val));
! 		wreq->wi_val[0] = strlen(sc->wi_ibss_name);
! 		wreq->wi_len += roundup(wreq->wi_val[0], 2) / 2 - 1;
! 		bcopy(sc->wi_ibss_name, &wreq->wi_val[1], 30);
! 		break;
! 	case WI_RID_PM_ENABLED:
! 		wreq->wi_val[0] = sc->wi_pm_enabled;
! 		break;
! 	case WI_RID_MAX_SLEEP:
! 		wreq->wi_val[0] = sc->wi_max_sleep;
! 		break;
! 	case WI_RID_ENCRYPTION:
! 		wreq->wi_val[0] = sc->wi_use_wep;
! 		break;
! 	case WI_RID_TX_CRYPT_KEY:
! 		wreq->wi_val[0] = sc->wi_tx_key;
! 		break;
! 	case WI_RID_DEFLT_CRYPT_KEYS:
! 		wreq->wi_len += sizeof(struct wi_ltv_keys) / 2 - 1;
! 		bcopy(&sc->wi_keys, wreq, sizeof(struct wi_ltv_keys));
! 		break;
! 	default:
! #if 0
! 		error = EIO;
! #else
! #ifdef DIAGNOSTIC
! 		printf("%s: wi_getdef: unknown request %d\n",
! 		    sc->sc_dev.dv_xname, wreq->wi_type);
! #endif
! #endif
! 		break;
! 	}
! 
! 	return (error);
  }
  
  static int wi_ioctl(ifp, command, data)
***************
*** 1011,1048 ****
  	caddr_t			data;
  {
  	int			s, error = 0;
! 	struct wi_softc		*sc;
  	struct wi_req		wreq;
  	struct ifreq		*ifr;
  	struct proc *p = curproc;
  	struct ifaddr *ifa = (struct ifaddr *)data;
  
  	s = splimp();
  
- 	sc = ifp->if_softc;
  	ifr = (struct ifreq *)data;
- 
- 	if (sc->wi_gone)
- 		return(ENODEV);
- 
  	switch (command) {
  	case SIOCSIFADDR:
! 		if (!(ifp->if_flags & IFF_RUNNING) &&
! 		    (error = wi_enable(sc)) != 0)
  			break;
  		ifp->if_flags |= IFF_UP;
  		switch (ifa->ifa_addr->sa_family) {
  #ifdef INET
  		case AF_INET:
  			wi_init(sc);
! 			arp_ifinit(&sc->sc_ethercom.ec_if, ifa);
  			break;
  #endif
  		default:
  			wi_init(sc);
  			break;
  		}
- 		error = 0;
  		break;
  #if 0
  	case SIOCSIFMTU:
--- 1094,1127 ----
  	caddr_t			data;
  {
  	int			s, error = 0;
! 	struct wi_softc		*sc = ifp->if_softc;
  	struct wi_req		wreq;
  	struct ifreq		*ifr;
  	struct proc *p = curproc;
  	struct ifaddr *ifa = (struct ifaddr *)data;
  
+ 	if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
+ 		return (ENXIO);
+ 
  	s = splimp();
  
  	ifr = (struct ifreq *)data;
  	switch (command) {
  	case SIOCSIFADDR:
! 		if ((error = wi_enable(sc)) != 0)
  			break;
  		ifp->if_flags |= IFF_UP;
  		switch (ifa->ifa_addr->sa_family) {
  #ifdef INET
  		case AF_INET:
  			wi_init(sc);
! 			arp_ifinit(ifp, ifa);
  			break;
  #endif
  		default:
  			wi_init(sc);
  			break;
  		}
  		break;
  #if 0
  	case SIOCSIFMTU:
***************
*** 1050,1079 ****
  		break;
  #endif
  	case SIOCSIFFLAGS:
! 		if (ifp->if_flags & IFF_UP) {
! 			if ((ifp->if_flags & IFF_RUNNING) == 0)
! 				wi_enable(sc);
! 			if (ifp->if_flags & IFF_RUNNING &&
! 			    ifp->if_flags & IFF_PROMISC &&
! 			    !(sc->wi_if_flags & IFF_PROMISC)) {
! 				WI_SETVAL(WI_RID_PROMISC, 1);
! 			} else if (ifp->if_flags & IFF_RUNNING &&
! 			    !(ifp->if_flags & IFF_PROMISC) &&
! 			    sc->wi_if_flags & IFF_PROMISC) {
! 				WI_SETVAL(WI_RID_PROMISC, 0);
! 			} else
  				wi_init(sc);
- 		} else {
- 			if (ifp->if_flags & IFF_RUNNING) {
- 				wi_stop(sc);
- 				wi_disable(sc);
- 			}
  		}
  		sc->wi_if_flags = ifp->if_flags;
- 		error = 0;
  		break;
  	case SIOCADDMULTI:
  	case SIOCDELMULTI:
  		/* Update our multicast list. */
  		error = (command == SIOCADDMULTI) ?
  		    ether_addmulti(ifr, &sc->sc_ethercom) :
--- 1129,1175 ----
  		break;
  #endif
  	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.
! 			 */
! 			wi_stop(sc);
! 			wi_disable(sc);
! 		} 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.
! 			 */
! 			if ((error = wi_enable(sc)) != 0)
! 				break;
! 			wi_init(sc);
! 		} else if ((ifp->if_flags & IFF_UP) != 0) {
! 			/*
! 			 * Reset the interface to pick up changes in any other
! 			 * flags that affect hardware registers.
! 			 */
! #if 0
! 			/* XXX We need to call wi_setmulti(), don't we? */
! 			if ((ifp->if_flags & IFF_PROMISC) ^
! 			    (sc->wi_if_flags & IFF_PROMISC))
! 				WI_SETVAL(WI_RID_PROMISC,
! 				    (ifp->if_flags & IFF_PROMISC) != 0);
! 			else
! #endif
  				wi_init(sc);
  		}
  		sc->wi_if_flags = ifp->if_flags;
  		break;
  	case SIOCADDMULTI:
  	case SIOCDELMULTI:
+ 		if (sc->sc_enabled == 0) {
+ 			error = EIO;
+ 			break;
+ 		}
+ 
  		/* Update our multicast list. */
  		error = (command == SIOCADDMULTI) ?
  		    ether_addmulti(ifr, &sc->sc_ethercom) :
***************
*** 1096,1112 ****
  			/* For non-root user, return all-zeroes keys */
  			if (suser(p->p_ucred, &p->p_acflag))
  				bzero((char *)&wreq,
! 				      sizeof(struct wi_ltv_keys));
  			else
  				bcopy((char *)&sc->wi_keys, (char *)&wreq,
! 				      sizeof(struct wi_ltv_keys));
  		} else {
! 			if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) {
  				error = EINVAL;
- 				break;
- 			}
  		}
! 		error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
  		break;
  	case SIOCSWAVELAN:
  		error = suser(p->p_ucred, &p->p_acflag);
--- 1192,1209 ----
  			/* For non-root user, return all-zeroes keys */
  			if (suser(p->p_ucred, &p->p_acflag))
  				bzero((char *)&wreq,
! 				    sizeof(struct wi_ltv_keys));
  			else
  				bcopy((char *)&sc->wi_keys, (char *)&wreq,
! 				    sizeof(struct wi_ltv_keys));
  		} else {
! 			if (sc->sc_enabled == 0)
! 				error = wi_getdef(sc, &wreq);
! 			else if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq))
  				error = EINVAL;
  		}
! 		if (error == 0)
! 			error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
  		break;
  	case SIOCSWAVELAN:
  		error = suser(p->p_ucred, &p->p_acflag);
***************
*** 1122,1130 ****
  			error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
  			    wreq.wi_len);
  		} else {
! 			error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq);
! 			if (!error)
! 				wi_setdef(sc, &wreq);
  		}
  		break;
  	default:
--- 1219,1232 ----
  			error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val,
  			    wreq.wi_len);
  		} else {
! 			if (sc->sc_enabled != 0)
! 				error = wi_write_record(sc,
! 				    (struct wi_ltv_gen *)&wreq);
! 			if (error == 0)
! 				error = wi_setdef(sc, &wreq);
! 			if (error == 0 && sc->sc_enabled != 0)
! 				/* Reinitialize WaveLAN. */
! 				wi_init(sc);
  		}
  		break;
  	default:
***************
*** 1134,1163 ****
  
  	splx(s);
  
! 	return(error);
  }
  
! static void wi_init(xsc)
! 	void			*xsc;
  {
! 	struct wi_softc		*sc = xsc;
! 	struct ifnet		*ifp = &sc->sc_ethercom.ec_if;
! 	int			s;
! 	struct wi_ltv_macaddr	mac;
! 	int			id = 0;
! 	int			running;
  
! 	if (sc->wi_gone)
! 		return;
  
  	s = splimp();
  
- 	running = ifp->if_flags & IFF_RUNNING;
- 	if (running)
- 		wi_stop(sc);
- 
- 	wi_reset(sc);
- 
  	/* Program max data length. */
  	WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
  
--- 1236,1257 ----
  
  	splx(s);
  
! 	return (error);
  }
  
! static void
! wi_init(sc)
! 	struct wi_softc *sc;
  {
! 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
! 	struct wi_ltv_macaddr mac;
! 	int s, id = 0;
  
! 	wi_stop(sc);
! 	wi_reset(sc);
  
  	s = splimp();
  
  	/* Program max data length. */
  	WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
  
***************
*** 1220,1226 ****
  	wi_setmulti(sc);
  
  	/* Enable desired port */
! 	wi_cmd(sc, WI_CMD_ENABLE|sc->wi_portnum, 0);
  
  	if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id))
  		printf("%s: tx buffer allocation failed\n",
--- 1314,1320 ----
  	wi_setmulti(sc);
  
  	/* Enable desired port */
! 	wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0);
  
  	if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id))
  		printf("%s: tx buffer allocation failed\n",
***************
*** 1232,1249 ****
  		    sc->sc_dev.dv_xname);
  	sc->wi_tx_mgmt_id = id;
  
- 	/* enable interrupts */
- 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
- 
  	splx(s);
  
! 	if (running)
! 		ifp->if_flags |= IFF_RUNNING;
  	ifp->if_flags &= ~IFF_OACTIVE;
  
  	timeout(wi_inquire, sc, hz * 60);
- 
- 	return;
  }
  
  static void wi_start(ifp)
--- 1326,1340 ----
  		    sc->sc_dev.dv_xname);
  	sc->wi_tx_mgmt_id = id;
  
  	splx(s);
  
! 	/* Enable interrupts */
! 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
! 
! 	ifp->if_flags |= IFF_RUNNING;
  	ifp->if_flags &= ~IFF_OACTIVE;
  
  	timeout(wi_inquire, sc, hz * 60);
  }
  
  static void wi_start(ifp)
***************
*** 1257,1265 ****
  
  	sc = ifp->if_softc;
  
- 	if (sc->wi_gone)
- 		return;
- 
  	if (ifp->if_flags & IFF_OACTIVE)
  		return;
  
--- 1348,1353 ----
***************
*** 1348,1356 ****
  	struct wi_80211_hdr	*hdr;
  	caddr_t			dptr;
  
- 	if (sc->wi_gone)
- 		return(ENODEV);
- 
  	hdr = (struct wi_80211_hdr *)data;
  	dptr = data + sizeof(struct wi_80211_hdr);
  
--- 1436,1441 ----
***************
*** 1380,1398 ****
  {
  	struct ifnet		*ifp;
  
- 	if (sc->wi_gone)
- 		return;
- 
  	ifp = &sc->sc_ethercom.ec_if;
  
  	CSR_WRITE_2(sc, WI_INT_EN, 0);
  	wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0);
  
  	untimeout(wi_inquire, sc);
- 
- 	ifp->if_flags &= ~IFF_OACTIVE;
  
! 	return;
  }
  
  static void wi_watchdog(ifp)
--- 1465,1479 ----
  {
  	struct ifnet		*ifp;
  
  	ifp = &sc->sc_ethercom.ec_if;
  
  	CSR_WRITE_2(sc, WI_INT_EN, 0);
  	wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0);
  
  	untimeout(wi_inquire, sc);
  
! 	ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING);
! 	ifp->if_timer = 0;
  }
  
  static void wi_watchdog(ifp)
***************
*** 1451,1458 ****
  	struct wi_softc *sc = (struct wi_softc *)self;
  	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  
! 	if (ifp->if_flags & IFF_RUNNING)
! 		untimeout(wi_inquire, sc);
  	wi_disable(sc);
  
  	if (sc->wi_resource & WI_RES_NET) {
--- 1532,1539 ----
  	struct wi_softc *sc = (struct wi_softc *)self;
  	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  
! 	untimeout(wi_inquire, sc);
! 	shutdownhook_disestablish(sc->sc_sdhook);
  	wi_disable(sc);
  
  	if (sc->wi_resource & WI_RES_NET) {