Please test this diff on all pcmcia cards and machines you can find,
and report the results directly to me (ie. test the zaurus with brand
new -current code, apm i386 laptops, and the other non-suspending
cases such as amd64/i386 acpi - but don't test suspend there).

PLEASE do this very soon since I want to move ahead quickly (I am
working on making all 4 (zaurus, i386-apm, i386-acpi, amd64-acpi)
suspend-resume codepaths use the same driver infastructure; this will
remove a butload of special cases.

This will not yet make pcmcia suspend/resume correctly on many acpi
machines; that requires more diffs which will come once pcmcia is
fixed.  That's a hint to test this on the other machines soon.  There
are also some usb changes coming, and then zaurus changes, and then
i386 changes fully using the new infrastructure.. and finally, removal
of all the powerhook code.

I know there are many bugs left in here; there were many here to start
with.  This diff will be split up when it is commited, but it is better
to have it all for testing.

A rough summary of the changes:

- pcmcia was converting suspend/resume into activate/deactivate to the
  card drivers. this is WRONG, since the needs of activate and deactivate
  are different.  I have started trying to resolve this in some drivers,
  and want to get this diff in with a few fixed drivers, so that the others
  can catch up to the new better way of doing this

- some drivers do the pcmcia_function_enable() and interrupt establishment
  in their xxattach, then do it again in xxactivate.  I am trying to work
  around this now, but not yet happy with the solution

- related to the previous comment, a massive amount of #ifdef notyet
  code in these drivers will be deleted later on, but I wanted to keep
  this simple for now.

- i found a few more drivers which need a workq for resume
- to interlock against the ioctl, kettenis wants us to move the
  tsleep(&sc->wi_flags thing to a rw_lock; someone has to do that work
  in some other drivers first then I will copy that here.
- there are other drivers in other subsystems which use workq and need
  the interlocks too.  is anyone going to help?

- pcmcia com continue talking serial in cu after an unsuspend

- i have been playing with looping ifconfig's and ping's through suspends
- ne works
- wi works
- malo is causing memory corruption on a re-insert and re-dhclient.  I
  cannot spot the bug.

- wdc controllers work fine; no more wdc timeout errors!
- wdc at install time requires that softraid be disabled because
  softraid is walking alldevs searching for disks and then calling a
  bucketload of functions which sleep.  It is a massive bug in softraid.

- sm, xe, an, ray are untested, but I will attempt to write diffs for
  them if someone shows up with hardware

Index: pci/if_wi_pci.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_wi_pci.c,v
retrieving revision 1.46
diff -u -p -u -r1.46 if_wi_pci.c
--- pci/if_wi_pci.c     27 Aug 2010 18:29:44 -0000      1.46
+++ pci/if_wi_pci.c     29 Aug 2010 18:06:17 -0000
@@ -187,7 +187,18 @@ wi_pci_resume(void *arg1, void *arg2)
 {
        struct wi_softc *sc = (struct wi_softc *)arg1;
 
+       int s;
+
+       s = splnet();
+       while (sc->wi_flags & WI_FLAGS_BUSY)
+               tsleep(&sc->wi_flags, 0, "wipwr", 0);
+       sc->wi_flags |= WI_FLAGS_BUSY;
+
        wi_init(sc);
+
+       sc->wi_flags &= ~WI_FLAGS_BUSY;
+       wakeup(&sc->wi_flags);
+       splx(s);
 }
 
 void
Index: ic/if_wi.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/if_wi.c,v
retrieving revision 1.148
diff -u -p -u -r1.148 if_wi.c
--- ic/if_wi.c  2 Jul 2010 02:40:15 -0000       1.148
+++ ic/if_wi.c  29 Aug 2010 18:24:33 -0000
@@ -1544,28 +1544,36 @@ STATIC int
 wi_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
 {
        int                     s, error = 0, i, j, len;
-       struct wi_softc         *sc;
-       struct ifreq            *ifr;
+       struct wi_softc         *sc = ifp->if_softc;
+       struct ifreq            *ifr = (struct ifreq *)data;
        struct proc             *p = curproc;
        struct ifaddr           *ifa = (struct ifaddr *)data;
        struct wi_scan_res      *res;
        struct wi_scan_p2_hdr   *p2;
        struct wi_req           *wreq = NULL;
        u_int32_t               flags;
-
        struct ieee80211_nwid           *nwidp = NULL;
        struct ieee80211_nodereq_all    *na;
        struct ieee80211_bssid          *bssid;
 
        s = splnet();
-
-       sc = ifp->if_softc;
-       ifr = (struct ifreq *)data;
-
        if (!(sc->wi_flags & WI_FLAGS_ATTACHED)) {
+               error = ENODEV;
+               goto fail;
+       }
+
+       /*
+        * Prevent processes from entering this function while another
+        * process is tsleep'ing in it.
+        */
+       while ((sc->wi_flags & WI_FLAGS_BUSY) && error == 0)
+               error = tsleep(&sc->wi_flags, PCATCH, "wiioc", 0);
+       if (error != 0) {
                splx(s);
-               return(ENODEV);
+               return error;
        }
+       sc->wi_flags |= WI_FLAGS_BUSY;
+
 
        DPRINTF (WID_IOCTL, ("wi_ioctl: command %lu data %p\n",
            command, data));
@@ -2032,6 +2040,9 @@ wi_ioctl(struct ifnet *ifp, u_long comma
        if (nwidp)
                free(nwidp, M_DEVBUF);
 
+fail:
+       sc->wi_flags &= ~WI_FLAGS_BUSY;
+       wakeup(&sc->wi_flags);
        splx(s);
        return(error);
 }
Index: ic/if_wivar.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/if_wivar.h,v
retrieving revision 1.29
diff -u -p -u -r1.29 if_wivar.h
--- ic/if_wivar.h       10 Aug 2009 20:29:54 -0000      1.29
+++ ic/if_wivar.h       29 Aug 2010 18:05:03 -0000
@@ -139,6 +139,7 @@ struct wi_softc     {
 #define WI_FLAGS_BUS_USB               0x0400
 #define WI_FLAGS_HAS_ENH_SECURITY      0x0800
 #define WI_FLAGS_TXPOWER               0x1000
+#define WI_FLAGS_BUSY                  0x2000
 
 #define WI_PRT_FMT "%s"
 #define WI_PRT_ARG(sc) (sc)->sc_dev.dv_xname
Index: pcmcia/cfxga.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/cfxga.c,v
retrieving revision 1.19
diff -u -p -u -r1.19 cfxga.c
--- pcmcia/cfxga.c      13 Oct 2009 19:33:16 -0000      1.19
+++ pcmcia/cfxga.c      29 Aug 2010 06:27:06 -0000
@@ -319,12 +319,8 @@ cfxga_activate(struct device *dev, int a
 
        switch (act) {
        case DVACT_ACTIVATE:
-               if (pcmcia_function_enable(sc->sc_pf) != 0) {
-                       printf("%s: function enable failed\n",
-                           sc->sc_dev.dv_xname);
-               } else {
-                       cfxga_reset_and_repaint(sc);
-               }
+               pcmcia_function_enable(sc->sc_pf);
+               cfxga_reset_and_repaint(sc);
                break;
        case DVACT_DEACTIVATE:
                pcmcia_function_disable(sc->sc_pf);
Index: pcmcia/com_pcmcia.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/com_pcmcia.c,v
retrieving revision 1.50
diff -u -p -u -r1.50 com_pcmcia.c
--- pcmcia/com_pcmcia.c 26 Jun 2010 23:24:45 -0000      1.50
+++ pcmcia/com_pcmcia.c 29 Aug 2010 19:22:48 -0000
@@ -210,22 +210,32 @@ com_pcmcia_activate(dev, act)
        int act;
 {
        struct com_pcmcia_softc *sc = (void *) dev;
-       int s;
 
-       s = spltty();
        switch (act) {
        case DVACT_ACTIVATE:
                pcmcia_function_enable(sc->sc_pf);
                sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_TTY,
                    comintr, sc, sc->sc_com.sc_dev.dv_xname);
                break;
-
+       case DVACT_SUSPEND:
+               if (sc->sc_ih)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               sc->sc_ih = NULL;
+               pcmcia_function_disable(sc->sc_pf);
+               break;
+       case DVACT_RESUME:
+               pcmcia_function_enable(sc->sc_pf);
+               sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_TTY,
+                   comintr, sc, sc->sc_com.sc_dev.dv_xname);
+               com_resume(&sc->sc_com);
+               break;
        case DVACT_DEACTIVATE:
-               pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               if (sc->sc_ih)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               sc->sc_ih = NULL;
                pcmcia_function_disable(sc->sc_pf);
                break;
        }
-       splx(s);
        return (0);
 }
 
Index: pcmcia/gpr.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/gpr.c,v
retrieving revision 1.14
diff -u -p -u -r1.14 gpr.c
--- pcmcia/gpr.c        29 Oct 2009 08:03:16 -0000      1.14
+++ pcmcia/gpr.c        29 Aug 2010 19:22:40 -0000
@@ -247,13 +247,13 @@ gpr_activate(struct device *dev, int act
                sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_TTY,
                    gpr_intr, sc, sc->sc_dev.dv_xname);
                break;
-
        case DVACT_DEACTIVATE:
-               pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               if (sc->sc_ih)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               sc->sc_ih = NULL;
                pcmcia_function_disable(sc->sc_pf);
                break;
        }
-
        return (0);
 }
 
Index: pcmcia/if_an_pcmcia.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/if_an_pcmcia.c,v
retrieving revision 1.20
diff -u -p -u -r1.20 if_an_pcmcia.c
--- pcmcia/if_an_pcmcia.c       13 Oct 2009 19:33:16 -0000      1.20
+++ pcmcia/if_an_pcmcia.c       29 Aug 2010 19:22:36 -0000
@@ -176,9 +176,7 @@ an_pcmcia_activate(struct device *dev, i
        struct an_softc *sc = &psc->sc_an;
        struct ieee80211com     *ic = &sc->sc_ic;
        struct ifnet            *ifp = &ic->ic_if;
-       int s;
 
-       s = splnet();
        switch (act) {
        case DVACT_ACTIVATE:
                pcmcia_function_enable(psc->sc_pf);
@@ -186,16 +184,15 @@ an_pcmcia_activate(struct device *dev, i
                    an_intr, sc, sc->sc_dev.dv_xname);
                an_init(ifp);
                break;
-
        case DVACT_DEACTIVATE:
                ifp->if_timer = 0;
                if (ifp->if_flags & IFF_RUNNING)
                        an_stop(ifp, 1);
-               pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
+               if (sc->sc_ih)
+                       pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
+               sc->sc_ih = NULL;
                pcmcia_function_disable(psc->sc_pf);
                break;
        }
-
-       splx(s);
        return (0);
 }
Index: pcmcia/if_cnw.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/if_cnw.c,v
retrieving revision 1.20
diff -u -p -u -r1.20 if_cnw.c
--- pcmcia/if_cnw.c     13 Oct 2009 19:33:16 -0000      1.20
+++ pcmcia/if_cnw.c     29 Aug 2010 19:22:32 -0000
@@ -860,9 +860,7 @@ cnw_activate(dev, act)
 {
        struct cnw_softc *sc = (struct cnw_softc *)dev;
         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
-       int s;
 
-       s = splnet();
        switch (act) {
        case DVACT_ACTIVATE:
                pcmcia_function_enable(sc->sc_pf);
@@ -870,14 +868,14 @@ cnw_activate(dev, act)
                    cnw_intr, sc, sc->sc_dev.dv_xname);
                cnw_init(sc);
                break;
-
        case DVACT_DEACTIVATE:
                ifp->if_timer = 0;
                ifp->if_flags &= ~IFF_RUNNING; /* XXX no cnw_stop() ? */
-               pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               if (sc->sc_ih)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               sc->sc_ih = NULL;
                pcmcia_function_disable(sc->sc_pf);
                break;
        }
-       splx(s);
        return (0);
 }
Index: pcmcia/if_ep_pcmcia.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/if_ep_pcmcia.c,v
retrieving revision 1.38
diff -u -p -u -r1.38 if_ep_pcmcia.c
--- pcmcia/if_ep_pcmcia.c       13 Oct 2009 19:33:16 -0000      1.38
+++ pcmcia/if_ep_pcmcia.c       29 Aug 2010 19:22:26 -0000
@@ -408,26 +408,38 @@ ep_pcmcia_activate(dev, act)
        struct ep_pcmcia_softc *sc = (struct ep_pcmcia_softc *)dev;
        struct ep_softc *esc = &sc->sc_ep;
        struct ifnet *ifp = &esc->sc_arpcom.ac_if;
-       int s;
 
-       s = splnet();
        switch (act) {
        case DVACT_ACTIVATE:
                pcmcia_function_enable(sc->sc_pf);
                sc->sc_ep.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
                    epintr, sc, esc->sc_dev.dv_xname);
-               epinit(esc);
+               if (ifp->if_flags & IFF_UP)
+                       epinit(esc);
                break;
-
-       case DVACT_DEACTIVATE:
+       case DVACT_SUSPEND:
                ifp->if_timer = 0;
                if (ifp->if_flags & IFF_RUNNING)
                        epstop(esc);
-               pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ep.sc_ih);
+               if (sc->sc_ep.sc_ih)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ep.sc_ih);
+               sc->sc_ep.sc_ih = NULL;
+               pcmcia_function_disable(sc->sc_pf);
+               break;
+       case DVACT_RESUME:
+               pcmcia_function_enable(sc->sc_pf);
+               sc->sc_ep.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
+                   epintr, sc, esc->sc_dev.dv_xname);
+               if (ifp->if_flags & IFF_UP)
+                       epinit(esc);
+               break;
+       case DVACT_DEACTIVATE:
+               if (sc->sc_ep.sc_ih)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ep.sc_ih);
+               sc->sc_ep.sc_ih = NULL;
                pcmcia_function_disable(sc->sc_pf);
                break;
        }
-       splx(s);
        return (0);
 }
 
Index: pcmcia/if_malo.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/if_malo.c,v
retrieving revision 1.70
diff -u -p -u -r1.70 if_malo.c
--- pcmcia/if_malo.c    27 Aug 2010 17:08:00 -0000      1.70
+++ pcmcia/if_malo.c    29 Aug 2010 19:22:19 -0000
@@ -29,6 +29,7 @@
 #include <sys/malloc.h>
 #include <sys/sockio.h>
 #include <sys/mbuf.h>
+#include <sys/workq.h>
 
 #if NBPFILTER > 0
 #include <net/bpf.h>
@@ -71,6 +72,7 @@ int   malo_pcmcia_match(struct device *, v
 void   malo_pcmcia_attach(struct device *, struct device *, void *);
 int    malo_pcmcia_detach(struct device *, int);
 int    malo_pcmcia_activate(struct device *, int);
+void   malo_pcmcia_resume(void *, void *);
 
 void   cmalo_attach(void *);
 int    cmalo_ioctl(struct ifnet *, u_long, caddr_t);
@@ -236,30 +238,64 @@ malo_pcmcia_activate(struct device *dev,
        struct malo_softc *sc = &psc->sc_malo;
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
-       int s;
 
-       s = splnet();
        switch (act) {
        case DVACT_ACTIVATE:
                pcmcia_function_enable(psc->sc_pf);
                psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
                    cmalo_intr, sc, sc->sc_dev.dv_xname);
-               cmalo_init(ifp);
+               workq_queue_task(NULL, &sc->sc_resume_wqt, 0,
+                   malo_pcmcia_resume, sc, NULL);
                break;
-       case DVACT_DEACTIVATE:
-               ifp->if_timer = 0;
-               if (ifp->if_flags & IFF_RUNNING)
+       case DVACT_SUSPEND:
+               if ((sc->sc_flags & MALO_DEVICE_ATTACHED) &&
+                   (ifp->if_flags & IFF_RUNNING))
                        cmalo_stop(sc);
-               if (psc->sc_ih != NULL)
+               if (psc->sc_ih)
+                       pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
+               psc->sc_ih = NULL;
+               pcmcia_function_disable(psc->sc_pf);
+               break;
+       case DVACT_RESUME:
+               pcmcia_function_enable(psc->sc_pf);
+               psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
+                   cmalo_intr, sc, sc->sc_dev.dv_xname);
+               workq_queue_task(NULL, &sc->sc_resume_wqt, 0,
+                   malo_pcmcia_resume, sc, NULL);
+               break;
+       case DVACT_DEACTIVATE:
+               if ((sc->sc_flags & MALO_DEVICE_ATTACHED) &&
+                   (ifp->if_flags & IFF_RUNNING))
+                       cmalo_stop(sc);         /* XXX tries to touch regs */
+               if (psc->sc_ih)
                        pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
+               psc->sc_ih = NULL;
                pcmcia_function_disable(psc->sc_pf);
                break;
        }
-       splx(s);
-
        return (0);
 }
 
+void
+malo_pcmcia_resume(void *arg1, void *arg2)
+{
+       struct malo_softc *sc = arg1;
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct ifnet *ifp = &ic->ic_if;
+       int s;
+       
+       s = splnet();
+       while (sc->sc_flags & MALO_BUSY)
+               tsleep(&sc->sc_flags, 0, "malopwr", 0);
+       sc->sc_flags |= MALO_BUSY;
+
+       cmalo_init(ifp);
+
+       sc->sc_flags &= ~MALO_BUSY;
+       wakeup(&sc->sc_flags);
+       splx(s);
+}
+
 /*
  * Driver.
  */
@@ -350,6 +386,17 @@ cmalo_ioctl(struct ifnet *ifp, u_long cm
        int i, j, s, error = 0;
 
        s = splnet();
+       /*
+        * Prevent processes from entering this function while another
+        * process is tsleep'ing in it.
+        */
+       while ((sc->sc_flags & MALO_BUSY) && error == 0)
+               error = tsleep(&sc->sc_flags, PCATCH, "maloioc", 0);
+       if (error != 0) {
+               splx(s);
+               return error;
+       }
+       sc->sc_flags |= MALO_BUSY;
 
        switch (cmd) {
        case SIOCSIFADDR:
@@ -430,6 +477,8 @@ cmalo_ioctl(struct ifnet *ifp, u_long cm
                error = 0;
        }
 
+       sc->sc_flags &= ~MALO_BUSY;
+       wakeup(&sc->sc_flags);
        splx(s);
 
        return (error);
@@ -587,7 +636,7 @@ cmalo_fw_load_main(struct malo_softc *sc
                for (i = 0; i < bsize / 2; i++)
                        MALO_WRITE_2(sc, MALO_REG_CMD_WRITE, htole16(uc[i]));
                MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
-                MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE,
+               MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE,
                    MALO_VAL_CMD_DL_OVER);
 
                /* poll for an acknowledgement */
@@ -648,8 +697,8 @@ cmalo_init(struct ifnet *ifp)
        sc->sc_flags &= ~MALO_ASSOC_FAILED;
 
        /* get current channel */
-        ic->ic_bss->ni_chan = ic->ic_ibss_chan;
-        sc->sc_curchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
+       ic->ic_bss->ni_chan = ic->ic_ibss_chan;
+       sc->sc_curchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
        DPRINTF(1, "%s: current channel is %d\n",
            sc->sc_dev.dv_xname, sc->sc_curchan);
 
@@ -704,7 +753,7 @@ void
 cmalo_stop(struct malo_softc *sc)
 {
        struct ieee80211com *ic = &sc->sc_ic;
-        struct ifnet *ifp = &ic->ic_if;
+       struct ifnet *ifp = &ic->ic_if;
 
        /* device down */
        ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
@@ -715,6 +764,7 @@ cmalo_stop(struct malo_softc *sc)
        /* reset device */
        cmalo_cmd_set_reset(sc);
        sc->sc_flags &= ~MALO_FW_LOADED;
+       ifp->if_timer = 0;
 
        DPRINTF(1, "%s: device down\n", sc->sc_dev.dv_xname);
 }
Index: pcmcia/if_malovar.h
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/if_malovar.h,v
retrieving revision 1.27
diff -u -p -u -r1.27 if_malovar.h
--- pcmcia/if_malovar.h 9 Oct 2007 20:37:32 -0000       1.27
+++ pcmcia/if_malovar.h 29 Aug 2010 06:33:54 -0000
@@ -42,7 +42,7 @@
 #define MALO_DEVICE_ATTACHED   (1 << 0)
 #define MALO_FW_LOADED         (1 << 1)
 #define MALO_ASSOC_FAILED      (1 << 2)
-
+#define MALO_BUSY              (1 << 3)
 /*
  * FW command structures
  */
@@ -365,4 +365,5 @@ struct malo_softc {
        int                      sc_net_cur;
        struct malo_networks     sc_net[12];
        struct timeout           sc_scan_to;
+       struct workq_task        sc_resume_wqt;
 };
Index: pcmcia/if_ne_pcmcia.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/if_ne_pcmcia.c,v
retrieving revision 1.93
diff -u -p -u -r1.93 if_ne_pcmcia.c
--- pcmcia/if_ne_pcmcia.c       13 Oct 2009 19:33:16 -0000      1.93
+++ pcmcia/if_ne_pcmcia.c       29 Aug 2010 19:21:28 -0000
@@ -865,29 +865,47 @@ ne_pcmcia_activate(dev, act)
        struct ne_pcmcia_softc *sc = (struct ne_pcmcia_softc *)dev;
        struct dp8390_softc *esc = &sc->sc_ne2000.sc_dp8390;
        struct ifnet *ifp = &esc->sc_arpcom.ac_if;
-       int s;
 
-       s = splnet();
        switch (act) {
        case DVACT_ACTIVATE:
                pcmcia_function_enable(sc->sc_pf);
                sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
                    dp8390_intr, sc, esc->sc_dev.dv_xname);
+               /* XXX this is ridiculous */
                dp8390_init(esc);
+               dp8390_stop(esc);
                break;
-
-       case DVACT_DEACTIVATE:
+       case DVACT_SUSPEND:
                ifp->if_timer = 0;
-               if (ifp->if_flags & IFF_RUNNING)
+               if (ifp->if_flags & IFF_RUNNING) {
                        dp8390_stop(esc);
-               if (sc->sc_ih != NULL) {
+                       ifp->if_flags &= ~IFF_RUNNING;
+               }
+               if (sc->sc_ih != NULL)
                        pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
-                       sc->sc_ih = NULL;
+               sc->sc_ih = NULL;
+               pcmcia_function_disable(sc->sc_pf);
+               break;
+       case DVACT_RESUME:
+               pcmcia_function_enable(sc->sc_pf);
+               sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
+                   dp8390_intr, sc, esc->sc_dev.dv_xname);
+               dp8390_enable(esc);
+               if (ifp->if_flags & IFF_UP)
+                       dp8390_init(esc);
+               break;
+       case DVACT_DEACTIVATE:
+               ifp->if_timer = 0;
+               if (ifp->if_flags & IFF_RUNNING) {
+                       dp8390_stop(esc);
+                       ifp->if_flags &= ~IFF_RUNNING;
                }
+               if (sc->sc_ih != NULL)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               sc->sc_ih = NULL;
                pcmcia_function_disable(sc->sc_pf);
                break;
        }
-       splx(s);
        return (0);
 }
 
Index: pcmcia/if_ray.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/if_ray.c,v
retrieving revision 1.42
diff -u -p -u -r1.42 if_ray.c
--- pcmcia/if_ray.c     27 Aug 2010 05:04:12 -0000      1.42
+++ pcmcia/if_ray.c     29 Aug 2010 19:22:02 -0000
@@ -654,11 +654,7 @@ ray_activate(struct device *dev, int act
 {
        struct ray_softc *sc = (struct ray_softc *)dev;
        struct ifnet *ifp = &sc->sc_if;
-       int s;
 
-       RAY_DPRINTF(("%s: activate\n", sc->sc_xname));
-
-       s = splnet();
        switch (act) {
        case DVACT_ACTIVATE:
                pcmcia_function_enable(sc->sc_pf);
@@ -666,18 +662,15 @@ ray_activate(struct device *dev, int act
                ray_enable(sc);
                printf("\n");
                break;
-
        case DVACT_DEACTIVATE:
                if (ifp->if_flags & IFF_RUNNING)
                        ray_disable(sc);
-               if (sc->sc_ih) {
+               if (sc->sc_ih)
                        pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
-                       sc->sc_ih = NULL;
-               }
+               sc->sc_ih = NULL;
                pcmcia_function_disable(sc->sc_pf);
                break;
        }
-       splx(s);
        return (0);
 }
 
Index: pcmcia/if_sm_pcmcia.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/if_sm_pcmcia.c,v
retrieving revision 1.29
diff -u -p -u -r1.29 if_sm_pcmcia.c
--- pcmcia/if_sm_pcmcia.c       13 Oct 2009 19:33:16 -0000      1.29
+++ pcmcia/if_sm_pcmcia.c       29 Aug 2010 19:21:56 -0000
@@ -252,9 +252,7 @@ sm_pcmcia_activate(dev, act)
 {
        struct sm_pcmcia_softc *sc = (struct sm_pcmcia_softc *)dev;
        struct ifnet *ifp = &sc->sc_smc.sc_arpcom.ac_if;
-       int s;
 
-       s = splnet();
        switch (act) {
        case DVACT_ACTIVATE:
                pcmcia_function_enable(sc->sc_pf);
@@ -262,16 +260,16 @@ sm_pcmcia_activate(dev, act)
                    smc91cxx_intr, sc, sc->sc_smc.sc_dev.dv_xname);
                smc91cxx_init(&sc->sc_smc);
                break;
-
        case DVACT_DEACTIVATE:
                ifp->if_timer = 0;
                if (ifp->if_flags & IFF_RUNNING)
                        smc91cxx_stop(&sc->sc_smc);
-               pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               if (sc->sc_ih)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               sc->sc_ih = NULL;
                pcmcia_function_disable(sc->sc_pf);
                break;
        }
-       splx(s);
        return (0);
 }
 
Index: pcmcia/if_wi_pcmcia.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/if_wi_pcmcia.c,v
retrieving revision 1.68
diff -u -p -u -r1.68 if_wi_pcmcia.c
--- pcmcia/if_wi_pcmcia.c       13 Oct 2009 19:33:16 -0000      1.68
+++ pcmcia/if_wi_pcmcia.c       29 Aug 2010 19:21:12 -0000
@@ -49,6 +49,7 @@
 #include <sys/socket.h>
 #include <sys/device.h>
 #include <sys/tree.h>
+#include <sys/workq.h>
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -76,6 +77,7 @@ int   wi_pcmcia_match(struct device *, voi
 void   wi_pcmcia_attach(struct device *, struct device *, void *);
 int    wi_pcmcia_detach(struct device *, int);
 int    wi_pcmcia_activate(struct device *, int);
+void   wi_pcmcia_resume(void *, void *);
 
 struct wi_pcmcia_softc {
        struct wi_softc sc_wi;
@@ -83,6 +85,7 @@ struct wi_pcmcia_softc {
        struct pcmcia_io_handle sc_pcioh;
        int                     sc_io_window;
        struct pcmcia_function  *sc_pf;
+       struct workq_task       sc_resume_wqt;
 };
 
 struct cfattach wi_pcmcia_ca = {
@@ -472,28 +475,57 @@ wi_pcmcia_activate(struct device *dev, i
        struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)dev;
        struct wi_softc *sc = &psc->sc_wi;
        struct ifnet *ifp = &sc->sc_ic.ic_if;
-       int s;
 
-       s = splnet();
        switch (act) {
        case DVACT_ACTIVATE:
                pcmcia_function_enable(psc->sc_pf);
                sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
                    wi_intr, sc, sc->sc_dev.dv_xname);
-               wi_cor_reset(sc);
-               wi_init(sc);
+               workq_queue_task(NULL, &psc->sc_resume_wqt, 0,
+                   wi_pcmcia_resume, sc, NULL);
                break;
-
-       case DVACT_DEACTIVATE:
+       case DVACT_SUSPEND:
                ifp->if_timer = 0;
                if (ifp->if_flags & IFF_RUNNING)
                        wi_stop(sc);
                sc->wi_flags &= ~WI_FLAGS_INITIALIZED;
                if (sc->sc_ih != NULL)
                        pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
+               sc->sc_ih = NULL;
+               pcmcia_function_disable(psc->sc_pf);
+               break;
+       case DVACT_RESUME:
+               pcmcia_function_enable(psc->sc_pf);
+               sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
+                   wi_intr, sc, sc->sc_dev.dv_xname);
+               workq_queue_task(NULL, &psc->sc_resume_wqt, 0,
+                   wi_pcmcia_resume, sc, NULL);
+               break;
+       case DVACT_DEACTIVATE:
+               if (sc->sc_ih != NULL)
+                       pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
+               sc->sc_ih = NULL;
                pcmcia_function_disable(psc->sc_pf);
                break;
        }
-       splx(s);
        return (0);
+}
+
+void
+wi_pcmcia_resume(void *arg1, void *arg2)
+{
+       struct wi_softc *sc = (struct wi_softc *)arg1;
+       int s;
+
+       s = splnet();
+       while (sc->wi_flags & WI_FLAGS_BUSY)
+               tsleep(&sc->wi_flags, 0, "wipwr", 0);
+       sc->wi_flags |= WI_FLAGS_BUSY;
+
+       wi_cor_reset(sc);
+       wi_init(sc);
+
+       sc->wi_flags &= ~WI_FLAGS_BUSY;
+       wakeup(&sc->wi_flags);
+       splx(s);
 }
Index: pcmcia/if_xe.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/if_xe.c,v
retrieving revision 1.38
diff -u -p -u -r1.38 if_xe.c
--- pcmcia/if_xe.c      13 Oct 2009 19:33:16 -0000      1.38
+++ pcmcia/if_xe.c      29 Aug 2010 20:55:01 -0000
@@ -420,11 +420,6 @@ xe_pcmcia_attach(parent, self, aux)
                ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE);
                xe_stop(sc);
        }
-
-#ifdef notyet
-       pcmcia_function_disable(pa->pf);
-#endif /* notyet */
-
        return;
 
 bad:
@@ -466,26 +461,42 @@ xe_pcmcia_activate(dev, act)
 {
        struct xe_pcmcia_softc *sc = (struct xe_pcmcia_softc *)dev;
        struct ifnet *ifp = &sc->sc_xe.sc_arpcom.ac_if;
-       int s;
 
-       s = splnet();
        switch (act) {
        case DVACT_ACTIVATE:
+               if (sc->sc_xe.sc_ih == NULL) {
+                       pcmcia_function_enable(sc->sc_pf);
+                       sc->sc_xe.sc_ih = pcmcia_intr_establish(sc->sc_pf, 
IPL_NET,
+                           xe_intr, sc, sc->sc_xe.sc_dev.dv_xname);
+               }
+               break;
+       case DVACT_SUSPEND:
+               if (ifp->if_flags & IFF_RUNNING)
+                       xe_stop(&sc->sc_xe);
+               ifp->if_flags &= ~IFF_RUNNING;
+               if (sc->sc_xe.sc_ih)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_xe.sc_ih);
+               sc->sc_xe.sc_ih = NULL;
+               pcmcia_function_disable(sc->sc_pf);
+               break;
+       case DVACT_RESUME:
                pcmcia_function_enable(sc->sc_pf);
                sc->sc_xe.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
                    xe_intr, sc, sc->sc_xe.sc_dev.dv_xname);
-               xe_init(&sc->sc_xe);
+               /* XXX this is a ridiculous */
+               xe_reset(&sc->sc_xe);
+               if ((ifp->if_flags & IFF_UP) == 0)
+                       xe_stop(&sc->sc_xe);
                break;
-
        case DVACT_DEACTIVATE:
                ifp->if_timer = 0;
-               if (ifp->if_flags & IFF_RUNNING)
-                       xe_stop(&sc->sc_xe);
-               pcmcia_intr_disestablish(sc->sc_pf, sc->sc_xe.sc_ih);
+               ifp->if_flags &= ~IFF_RUNNING;
+               if (sc->sc_xe.sc_ih)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_xe.sc_ih);
+               sc->sc_xe.sc_ih = NULL;
                pcmcia_function_disable(sc->sc_pf);
                break;
        }
-       splx(s);
        return (0);
 }
 
Index: pcmcia/pcmcia.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/pcmcia.c,v
retrieving revision 1.39
diff -u -p -u -r1.39 pcmcia.c
--- pcmcia/pcmcia.c     11 Sep 2007 13:39:34 -0000      1.39
+++ pcmcia/pcmcia.c     29 Aug 2010 18:50:46 -0000
@@ -55,6 +55,7 @@ int   pcmcia_verbose = 0;
 int    pcmcia_match(struct device *, void *, void *);
 int    pcmcia_submatch(struct device *, void *, void *);
 void   pcmcia_attach(struct device *, struct device *, void *);
+int    pcmcia_activate(struct device *, int);
 int    pcmcia_print(void *, const char *);
 void   pcmcia_card_detach_notify(struct device *, void *);
 void   pcmcia_power(int why, void *arg);
@@ -71,7 +72,8 @@ struct cfdriver pcmcia_cd = {
 };
 
 struct cfattach pcmcia_ca = {
-       sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach
+       sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach, NULL,
+       pcmcia_activate
 };
 
 int
@@ -131,31 +133,43 @@ pcmcia_attach(parent, self, aux)
        powerhook_establish(pcmcia_power, sc);
 }
 
-void
-pcmcia_power(why, arg)
-       int why;
-       void *arg;
+int
+pcmcia_activate(struct device *self, int act)
 {
-       struct pcmcia_softc *sc = (struct pcmcia_softc *) arg;
+       struct pcmcia_softc *sc = (struct pcmcia_softc *)self;
        struct pcmcia_function *pf;
-       struct device *d;
-       int act = DVACT_ACTIVATE;
-
-       if (why != PWR_RESUME)
-               act = DVACT_DEACTIVATE;
 
-       for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
-            pf = SIMPLEQ_NEXT(pf, pf_list)) {
-               if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL)
-                       continue;
-               d = pf->child;
-               if (d == NULL)
-                       continue;
-               if (act == DVACT_ACTIVATE)
-                       config_activate(pf->child);
-               else
+       switch (act) {
+       case DVACT_ACTIVATE:
+               /* No children yet */
+               break;
+       case DVACT_DEACTIVATE:
+               for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
+                    pf = SIMPLEQ_NEXT(pf, pf_list)) {
+                       if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL ||
+                           pf->child == NULL)
+                               continue;
                        config_deactivate(pf->child);
+               }
+               break;
+       case DVACT_SUSPEND:
+       case DVACT_RESUME:
+               for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
+                    pf = SIMPLEQ_NEXT(pf, pf_list)) {
+                       if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL ||
+                           pf->child == NULL)
+                               continue;
+                       config_suspend(pf->child, act);
+               }
+               break;
        }
+       return 0;
+}
+
+void
+pcmcia_power(int why, void *arg)
+{
+       pcmcia_activate(arg, why);
 }
 
 int
@@ -296,9 +310,8 @@ pcmcia_card_deactivate(dev)
         */
        for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
             pf = SIMPLEQ_NEXT(pf, pf_list)) {
-               if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL)
-                       continue;
-               if (pf->child == NULL)
+               if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL ||
+                   pf->child == NULL)
                        continue;
                DPRINTF(("%s: deactivating %s (function %d)\n",
                    sc->dev.dv_xname, pf->child->dv_xname, pf->number));
Index: pcmcia/wdc_pcmcia.c
===================================================================
RCS file: /cvs/src/sys/dev/pcmcia/wdc_pcmcia.c,v
retrieving revision 1.22
diff -u -p -u -r1.22 wdc_pcmcia.c
--- pcmcia/wdc_pcmcia.c 29 Aug 2010 18:41:24 -0000      1.22
+++ pcmcia/wdc_pcmcia.c 29 Aug 2010 20:21:50 -0000
@@ -138,8 +138,6 @@ int wdc_pcmcia_disk_device_interface(str
 struct wdc_pcmcia_product *
        wdc_pcmcia_lookup(struct pcmcia_attach_args *);
 
-int    wdc_pcmcia_enable(void *, int);
-
 int
 wdc_pcmcia_disk_device_interface_callback(tuple, arg)
        struct pcmcia_tuple *tuple;
@@ -354,23 +352,12 @@ wdc_pcmcia_attach(parent, self, aux)
        if (quirks & WDC_PCMCIA_NO_EXTRA_RESETS)
                sc->sc_wdcdev.cap |= WDC_CAPABILITY_NO_EXTRA_RESETS;
 
-#ifdef notyet
-       /* We can enable and disable the controller. */
-       sc->sc_wdcdev.sc_atapi_adapter.scsipi_enable = wdc_pcmcia_enable;
-
-       /*
-        * Disable the pcmcia function now; wdcattach() will enable
-        * us again as it adds references to probe for children.
-        */
-       pcmcia_function_disable(pa->pf);
-#else
        /* Establish the interrupt handler. */
        sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, wdcintr,
            &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname);
        intrstr = pcmcia_intr_string(sc->sc_pf, sc->sc_ih);
        if (*intrstr)
                printf(": %s", intrstr);
-#endif
 
        printf("\n");
 
@@ -438,81 +425,44 @@ wdc_pcmcia_activate(self, act)
        int act;
 {
        struct wdc_pcmcia_softc *sc = (struct wdc_pcmcia_softc *)self;
-       int rv = 0, s;
+       int rv = 0;
 
        if (sc->sc_iowindow == -1)
                /* Nothing to activate/deactivate. */
                return (0);
 
-       s = splbio();
        switch (act) {
        case DVACT_ACTIVATE:
-               if (pcmcia_function_enable(sc->sc_pf)) {
-                       printf("%s: couldn't enable PCMCIA function\n",
-                           sc->sc_wdcdev.sc_dev.dv_xname);
-                       rv = EIO;
-                       break;
+               if (sc->sc_ih == NULL) {
+                       /* XXX attach function already did the work */
+                       pcmcia_function_enable(sc->sc_pf);
+                       sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, 
+                           wdcintr, &sc->wdc_channel, 
sc->sc_wdcdev.sc_dev.dv_xname);
+                       wdcreset(&sc->wdc_channel, VERBOSE);
                }
-
+               rv = config_activate_children(self, act);
+               break;
+       case DVACT_SUSPEND:
+               rv = config_activate_children(self, act);
+               if (sc->sc_ih)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               sc->sc_ih = NULL;
+               pcmcia_function_disable(sc->sc_pf);
+               break;
+       case DVACT_RESUME:
+               pcmcia_function_enable(sc->sc_pf);
                sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, 
                    wdcintr, &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname);
-               if (sc->sc_ih == NULL) {
-                       printf("%s: "
-                           "couldn't establish interrupt handler\n",
-                           sc->sc_wdcdev.sc_dev.dv_xname);
-                       pcmcia_function_disable(sc->sc_pf);
-                       rv = EIO;
-                       break;
-               }
-
                wdcreset(&sc->wdc_channel, VERBOSE);
                rv = config_activate_children(self, act);
                break;
-
        case DVACT_DEACTIVATE:
-               pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
-               pcmcia_function_disable(sc->sc_pf);
                rv = config_activate_children(self, act);
-               break;
-       }
-       splx(s);
-       return (rv);
-}
-
-#if 0
-int
-wdc_pcmcia_enable(arg, onoff)
-       void *arg;
-       int onoff;
-{
-       struct wdc_pcmcia_softc *sc = arg;
-
-       if (onoff) {
-                if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0) {
-                       if (pcmcia_function_enable(sc->sc_pf)) {
-                               printf("%s: couldn't enable PCMCIA function\n",
-                                   sc->sc_wdcdev.sc_dev.dv_xname);
-                               return (EIO);
-                       }
-
-                       sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, 
-                           wdcintr, &sc->wdc_channel, sc->sc_dev.dv_xname);
-                       if (sc->sc_ih == NULL) {
-                               printf("%s: "
-                                   "couldn't establish interrupt handler\n",
-                                   sc->sc_wdcdev.sc_dev.dv_xname);
-                               pcmcia_function_disable(sc->sc_pf);
-                               return (EIO);
-                       }
-
-                       wdcreset(&sc->wdc_channel, VERBOSE);
-               }
-       } else {
-                if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0)
+               if (sc->sc_ih)
                        pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               sc->sc_ih = NULL;
                pcmcia_function_disable(sc->sc_pf);
+               break;
        }
-
-       return (0);
+       return (rv);
 }
-#endif

Reply via email to