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) {