Last of the glue and devices for for PCMCIA support from Stefan Grefen
authorhvozda <hvozda@openbsd.org>
Tue, 16 Jan 1996 20:12:58 +0000 (20:12 +0000)
committerhvozda <hvozda@openbsd.org>
Tue, 16 Jan 1996 20:12:58 +0000 (20:12 +0000)
<grefen@convex.com> with modifications by John Kohl <jtk@kolvir.blrc.ma.us>

sys/dev/ic/com.c
sys/dev/isa/com.c
sys/dev/isa/files.isa
sys/dev/isa/if_ed.c
sys/dev/isa/if_ep.c
sys/dev/isa/pcmcia_isa.c [new file with mode: 0644]
sys/dev/isa/pcmcia_pcic.c [new file with mode: 0644]

index ad63516..c0003de 100644 (file)
@@ -134,6 +134,50 @@ extern int kgdb_debug_init;
 #define        CLR(t, f)       (t) &= ~(f)
 #define        ISSET(t, f)     ((t) & (f))
 
+#include "pcmciabus.h"
+#if NPCMCIABUS >0                       
+/* additional setup needed for pcmcia devices */
+#include <dev/pcmcia/pcmciabus.h>
+/* modify config entry */
+static int 
+commod(pc_link,self,pc_cf,cf)
+    struct pcmcia_link *pc_link;
+    struct device *self;
+    struct pcmcia_conf *pc_cf; 
+    struct cfdata *cf;
+{               
+    int err; 
+    struct pcmciadevs *dev=pc_link->device;
+    struct ed_softc *sc = (void *)self; 
+    if(!(err=pc_link->adapter->bus_link->bus_config(pc_link,self,pc_cf,cf))) {
+        pc_cf->memwin=0;
+       if(pc_cf->cfgtype==0) 
+           pc_cf->cfgtype=CFGENTRYID; /* determine from ioaddr */
+    }
+    return err;
+}
+static struct pcmcia_com {
+    struct pcmcia_device pcd;
+} pcmcia_com= {
+    "PCMCIA Modem card",commod,NULL,NULL,NULL
+};          
+struct pcmciadevs pcmcia_com_devs[]={
+  { "com", 0, 
+  NULL, "*MODEM*", NULL, NULL,
+  NULL, (void *)&pcmcia_com 
+  },
+  { "com", 0, 
+  NULL, NULL, "*MODEM*", NULL,
+  NULL, (void *)&pcmcia_com 
+  },
+  { "com", 0, 
+  NULL, NULL, NULL, "*MODEM*",
+  NULL, (void *)&pcmcia_com 
+  },
+  {NULL}
+};
+#endif
+
 int
 comspeed(speed)
        long speed;
@@ -163,12 +207,21 @@ int
 comprobe1(iobase)
        int iobase;
 {
+       int tmp;
+       int i,k;
 
        /* force access to id reg */
        outb(iobase + com_lcr, 0);
        outb(iobase + com_iir, 0);
-       if (inb(iobase + com_iir) & 0x38)
-               return 0;
+       for(i=0;i<32;i++) {
+           k=inb(iobase + com_iir);
+           if (k & 0x38) {
+               inb(iobase + com_data ); /* cleanup */
+           } else
+               break;
+       }
+       if(i>=32) 
+           return 0;
 
        return 1;
 }
index ad63516..c0003de 100644 (file)
@@ -134,6 +134,50 @@ extern int kgdb_debug_init;
 #define        CLR(t, f)       (t) &= ~(f)
 #define        ISSET(t, f)     ((t) & (f))
 
+#include "pcmciabus.h"
+#if NPCMCIABUS >0                       
+/* additional setup needed for pcmcia devices */
+#include <dev/pcmcia/pcmciabus.h>
+/* modify config entry */
+static int 
+commod(pc_link,self,pc_cf,cf)
+    struct pcmcia_link *pc_link;
+    struct device *self;
+    struct pcmcia_conf *pc_cf; 
+    struct cfdata *cf;
+{               
+    int err; 
+    struct pcmciadevs *dev=pc_link->device;
+    struct ed_softc *sc = (void *)self; 
+    if(!(err=pc_link->adapter->bus_link->bus_config(pc_link,self,pc_cf,cf))) {
+        pc_cf->memwin=0;
+       if(pc_cf->cfgtype==0) 
+           pc_cf->cfgtype=CFGENTRYID; /* determine from ioaddr */
+    }
+    return err;
+}
+static struct pcmcia_com {
+    struct pcmcia_device pcd;
+} pcmcia_com= {
+    "PCMCIA Modem card",commod,NULL,NULL,NULL
+};          
+struct pcmciadevs pcmcia_com_devs[]={
+  { "com", 0, 
+  NULL, "*MODEM*", NULL, NULL,
+  NULL, (void *)&pcmcia_com 
+  },
+  { "com", 0, 
+  NULL, NULL, "*MODEM*", NULL,
+  NULL, (void *)&pcmcia_com 
+  },
+  { "com", 0, 
+  NULL, NULL, NULL, "*MODEM*",
+  NULL, (void *)&pcmcia_com 
+  },
+  {NULL}
+};
+#endif
+
 int
 comspeed(speed)
        long speed;
@@ -163,12 +207,21 @@ int
 comprobe1(iobase)
        int iobase;
 {
+       int tmp;
+       int i,k;
 
        /* force access to id reg */
        outb(iobase + com_lcr, 0);
        outb(iobase + com_iir, 0);
-       if (inb(iobase + com_iir) & 0x38)
-               return 0;
+       for(i=0;i<32;i++) {
+           k=inb(iobase + com_iir);
+           if (k & 0x38) {
+               inb(iobase + com_data ); /* cleanup */
+           } else
+               break;
+       }
+       if(i>=32) 
+           return 0;
 
        return 1;
 }
index 99ac2a0..63981d6 100644 (file)
@@ -21,6 +21,12 @@ file dev/isa/isa.c                   isa needs-flag
 define isadma
 file   dev/isa/isadma.c                isadma needs-flag
 
+#pcmcia
+#config problems
+#device pcic at isa
+#file dev/isa/pcmcia_pcic.c  pcic pcmciabus
+file dev/isa/pcmcia_isa.c  pcmciabus
+
 #
 # 8250/16[45]50-based multi-port serial boards
 #
@@ -44,7 +50,7 @@ file  dev/isa/rtfps.c                 rtfps
 #
 
 # 8250/16[45]50-based "com" ports
-device com at isa, commulti: tty
+device com at isa, commulti, pcmciabus: tty
 file   dev/isa/com.c                   com needs-flag
 
 # Cyclades Cyclom multiport serial cards
@@ -120,7 +126,7 @@ file        dev/isa/elink.c                 elink
 
 # National Semiconductor DS8390/WD83C690-based boards
 # (WD/SMC 80x3 family, SMC Ultra [8216], 3Com 3C503, NE[12]000, and clones)
-device ed at isa: ether, ifnet
+device ed at isa, pcmciabus: ether, ifnet
 file   dev/isa/if_ed.c                 ed
 
 # 3Com 3C505
@@ -132,7 +138,7 @@ device      el at isa: ether, ifnet
 file   dev/isa/if_el.c                 el
 
 # 3Com 3C5x9, 3c59x (EtherLink III) family
-device ep at isa, pci: ether, ifnet, elink
+device ep at isa, pci, pcmciabus: ether, ifnet, elink
 file   dev/isa/if_ep.c                 ep
 
 # Fujitsu MB8696[05]-based boards
index a3617cd..06c0142 100644 (file)
@@ -17,6 +17,7 @@
  * similar clones.
  */
 
+#include "pcmciabus.h"
 #include "bpfilter.h"
 
 #include <sys/param.h>
@@ -68,10 +69,15 @@ struct ed_softc {
        void *sc_ih;
 
        struct  arpcom sc_arpcom;       /* ethernet common */
+       void *sc_sh;                    /* shutdown hook */
 
        char    *type_str;      /* pointer to type string */
        u_char  vendor;         /* interface vendor */
        u_char  type;           /* interface type code */
+       u_short spec_flags;
+#define ED_REATTACH    0x0001  /* Reattach */
+#define ED_NOTPRESENT  0x0002  /* card not present; do not allow
+                                  reconfiguration */
 
        int     asic_addr;      /* ASIC I/O bus address */
        int     nic_addr;       /* NIC (DS8390) I/O bus address */
@@ -143,6 +149,148 @@ struct cfdriver edcd = {
 #define        NIC_PUT(sc, off, val)   outb(sc->nic_addr + off, val)
 #define        NIC_GET(sc, off)        inb(sc->nic_addr + off)
 
+#if NPCMCIABUS > 0 
+
+#include <dev/pcmcia/pcmciabus.h>
+static int ed_probe_pcmcia_ne __P((struct device *, void *,
+                                  void *, struct pcmcia_link *));
+
+static int edmod __P((struct pcmcia_link *, struct device *,
+                     struct pcmcia_conf *, struct cfdata *cf));
+
+static int ed_remove __P((struct pcmcia_link *, struct device *));
+
+/* additional setup needed for pcmcia devices */
+static int
+ed_probe_pcmcia_ne(parent, match, aux, pc_link)
+       struct device *parent;
+       void *match;
+       void *aux;
+       struct pcmcia_link *pc_link;
+{
+       struct ed_softc *sc = match;
+       struct cfdata *cf = sc->sc_dev.dv_cfdata;
+       struct isa_attach_args *ia = aux;
+       struct pcmciadevs *dev=pc_link->device;
+       int err;
+       extern int ifqmaxlen;
+       u_char enaddr[ETHER_ADDR_LEN];
+
+       if ((int)dev->param >= 0)
+               err = pcmcia_read_cis(pc_link, enaddr, 
+                                     (int) dev->param, ETHER_ADDR_LEN);
+       else
+               err = 0;
+       if (err)
+               printf("Cannot read cis info %d\n", err);
+
+       if (ed_probe_Novell(sc, cf, ia)) {
+               delay(100);
+               if ((int)dev->param >= 0) {
+                   err = pcmcia_read_cis(pc_link, sc->sc_arpcom.ac_enaddr,
+                                     (int) dev->param, ETHER_ADDR_LEN);
+                   if (err) {
+                           printf("Cannot read cis info %d\n", err);
+                           return 0;
+                   }
+                   if(bcmp(enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN)) {
+                           printf("ENADDR MISMATCH %s ",
+                                  ether_sprintf(sc->sc_arpcom.ac_enaddr));
+                           printf("- %s\n", ether_sprintf(enaddr));
+                           bcopy(enaddr,sc->sc_arpcom.ac_enaddr,
+                                           ETHER_ADDR_LEN);
+                   }
+               }
+               /* clear ED_NOTPRESENT, set ED_REATTACH if needed */
+               sc->spec_flags=pc_link->flags&PCMCIA_REATTACH?ED_REATTACH:0;
+               sc->type_str = dev->model;
+               sc->sc_arpcom.ac_if.if_snd.ifq_maxlen=ifqmaxlen;
+               return 1;
+       }
+       return 0;
+}
+
+/* modify config entry */
+static int
+edmod(pc_link, self, pc_cf, cf) 
+       struct pcmcia_link *pc_link;
+       struct device *self;
+       struct pcmcia_conf *pc_cf;
+       struct cfdata *cf;
+{
+       int err;
+       struct pcmciadevs *dev=pc_link->device;
+       struct ed_softc *sc = (void *)self;
+       int svec_card = strcmp(dev->manufacturer, "SVEC") == 0;
+       int de650_0 = (pc_cf->memwin != 0) && !svec_card;
+       err = pc_link->adapter->bus_link->bus_config(pc_link, self, pc_cf, cf);
+       if (err)
+               return err;
+
+       if (svec_card) {
+               pc_cf->memwin = 0;
+       }
+       if (de650_0) {
+               pc_cf->io[0].flags =
+                   (pc_cf->io[0].flags&~PCMCIA_MAP_16)|PCMCIA_MAP_8;
+               pc_cf->memwin = 0;
+               pc_cf->cfgtype = DOSRESET|1;
+       }
+       else {
+               /* still wrong in CIS; fix it here */
+               pc_cf->io[0].flags = PCMCIA_MAP_8|PCMCIA_MAP_16;
+               pc_cf->cfgtype = 1;
+       }
+
+       return err;
+}
+
+
+static int
+ed_remove(pc_link,self) 
+       struct pcmcia_link *pc_link;
+       struct device *self;
+{
+       struct ed_softc *sc = (void *)self;
+       struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+       if_down(ifp);
+       edstop(sc);
+       shutdownhook_disestablish(sc->sc_sh);
+       ifp->if_flags &= ~(IFF_RUNNING|IFF_UP);
+       sc->spec_flags |= ED_NOTPRESENT;
+       return pc_link->adapter->bus_link->bus_unconfig(pc_link); 
+}
+
+static struct pcmcia_dlink {
+       struct pcmcia_device pcd;
+} pcmcia_dlink= {
+       "PCMCIA Novell compatible", edmod, ed_probe_pcmcia_ne, NULL, ed_remove
+};
+
+struct pcmciadevs pcmcia_ed_devs[]={
+      { "ed", 0, "D-Link", "DE-650", "Ver 01.00", NULL, (void *) -1,
+       (void *)&pcmcia_dlink },
+      { "ed", 0, "D-Link", "DE-650", "", NULL, (void *) 0x40,
+       (void *)&pcmcia_dlink },
+      { "ed", 0, "LINKSYS", "E-CARD", "Ver 01.00", NULL, (void *)-1,
+        (void *)&pcmcia_dlink },
+      { "ed", 0, "IBM Corp.", "Ethernet", "0933495", NULL, (void *) 0xff0,
+       (void *)&pcmcia_dlink },
+      { "ed", 0, "Socket Communications Inc",
+       "Socket EA PCMCIA LAN Adapter Revision D", "Ethernet ID 000000000000",
+       NULL, (void *) -1,
+       (void *)&pcmcia_dlink },
+       /* probably not right for ethernet address--card does not seem to
+          have it anywhere. */
+      { "ed", 0, "SVEC", "FD605 PCMCIA EtherNet Card", "V1-1", NULL,
+       (void *)0xb4, (void *)&pcmcia_dlink },
+      { "ed", 0, "PMX   ", "PE-200", "ETHERNET", "R01", (void *) 0x110,
+        (void *)&pcmcia_dlink }, /* 0x110 is a guess */
+      { NULL }
+};
+#endif
+
+
 /*
  * Determine if the device is present.
  */
@@ -1078,7 +1226,10 @@ edattach(parent, self, aux)
        }
 
        /* Attach the interface. */
-       if_attach(ifp);
+       if ((sc->spec_flags & ED_REATTACH) == 0) {
+               if_attach(ifp);
+               ether_ifattach(ifp);
+       }
        ether_ifattach(ifp);
 
        /* Print additional info when attached. */
@@ -1106,11 +1257,14 @@ edattach(parent, self, aux)
        printf("\n");
 
 #if NBPFILTER > 0
-       bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+       if ((sc->spec_flags & ED_REATTACH) == 0)
+               bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB,
+                         sizeof(struct ether_header));
 #endif
 
        sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NET, edintr,
            sc);
+       sc->sc_sh = shutdownhook_establish((void (*)(void *))edstop, sc);
 }
 
 /*
@@ -1784,6 +1938,12 @@ edioctl(ifp, cmd, data)
        int s, error = 0;
 
        s = splnet();
+       if ((sc->spec_flags & ED_NOTPRESENT) != 0) {
+               if_down(ifp);
+               printf("%s: device offline\n", sc->sc_dev.dv_xname);
+               splx(s);
+               return ENXIO;           /* may be ignored, oh well. */
+       }
 
        switch (cmd) {
 
index 50c9a63..4ee4dcc 100644 (file)
@@ -30,6 +30,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "pcmciabus.h"
 #include "bpfilter.h"
 
 #include <sys/param.h>
@@ -167,6 +168,142 @@ epaddcard(iobase, irq, bustype)
        nepcards++;
 }
 
+#if NPCMCIABUS > 0
+#include <dev/pcmcia/pcmciabus.h>
+static int ep_probe_pcmcia __P((struct device *, void *,
+                               void *, struct pcmcia_link *));
+static int epmod __P((struct pcmcia_link *, struct device *,
+                     struct pcmcia_conf *, struct cfdata * cf));
+static int ep_remove __P((struct pcmcia_link *, struct device *));
+
+/* additional setup needed for pcmcia devices */
+static int
+ep_probe_pcmcia(parent, match, aux, pc_link)
+       struct device   *parent;
+       void            *match;
+       void            *aux;
+       struct pcmcia_link *pc_link;
+{
+       struct ep_softc *sc = (void *) match;
+       struct cfdata  *cf = sc->sc_dev.dv_cfdata;
+       struct isa_attach_args *ia = aux;
+       struct pcmciadevs *dev = pc_link->device;
+       struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+       int             i;
+       extern int      ifqmaxlen;
+       short           addr[3];
+
+       outw(ia->ia_iobase + EP_COMMAND, WINDOW_SELECT | 0);
+       outw(ia->ia_iobase + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
+       outw(ia->ia_iobase + EP_W0_RESOURCE_CFG, 0x3f00);
+
+       /*
+        * ok til here. Now try to figure out which link we have.
+        * try coax first...
+        */
+       sc->bustype = EP_BUS_PCMCIA;
+#ifdef EP_COAX_DEFAULT
+       outw(ia->ia_iobase + EP_W0_ADDRESS_CFG, 0xC000);
+#else
+       /* COAX as default is reportet to be a problem */
+       outw(ia->ia_iobase + EP_W0_ADDRESS_CFG, 0x0000);
+#endif
+       ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+       epaddcard(ia->ia_iobase, ia->ia_irq, 0);
+
+       for (i = 0; i < nepcards; i++) {
+               if (epcards[i].available == 0)
+                       continue;
+               if (ia->ia_iobase != IOBASEUNK &&
+                   ia->ia_iobase != epcards[i].iobase)
+                       continue;
+               if (ia->ia_irq != IRQUNK &&
+                   ia->ia_irq != epcards[i].irq)
+                       continue;
+               goto good;
+       }
+       return 0;
+
+good:
+
+       epcards[i].available = 0;
+       ia->ia_iobase = epcards[i].iobase;
+       ia->ia_irq = epcards[i].irq;
+       ia->ia_iosize = 0x10;
+       ia->ia_msize = 0;
+
+       return 1;
+}
+
+
+/* modify config entry */
+static int
+epmod(pc_link, self, pc_cf, cf)
+       struct pcmcia_link *pc_link;
+       struct device  *self;
+       struct pcmcia_conf *pc_cf;
+       struct cfdata  *cf;
+{
+       int             err;
+       struct pcmciadevs *dev = pc_link->device;
+       struct ep_softc *sc = (void *) self;
+
+       if ((err = pc_link->adapter->bus_link->bus_config(pc_link, self,
+                                                         pc_cf, cf)) != 0) {
+               printf("bus_config failed %d\n", err);
+               return err;
+       }
+
+       if (pc_cf->io[0].len > 0x10)
+           pc_cf->io[0].len = 0x10;
+#if 0
+       pc_cf->cfgtype = DOSRESET;
+#endif
+       pc_cf->cfgtype = 1;
+
+       return 0;
+}
+
+static int
+ep_remove(pc_link, self)
+       struct pcmcia_link *pc_link;
+       struct device  *self;
+{
+       struct ep_softc *sc = (void *) self;
+       struct ifnet   *ifp = &sc->sc_arpcom.ac_if;
+       if_down(ifp);
+       epstop(sc);
+       ifp->if_flags &= ~(IFF_RUNNING | IFF_UP);
+       return pc_link->adapter->bus_link->bus_unconfig(pc_link);
+}
+
+static struct pcmcia_3com {
+       struct pcmcia_device pcd;
+} pcmcia_3com = {
+       "PCMCIA 3COM 3C589", epmod, ep_probe_pcmcia, NULL, ep_remove
+};
+
+struct pcmciadevs pcmcia_ep_devs[] = {
+       {
+               "ep", 0, "3Com Corporation", "3C589",
+#if 0
+               "TP/BNC LAN Card Ver. 1a", "000001",
+#else
+               NULL, NULL,
+#endif
+               (void *) -1, (void *) &pcmcia_3com
+       },
+#if 0
+       {
+               "ep", 0, "3Com Corporation", "3C589", "TP/BNC LAN Card Ver. 2a", "000002",
+               (void *) -1, (void *) &pcmcia_3com
+       },
+#endif
+       { NULL }
+};
+#endif
+
 /*
  * 3c579 cards on the EISA bus are probed by their slot number. 3c509
  * cards on the ISA bus are probed in ethernet address order. The probe
@@ -339,8 +476,9 @@ epconfig(sc, conn)
         */
        for (i = 0; i < 3; i++) {
                u_short x;
-               if (epbusyeeprom(sc))
+               if (epbusyeeprom(sc)) {
                        return;
+               }
                outw(BASE + EP_W0_EEPROM_COMMAND, READ_EEPROM | i);
                if (epbusyeeprom(sc))
                        return;
diff --git a/sys/dev/isa/pcmcia_isa.c b/sys/dev/isa/pcmcia_isa.c
new file mode 100644 (file)
index 0000000..d2fd46e
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 1994 Stefan Grefen.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by Charles Hannum.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *      $Id: pcmcia_isa.c,v 1.1 1996/01/16 20:13:01 hvozda Exp $
+ */
+
+/* TODO add modload support and loadable lists of devices */
+/* How to do cards with more than one function (modem/ethernet ..) */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+
+#include <dev/pcmcia/pcmcia.h>
+#include <dev/pcmcia/pcmciabus.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+#include <dev/ic/i8042reg.h>
+#include <i386/isa/isa_machdep.h>       /* XXX USES ISA HOLE DIRECTLY */
+
+#ifdef IBM_WD
+#define PCMCIA_ISA_DEBUG
+#endif
+
+static int pcmcia_isa_init __P((struct device *, struct cfdata *,
+                               void *, struct pcmcia_adapter *, int));
+static int pcmcia_isa_search __P((struct device *, void *, cfprint_t));
+static int pcmcia_isa_probe __P((struct device *, void *,
+                                void *, struct pcmcia_link *));
+static int pcmcia_isa_config __P((struct pcmcia_link *, struct device *,
+                                 struct pcmcia_conf *, struct cfdata *));
+static int pcmcia_isa_unconfig __P((struct pcmcia_link *));
+
+struct pcmciabus_link pcmcia_isa_link = {
+       pcmcia_isa_config,
+       pcmcia_isa_unconfig,
+       pcmcia_isa_probe,
+       pcmcia_isa_search,
+       pcmcia_isa_init
+};
+
+/* copy out the addr and length from machine specific attach struct */
+static int
+pcmcia_isa_init(parent, cf, aux, pca, flag)
+       struct device  *parent;
+       struct cfdata  *cf;
+       void           *aux;
+       struct pcmcia_adapter *pca;
+       int             flag;
+{
+       struct isa_attach_args *ia = aux;
+
+#ifdef PCMCIA_ISA_DEBUG
+       if (parent != NULL)
+               printf("PARENT %s\n", parent->dv_xname);
+#endif
+       if (flag) {             /* attach */
+               pca->scratch_mem = (caddr_t) ISA_HOLE_VADDR(ia->ia_maddr);
+               pca->scratch_memsiz = ia->ia_msize;
+       }
+       ia->ia_iosize = 0;
+       return 1;
+}
+
+/* probe and attach a device, the has to be configured already */
+static int
+pcmcia_isa_probe(parent, match, aux, pc_link)
+       struct device  *parent;
+       void           *match;
+       void           *aux;
+       struct pcmcia_link *pc_link;
+{
+       struct device *dev = match;
+       struct cfdata  *cf = aux;
+       struct isa_attach_args ia;
+       struct pcmciadevs *pcs = pc_link->device;
+       int (*probe) () = (pcs != NULL) ? pcs->dev->pcmcia_probe : NULL;
+
+       ia.ia_iobase = cf->cf_loc[0];
+       ia.ia_iosize = 0x666;
+       ia.ia_maddr = cf->cf_loc[2];
+       ia.ia_msize = cf->cf_loc[3];
+       ia.ia_irq = cf->cf_loc[4];
+       ia.ia_drq = cf->cf_loc[5];
+       if (probe == NULL)
+               probe = cf->cf_driver->cd_match;
+
+#ifdef PCMCIA_ISA_DEBUG
+       printf("pcmcia probe %x %x %x\n", ia.ia_iobase, ia.ia_irq, probe);
+       printf("parentname = %s\n", parent->dv_xname);
+       printf("devname = %s\n", dev->dv_xname);
+       printf("driver name = %s\n", cf->cf_driver->cd_name);
+#endif
+       if ((*probe) (parent, dev, &ia, pc_link) > 0) {
+               extern          isaprint();
+               config_attach(parent, dev, &ia, isaprint);
+#ifdef PCMCIA_ISA_DEBUG
+               printf("biomask %x netmask %x ttymask %x\n",
+                      (u_short) imask[IPL_BIO], (u_short) imask[IPL_NET],
+                      (u_short) imask[IPL_TTY]);
+#endif
+               return 1;
+       }
+       else
+               free(dev, M_DEVBUF);
+       return 0;
+}
+
+/*
+ * Modify a pcmcia_conf struct to match the config entry. Pc_cf was filled
+ * with config data from the card and may be modified before and after the
+ * call to pcmcia_isa_config. Unless the FIXED_WIN flag is set we assume
+ * contiguous windows and shift according to the offset for the first not
+ * fixed window
+ */
+static int
+pcmcia_isa_config(pc_link, self, pc_cf, cf)
+       struct pcmcia_link *pc_link;
+       struct device  *self;
+       struct pcmcia_conf *pc_cf;
+       struct cfdata  *cf;
+{
+       struct isa_attach_args ia;
+
+       ia.ia_iobase = cf->cf_loc[0];
+       ia.ia_iosize = 0x666;
+       ia.ia_maddr = cf->cf_loc[2];
+       ia.ia_msize = cf->cf_loc[3];
+       ia.ia_irq = cf->cf_loc[4];
+       ia.ia_drq = cf->cf_loc[5];
+#ifdef PCMCIA_ISA_DEBUG
+       printf("pcmcia_isa_config iobase=%x maddr=%x msize=%x irq=%x drq=%x\n",
+              ia.ia_iobase, ISA_HOLE_VADDR(ia.ia_maddr), ia.ia_msize,
+              ia.ia_irq, ia.ia_drq);
+#endif
+
+       if (ia.ia_irq != IRQUNK) {
+               int             irq = 1 << ia.ia_irq;
+               /*
+                * This is tricky irq 9 must match irq 2 in a device mask and
+                * configured  irq 9 must match irq 2
+                */
+#ifdef PCMCIA_ISA_DEBUG
+               printf("pcmcia_isa_config irq=%x num=%x mask=%x and=%x\n", irq,
+                      1 << pc_cf->irq_num, pc_cf->irq_mask,
+                      irq & pc_cf->irq_mask);
+#endif
+               if (irq != (1 << pc_cf->irq_num) &&
+                   !(irq == (1 << 9) && pc_cf->irq_num == 2)) {
+                       if (irq == (1 << 9) || irq == (1 << 2))
+                               irq = (1 << 9) | (1 << 2);
+                       if ((irq & pc_cf->irq_mask) == 0) {
+                               printf("irq %d mask %x\n", ia.ia_irq,
+                                      pc_cf->irq_mask);
+                               return ENODEV;
+                       }
+                       /* 2 is 9 is 2 ... */
+                       irq&=~(1 << 2);
+                       cf->cf_loc[4] = pc_cf->irq_num = ffs(irq) - 1;
+#ifdef PCMCIA_ISA_DEBUG
+                       printf("pcmcia_isa_config modify num=%x\n",
+                              pc_cf->irq_num);
+#endif
+               }
+       }
+       if (ia.ia_iobase != IOBASEUNK) {
+               int             i;
+               int             offs = 0;
+               if (pc_cf->iowin == 0)
+                       return 0;
+               for (i = 0; i < pc_cf->iowin; i++) {
+                       if (pc_cf->io[i].flags & PCMCIA_FIXED_WIN)
+                               continue;
+                       if (offs == 0) {
+                               if (pc_cf->io[i].start != ia.ia_iobase) {
+                                       offs = ia.ia_iobase - 
+                                              pc_cf->io[i].start;
+                               } else
+                                       break;
+                       }
+                       pc_cf->io[i].start += offs;
+               }
+       } else
+               pc_cf->iowin = 0;
+       if (ia.ia_maddr != MADDRUNK && ia.ia_msize) {
+               int             i;
+               unsigned long   offs = 0;
+               int             mlen = ia.ia_msize;
+               int             maddr = (int) ISA_HOLE_VADDR(ia.ia_maddr);
+
+               if (pc_cf->memwin == 0)
+                       return ENODEV;
+
+#ifdef PCMCIA_ISA_DEBUG
+               printf("Doing ia=%x ma=%x ms=%d\n", ia.ia_maddr,
+                      maddr, ia.ia_msize);
+#endif
+               for (i = 0; i < pc_cf->memwin && mlen > 0; i++) {
+#ifdef PCMCIA_ISA_DEBUG
+               printf("Doing i=%d st=%x len=%d, flags=%x offs=%d mlen=%d\n",
+                      i, pc_cf->mem[i].start, pc_cf->mem[i].len,
+                      pc_cf->mem[i].flags, offs, mlen);
+#endif
+                       if (pc_cf->mem[i].flags & PCMCIA_FIXED_WIN)
+                               continue;
+                       if (offs == 0) {
+                               if (pc_cf->mem[i].start != maddr) {
+                                       offs = maddr - pc_cf->mem[i].start;
+                               } else
+                                       break;
+                       }
+                       mlen -= pc_cf->mem[i].len;
+                       if (mlen < 0)
+                               pc_cf->mem[i].len += mlen;
+                       pc_cf->mem[i].start += offs;
+               }
+       } else
+               pc_cf->memwin = 0;
+       return 0;
+}
+
+
+static int
+pcmcia_isa_unconfig(pc_link)
+       struct pcmcia_link *pc_link;
+{
+       if (pc_link && pc_link->intr > 0) {
+               /* THIS IS A GUESS ... TODO check all possible drivers */
+               struct softc {
+                       struct device   sc_dev;
+                       void *sc_ih;
+               } *sc = pc_link->devp;
+               if (sc)
+                       isa_intr_disestablish(sc->sc_ih);
+       }
+       return 0;
+}
+
+/* Searches for for configured devices on the pcmciabus */
+static int
+pcmcia_isa_search(parent, aux, print)
+       struct device  *parent;
+       void           *aux;
+       cfprint_t       print;
+{
+       static char    *msgs[3] = {"", " not configured\n", " unsupported\n"};
+
+#ifdef PCMCIA_ISA_DEBUG
+       printf("pcmcia_isa_search\n");
+#endif
+       if (config_search(pcmcia_configure, parent, aux) != NULL)
+               return 1;
+
+       if (print) {
+               int i;
+               i = (*print) (aux, parent->dv_xname);
+               printf(msgs[i]);
+       }
+       return 0;
+}
diff --git a/sys/dev/isa/pcmcia_pcic.c b/sys/dev/isa/pcmcia_pcic.c
new file mode 100644 (file)
index 0000000..30e4d84
--- /dev/null
@@ -0,0 +1,733 @@
+/*
+ * Device Driver for Intel 82365 based pcmcia slots
+ *
+ * Copyright (c) 1994 Stefan Grefen. This software may be used, modified,
+ * copied, distributed, and sold, in both source and binary form provided that
+ * the above copyright and these terms are retained.  Under no circumstances is
+ * the author responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with its use.
+ *
+ */
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/mbuf.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+#include <machine/pio.h>
+
+#include <dev/isa/isavar.h>
+#include <dev/ic/i82365reg.h>
+
+#include <dev/pcmcia/pcmciabus.h>
+#ifdef IBM_WD
+#define PCIC_DEBUG 0xf
+#endif
+#if PCIC_DEBUG
+#define PCDMEM  0x01
+#define PCDIO   0x02
+#define PCDINTR 0x04
+#define PCDSERV 0x08
+#define PCDRW   0x10
+int             pcic_debug = PCIC_DEBUG;
+#define DEBUG(a)       (pcic_debug & (a))
+#else
+#define DEBUG(a)       (0)
+#endif
+
+
+/*
+ *  pcic_softc: per line info and status
+ */
+#define MAX_IOSECTION  2
+#define MAX_MEMSECTION         5
+struct slot {
+       int             status;
+#define SLOT_EMPTY    0x01
+#define SLOT_PROBING  0x02
+#define SLOT_INUSE    0x04
+       u_short         io_addr[MAX_IOSECTION], io_len[MAX_IOSECTION];
+       u_short         io_used[MAX_IOSECTION];
+       caddr_t         mem_caddr[MAX_MEMSECTION];
+       u_int           mem_haddr[MAX_MEMSECTION];
+       u_int           mem_len[MAX_MEMSECTION], mem_used[MAX_MEMSECTION];
+       u_short         region_flag;
+       u_short         ioctl_flag;
+       u_short         irq;
+       u_short         pow;
+       u_short         irqt;
+       u_short         reg_off;/* 2 chips share an address */
+       void            (*handler)(struct slot *, void *);
+       void *          handle_arg;
+       struct pcmcia_link *link;
+       struct pcic_softc *chip;
+};
+struct pcic_softc {
+       struct device   sc_dev;
+       void *sc_ih;
+
+       int     sc_polltimo;
+       int     sc_pcic_irq;
+       u_short         pcic_base;      /* base port for each board */
+       u_char          slot_id;
+       u_char          chip_inf;
+       struct slot     slot[2];
+} pcic_softc[4];
+
+static int      pcic_map_io __P((struct pcmcia_link *, u_int, u_int, int));
+static int      pcic_map_mem __P((struct pcmcia_link *, caddr_t,
+                                 u_int, u_int, int));
+static int      pcic_map_intr __P((struct pcmcia_link *, int, int));
+static int      pcic_service __P((struct pcmcia_link *, int, void *, int));
+
+static struct pcmcia_funcs pcic_funcs = {
+       pcic_map_io,
+       pcic_map_mem,
+       pcic_map_intr,
+       pcic_service
+};
+
+int             pcicprobe __P((struct device *, void *, void *));
+void            pcicattach __P((struct device  *, struct device *, void *));
+
+extern struct pcmciabus_link pcmcia_isa_link;
+
+struct cfdriver pciccd = {
+       NULL, "pcic", pcicprobe, pcicattach, DV_DULL, sizeof(struct pcic_softc)
+};
+
+
+static u_char pcic_rd __P((struct slot *, int));
+static void pcic_wr __P((struct slot *, int, int));
+
+
+static __inline u_char
+pcic_rd(slot, reg)
+       struct slot    *slot;
+       int             reg;
+{
+       u_char          res;
+       if (DEBUG(PCDRW))
+               printf("pcic_rd(%x [%x %x]) = ", reg, slot->reg_off,
+                      slot->chip->pcic_base);
+       outb(slot->chip->pcic_base, slot->reg_off + reg);
+       delay(1);
+       res = inb(slot->chip->pcic_base + 1);
+       if (DEBUG(PCDRW))
+               printf("%x\n", res);
+       return res;
+}
+
+static __inline void
+pcic_wr(slot, reg, val)
+       struct slot    *slot;
+       int             reg, val;
+{
+       outb(slot->chip->pcic_base, slot->reg_off + reg);
+       delay(1);
+       outb(slot->chip->pcic_base + 1, val);
+       if (DEBUG(PCDRW)) {
+               int res;
+               delay(1);
+               outb(slot->chip->pcic_base, slot->reg_off + reg);
+               delay(1);
+               res = inb(slot->chip->pcic_base + 1);
+               printf("pcic_wr(%x %x) = %x\n", reg, val, res);
+       }
+}
+
+static __inline int
+pcic_wait(slot, i)
+       struct slot *slot;
+       int i;
+{
+       while (i-- && ((pcic_rd(slot, PCIC_STATUS) & PCIC_READY) == 0))
+               delay(500);
+       return i;
+}
+
+int
+pcicprobe(parent, self, aux)
+       struct device   *parent;
+       void            *self;
+       void            *aux;
+{
+       struct pcic_softc *pcic = (void *) self;
+       struct isa_attach_args *ia = aux;
+       struct cfdata *cf = pcic->sc_dev.dv_cfdata;
+       u_int           chip_inf = 0;
+       int             i;
+
+       pcic->pcic_base = ia->ia_iobase;
+       pcic->slot_id = 0; /* XXX */
+       bzero(pcic->slot, sizeof(pcic->slot));
+       pcic->slot[0].chip = pcic;
+       pcic->slot[0].reg_off = (pcic->slot_id & 1) * 0x80;
+       pcic->slot[1].chip = pcic;
+       pcic->slot[1].reg_off = ((pcic->slot_id & 1) * 0x80) + 0x40;
+       chip_inf = pcic_rd(&pcic->slot[0], PCIC_ID_REV);
+       switch (chip_inf) {
+       case PCIC_INTEL0:
+               pcic->chip_inf = PCMICA_CHIP_82365_0;
+               goto ok;
+       case PCIC_INTEL1:
+               pcic->chip_inf = PCMICA_CHIP_82365_1;
+               goto ok;
+       case PCIC_IBM1:
+               pcic->chip_inf = PCMICA_CHIP_IBM_1;
+               goto ok;
+       case PCIC_IBM2:
+               pcic->chip_inf = PCMICA_CHIP_IBM_2;
+ok:
+               ia->ia_msize = 0;
+               ia->ia_iosize = 2;
+               pcmcia_register(pcic, &pcmcia_isa_link, &pcic_funcs,
+                               pcic->slot_id);
+               return 1;
+       default:
+               printf("found ID %x at pcic position\n", chip_inf & 0xff);
+               break;
+       }
+       /* reset mappings .... */
+       pcic_wr(&pcic->slot[0], PCIC_POWER, pcic->slot[0].pow=PCIC_DISRST);
+       pcic_wr(&pcic->slot[1], PCIC_POWER, pcic->slot[1].pow=PCIC_DISRST);
+
+       delay(1000);
+
+       for (i = PCIC_INT_GEN; i < 0x40; i++) {
+               pcic_wr(&pcic->slot[0], i, 0);
+               pcic_wr(&pcic->slot[1], i, 0);
+       }
+       delay(10000);
+       return 0;
+}
+
+int
+pcic_intr __P((void *));
+
+
+void
+pcicattach(parent, self, aux)
+       struct device  *parent, *self;
+       void           *aux;
+{
+       struct pcic_softc *pcic = (void *) self;
+       struct isa_attach_args *ia = aux;
+       struct slot *slot;
+       int i;
+       static char    *pcic_names[] = {
+               "Intel 82365sl Rev. 0",
+               "Intel 82365sl Rev. 1",
+               "IBM 82365sl clone Rev. 1",
+       "IBM 82365sl clone Rev. 2"};
+       printf(": %s slots %d-%d (%x %x)\n", pcic_names[pcic->chip_inf -
+           PCMICA_CHIP_82365_0], pcic->slot_id * 2, pcic->slot_id * 2 + 1,
+              &pcic->slot[0], &pcic->slot[1]);
+       /* enable interrupts on events */
+       if (ia->ia_irq != IRQUNK)
+           pcic->sc_pcic_irq = ia->ia_irq;
+       else
+           pcic->sc_pcic_irq = 0;
+
+       for (i = 0; i < 2; i++) {
+           slot = &pcic->slot[i];
+           slot->irq = pcic->sc_pcic_irq |  PCIC_INTR_ENA;
+           pcic_wr(slot, PCIC_STAT_INT,
+                   (pcic->sc_pcic_irq << 4) |PCIC_CDTCH | PCIC_STCH);
+           pcic_wr(&pcic->slot[i], PCIC_INT_GEN, slot->irq);
+           (void) pcic_rd(&pcic->slot[i], PCIC_STAT_CHG);
+       }
+       if (ia->ia_irq == IRQUNK) {
+           pcic->sc_polltimo = hz/2;
+           timeout((void (*)(void *))pcic_intr, pcic, pcic->sc_polltimo);
+       } else {
+           pcic->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE,
+                                            IPL_NET, pcic_intr, pcic);
+           pcic->sc_polltimo = 0;
+       }
+}
+
+#ifdef DDB
+int pcic_intr_test(slot)
+struct slot *slot;
+{
+    printf("CSC interrupt state: %x\n", pcic_rd(slot, PCIC_STAT_INT));
+    printf("General interrupt state: %x\n", pcic_rd(slot, PCIC_INT_GEN));
+}
+
+int pcic_intr_set(slot)
+struct slot *slot;
+{
+    pcic_wr(slot, PCIC_INT_GEN, pcic_rd(slot, PCIC_INT_GEN)|PCIC_INTR_ENA);
+    pcic_intr_test(slot);
+}
+#endif
+
+int
+pcic_intr(arg)
+void *arg;
+{
+       struct pcic_softc *pcic = arg;
+       u_char statchg, intgen;
+       register int i;
+
+       if (pcic->sc_polltimo == 0)
+               printf("%s: interrupt:", pcic->sc_dev.dv_xname);
+       for (i = 0; i < 2; i++) {
+               struct pcmcia_link *link = pcic->slot[i].link;
+               statchg = pcic_rd(&pcic->slot[i], PCIC_STAT_CHG);
+               if (statchg == 0)
+                       continue;
+               intgen = pcic_rd(&pcic->slot[i], PCIC_INT_GEN);
+               if (intgen & PCIC_IOCARD) {
+                       printf("%s: slot %d iocard status %s%s\n", 
+                              pcic->sc_dev.dv_xname, i,
+                              statchg & PCIC_STCH ? "statchange " : "",
+                              statchg & PCIC_CDTCH ? "cardchange" : "");
+               } else {
+                       printf("%s: slot %d memcard status %x\n",
+                              pcic->sc_dev.dv_xname, i, statchg);
+               } 
+               if ((statchg & PCIC_CDTCH) &&
+                   (link->flags & PCMCIA_SLOT_OPEN) == 0) {
+#if 0
+                       if (pcic->slot[i].status & SLOT_INUSE) {
+                               pcmcia_unconfigure(link);
+                       } else {
+                               if (link) {
+                                       link->fordriver = NULL;
+                                       pcmcia_probe_bus(link, 0, link->slot,
+                                                        NULL);
+                               }
+                       }
+#endif
+               }
+               if (link && (link->flags & PCMCIA_SLOT_OPEN)) {
+                       link->flags |= PCMCIA_SLOT_EVENT;
+                       selwakeup(&link->pcmcialink_sel);
+               }
+               if (pcic->slot[i].handler == NULL)
+                       continue;
+               (*pcic->slot[i].handler)(&pcic->slot[i],
+                                        pcic->slot[i].handle_arg);
+       }
+       if (pcic->sc_polltimo)
+               timeout((void (*)(void *))pcic_intr, pcic, pcic->sc_polltimo);
+       return 1;
+}
+
+static int
+pcic_map_io(link, start, len, flags)
+       struct pcmcia_link *link;
+       u_int           start, len;
+       int             flags;
+{
+       struct pcic_softc *sc = link->adapter->adapter_softc;
+       struct slot    *slot = &sc->slot[link->slot & 1];
+
+       len--;
+       if (DEBUG(PCDIO)) {
+               printf("pcic_map_io %x %x %x\n", start, len, flags);
+       }
+       if (!(flags & PCMCIA_UNMAP)) {
+               u_int           stop;
+               int             window;
+               int             winid;
+               int             ioflags;
+
+               if (flags & PCMCIA_LAST_WIN) {
+                       window = MAX_IOSECTION - 1;
+               } else if (flags & PCMCIA_FIRST_WIN) {
+                       window = 0;
+               } else if (flags & PCMCIA_ANY_WIN) {
+                       for (window = 0; window < MAX_IOSECTION; window++) {
+                               if (slot->io_used[window] == 0)
+                                       break;
+                               if (window >= MAX_IOSECTION)
+                                       return EBUSY;
+                       }
+               } else {
+                       window = flags & 0xf;
+                       if (window >= MAX_IOSECTION)
+                               return EINVAL;
+               }
+               slot->status |= SLOT_INUSE;
+               slot->io_used[window] = 1;
+               winid = window * 0x4 + 0x08;
+               stop = start + len;
+
+               pcic_wr(slot, winid | PCIC_START | PCIC_ADDR_LOW,
+                       (u_long) start & 0xff);
+               pcic_wr(slot, winid | PCIC_START | PCIC_ADDR_HIGH,
+                       ((u_long) start >> 8) & 0xff);
+
+               pcic_wr(slot, winid | PCIC_END | PCIC_ADDR_LOW,
+                       stop & 0xff);
+               pcic_wr(slot, winid | PCIC_END | PCIC_ADDR_HIGH,
+                       (stop >> 8) & 0xff);
+               flags &= (PCMCIA_MAP_8 | PCMCIA_MAP_16);
+               switch (flags) {
+               case PCMCIA_MAP_8:
+                       ioflags = PCIC_IO0_0WS;
+                       break;
+               case PCMCIA_MAP_16:
+                       ioflags = PCIC_IO0_16BIT;
+                       break;
+               default:
+                       ioflags = PCIC_IO0_CS16;
+                       break;
+               }
+
+               if (window == 1) {
+                       ioflags <<= 4;
+                       slot->ioctl_flag &= ~(3 << 4);
+               }
+               else {
+                       slot->ioctl_flag &= ~3;
+               }
+
+               delay(1000);
+
+               pcic_wr(slot, PCIC_IOCTL, slot->ioctl_flag |= ioflags);
+               pcic_wr(slot, PCIC_ADDRWINE,
+                       slot->region_flag |= (0x40 << window));
+               slot->io_addr[window] = start;
+               slot->io_len[window] = len;
+               delay(1000);
+               return 0;
+       } else {
+               u_int           stop;
+               int             window;
+               int             winid;
+               int             ioflags;
+               if (flags & PCMCIA_LAST_WIN) {
+                       window = MAX_IOSECTION - 1;
+               } else if (flags & PCMCIA_FIRST_WIN) {
+                       window = 0;
+               } else if (flags & PCMCIA_ANY_WIN) {
+                       for (window = 0; window < MAX_IOSECTION; window++) {
+                               if (slot->io_addr[window] == start)
+                                       if (len == -1 ||
+                                           slot->io_len[window] == len)
+                                               break;
+                       }
+                       if (window >= MAX_IOSECTION)
+                               return EINVAL;
+               } else {
+                       window = flags & 0xf;
+                       if (window >= MAX_IOSECTION)
+                               return EINVAL;
+               }
+               slot->status &= ~SLOT_INUSE;
+               winid = window * 0x4 + 0x08;
+
+               pcic_wr(slot, PCIC_ADDRWINE,
+                       slot->region_flag &= ~(0x40 << window));
+               delay(1000);
+               pcic_wr(slot, PCIC_IOCTL,
+                       slot->ioctl_flag &= ~(0xf << window));
+               pcic_wr(slot, winid | PCIC_START | PCIC_ADDR_LOW, 0);
+               pcic_wr(slot, winid | PCIC_START | PCIC_ADDR_HIGH, 0);
+               pcic_wr(slot, winid | PCIC_END | PCIC_ADDR_LOW, 0);
+               pcic_wr(slot, winid | PCIC_END | PCIC_ADDR_HIGH, 0);
+
+               slot->io_addr[window] = start;
+               slot->io_len[window] = len;
+       }
+
+}
+static int
+pcic_map_mem(link, haddr, start, len, flags)
+       struct pcmcia_link *link;
+       caddr_t         haddr;
+       u_int           start, len;
+       int             flags;
+{
+       struct pcic_softc *sc = link->adapter->adapter_softc;
+       struct slot    *slot = &sc->slot[link->slot & 1];
+       vm_offset_t     physaddr;
+
+       if (flags & PCMCIA_PHYSICAL_ADDR)
+               physaddr = (vm_offset_t) haddr;
+       else
+               physaddr = pmap_extract(pmap_kernel(), (vm_offset_t) haddr);
+       if (DEBUG(PCDMEM))
+               printf("pcic_map_mem %x %x %x %x %x\n", haddr, physaddr,
+                      start, len, flags);
+
+       (u_long) physaddr >>= 12;
+       start >>= 12;
+       len = (len - 1) >> 12;
+
+       if (!(flags & PCMCIA_UNMAP)) {
+               u_int           offs;
+               u_int           stop;
+               int             window;
+               int             winid;
+               if (flags & PCMCIA_LAST_WIN) {
+                       window = MAX_MEMSECTION - 1;
+               } else if (flags & PCMCIA_FIRST_WIN) {
+                       window = 0;
+               } else if (flags & PCMCIA_ANY_WIN) {
+                       for (window = 0; window < MAX_MEMSECTION; window++) {
+                               if (slot->mem_used[window] == 0)
+                                       break;
+                               if (window >= MAX_MEMSECTION)
+                                       return EBUSY;
+                       }
+               } else {
+                       window = flags & 0xf;
+                       if (window >= MAX_MEMSECTION)
+                               return EINVAL;
+               }
+               slot->mem_used[window] = 1;
+
+               offs = (start - (u_long) physaddr) & 0x3fff;
+               if (DEBUG(PCDMEM))
+                       printf("mapmem 2:%x %x %x\n", offs, physaddr + offs,
+                              start);
+
+               stop = (u_long) physaddr + len;
+
+               winid = window * 0x8 + 0x10;
+
+
+               pcic_wr(slot, winid | PCIC_START | PCIC_ADDR_LOW,
+                       (u_long) physaddr & 0xff);
+               pcic_wr(slot, winid | PCIC_START | PCIC_ADDR_HIGH,
+                       (((u_long) physaddr >> 8) & 0x3f) |
+               /* PCIC_ZEROWS|/* */
+                       ((flags & PCMCIA_MAP_16) ? PCIC_DATA16 : 0));
+
+               pcic_wr(slot, winid | PCIC_END | PCIC_ADDR_LOW,
+                       stop & 0xff);
+               pcic_wr(slot, winid | PCIC_END | PCIC_ADDR_HIGH,
+                       PCIC_MW1 | ((stop >> 8) & 0x3f));
+
+
+               pcic_wr(slot, winid | PCIC_MOFF | PCIC_ADDR_LOW,
+                       offs & 0xff);
+               pcic_wr(slot, winid | PCIC_MOFF | PCIC_ADDR_HIGH,
+                       ((offs >> 8) & 0x3f) |
+                       ((flags & PCMCIA_MAP_ATTR) ? PCIC_REG : 0));
+               delay(1000);
+
+               pcic_wr(slot, PCIC_ADDRWINE,
+                       slot->region_flag |= ((1 << window) | PCIC_MEMCS16));
+               slot->mem_caddr[window] = (caddr_t) physaddr;
+               slot->mem_haddr[window] = start;
+               slot->mem_len[window] = len;
+               delay(1000);
+               return 0;
+       } else {
+               u_int           offs;
+               u_int           stop;
+               int             window;
+               int             winid;
+
+               if (flags & PCMCIA_LAST_WIN) {
+                       window = MAX_MEMSECTION - 1;
+               } else if (flags & PCMCIA_FIRST_WIN) {
+                       window = 0;
+               } else if (flags & PCMCIA_ANY_WIN) {
+                       for (window = 0; window < MAX_MEMSECTION; window++) {
+                               if ((slot->mem_caddr[window] ==
+                                    (caddr_t) physaddr) &&
+                                   ((start == -1) ||
+                                    (slot->mem_haddr[window] == start)) &&
+                                   ((len == -1) ||
+                                    (slot->mem_len[window] == len)))
+                                       break;
+                       }
+                       if (window >= MAX_MEMSECTION)
+                               return EINVAL;
+               } else {
+                       window = flags & 0xf;
+                       if (window >= MAX_MEMSECTION)
+                               return EINVAL;
+               }
+               winid = window * 0x8 + 0x10;
+
+               slot->region_flag &= (~(1 << window));
+               pcic_wr(slot, PCIC_ADDRWINE, slot->region_flag);
+               delay(1000);
+               pcic_wr(slot, winid | PCIC_START | PCIC_ADDR_LOW, 0);
+               pcic_wr(slot, winid | PCIC_START | PCIC_ADDR_HIGH, 0);
+               pcic_wr(slot, winid | PCIC_END | PCIC_ADDR_LOW, 0);
+               pcic_wr(slot, winid | PCIC_END | PCIC_ADDR_HIGH, 0);
+               pcic_wr(slot, winid | PCIC_MOFF | PCIC_ADDR_LOW, 0);
+               pcic_wr(slot, winid | PCIC_MOFF | PCIC_ADDR_HIGH, 0);
+               slot->mem_caddr[window] = 0;
+               slot->mem_haddr[window] = 0;
+               slot->mem_len[window] = 0;
+               slot->mem_used[window] = 0;
+               return 0;
+       }
+}
+static int
+pcic_map_intr(link, irq, flags)
+       struct pcmcia_link *link;
+       int             irq, flags;
+{
+       struct pcic_softc *sc = link->adapter->adapter_softc;
+       struct slot    *slot = &sc->slot[link->slot & 1];
+
+       if (DEBUG(PCDINTR))
+               printf("pcic_map_intr %x %x\n", irq, flags);
+
+       if (flags & PCMCIA_UNMAP) {
+               slot->irq &= ~PCIC_INT_MASK;
+               slot->irq |= sc->sc_pcic_irq | PCIC_INTR_ENA;
+               pcic_wr(slot, PCIC_INT_GEN, slot->irq);
+       }
+       else {
+               if (irq < 2 || irq > 15 || irq == 6 || irq == 8 || irq == 13)
+                       return EINVAL;
+               if(irq==2)
+                   irq=9;
+               slot->irq = (slot->irq & PCIC_INT_FLAGMASK) |
+                   irq | PCIC_INTR_ENA;
+               pcic_wr(slot, PCIC_INT_GEN, slot->irq);
+       }
+       return 0;
+}
+
+
+static int
+pcic_service(link, opcode, arg, flags)
+       struct pcmcia_link *link;
+       int             opcode;
+       void           *arg;
+       int             flags;
+{
+       struct pcic_softc *sc = link->adapter->adapter_softc;
+       struct slot    *slot = &sc->slot[link->slot & 1];
+
+       slot->link = link;              /* save it for later :) */
+       switch (opcode) {
+       case PCMCIA_OP_STATUS:{
+                       u_char          cp;
+                       int            *iarg = arg;
+
+                       if (DEBUG(PCDSERV))
+                               printf("pcic_service(status)\n");
+                       cp = pcic_rd(slot, PCIC_STATUS);
+                       if (DEBUG(PCDSERV))
+                               printf("status for slot %d %b\n",
+                                      link->slot, cp, PCIC_STATUSBITS);
+                       *iarg = 0;
+#define DO_STATUS(cp, val, map)        ((cp & val) == val ? map : 0)
+                       *iarg |= DO_STATUS(cp, PCIC_CD, PCMCIA_CARD_PRESENT);
+                       *iarg |= DO_STATUS(cp, PCIC_BVD, PCMCIA_BATTERY);
+                       *iarg |= DO_STATUS(cp, PCIC_MWP, PCMCIA_WRITE_PROT);
+                       *iarg |= DO_STATUS(cp, PCIC_READY, PCMCIA_READY);
+                       *iarg |= DO_STATUS(cp, PCIC_POW, PCMCIA_POWER);
+                       *iarg |= DO_STATUS(cp, PCIC_VPPV, PCMCIA_POWER_PP);
+                       return 0;
+
+               }
+       case PCMCIA_OP_WAIT:{
+                       int             iarg = (int) arg;
+                       int             i = iarg * 4;
+
+                       if (DEBUG(PCDSERV))
+                               printf("pcic_service(wait)\n");
+                       i = pcic_wait(slot, i);
+                       if (DEBUG(PCDSERV))
+                               printf("op99 %b %d\n", 
+                                      pcic_rd(slot, PCIC_STATUS),
+                                      PCIC_STATUSBITS, i);
+                       if (i <= 0)
+                               return EIO;
+                       else
+                               return 0;
+               }
+       case PCMCIA_OP_RESET:{
+                       int             force = ((int) arg) < 0;
+                       int             iarg = abs((int) arg);
+                       int             i = iarg * 4;
+
+                       if (DEBUG(PCDSERV))
+                               printf("pcic_service(reset)\n");
+                       slot->irq |= flags ? PCIC_IOCARD : 0;
+                       pcic_wr(slot, PCIC_POWER, slot->pow &= ~PCIC_DISRST);
+                       slot->irq &= ~PCIC_CARDRESET;
+                       pcic_wr(slot, PCIC_INT_GEN, slot->irq);
+                       if (iarg == 0)
+                               return 0;
+                       delay(iarg);
+                       pcic_wr(slot, PCIC_POWER, slot->pow |= PCIC_DISRST);
+                       slot->irq |= PCIC_CARDRESET;
+                       pcic_wr(slot, PCIC_INT_GEN, slot->irq);
+                       delay(iarg);
+                       i = pcic_wait(slot, i);
+                       if (DEBUG(PCDSERV))
+                               printf("opreset %d %b %d\n", force, 
+                                      pcic_rd(slot, PCIC_STATUS),
+                                      PCIC_STATUSBITS, i);
+                       if (i <= 0)
+                               return EIO;
+                       else
+                               return 0;
+               }
+       case PCMCIA_OP_POWER:{
+                       int             iarg = (int) arg;
+                       if (DEBUG(PCDSERV))
+                               printf("pcic_service(power): ");
+                       if (flags & PCMCIA_POWER_ON) {
+                               int nv = (PCIC_DISRST|PCIC_OUTENA);
+                               pcic_wr(slot, PCIC_INT_GEN, slot->irq = 0);
+                               if(flags & PCMCIA_POWER_3V)
+                                       nv |= PCIC_VCC3V;
+                               if(flags & PCMCIA_POWER_5V)
+                                       nv |= PCIC_VCC5V;
+                               if(flags & PCMCIA_POWER_AUTO)
+                                       nv |= PCIC_APSENA|
+                                             PCIC_VCC5V|PCIC_VCC3V;
+                               slot->pow &= ~(PCIC_APSENA|PCIC_VCC5V|
+                                              PCIC_VCC3V|PCIC_VPP12V|
+                                              PCIC_VPP5V);
+                               slot->pow |= nv;
+                               pcic_wr(slot, PCIC_POWER, slot->pow);
+#if 0
+                               delay(iarg);
+                               slot->pow |= PCIC_OUTENA;
+                               pcic_wr(slot, PCIC_POWER, slot->pow);
+#endif
+                               delay(iarg);
+                               if (DEBUG(PCDSERV))
+                                       printf("on\n");
+                       } else {
+                               slot->pow &= ~(PCIC_APSENA|PCIC_VCC5V|
+                                              PCIC_VCC3V);
+                               slot->pow &= ~(PCIC_DISRST|PCIC_OUTENA);
+                               pcic_wr(slot,PCIC_POWER, slot->pow);
+                               if (DEBUG(PCDSERV))
+                                       printf("off\n");
+                       }
+                       return 0;
+               }
+       case PCMCIA_OP_GETREGS:{
+                       struct pcic_regs *pi = arg;
+                       int             i;
+                       if (DEBUG(PCDSERV))
+                               printf("pcic_service(getregs)\n");
+                       pi->chip_vers = sc->chip_inf;
+                       for (i = 0; i < pi->cnt; i++)
+                               pi->reg[i].val =
+                                   pcic_rd(slot, pi->reg[i].addr);
+                       return 0;
+               }
+       default:
+               if (DEBUG(PCDSERV))
+                       printf("pcic_service(%x)\n", opcode);
+               return EINVAL;
+       }
+}