ISA <-> PCMCIA glue for PCMCIA support.
authorhvozda <hvozda@openbsd.org>
Mon, 15 Jan 1996 00:05:03 +0000 (00:05 +0000)
committerhvozda <hvozda@openbsd.org>
Mon, 15 Jan 1996 00:05:03 +0000 (00:05 +0000)
sys/dev/pcmcia/pcmcia.c [new file with mode: 0644]
sys/dev/pcmcia/pcmcia.h [new file with mode: 0644]
sys/dev/pcmcia/pcmcia_conf.c [new file with mode: 0644]
sys/dev/pcmcia/pcmcia_ioctl.h [new file with mode: 0644]
sys/dev/pcmcia/pcmciabus.h [new file with mode: 0644]

diff --git a/sys/dev/pcmcia/pcmcia.c b/sys/dev/pcmcia/pcmcia.c
new file mode 100644 (file)
index 0000000..baae3fe
--- /dev/null
@@ -0,0 +1,1429 @@
+/*
+ * 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.
+ *     This product includes software developed by Stefan Grefen.
+ * 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.c,v 1.1 1996/01/15 00:05:03 hvozda Exp $
+ */
+
+/* derived from scsiconf.c writte by Julian Elischer et al */
+/* TODO add modload support and loadable lists of devices */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+
+#include <dev/pcmcia/pcmcia.h>
+#include <dev/pcmcia/pcmciabus.h>
+#include <dev/pcmcia/pcmcia_ioctl.h>
+
+#ifdef IBM_WD
+#define PCMCIA_DEBUG
+#endif
+#ifdef PCMCIA_DEBUG
+# define PPRINTF(a)    printf a
+#else
+# define PPRINTF(a)
+#endif
+
+static void pcmciadumpcf __P((struct pcmcia_conf *));
+static int pcmcia_strcmp __P((char *, char *, int, char *));
+
+void pcmcia_shuthook __P((void *));
+
+static struct pcmcia_adapter pcmcia_drivers[4];
+static int      pcmcia_cntrl = 0;
+static int      probed = 0;
+static struct device **deldevs = NULL;
+static int      ndeldevs = 0;
+
+/* I've decided to re-ifdef these.  It makes making a kernel easier
+    until I either get config(8) modified to deal somehow
+    or figure out a better to way declare the prototypes and
+    build up the knowndevs struct.  Stefan may have ideas...
+*/
+
+#ifdef PCMCIA_ED
+extern struct pcmciadevs pcmcia_ed_devs[];
+#endif
+#ifdef PCMCIA_COM
+extern struct pcmciadevs pcmcia_com_devs[];
+#endif
+#ifdef PCMCIA_EP
+extern struct pcmciadevs pcmcia_ep_devs[];
+#endif
+
+static struct pcmciadevs *knowndevs[] = {
+#ifdef PCMCIA_ED
+       pcmcia_ed_devs,
+#endif
+#ifdef PCMCIA_COM
+       pcmcia_com_devs,
+#endif
+#ifdef PCMCIA_EP
+       pcmcia_ep_devs,
+#endif
+       NULL
+};
+
+#ifdef notyet
+static struct pcmciadevs *knowndevs[10] = { NULL };
+#define KNOWNSIZE (sizeof(knowndevs) / sizeof(knowndevs[0]))
+#endif
+
+#define PCMCIA_SERVICE(a,b,c,d,e)   ((a)->chip_link->pcmcia_service(b,c,\
+                                                               (void *) d,e))
+#define PCMCIA_MAP_IO(a,b,c,d,e)    ((a)->chip_link->pcmcia_map_io(b,c,d,e))
+#define PCMCIA_MAP_INTR(a,b,c,d)    ((a)->chip_link->pcmcia_map_intr(b,c,d))
+#define PCMCIA_MAP_MEM(a,b,c,d,e,f) ((a)->chip_link->pcmcia_map_mem(b,c,d,e,f))
+
+#define PCMCIA_BUS_INIT(a,b,c,d,e,f)((a)->bus_link->bus_init((b),(c),(d),(e)\
+                                                                       ,(f)))
+#define PCMCIA_BUS_SEARCH(a,b,c,d)  ((a)->bus_link->bus_search((b),(c),(d)))
+#define PCMCIA_BUS_PROBE(a,b,c,d,e) ((a)->bus_link->bus_probe((b),(c),(d),(e)))
+#define PCMCIA_BUS_CONFIG(a,b,c,d,e)((a)->bus_link->bus_config((b),(c),(d),(e)))
+#define PCMCIA_BUS_UNCONFIG(a,b)    ((a)->bus_link->bus_unconfig((b)))
+
+#define SCRATCH_MEM(a) ((a)->scratch_mem)
+#define SCRATCH_SIZE(a)        ((a)->scratch_memsiz)
+#define SCRATCH_INUSE(a)((a)->scratch_inuse)
+
+/*
+ * Declarations
+ */
+struct pcmciadevs *pcmcia_probedev __P((struct pcmcia_link *));
+struct pcmciadevs *pcmcia_selectdev __P((char *, char *, char *, char *));
+int pcmcia_probe_bus __P((struct pcmcia_link *, int, int,
+                         struct pcmcia_conf *));
+int pcmciabusmatch __P((struct device *, void *, void *));
+void pcmciabusattach __P((struct device *, struct device *, void *));
+
+struct cfdriver pcmciabuscd = {
+       NULL, "pcmcia", pcmciabusmatch, pcmciabusattach, DV_DULL,
+       sizeof(struct pcmciabus_softc), 1
+};
+
+#ifdef notyet
+int
+pcmcia_add_device(devs)
+       struct pcmciadevs *devs;
+{
+       int i;
+
+       if (devs == NULL)
+               return 0;
+
+       for (i = 0; i < KNOWNSIZE; i++)
+               if (knowndevs[i] == NULL)
+                       break;
+
+       if (i == KNOWNSIZE)
+               panic("Too many pcmcia devices");
+
+       knowndevs[i] = devs;
+       for (; devs->devname != NULL; devs++)
+               printf("added %s\n", devs->devname);
+       return i;
+}
+#endif
+
+int
+pcmcia_register(adapter_softc, bus_link, chip_link, slot)
+       void           *adapter_softc;
+       struct pcmciabus_link *bus_link;
+       struct pcmcia_funcs *chip_link;
+       int             slot;
+{
+       PPRINTF(("- pcmcia_register\n"));
+       if (pcmcia_cntrl == 0)
+               bzero(pcmcia_drivers, sizeof(pcmcia_drivers));
+
+       if (pcmcia_cntrl < 4) {
+               pcmcia_drivers[slot].adapter_softc = adapter_softc;
+               pcmcia_drivers[slot].chip_link = chip_link;
+               pcmcia_drivers[slot].bus_link = bus_link;
+               pcmcia_cntrl++;
+               return 1;
+       }
+       return 0;
+}
+
+int
+pcmciabusmatch(parent, self, aux)
+       struct device   *parent;
+       void            *self;
+       void            *aux;
+{
+       struct pcmciabus_softc *sc = (void *)self;
+       struct cfdata *cf = sc->sc_dev.dv_cfdata;
+       int             i, found = 0;
+
+       PPRINTF(("- pcmciabusmatch\n"));
+       if (pcmcia_cntrl <= 0)
+               return 0;
+
+       for (i = 0; i < 4; i++)
+               if (pcmcia_drivers[i].bus_link) {
+                       if (PCMCIA_BUS_INIT(&pcmcia_drivers[i], parent, cf,
+                                           aux, &pcmcia_drivers[i], 0))
+                               found++;
+               }
+       return found != 0;
+}
+
+/*
+ * The routine called by the adapter boards to get all their
+ * devices configured in.
+ */
+void
+pcmciabusattach(parent, self, aux)
+       struct device   *parent;
+       struct device   *self;
+       void            *aux;
+{
+       struct pcmciabus_softc *sc = (struct pcmciabus_softc *) self;
+       struct cfdata  *cf = self->dv_cfdata;
+       int             i, found = 0;
+
+       PPRINTF(("- pcmciabusattach\n"));
+       for (i = 0; i < 4; i++)
+               if (pcmcia_drivers[i].bus_link) {
+                       if (PCMCIA_BUS_INIT(&pcmcia_drivers[i], parent, cf,
+                                           aux, &pcmcia_drivers[i], 1))
+                               found++;
+               }
+
+       printf("\n");
+
+       pcmcia_probe_bus(NULL, sc->sc_dev.dv_unit, -1, NULL);
+}
+
+/*
+ * Probe the requested pcmcia bus. It must be already set up.
+ * -1 requests all set up pcmcia busses.
+ */
+int
+pcmcia_probe_busses(bus, slot)
+       int             bus, slot;
+{
+       PPRINTF(("- pcmcia_probe_busses\n"));
+       if (bus == -1) {
+               for (bus = 0; bus < pcmciabuscd.cd_ndevs; bus++)
+                       if (pcmciabuscd.cd_devs[bus])
+                               pcmcia_probe_bus(NULL, bus, slot, NULL);
+               return 0;
+       } else {
+               return pcmcia_probe_bus(NULL, bus, slot, NULL);
+       }
+}
+
+/*
+ * Probe the requested pcmcia bus. It must be already set up.
+ */
+int
+pcmcia_probe_bus(link, bus, slot, cf)
+       struct pcmcia_link *link;
+       int             bus, slot;
+       struct pcmcia_conf *cf;
+{
+       struct pcmciabus_softc *pcmcia;
+       int             maxslot, minslot, maxlun, minlun;
+       struct pcmciadevs *bestmatch = NULL;
+       int             spec_probe = (link != NULL);
+
+       PPRINTF(("- pcmcia_probe_bus\n"));
+       if (bus < 0 || bus >= pcmciabuscd.cd_ndevs)
+               return ENXIO;
+       pcmcia = pcmciabuscd.cd_devs[bus];
+       if (!pcmcia)
+               return ENXIO;
+
+       if (slot == -1) {
+               maxslot = 7;
+               minslot = 0;
+       } else {
+               if (slot < 0 || slot > 7)
+                       return EINVAL;
+               maxslot = minslot = slot;
+       }
+
+       for (slot = minslot; slot <= maxslot; slot++) {
+               if (link = pcmcia->sc_link[slot]) {
+                       if (link->devp)
+                               continue;
+               }
+               if (pcmcia_drivers[slot >> 1].adapter_softc == NULL)
+                       continue;
+
+               /*
+                * If we presently don't have a link block
+                * then allocate one
+                */
+               if (!link) {
+                       pcmcia->sc_link[slot] = link =
+                               malloc(sizeof(*link), M_TEMP, M_NOWAIT);
+                       if (link == NULL)
+                               return ENOMEM;
+                       bzero(link, sizeof(*link));
+                       link->opennings = 1;
+                       link->adapter = &pcmcia_drivers[slot >> 1];
+                       link->slot = slot;
+               }
+               bestmatch = pcmcia_probedev(link);
+               /*
+                * We already know what the device is.  We use a
+                * special matching routine which insists that the
+                * cfdata is of the right type rather than putting
+                * more intelligence in individual match routines for
+                * each high-level driver.
+                * We must have the final probe do all of the comparisons,
+                * or we could get stuck in an infinite loop trying the same
+                * device repeatedly.  We use the `fordriver' field of
+                * the pcmcia_link for now, rather than inventing a new
+                * structure just for the config_search().
+                */
+               if (link->fordriver == NULL) {
+                       if (bestmatch)
+                               link->fordriver = bestmatch->devname;
+                       else {
+                               if (!spec_probe) {
+                                       link->device = NULL;
+                                       link->devp = NULL;
+                                       PCMCIA_SERVICE(link->adapter,
+                                                      link, PCMCIA_OP_POWER,
+                                                      0, 0);
+                               }
+                       }
+               }
+
+               if (spec_probe) {
+                       if (cf && pcmcia_mapcard(link, -1, cf) != 0)
+                               link->fordriver = NULL;
+               }
+
+               if (link->fordriver != NULL) {
+                       int             i;
+                       struct device **delp = deldevs;
+                       int             found = 0;
+                       link->device = bestmatch;
+                       link->flags = (link->flags &
+                                         ~(PCMCIA_ATTACH_TYPE)) |
+                                           PCMCIA_REATTACH;
+                       for (i = 0; i < ndeldevs; i++, delp++) {
+                               if (*delp &&
+                                   pcmcia_configure((*delp)->dv_parent, *delp,
+                                                    link)) {
+                                       link->flags = (link->flags &
+                                                         ~PCMCIA_ATTACH_TYPE)
+                                                      | PCMCIA_SLOT_INUSE;
+                                       found = 1;
+                                       *delp = NULL;
+                                       break;
+                               }
+                       }
+                       if (!found) {
+                               link->flags = (link->flags &
+                                      ~PCMCIA_ATTACH_TYPE) | PCMCIA_ATTACH;
+                               if (PCMCIA_BUS_SEARCH(link->adapter,
+                                                     &pcmcia->sc_dev,
+                                                     link, NULL)) {
+                                       link->flags = (link->flags &
+                                                         ~PCMCIA_ATTACH_TYPE)
+                                                      | PCMCIA_SLOT_INUSE;
+                               } else {
+                                       link->flags &= ~(PCMCIA_ATTACH_TYPE |
+                                                        PCMCIA_SLOT_INUSE);
+                                       link->device = NULL;
+                                       printf(
+                                           "No matching config entry %s.\n",
+                                              link->fordriver ? 
+                                              link->fordriver : "(NULL)");
+                                       if (!spec_probe)
+                                               PCMCIA_SERVICE(link->adapter,
+                                                              link,
+                                                              PCMCIA_OP_POWER,
+                                                              0, 0);
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+/*
+ * given a target ask the device what
+ * it is, and find the correct driver table
+ * entry.
+ */
+struct pcmciadevs *
+pcmcia_probedev(link)
+       struct pcmcia_link *link;
+{
+       struct pcmcia_adapter *pca = link->adapter;
+       u_char          scratch[CIS_MAXSIZE];
+       char            manu[MAX_CIS_NAMELEN];
+       char            model[MAX_CIS_NAMELEN];
+       char            add_inf1[MAX_CIS_NAMELEN];
+       char            add_inf2[MAX_CIS_NAMELEN];
+       int             card_stat;
+       int             err;
+       int             pow = 0;
+       int             slot = link->slot;
+
+       PPRINTF(("- pcmcia_probe_dev\n"));
+
+       printf("%s slot %d:",
+              ((struct device *) link->adapter->adapter_softc)->dv_xname,
+              slot & 1);
+
+       if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_STATUS,
+                                 &card_stat, 0)) != 0) {
+               printf("failed to get status %d\n", err);
+               return NULL;
+       }
+
+       if ((card_stat & PCMCIA_CARD_PRESENT) == 0) {
+               printf(" <slot empty>\n");
+               return NULL;
+       }
+
+       if (!(card_stat & PCMCIA_POWER)) {
+               pow = 1;
+               if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_POWER, 10000,
+                                         PCMCIA_POWER_ON|
+                                         PCMCIA_POWER_5V)) != 0) {
+                       printf("failed to turn on power %d\n", err);
+                       return NULL;
+               }
+       }
+
+       if (!(link->flags & (PCMCIA_SLOT_INUSE | CARD_IS_MAPPED))) {
+               if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_RESET,
+                                         500000, 0)) != 0) {
+                       printf("failed to reset %d\n", err);
+                       PCMCIA_SERVICE(pca, link, PCMCIA_OP_POWER, 0, 0);
+                       return NULL;
+               }
+       }
+
+       /*
+        * Ask the device what it is
+        */
+       if ((err = pcmcia_read_cis(link, scratch, 0, sizeof(scratch))) != 0) {
+               printf("failed to read cis info %d\n", err);
+               goto bad;
+       }
+
+       if ((err = pcmcia_get_cisver1(link, scratch, sizeof(scratch),
+                                     manu, model, add_inf1,
+                                     add_inf2)) != 0) {
+               printf("failed to get cis info %d\n", err);
+               goto bad;
+       }
+
+       printf(" <%s, %s", manu, model);
+       if (add_inf1[0])
+               printf(", %s", add_inf1);
+       if (add_inf2[0])
+               printf(", %s", add_inf2);
+       printf(">\n");
+
+
+       /*
+        * Try make as good a match as possible with
+        * available sub drivers
+        */
+       return pcmcia_selectdev(manu, model, add_inf1, add_inf2);
+bad:
+       if (!pow)
+               PCMCIA_SERVICE(pca, link, PCMCIA_OP_POWER, 0, 0);
+       return NULL;
+}
+
+/*
+ * Try make as good a match as possible with
+ * available sub drivers
+ */
+struct pcmciadevs *
+pcmcia_selectdev(manu, model, add_inf1, add_inf2)
+       char *manu, *model, *add_inf1, *add_inf2;
+{
+       u_int bestmatches = 0;
+       struct pcmciadevs *bestmatch = (struct pcmciadevs *) 0;
+       struct pcmciadevs **dlist, *dentry;
+
+       PPRINTF(("- pcmcia_selectdev\n"));
+       for (dlist = knowndevs; *dlist; dlist++)
+               for (dentry = *dlist; dentry && 
+                                     dentry->devname != NULL; dentry++) {
+                       int match = 0;
+
+#ifdef PCMCIA_DEBUG
+                       dentry->flags |= PC_SHOWME;
+#endif
+                       match|=pcmcia_strcmp(dentry->manufacturer,
+                                   manu,dentry->flags,"manufacturer")<<6;
+                       match|=pcmcia_strcmp(dentry->model,
+                                   model,dentry->flags,"model")<<4;
+                       match|=pcmcia_strcmp(dentry->add_inf1,
+                                   add_inf1,dentry->flags,"info1")<<2;
+                       match|=pcmcia_strcmp(dentry->add_inf2,
+                                   add_inf2,dentry->flags,"info2");
+/* the following was replaced by the wildcard function called above */
+#if 0
+                       if (dentry->flags & PC_SHOWME)
+                               printf("manufacturer = `%s'-`%s'\n", 
+                                      dentry->manufacturer ?
+                                      dentry->manufacturer :
+                                      "X",
+                                      manu);
+                       if (dentry->manufacturer) {
+                           if (strcmp(dentry->manufacturer, manu) == 0) {
+                               match |= 8;
+                           } else {
+                               continue;
+                           }
+                       }
+
+                       if (dentry->flags & PC_SHOWME)
+                               printf("model = `%s'-`%s'\n",
+                                      dentry->model ? dentry->model :
+                                      "X",
+                                      model);
+                       if (dentry->model)  {
+                           if (strcmp(dentry->model, model) == 0) {
+                               match |= 4;
+                           } else {
+                               continue;
+                           }
+                       }
+
+
+                       if (dentry->flags & PC_SHOWME)
+                               printf("info1 = `%s'-`%s'\n",
+                                      dentry->add_inf1 ? dentry->add_inf1 :
+                                      "X",
+                                      add_inf1);
+                       if (dentry->add_inf1) {
+                           if (strcmp(dentry->add_inf1, add_inf1) == 0) {
+                               match |= 2;
+                           } else {
+                               continue;
+                           }
+                       }
+
+                       if (dentry->flags & PC_SHOWME)
+                               printf("info2 = `%s'-`%s'\n", 
+                                      dentry->add_inf2 ? dentry->add_inf2 :
+                                      "X",
+                                      add_inf2);
+                       if (dentry->add_inf2) {
+                           if (strcmp(dentry->add_inf2, add_inf2) == 0) {
+                               match |= 1;
+                           } else {
+                               continue;
+                           }
+                       }
+#endif
+#ifdef PCMCIA_DEBUG
+                       printf("match == %d [%d]\n",match,bestmatches);
+#endif
+
+                       if(match > bestmatches) {
+                               bestmatches = match;
+                               bestmatch = dentry;
+                       }
+               }
+
+       return bestmatch;
+}
+
+int
+pcmcia_configure(parent, self, aux)
+       struct device  *parent;
+       void           *self;
+       void           *aux;
+{
+       struct device  *dev = self;
+       struct pcmcia_link *link = aux;
+       struct cfdata  *cf = dev->dv_cfdata;
+       struct cfdriver *cd = cf->cf_driver;
+       char           *devname = (char *) link->fordriver;
+       struct pcmciadevs *pcs = link->device;
+       struct pcmcia_device *pcd;
+       struct pcmcia_adapter *pca = link->adapter;
+       struct pcmcia_conf pc_cf;
+       u_char          scratch[CIS_MAXSIZE];
+       int             mymap = 0;
+
+       PPRINTF(("- pcmcia_configure\n"));
+
+       if (strcmp(devname, cd->cd_name) || !pca)
+               return 0;
+
+       if (pcs == NULL)
+               pcd = NULL;
+       else
+               pcd = pcs->dev;
+
+       PPRINTF(("pcmcia_configure: %x\n", pcd));
+       if (!(link->flags & CARD_IS_MAPPED)) {
+               /* read 'suggested' configuration */
+               PPRINTF(("pcmcia_configure: calling read cis\n"));
+               if (pcmcia_read_cis(link, scratch, 0, sizeof(scratch)) != 0)
+                       return 0;
+
+               bzero(&pc_cf, sizeof(pc_cf));
+
+               PPRINTF(("pcmcia_configure: calling get cf\n"));
+               if (pcmcia_get_cf(link, scratch, sizeof(scratch), -1,
+                                 &pc_cf) != 0)
+                       return 0;
+#ifdef PCMCIA_DEBUG
+               pcmciadumpcf(&pc_cf);
+#endif
+               /* and modify it (device specific) */
+               if (pcd && pcd->pcmcia_config) {
+                       PPRINTF(("pcmcia_configure: calling config\n"));
+                       if (pcd->pcmcia_config(link, dev, &pc_cf, cf))
+                               return 0;
+
+                       if ((pc_cf.cfgtype & CFGENTRYMASK) == CFGENTRYID) {
+                               PPRINTF(("pcmcia_configure: calling cf2\n"));
+                               if (pcmcia_get_cf(link, scratch,
+                                                 sizeof(scratch), -2,
+                                                 &pc_cf) != 0)
+                                       return 0;
+
+                               PPRINTF(("pcmcia_configure: calling conf2\n"));
+                               if (pcd->pcmcia_config(link, dev, &pc_cf, cf))
+                                       return 0;
+                               /* give it a try */
+                               if(pc_cf.cfgid==0)
+                                   pc_cf.cfgid=1;
+                       }
+               } else {
+                       PPRINTF(("pcmcia_configure: calling bus config\n"));
+                       if (PCMCIA_BUS_CONFIG(pca, link, dev, &pc_cf, cf))
+                               return 0;
+               }
+#ifdef PCMCIA_DEBUG
+               pcmciadumpcf(&pc_cf);
+#endif
+
+               if (pcmcia_mapcard(link, -1, &pc_cf) != 0)
+                       return 0;
+
+               mymap = 1;
+       }
+       link->devp = dev;
+
+       PPRINTF(("pcmcia_configure: calling bus probe\n"));
+       if (!(PCMCIA_BUS_PROBE(pca, parent, dev, cf, link))) {
+               PPRINTF(("pcmcia_configure: bus probe failed\n"));
+               goto bad;
+       }
+
+       if (pcd && pcd->pcmcia_insert && pcd->pcmcia_insert(link, dev, cf)) {
+               PPRINTF(("pcmcia_configure: pcmcia_insert failed\n"));
+               goto bad;
+       }
+
+       link->shuthook = shutdownhook_establish(pcmcia_shuthook,
+                                               (void *)link);
+       return 1;
+
+bad:
+       link->devp = NULL;
+       if (mymap)
+               pcmcia_unmapcard(link);
+       printf("pcmcia_configure: configuration error\n");
+       return 0;
+}
+
+void
+pcmcia_shuthook(arg)
+void *arg;
+{
+    struct pcmcia_link *link = (struct pcmcia_link *)arg;
+    if (pcmcia_unconfigure(link) == 0) {
+       /*
+        * turn off power too.
+        */
+       PCMCIA_SERVICE(link->adapter, link, PCMCIA_OP_RESET, 500000, 0);
+       PCMCIA_SERVICE(link->adapter, link, PCMCIA_OP_POWER, 0, 0);
+    }
+}
+
+int
+pcmcia_unconfigure(link)
+       struct pcmcia_link *link;
+{
+       int             status;
+       int             i, err;
+       struct device **delp;
+       struct device  *dev;
+       struct pcmcia_adapter *pca = link->adapter;
+       struct pcmcia_device *pcd;
+
+       PPRINTF(("- pcmcia_unconfigure\n"));
+       if (link->devp == NULL)
+               return ENODEV;
+
+       if (link->device)
+               pcd = link->device->dev;
+       else
+               pcd = NULL;
+
+       if (link->flags & CARD_IS_MAPPED) {
+               if (pcd && pcd->pcmcia_remove) {
+                       if (pcd->pcmcia_remove(link, link->devp))
+                               return EBUSY;
+               }
+               else {
+                       if (PCMCIA_BUS_UNCONFIG(pca, link))
+                               return EBUSY;
+               }
+               if (pcmcia_unmapcard(link) != 0)
+                       return EBUSY;
+       }
+       delp = deldevs;
+       for (i = 0; delp && *delp && i < ndeldevs; i++, delp++)
+               continue;
+       if (i >= ndeldevs) {
+               int sz = ndeldevs ? (ndeldevs * 2) : 
+                                   (MINALLOCSIZE / sizeof(void *));
+               struct device **ndel = malloc(sz * sizeof(void *),
+                                             M_DEVBUF, M_NOWAIT);
+               if (!ndel) {
+                       PPRINTF(("pcmcia_delete: creating dev array"));
+                       return ENOMEM;
+               }
+               bzero(ndel, sz * sizeof(void *));
+               if (ndeldevs) {
+                       bcopy(deldevs, ndel, ndeldevs * sizeof(void *));
+                       free(deldevs, M_DEVBUF);
+               }
+               ndeldevs = sz - 1;
+               deldevs = ndel;
+               delp = deldevs + i;
+       }
+       dev = *delp = link->devp;
+       link->devp = NULL;
+       printf("device %s in pcmcia slot %d detached\n", dev->dv_xname,
+              link->slot);
+       shutdownhook_disestablish(link->shuthook);
+       link->shuthook = 0;
+       return 0;
+}
+
+int
+pcmcia_mapcard(link, unit, pc_cf)
+       struct pcmcia_link *link;
+       struct pcmcia_conf *pc_cf;
+{
+       struct pcmcia_adapter *pca = link->adapter;
+       int s, i, err;
+       PPRINTF(("- pcmcia_mapcard\n"));
+
+       if (pca == NULL)
+               return ENXIO;
+       s = splbio();
+
+       while (SCRATCH_INUSE(pca))
+               sleep((caddr_t) & SCRATCH_INUSE(pca), PZERO - 1);
+
+       SCRATCH_INUSE(pca) = 1;
+       splx(s);
+       for (i = 0; i < pc_cf->memwin; i++) {
+               if ((err = PCMCIA_MAP_MEM(pca, link,
+                                         (caddr_t) pc_cf->mem[i].start,
+                                         pc_cf->mem[i].caddr,
+                                         pc_cf->mem[i].len,
+                                         (pc_cf->mem[i].flags &
+                                         (PCMCIA_MAP_16 | PCMCIA_MAP_ATTR)) |
+                                         i | PCMCIA_PHYSICAL_ADDR)) != 0) {
+                       PPRINTF(("pcmcia_mapcard: mapmem %d err%d\n", i, err));
+                       goto error;
+               }
+       }
+       for (i = 0; i < pc_cf->iowin; i++) {
+               if ((err = PCMCIA_MAP_IO(pca, link, pc_cf->io[i].start,
+                                        pc_cf->io[i].len,
+                                        (pc_cf->io[i].flags & (PCMCIA_MAP_16 |
+                                        PCMCIA_MAP_8)) | i)) != 0) {
+                       PPRINTF(("pcmcia_mapcard: mapio %d err %d\n", i, err));
+                       goto error;
+               }
+       }
+
+       if ((pc_cf->irq_num & 0xf) > 0) {
+               if ((err = PCMCIA_MAP_INTR(pca, link, pc_cf->irq_num & 0xf,
+                                          0)) != 0) {
+                       PPRINTF(("pcmcia_mapcard: map_intr %d err %d\n", 
+                                pc_cf->irq_num & 0xf, err));
+                       goto error;
+               }
+       }
+       /* Now we've mapped everything enable it */
+       if ((err = PCMCIA_MAP_MEM(pca, link, SCRATCH_MEM(pca),
+            pc_cf->cfg_off & (~(SCRATCH_SIZE(pca) - 1)), SCRATCH_SIZE(pca),
+                                 PCMCIA_MAP_ATTR | PCMCIA_LAST_WIN)) != 0) {
+               PPRINTF(("pcmcia_mapcard: enable err %d\n", err));
+               goto error;
+       }
+
+       if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_RESET, -500000,
+                                 pc_cf->iocard)) != 0) {
+               PPRINTF(("failed to reset %d\n", err));
+               goto error;
+       }
+
+#define GETMEM(x) SCRATCH_MEM(pca)[(pc_cf->cfg_off & \
+                                   (SCRATCH_SIZE(pca) - 1)) + x]
+       if ((pc_cf->cfgtype & DOSRESET)) {
+               GETMEM(0) = PCMCIA_SRESET;
+               delay(50000);
+       }
+
+
+       PPRINTF(("CMDR %x\n",((pc_cf->cfgtype & CFGENTRYID) ?
+                        pc_cf->cfgid |CFGENTRYID:
+                        (pc_cf->cfgtype & CFGENTRYMASK)|1)|
+                   (pc_cf->irq_level ? PCMCIA_LVLREQ : 0)
+       ));
+
+       GETMEM(0) = ((pc_cf->cfgtype & CFGENTRYID) ?
+                        pc_cf->cfgid |CFGENTRYID:
+                        (pc_cf->cfgtype & CFGENTRYMASK)|1)|
+                   (pc_cf->irq_level ? PCMCIA_LVLREQ : 0);
+       delay(50000);
+
+       if (pc_cf->cfg_regmask & (1 << (PCMCIA_SCR / 2)))
+               GETMEM(PCMCIA_SCR) = (link->slot & 1) | 0x10;
+
+#if 0
+       DPRINTF(("CCSR %x\n", GETMEM(PCMCIA_CCSR]));
+       if (GETMEM(PCMCIA_CCSR] & PCMCIA_POWER_DOWN) {
+               GETMEM(PCMCIA_CCSR] &= ~PCMCIA_POWER_DOWN;
+               DPRINTF(("CCSR now %x\n", GETMEM(PCMCIA_CCSR]));
+       }
+#endif
+
+       if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_WAIT,
+                                 500000, 0)) != 0)
+               PPRINTF(("failed to initialize %d\n", err));
+error:
+       PCMCIA_MAP_MEM(pca, link, 0, 0, 0, PCMCIA_LAST_WIN | PCMCIA_UNMAP);
+       if (err != 0) {
+               for (i = 0; i < pc_cf->memwin; i++) {
+                       PCMCIA_MAP_MEM(pca, link,
+                                      (caddr_t) pc_cf->mem[i].start,
+                                      pc_cf->mem[i].caddr,
+                                      pc_cf->mem[i].len,
+                                      (pc_cf->mem[i].flags & (PCMCIA_MAP_16 |
+                                      PCMCIA_MAP_ATTR)) | i |
+                                      PCMCIA_PHYSICAL_ADDR | PCMCIA_UNMAP);
+               }
+               for (i = 0; i < pc_cf->iowin; i++) {
+                       PCMCIA_MAP_IO(pca, link, pc_cf->io[i].start,
+                                     pc_cf->io[i].len,
+                                     (pc_cf->io[i].flags & (PCMCIA_MAP_16 |
+                                     PCMCIA_MAP_8)) | i | PCMCIA_UNMAP);
+               }
+               PCMCIA_MAP_INTR(pca, link, pc_cf->irq_num, PCMCIA_UNMAP);
+               link->flags &= ~CARD_IS_MAPPED;
+               link->iowin = 0;
+               link->memwin = 0;
+               link->intr = 0;
+       } else {
+               link->flags |= CARD_IS_MAPPED;
+               link->iowin = pc_cf->iowin;
+               link->memwin = pc_cf->memwin;
+               link->intr = pc_cf->irq_num;
+       }
+       s = splbio();
+       SCRATCH_INUSE(pca) = 0;
+       wakeup((caddr_t) & SCRATCH_INUSE(pca));
+       splx(s);
+       return err;
+}
+
+int
+pcmcia_unmapcard(link)
+       struct pcmcia_link *link;
+{
+       int             i;
+       struct pcmcia_adapter *pca = link->adapter;
+       PPRINTF(("- pcmcia_unmapcard\n"));
+       if (!pca)
+               return ENODEV;
+
+       for (i = 0; i < link->memwin; i++)
+               PCMCIA_MAP_MEM(pca, link, 0, 0, 0, (i | PCMCIA_UNMAP));
+
+       for (i = 0; i < link->iowin; i++)
+               PCMCIA_MAP_IO(pca, link, 0, 0, (i | PCMCIA_UNMAP));
+
+       PCMCIA_MAP_INTR(pca, link, link->intr, PCMCIA_UNMAP);
+       PCMCIA_SERVICE(pca, link, PCMCIA_OP_RESET, 0, 0);
+       link->flags &= ~(CARD_IS_MAPPED | PCMCIA_SLOT_INUSE);
+       link->iowin = 0;
+       link->memwin = 0;
+       link->intr = 0;
+       return 0;
+}
+
+
+static int
+pcmcia_mapcard_and_configure(link, unit, pc_cf)
+       struct pcmcia_link *link;
+       struct pcmcia_conf *pc_cf;
+       int             unit;
+{
+       int             err;
+       int             mymap = 0;
+
+       PPRINTF(("- pcmcia_mapcard_and_configure\n"));
+       if (pc_cf->driver_name[0][0]) {
+#if 0
+               if ((err = pcmcia_mapcard(link, unit, pc_cf)) != 0) {
+                       return err;
+               }
+               mymap=1;
+#endif
+               link->fordriver = pc_cf->driver_name[0];
+       } else {
+               link->fordriver = NULL;
+               pc_cf = NULL;
+       }
+       pcmcia_probe_bus(link, 0, link->slot, pc_cf);
+       if ((link->flags & PCMCIA_SLOT_INUSE) == 0) {
+               if (mymap)
+                       pcmcia_unmapcard(link);
+               return ENODEV;
+       }
+       return 0;
+}
+
+
+int
+pcmcia_read_cis(link, scratch, offs, len)
+       struct pcmcia_link *link;
+       u_char         *scratch;
+       int             offs, len;
+{
+       struct pcmcia_adapter *pca = link->adapter;
+       int             s;
+       int             err = 0;
+       int             j = 0;
+       u_char *p = SCRATCH_MEM(pca);
+       int size = SCRATCH_SIZE(pca);
+       volatile int *inuse = &SCRATCH_INUSE(pca);
+
+       PPRINTF(("- pcmcia_read_cis\n"));
+       if (pca == NULL)
+               return ENXIO;
+
+       s = splbio();
+       while (*inuse)
+               sleep((caddr_t) inuse, PZERO - 1);
+       *inuse = 1;
+       splx(s);
+
+       while (len > 0) {
+               int pgoff = offs / size;
+               int toff = offs - (pgoff * size);
+               int tlen = min(len + toff, size / 2) - toff;
+               int i;
+
+               if ((err = PCMCIA_MAP_MEM(pca, link, p, pgoff, size,
+                                         PCMCIA_MAP_ATTR |
+                                         PCMCIA_LAST_WIN)) != 0)
+                       goto error;
+
+               for (i = 0; i < tlen; j++, i++)
+                       scratch[j] = p[toff + i * 2];
+
+               PCMCIA_MAP_MEM(pca, link, p, 0, size,
+                              PCMCIA_LAST_WIN | PCMCIA_UNMAP);
+               len -= tlen;
+       }
+error:
+       s = splbio();
+       *inuse = 0;
+       wakeup((caddr_t) inuse); 
+       splx(s);
+
+       return err;
+}
+
+/* here we start our pseudodev for controlling the slots */
+#define PCMCIABUS_UNIT(a)    (minor(a))
+#define PCMCIABUS_SLOT(a)    (a&0x7)
+#define PCMCIABUS_CHIPIID(a) (a&0x3)
+#define PCMCIABUS_CHIP       0x10
+#define PCMCIABUS_BUS        0x20
+#define PCMCIABUS_DEVTYPE(a) ((a)&(PCMCIABUS_CHIP|PCMCIABUS_BUS))
+static int      busopen = 0;
+static int      chipopen[4] = {0, 0, 0, 0};
+
+int
+pcmciabusopen(dev, flag, mode, p)
+       dev_t           dev;
+       int             flag, mode;
+       struct proc    *p;
+{
+       int             unit = PCMCIABUS_UNIT(dev);
+       int             chipid, slot;
+       struct  pcmcia_link *link;
+       struct pcmciabus_softc *pcmcia;
+
+       PPRINTF(("- pcmciabusopen\n"));
+       if (pcmcia_cntrl == 0)
+               return ENXIO;
+       switch (PCMCIABUS_DEVTYPE(unit)) {
+       case PCMCIABUS_BUS:
+               if (unit != PCMCIABUS_BUS)
+                       return ENXIO;
+               if (busopen)
+                       return EBUSY;
+               busopen = 1;
+               break;
+
+       case PCMCIABUS_CHIP:
+               chipid = PCMCIABUS_CHIPIID(unit);
+               if (chipid > 3)
+                       return ENXIO;
+               if (pcmcia_drivers[chipid].adapter_softc == NULL)
+                       return ENXIO;
+
+               if (chipopen[chipid])
+                       return EBUSY;
+
+               chipopen[chipid] = 1;
+               break;
+
+       case 0:
+               slot = PCMCIABUS_SLOT(unit);
+               chipid = slot >> 1;
+
+               if (chipid > 7)
+                       return ENXIO;
+
+               if (pcmcia_drivers[chipid].adapter_softc == NULL)
+                       return ENXIO;
+               pcmcia = pcmciabuscd.cd_devs[0];
+               link = pcmcia->sc_link[slot];
+
+               if (link->flags & PCMCIA_SLOT_OPEN)
+                       return EBUSY;
+
+               link->flags |= PCMCIA_SLOT_OPEN;
+               break;
+
+       default:
+               return ENXIO;
+
+       }
+       return 0;
+}
+
+
+int
+pcmciabusclose(dev)
+{
+       int unit = PCMCIABUS_UNIT(dev);
+       int chipid, slot;
+       struct  pcmcia_link *link;
+       struct pcmciabus_softc *pcmcia;
+       int s;
+
+       PPRINTF(("- pcmciabusclose\n"));
+       if (pcmcia_cntrl == 0)
+               return ENXIO;
+       switch (PCMCIABUS_DEVTYPE(unit)) {
+       case PCMCIABUS_BUS:
+               busopen = 0;
+               break;
+
+       case PCMCIABUS_CHIP:
+               chipid = PCMCIABUS_CHIPIID(unit);
+               chipopen[chipid] = 0;
+               break;
+
+       case 0:
+               slot = PCMCIABUS_SLOT(unit);
+               pcmcia = pcmciabuscd.cd_devs[0];
+               link = pcmcia->sc_link[slot];
+
+               s = splclock();
+               link->flags &= ~(PCMCIA_SLOT_OPEN|PCMCIA_SLOT_EVENT);
+               splx(s);
+               break;
+
+       default:
+               return ENXIO;
+       }
+       return 0;
+}
+
+int
+pcmciachip_ioctl(chipid, cmd, data)
+       int             chipid, cmd;
+       caddr_t         data;
+{
+       int             err = 0;
+       struct pcmcia_adapter *pca = &pcmcia_drivers[chipid];
+       struct pcmcia_link link;
+       struct pcmcia_regs *pi = (void *) data;
+
+       PPRINTF(("- pcmciachip_ioctl\n"));
+       if (pca->chip_link == NULL || pca->adapter_softc == NULL)
+               return ENXIO;
+
+       switch (cmd) {
+       case PCMCIAIO_READ_REGS:
+               pi->chip = chipid;
+               link.adapter = pca;
+               link.slot = chipid << 1;
+               return PCMCIA_SERVICE(pca, &link, PCMCIA_OP_GETREGS,
+                                     pi->chip_data, 0);
+       }
+       return ENOTTY;
+}
+
+int
+pcmciaslot_ioctl(link, slotid, cmd, data)
+       struct pcmcia_link *link;
+       int             slotid, cmd;
+       caddr_t         data;
+{
+       int             err = 0;
+       struct pcmcia_adapter *pca = &pcmcia_drivers[slotid >> 1];
+
+       PPRINTF(("- pcmciaslot_ioctl\n"));
+       if (link == NULL || pca->chip_link == NULL ||
+           pca->adapter_softc == NULL)
+               return ENXIO;
+
+       switch (cmd) {
+       case PCMCIAIO_GET_STATUS:
+               {
+                       struct pcmcia_status *pi = (void *) data;
+                       pi->slot = slotid;
+                       pi->status = 0;
+                       err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_STATUS,
+                                            &pi->status, 0);
+                       if (!err) {
+                               pi->status |= ((link->flags & CARD_IS_MAPPED) ?
+                                              PCMCIA_CARD_IS_MAPPED : 0) |
+                                       ((link->flags & PCMCIA_SLOT_INUSE) ?
+                                        PCMCIA_CARD_INUSE : 0);
+                       }
+                       return err;
+               }
+
+       case PCMCIAIO_GET_INFO:
+               {
+                       struct pcmcia_info *pi = (void *) data;
+                       int             status;
+
+                       if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_STATUS,
+                                                 &status, 0)) != 0)
+                               return err;
+                       if ((status & PCMCIA_CARD_PRESENT) == 0)
+                               return ENODEV;
+                       pi->slot = slotid;
+                       return pcmcia_read_cis(link, pi->cis_data, 0,
+                                              CIS_MAXSIZE);
+               }
+
+       case PCMCIAIO_CONFIGURE:
+               {
+                       struct pcmcia_conf *pc_cf = (void *) data;
+                       return pcmcia_mapcard_and_configure(link, -1, pc_cf);
+               }
+
+       case PCMCIAIO_UNCONFIGURE:
+               return pcmcia_unconfigure(link);
+
+       case PCMCIAIO_UNMAP:
+               return pcmcia_unmapcard(link);
+
+       case PCMCIAIO_SET_POWER:
+               {
+                       int             pi = *(int *) data;
+                       pi &= 0x3;
+                       switch (pi) {
+                       case PCMCIASIO_POWER_OFF:
+                               return PCMCIA_SERVICE(pca, link,
+                                                     PCMCIA_OP_POWER, 0, 0);
+
+                       case PCMCIASIO_POWER_5V:
+                       case PCMCIASIO_POWER_3V:
+                       case PCMCIASIO_POWER_AUTO:
+                               err = PCMCIA_SERVICE(pca, link,
+                                                    PCMCIA_OP_POWER,
+                                                    10000, pi);
+                               if (err)
+                                       return err;
+
+                               err = PCMCIA_SERVICE(pca, link,
+                                                    PCMCIA_OP_RESET,
+                                                    500000, 0);
+                               if (err) {
+                                       PPRINTF(("failed to reset %d\n", err));
+                                       PCMCIA_SERVICE(pca, link,
+                                                      PCMCIA_OP_POWER, 0, 0);
+                                       return err;
+                               }
+                               return 0;
+
+                       default:
+                               return EINVAL;
+                       }
+               }
+
+       case PCMCIAIO_READ_COR:
+               {
+                       struct pcmcia_info *pi = (void *)data;
+                       struct pcmcia_conf pc_cf;
+                       int status,s;
+
+                       err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_STATUS, 
+                                            &status, 0);
+                       if (err)
+                               return err;
+                       if ((status & PCMCIA_CARD_PRESENT) == 0) 
+                               return ENODEV;
+
+                       if (status = pcmcia_read_cis(link, pi->cis_data, 0,
+                                                    CIS_MAXSIZE))
+                               return status;
+
+                       bzero(&pc_cf, sizeof(pc_cf));
+                       if (pcmcia_get_cf(link, pi->cis_data,
+                                         sizeof(pi->cis_data), -1,
+                                         &pc_cf) != 0 )
+                               return EIO;
+
+                       s=splbio();
+
+                       while(SCRATCH_INUSE(pca))
+                               sleep((caddr_t)&SCRATCH_INUSE(pca), PZERO - 1);
+
+                       SCRATCH_INUSE(pca) = 1;
+                       splx(s);
+                       if ((err = PCMCIA_MAP_MEM(pca, link, SCRATCH_MEM(pca),
+                                                 pc_cf.cfg_off &
+                                                 ~(SCRATCH_SIZE(pca)-1),
+                                                 SCRATCH_SIZE(pca),
+                                                 PCMCIA_MAP_ATTR|
+                                                 PCMCIA_LAST_WIN)) == 0) {
+                               int m, i;
+                               u_char *d = pi->cis_data,*p;
+                               p = SCRATCH_MEM(pca)+
+                                   (pc_cf.cfg_off & (SCRATCH_SIZE(pca)-1));
+                               for (i = 0, m = 1; i < 32; i++, m <<= 1) {
+                                       if (pc_cf.cfg_regmask & m) {
+                                               *d++ = i;
+                                               *d++ = p[i*2];
+                                       }
+                               }
+                               *d++ = 0xff;
+                               *d++ = 0xff;
+                               PCMCIA_MAP_MEM(pca, link, SCRATCH_MEM(pca),
+                                              0,SCRATCH_SIZE(pca), 
+                                              PCMCIA_LAST_WIN|PCMCIA_UNMAP);
+                       } 
+                       s = splbio();
+                       SCRATCH_INUSE(pca)=0;
+                       wakeup((caddr_t)&SCRATCH_INUSE(pca));
+                       splx(s);
+                       return err;
+               }
+       default:
+               return ENOTTY;
+       }
+       return ENOTTY;
+}
+
+int
+pcmciabusioctl(dev, cmd, data, flag, p)
+       dev_t           dev;
+       int             cmd;
+       caddr_t         data;
+       int             flag;
+       struct proc    *p;
+{
+       int             unit = PCMCIABUS_UNIT(dev);
+       struct pcmciabus_softc *pcmcia;
+       struct pcmcia_link *link;
+
+       PPRINTF(("- pcmciabus_ioctl\n"));
+       pcmcia = pcmciabuscd.cd_devs[0];
+       if (pcmcia_cntrl == 0 || pcmcia == NULL)
+               return ENXIO;
+       switch (PCMCIABUS_DEVTYPE(unit)) {
+#if 0
+       case PCMCIABUS_BUS:
+               return pcmciabus_ioctl(0, cmd, data);
+#endif
+       case PCMCIABUS_CHIP:
+               return pcmciachip_ioctl(PCMCIABUS_CHIPIID(unit), cmd, data);
+       case 0:
+               link = pcmcia->sc_link[PCMCIABUS_SLOT(unit)];
+               return pcmciaslot_ioctl(link, PCMCIABUS_SLOT(unit), cmd, data);
+       default:
+               return ENXIO;
+       }
+}
+
+int
+pcmciabusselect(device, rw, p)
+       dev_t device;
+       int rw;
+       struct proc *p;
+{
+       int s;
+       int unit = PCMCIABUS_UNIT(device);
+       struct pcmciabus_softc *pcmcia;
+       struct pcmcia_link *link;
+
+       PPRINTF(("- pcmciabus_ioctl\n"));
+       pcmcia = pcmciabuscd.cd_devs[0];
+       
+       switch (PCMCIABUS_DEVTYPE(unit)) {
+       case 0:
+               link = pcmcia->sc_link[PCMCIABUS_SLOT(unit)];
+               break;
+       case PCMCIABUS_BUS:
+       case PCMCIABUS_CHIP:
+       default:
+               return 0;
+       }
+
+       s = splclock();         /* XXX something higher than all devices that can plug in.... */
+       switch (rw) {
+       case FREAD:
+       case FWRITE:
+               break;
+       case 0:
+               if (link->flags & PCMCIA_SLOT_EVENT) {
+                       link->flags &= ~PCMCIA_SLOT_EVENT;
+                       splx(s);
+                       return 1;
+               }
+               selrecord(p, &link->pcmcialink_sel);
+               break;
+       }
+       splx(s);
+       return 0;
+}
+
+int
+pcmciabusmmap()
+{
+       return ENXIO;
+}
+
+/* pcmcia template string match. A '*' matches any number of characters.
+   A NULL template matches all strings.
+   return-value 
+    0 nomatch 
+    1 wildcard match 
+    2 excact match
+ */
+static int
+pcmcia_strcmp(templ,val,flags,msg)
+    char *templ;
+    char *val;
+    int flags;
+    char *msg;
+{
+    char *ltempl=NULL,*lval=NULL;
+
+    if (flags & PC_SHOWME)
+           printf("%s = `%s'-`%s'\n", msg, templ ? templ : "X", val);
+
+    if(templ==NULL)
+        return 1;
+    while(*val) {
+        while(*templ=='*') {
+            ltempl=++templ;
+            lval=val;
+        }
+        if(*templ==*val) {
+            templ++;
+            val++;
+        } else {
+            if(ltempl==NULL)
+                return 0;
+            val=++lval;
+            templ=ltempl;
+        }
+    }
+    if(*templ!=0 && *templ!='*')
+        return 0;
+    return  ltempl?1:2;
+}
+
+#ifdef PCMCIA_DEBUG
+static void
+pcmciadumpcf(cf)
+       struct pcmcia_conf * cf;
+{
+       int             i;
+       static char    *ios[] = {
+               "auto", "8bit", "16bit", "illegal"
+       };
+       printf("Driver name %s\n", cf->driver_name[0]);
+       printf("CFG offset %x\n", cf->cfg_off);
+       printf("IRQ type %s%s\n", cf->irq_level ? "Level " : "", 
+                                 cf->irq_pulse ? "Pulse" : "");
+       printf("IRQ num %x\n", cf->irq_num);
+       printf("CFG type %x %x\n", cf->cfgtype,cf->cfgid);
+       printf("Cardtype %s\n", cf->iocard ? "IO" : "MEM");
+       for (i = 0; i < cf->iowin; i++) {
+               printf("iowin  %x-%x %s\n", cf->io[i].start,
+                      cf->io[i].start + cf->io[i].len - 1,
+                      ios[(cf->io[i].flags & 
+                           (PCMCIA_MAP_8 | PCMCIA_MAP_16)) >> 8]);
+       }
+       for (i = 0; i < cf->memwin; i++) {
+               printf("memwin  (%x)%x-%x %x\n",
+                      cf->mem[i].caddr,
+                      cf->mem[i].start,
+                      cf->mem[i].start + cf->mem[i].len - 1,
+                      cf->mem[i].flags);
+       }
+}
+#endif
diff --git a/sys/dev/pcmcia/pcmcia.h b/sys/dev/pcmcia/pcmcia.h
new file mode 100644 (file)
index 0000000..67df721
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef __PCMCIA_H__
+#define __PCMCIA_H__
+
+#define MAX_CIS_NAMELEN /*32*/64               /* version info string len */
+
+/*
+ * Configuration Registers
+ *
+ * These are the registers required by Release 2.0 of the standard
+ * (Section 4.15)
+ */
+
+/* Offsets for register ordering */
+#define PCMCIA_COR     0x00    /* Configuration and Option Register */
+#define PCMCIA_CCSR    0x02    /* Card Configuration and Status Register */
+#define PCMCIA_PIR     0x04    /* Pin Replacement Register */
+#define PCMCIA_SCR     0x06    /* Socket and Copy Register */
+
+/* Now register bits, ordered by reg # */
+
+/* For Configuration and Option Register (PCMCIA_COR) */
+/*#define PCMCIA_MEMIO 0x01    /* Use I/O Space */
+/*#define PCMCIA_CNFG  0x0e    /* I/O decoding configuration */
+#define PCMCIA_CNFGMASK 0x3f   /* Use template */
+#define PCMCIA_LVLREQ  0x40    /* Generate level mode interrupts */
+#define PCMCIA_SRESET  0x80    /* Reset Card */
+
+/* For Card Configuration and Status Register (PCMCIA_CCSR) */
+#define PCMCIA_INTR            0x02    /* Interrupt Pending */
+#define PCMCIA_POWER_DOWN      0x04
+#define PCMCIA_AUDIO_ENA       0x08
+#define PCMCIA_IOIS8           0x20
+#define PCMCIA_SIGCHG_ENA      0x40
+#define PCMCIA_CHANGED         0x80
+
+/* Pin Replacement Register (PCMCIA_PIR) */
+#define PCMCIA_WP_STATUS          0x01
+#define PCMCIA_READY_STATUS       0x02
+#define PCMCIA_BVD2_STATUS        0x04
+#define PCMCIA_BVD1_STATUS        0x08
+#define PCMCIA_WP_EVENT                   0x10
+#define PCMCIA_READY_EVENT        0x20
+#define PCMCIA_BVD2_EVENT         0x40
+#define PCMCIA_BVD1_EVENT         0x80
+
+
+/* For Socket and Copy Register (PCMCIA_SCR) */
+#define PCMCIA_SOCKNUM 0x0f    /* Which socket I'm sitting in */
+#define PCMCIA_COPNUM  0x70    /* Which instance I am. */
+
+/*
+ * CIS Tuple defines
+ */
+#define CIS_MAXSIZE    512
+
+/* Define tuple types */
+#define CIS_NULL       0x00    /* null tuple */
+#define CIS_DEVICE     0x01    /* Device descriptor, common mem */
+#define CIS_DEVICE_A   0x17    /* Device descriptor, attribute mem */
+#define                CIS_DEVICE_TYPE         0xf0    /* type mask */
+#define                CIS_DEVICE_TYPE_SHIFT   4       /* type offset */
+#define                CIS_DEVICE_WPS          0x08    /* WPS mask */
+#define                CIS_DEVICE_SPEED        0x07    /* speed mask */
+#define                CIS_DEVICE_ADDRS        0xf8    /* # addr units */
+#define                CIS_DEVICE_ADDRS_SHIFT  3       /* # addr units offset */
+#define                CIS_DEVICE_SIZE         0x07
+#define CIS_CSUM       0x10    /* Checksum field */
+#define CIS_NOLINK     0x14    /* No Link */
+#define CIS_VER1       0x15    /* Level 1 Version/Product info */
+#define CIS_CFG_INFO   0x1a    /* Configuration info map */
+#define                TPCC_RASZ               0x03    /* size of regaddr */
+#define                TPCC_RASZ_SHIFT         0
+#define                TPCC_RMSZ               0x3c    /* size of regmask */
+#define                TPCC_RMSZ_SHIFT         2
+#define                TPCC_LAST               0x3f    /* last con entry idx */
+#define                TPCC_LAST_SHIFT         0
+#define CIS_CFG_ENT    0x1b    /* Configuration info entry */
+#define                TPCE_INDX_ENTRY         0x3f    /* config entry # */
+#define                TPCE_INDX_DEF           0x40    /* default bit */
+#define                TPCE_INDX_INT           0x80    /* interface bit */
+#define                TPCE_IF_TYPE            0x0f    /* interface type */
+#define                TPCE_IF_BVD             0x10    /* BVD active bit */
+#define                TPCE_IF_WP              0x20    /* WP active bit */
+#define                TPCE_IF_RDYBSY          0x40    /* RdyBsy active bit */
+#define                TPCE_IF_MWAIT           0x80    /* Wait Sig req. bit */
+#define                TPCE_FS_PWR             0x03    /* Power */
+#define                        TPCE_FS_PWR_VCC         0x01    /* Vcc struct */
+#define                        TPCE_FS_PWR_VPP         0x02    /* Vpp struct */
+#define                TPCE_FS_TD              0x04    /* Timing */
+#define                        TPCE_FS_TD_WAIT         0x03    /* wait scale */
+#define                        TPCE_FS_TD_RDY          0x1c    /* rdy/bsy scale */
+#define                        TPCE_FS_TD_RDY_SHIFT    2
+#define                        TPCE_FS_TD_RSV          0xe0    /* reserved scale */
+#define                        TPCE_FS_TD_RSV_SHIFT    5
+#define                TPCE_FS_IO              0x08    /* I/O Space */
+#define                        TPCE_FS_IO_LINES        0x1f    /* IO addr lines */
+#define                        TPCE_FS_IO_BUS8         0x20    /* bus 8 bit */
+#define                        TPCE_FS_IO_BUS16        0x40    /* bus 16 bit */
+#define                        TPCE_FS_IO_RANGE        0x80    /* range bit */
+#define                        TPCE_FS_IO_LEN          0xc0    /* block len size */
+#define                        TPCE_FS_IO_LEN_SHIFT    6
+#define                        TPCE_FS_IO_SIZE         0x30    /* block size size */
+#define                        TPCE_FS_IO_SIZE_SHIFT   4
+#define                        TPCE_FS_IO_NUM          0x0f    /* # of blocks */
+#define                TPCE_FS_IRQ             0x10    /* IRQ */
+#define                        TPCE_FS_IRQ_SHARE       0x80    /* int sharing */
+#define                        TPCE_FS_IRQ_PULSE       0x40    /* pulse request */
+#define                        TPCE_FS_IRQ_LEVEL       0x20    /* level-trig int */
+#define                        TPCE_FS_IRQ_MASK        0x10    /* irq mask bit */
+#define                        TPCE_FS_IRQ_IRQN        0x0f    /* irqn mask */
+#define                        TPCE_FS_IRQ_VEND        0x08    /* vendor sig */
+#define                        TPCE_FS_IRQ_BERR        0x04    /* bus error */
+#define                        TPCE_FS_IRQ_IOCK        0x02    /* io check */
+#define                        TPCE_FS_IRQ_NMI         0x01    /* nmi */
+#define                TPCE_FS_MEM             0x60    /* Mem Space */
+#define                TPCE_FS_MEM_SHIFT       5
+#define                        TPCE_FS_MEM_HOST        0x80
+#define                        TPCE_FS_MEM_ADDR        0x60
+#define                        TPCE_FS_MEM_ADDR_SHIFT  5
+#define                        TPCE_FS_MEM_LEN         0x18
+#define                        TPCE_FS_MEM_LEN_SHIFT   3
+#define                        TPCE_FS_MEM_WINS        0x07
+#define                TPCE_FS_MISC            0x80    /* Misc */
+#define CIS_MFG                0x20    /* Manufacturer's ID */
+#define CIS_FUNC       0x21    /* Function ID */
+#define CIS_FUNE       0x22    /* Function Extension */
+#define CIS_DRIVER     0x77    /* Driver ID */
+#define CIS_END                0xff    /* Last Entry */
+
+extern int   pcmcia_configure __P((struct device *, void *, void *));
+
+#endif /* __PCMCIA_H__ */
diff --git a/sys/dev/pcmcia/pcmcia_conf.c b/sys/dev/pcmcia/pcmcia_conf.c
new file mode 100644 (file)
index 0000000..ab0e5b0
--- /dev/null
@@ -0,0 +1,477 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+
+#include <dev/pcmcia/pcmcia.h>
+#include <dev/pcmcia/pcmciabus.h>
+#include <dev/pcmcia/pcmcia_ioctl.h>
+
+#ifdef CFG_DEBUG
+static
+void dump(addr, len)
+       u_char *addr;
+       int len;
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               printf("%02x ", addr[i]);
+               if (i != 0 && (i & 0xf) == 0)
+                       printf("\n");
+       }
+       if (i != 0 && (i & 0xf) == 0)
+               printf("\n");
+}
+#endif
+
+int
+pcmcia_get_cf(pc_link, data, dlen, idx, pc_cf)
+       struct pcmcia_link *pc_link;
+       u_char         *data;
+       int             dlen, idx;
+       struct pcmcia_conf *pc_cf;
+{
+       u_char          code, len, *tbuf, *endp;
+       int             done;
+
+       endp = data + dlen;
+
+       done = 0;
+       while (!done && data < endp) {
+               code = *data++;
+               if (code == CIS_NULL) {
+                       continue;
+               }
+               len = *data++;
+
+               tbuf = data;
+               data += len;
+               switch (code) {
+               case CIS_END:
+                       done = 1;
+                       break;
+               case CIS_CFG_INFO:
+                       read_cfg_info(tbuf, len, pc_cf);
+                       break;
+               case CIS_CFG_ENT:
+                       if ((idx & CFGENTRYMASK) != CFGENTRYID ||
+                           pc_cf->cfgid == 0)
+                               parse_cfent(tbuf, len, idx, pc_cf);
+                       break;
+               default:
+                       break;
+               }
+       }
+       return 0;
+}
+
+
+int
+read_cfg_info(tbuf, len, pc_cf)
+       u_char         *tbuf;
+       int             len;
+       struct pcmcia_conf *pc_cf;
+{
+       int             rasz, rmsz;
+
+       rasz = (tbuf[0] & TPCC_RASZ) >> TPCC_RASZ_SHIFT;
+       rmsz = (tbuf[0] & TPCC_RMSZ) >> TPCC_RMSZ_SHIFT;
+
+#ifdef CFG_DEBUG
+       printf("read_cfg_info\n");
+       dump(tbuf, len);
+#endif
+
+       pc_cf->cfg_off = 0;
+       switch (rasz) {
+       case 3:
+               pc_cf->cfg_off |= (tbuf[5] << 24);
+       case 2:
+               pc_cf->cfg_off |= (tbuf[4] << 16);
+       case 1:
+               pc_cf->cfg_off |= (tbuf[3] << 8);
+       case 0:
+               pc_cf->cfg_off |= tbuf[2];
+       }
+
+       tbuf += rasz + 3;
+       pc_cf->cfg_regmask = 0;
+       switch (rmsz & 3) {
+       case 3:
+               pc_cf->cfg_regmask |= (tbuf[3] << 24);
+       case 2:
+               pc_cf->cfg_regmask |= (tbuf[2] << 16);
+       case 1:
+               pc_cf->cfg_regmask |= (tbuf[1] << 8);
+       case 0:
+               pc_cf->cfg_regmask |= tbuf[0];
+       }
+}
+
+int
+parse_cfent(tbuf, len, slotid, pc_cf)
+       u_char         *tbuf;
+       int             len;
+       int             slotid;
+       struct pcmcia_conf *pc_cf;
+{
+       int i, idx, defp, iop, io_16, ios, ftrs, intface, k;
+       int host_addr_p, addr_size, len_size;
+
+#ifdef CFG_DEBUG
+       printf("parse_cfent\n");
+       dump(tbuf, len);
+#endif
+
+       i = 0;
+       intface = (tbuf[i] & TPCE_INDX_INT);
+       idx = (tbuf[i] & TPCE_INDX_ENTRY);
+       defp = (tbuf[i] & TPCE_INDX_DEF);
+
+       if ((idx == slotid) || (defp && slotid!=-2 && 
+                               (slotid & CFGENTRYMASK) == CFGENTRYMASK)) {
+               int j;
+               if (intface) {
+                       i++;
+                       pc_cf->iocard = (tbuf[i] & TPCE_IF_TYPE) == 1;
+               }
+               i++;
+               ftrs = tbuf[i++];
+               for (j = 0; j < (ftrs & TPCE_FS_PWR); j++) {
+                       int             pwr_desc = tbuf[i++];
+                       /* for each struct, skip all parameter defns */
+                       for (k = 0; k < 8; pwr_desc >>= 1, k++) {
+                               if (pwr_desc & 0x01) {
+                                       /* skip bytes until non-ext found */
+                                       while (tbuf[i++] & 0x80)
+                                               continue;
+                               }
+                       }
+               }
+               /* TODO read timing info */
+               if (ftrs & TPCE_FS_TD) {
+#define BONE(a,b)      (j & a) != 7 << b ? 1 : 0
+                       int j = tbuf[i++];
+                       i += ((j & TPCE_FS_TD_WAIT) != 3 ? 1 : 0);
+                       i += BONE(TPCE_FS_TD_RDY,TPCE_FS_TD_RDY_SHIFT);
+                       i += BONE(TPCE_FS_TD_RSV,TPCE_FS_TD_RSV_SHIFT);
+#undef BONE
+               }
+               if (ftrs & TPCE_FS_IO) {
+                       int io_addrs[16], io_lens[16];
+                       int io_16, io_block_len, io_block_size, io_lines;
+                       int io_range;
+
+                       iop = 1;
+                       io_lines = tbuf[i] & TPCE_FS_IO_LINES;
+                       io_16 = tbuf[i] & TPCE_FS_IO_BUS16;
+                       io_range = tbuf[i] &TPCE_FS_IO_RANGE;
+                       i++;
+                       if (io_range) {
+                               int iptr, ilen, elen;
+
+                               io_block_len = (tbuf[i] & TPCE_FS_IO_LEN) >>
+                                               TPCE_FS_IO_LEN_SHIFT;
+                               io_block_size = (tbuf[i] & TPCE_FS_IO_SIZE) >>
+                                               TPCE_FS_IO_SIZE_SHIFT;
+                               ios = (tbuf[i] & TPCE_FS_IO_NUM) + 1;
+                               i++;
+                               if ((ftrs & TPCE_FS_IRQ) != 0) {
+                                       iptr=(ios * elen) + i;
+#define IRQTYPE (TPCE_FS_IRQ_PULSE|TPCE_FS_IRQ_LEVEL)
+#define IRQMASK TPCE_FS_IRQ_MASK
+                                       if ((tbuf[iptr] & IRQTYPE) == 0)
+                                               if ((tbuf[iptr-elen] &
+                                                    IRQTYPE) != 0)
+                                                       iptr -= elen;
+                                       if ((tbuf[iptr] & IRQMASK) != 0)
+                                               ilen = 2;
+                                       else
+                                               ilen=1;
+                               }
+                               else
+                                       ilen=0;
+
+                               if ((i + (ios * elen) + ilen) > len) {
+                                       printf(
+"Warning: CIS range info doesn't fit in entry! Reducing # of ranges by 1\n");
+                                       ios--;
+                               }
+
+                               for (j = 0; j < ios; j++) {
+                                       io_addrs[j] = io_lens[j] = 0;
+                                       switch (io_block_size) {
+                                       case 3:
+                                               io_addrs[j] |= tbuf[i+3] << 24;
+                                               io_addrs[j] |= tbuf[i+2] << 16;
+                                       case 2:
+                                               io_addrs[j] |= tbuf[i+1] << 8;
+                                       case 1:
+                                               io_addrs[j] |= tbuf[i];
+                                               break;
+                                       }
+                                       pc_cf->io[j].start = io_addrs[j];
+                                       i += io_block_size +
+                                               (io_block_size == 3 ? 1 : 0);
+                                       switch (io_block_len) {
+                                       case 3:
+                                               io_lens[j] |= tbuf[i+3] << 24;
+                                               io_lens[j] |= tbuf[i+2] << 16;
+                                       case 2:
+                                               io_lens[j] |= tbuf[i+1] << 8;
+                                       case 1:
+                                               io_lens[j] |= tbuf[i];
+                                               break;
+                                       }
+                                       io_lens[j]++;
+                                       if(io_lens[j] & 1) {
+                                              printf(
+"Odd IO window length!! (Assuming incorrect CIS entry %d)\n", io_lens[j]);
+                                              io_lens[j]--;
+                                       }
+                        
+                                       pc_cf->io[j].len = io_lens[j];
+                                       pc_cf->io[j].flags = io_16 ?
+                                               PCMCIA_MAP_16 : PCMCIA_MAP_8;
+                                       i += io_block_len +
+                                               (io_block_len == 3 ? 1 : 0);
+                               }
+                               pc_cf->iowin = ios;
+                       }
+                       else {
+                               pc_cf->iowin = 1;
+                               pc_cf->io[0].len  = 1 << io_lines;
+                               pc_cf->io[0].start= 0 ;
+                               pc_cf->io[0].flags = io_16 ? 
+                                       PCMCIA_MAP_16 : PCMCIA_MAP_8;
+                       }
+               }
+               if (ftrs & TPCE_FS_IRQ) {
+                       int             irq_mask, irqp, irq;
+                       pc_cf->irq_level = (tbuf[i] & TPCE_FS_IRQ_LEVEL) != 0;
+                       pc_cf->irq_pulse = (tbuf[i] & TPCE_FS_IRQ_PULSE) != 0;
+                       pc_cf->irq_share = (tbuf[i] & TPCE_FS_IRQ_SHARE) != 0;
+                       if (tbuf[i] & TPCE_FS_IRQ_MASK) {
+                               pc_cf->irq_mask = (tbuf[i+2] << 8) + tbuf[i+1];
+                               if (pc_cf->irq_mask & (1 << 2))
+                                       pc_cf->irq_mask |= 1 << 9;
+                               i += 2;
+                       } else {
+                               pc_cf->irq_num = tbuf[i] & TPCE_FS_IRQ_IRQN;
+                               pc_cf->irq_mask = -1;
+                       }
+
+                       i++;
+               }
+               if (ftrs & TPCE_FS_MEM) {
+                       int memp, mems, mem_lens[16], mem_caddrs[16],
+                           mem_haddrs[16];
+                       memp = 1;
+                       switch ((ftrs & TPCE_FS_MEM) >> TPCE_FS_MEM_SHIFT) {
+                       case 1:
+                               mems = 1;
+                               mem_lens[0] = (tbuf[i+1] << 8) + tbuf[i];
+                               mem_lens[0] <<= 8;
+
+                               break;
+                       case 2:
+                               mems = 1;
+                               mem_lens[0] = (tbuf[i+1] << 8) + tbuf[i];
+                               mem_caddrs[0] = mem_haddrs[0] =
+                                       (tbuf[i+3] << 8) + tbuf[i+2];
+
+                               mem_lens[0] <<= 8;
+                               mem_caddrs[0] <<= 8;
+
+                               break;
+                       case 3:
+                               host_addr_p = tbuf[i] & TPCE_FS_MEM_HOST;
+                               addr_size = (tbuf[i] & TPCE_FS_MEM_ADDR) >>
+                                       TPCE_FS_MEM_ADDR_SHIFT;
+                               len_size = (tbuf[i] & TPCE_FS_MEM_LEN) >>
+                                       TPCE_FS_MEM_LEN_SHIFT;
+                               mems = (tbuf[i] & TPCE_FS_MEM_WINS) + 1;
+                               i++;
+                               for (j = 0; j < mems; j++) {
+                                       mem_lens[j] = 0;
+                                       mem_caddrs[j] = 0;
+                                       mem_haddrs[j] = 0;
+                                       switch (len_size) {
+                                       case 3:
+                                               mem_lens[j] |=
+                                                   (tbuf[i+2] << 16);
+                                       case 2:
+                                               mem_lens[j] |=
+                                                   (tbuf[i+1] << 8);
+                                       case 1:
+                                               mem_lens[j] |= tbuf[i];
+                                       }
+                                       i += len_size;
+                                       switch (addr_size) {
+                                       case 3:
+                                               mem_caddrs[j] |=
+                                                   (tbuf[i+2] << 16);
+                                       case 2:
+                                               mem_caddrs[j] |=
+                                                   (tbuf[i+1] << 8);
+                                       case 1:
+                                               mem_caddrs[j] |= tbuf[i];
+                                       }
+                                       i += addr_size;
+                                       if (host_addr_p) {
+                                               switch (addr_size) {
+                                               case 3:
+                                                       mem_haddrs[j] |=
+                                                           (tbuf[i+2] << 16);
+                                               case 2:
+                                                       mem_haddrs[j] |=
+                                                           (tbuf[i+1] << 8);
+                                               case 1:
+                                                       mem_haddrs[j] |=
+                                                               tbuf[i];
+                                               }
+                                               i += addr_size;
+                                       }
+                                       mem_lens[j] <<= 8;
+                                       mem_caddrs[j] <<= 8;
+                                       mem_haddrs[j] <<= 8;
+
+                               }
+                       }
+                       for (j = 0; j < mems; j++) {
+                               pc_cf->mem[j].len = mem_lens[j];
+                               pc_cf->mem[j].caddr = mem_caddrs[j];
+                               pc_cf->mem[j].start = mem_haddrs[j];
+                               pc_cf->mem[j].flags = 0;
+                       }
+                       pc_cf->memwin = mems;
+               } else
+                       pc_cf->memwin = 0;
+               return;
+       }
+
+
+       if (slotid == -2 ) {
+               /* find matching slotid */
+               struct pcmcia_conf tmp_cf;
+               /* get defaults */
+               parse_cfent(tbuf, len, -1, &tmp_cf);
+               /* change to selected */
+               parse_cfent(tbuf, len, idx, &tmp_cf);
+#ifdef CFG_DEBUG
+               printf("slotid %d %d iowin %d %d memwin %d %d wins %x %x %d %d\n",
+                   pc_cf->iocard , tmp_cf.iocard,
+                   pc_cf->iowin , tmp_cf.iowin,
+                   pc_cf->memwin , tmp_cf.memwin,
+                   pc_cf->io[0].start , tmp_cf.io[0].start,
+                   pc_cf->io[0].len , tmp_cf.io[0].len
+                   );
+#endif
+
+               if((pc_cf->iocard == tmp_cf.iocard) && /* same type */
+                  (pc_cf->iowin == tmp_cf.iowin) &&
+                  (pc_cf->memwin == tmp_cf.memwin)) {
+                       int i;
+                       for (i = 0; i < tmp_cf.iowin; i++)
+                               if (pc_cf->io[i].len != tmp_cf.io[i].len ||
+                                   pc_cf->io[i].start != tmp_cf.io[i].start)
+                                       return;
+
+                       for (i = 0; i < tmp_cf.memwin; i++)
+                           if (pc_cf->mem[i].len!=tmp_cf.mem[i].len ||
+                               pc_cf->mem[i].start!=tmp_cf.mem[i].start)
+                                   return;
+
+                       /* *pc_cf = tmp_cf;/**/
+                       pc_cf->cfgid = idx;
+               }
+               return;
+       }
+}
+
+void
+pcmcia_getstr(buf, pptr, end)
+       char *buf;
+       u_char **pptr;
+       u_char *end;
+{
+       u_char *ptr = *pptr;
+       char *eb = buf + MAX_CIS_NAMELEN - 1;
+
+       while (buf < eb && ptr < end)
+               switch (*ptr) {
+               case 0x00:
+                       ptr++;
+                       /*FALLTHROUGH*/
+               case 0xff:
+                       *pptr = ptr;
+                       *buf = '\0';
+                       return;
+
+               default:
+                       *buf++ = *ptr++;
+                       break;
+               }
+       printf("Warning: Maximum CIS string length exceeded\n");
+       *buf = '\0';
+
+       /* Keep going until we find the end */
+       while (ptr < end)
+               switch (*ptr) {
+               case 0x00:
+                       ptr++;
+                       /*FALLTHROUGH*/
+               case 0xff:
+                       *pptr = ptr;
+                       return;
+
+               default:
+                       ptr++;
+                       break;
+               }
+
+       *pptr = ptr;
+}
+
+
+int
+pcmcia_get_cisver1(pc_link, data, len, manu, model, add_inf1, add_inf2)
+       struct pcmcia_link *pc_link;
+       u_char         *data;
+       int             len;
+       char           *manu, *model, *add_inf1, *add_inf2;
+{
+       u_char         *p, *end;
+
+       p = data;
+       end = data + len;
+       while ((*p != (u_char) 0xff) && (p < end)) {
+               int             clen = *(p + 1);
+               int             maj, min;
+               if (*p == CIS_VER1) {
+                       u_char         *pp = p + 2;
+                       maj = *pp++;
+                       min = *pp++;
+                       if (maj != 4 || min != 1) {
+                               printf("wrong version id %d.%d for card in slot %d\n",
+                                      maj, min, pc_link->slot);
+                               return ENODEV;
+                       }
+                       pcmcia_getstr(manu, &pp, end); 
+                       pcmcia_getstr(model, &pp, end);
+                       pcmcia_getstr(add_inf1, &pp, end);
+                       pcmcia_getstr(add_inf2, &pp, end);
+                       if (*pp != (u_char) 0xff) {
+                               printf("WARNING: broken id for card in slot %d\n", pc_link->slot);
+                               printf("manu %s model %s add_inf1 %s add_inf2 %s\n", manu, model, add_inf1, add_inf2);
+                               return 0;
+                       }
+                       return 0;
+               }
+               p += clen + 2;
+       }
+       printf("%x %x\n", p, end);
+       return ENODEV;
+}
diff --git a/sys/dev/pcmcia/pcmcia_ioctl.h b/sys/dev/pcmcia/pcmcia_ioctl.h
new file mode 100644 (file)
index 0000000..535e122
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1993, 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 dipclaimer.
+ * 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 Stefan Grefen.
+ * 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.
+ */
+struct pcmcia_info {
+       int slot;
+       u_char cis_data[CIS_MAXSIZE];
+};
+
+struct pcmcia_status {
+       int slot;
+       int status;
+};
+
+struct pcmcia_regs {
+       int chip;
+       int chiptype;
+#define PCMCIA_CHIP_UNKNOWN    0
+#define PCMCIA_PCIC            1
+       u_char chip_data[CIS_MAXSIZE];
+};
+
+#define PCMCIAIO_GET_STATUS       _IOR('s', 128, struct pcmcia_status)
+#define PCMCIAIO_GET_INFO         _IOR('s', 129, struct pcmcia_info)
+#define PCMCIAIO_SET_POWER        _IOW('s', 139, int)
+#define PCMCIASIO_POWER_5V         0x3
+#define PCMCIASIO_POWER_3V         0x5
+#define PCMCIASIO_POWER_AUTO       0x7
+#define PCMCIASIO_POWER_OFF        0x0
+#define PCMCIAIO_CONFIGURE        _IOW('s', 140, struct pcmcia_conf)
+#define PCMCIAIO_UNMAP            _IOW('s', 141, int)
+#define PCMCIAIO_UNCONFIGURE      _IOW('s', 142, int)
+#define PCMCIAIO_READ_COR         _IOR('s', 143, struct pcmcia_info)
+#define PCMCIAIO_READ_REGS        _IOWR('s', 160, struct pcmcia_regs)
+
diff --git a/sys/dev/pcmcia/pcmciabus.h b/sys/dev/pcmcia/pcmciabus.h
new file mode 100644 (file)
index 0000000..4dceb98
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 1993, 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 dipclaimer.
+ * 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: pcmciabus.h,v 1.1 1996/01/15 00:05:13 hvozda Exp $
+ */
+ /* derived from scsicconf.[ch] writenn by Julian Elischer et al */
+
+#ifndef        _PCMCIA_PCMCIABUS_H_
+#define _PCMCIA_PCMCIABUS_H_ 1
+
+#include <sys/queue.h>
+#include <sys/select.h>
+#include <machine/cpu.h>
+
+/*
+ * The following documentation tries to describe the relationship between the
+ * various structures defined in this file:
+ *
+ * each adapter type has a pcmcia_adapter struct. This describes the adapter and
+ *    identifies routines that can be called to use the adapter.
+ * each device type has a pcmcia_device struct. This describes the device and
+ *    identifies routines that can be called to use the device.
+ * each existing device position (pcmciabus + port)
+ *    can be described by a pcmcia_link struct.
+ *    Only port positions that actually have devices, have a pcmcia_link
+ *    structure assigned. so in effect each device has pcmcia_link struct.
+ *    The pcmcia_link structure contains information identifying both the
+ *    device driver and the adapter driver for that port on that pcmcia bus,
+ *    and can be said to 'link' the two.
+ * each individual pcmcia bus has an array that points to all the pcmcia_link
+ *    structs associated with that pcmcia bus. Slots with no device have
+ *    a NULL pointer.
+ * each individual device also knows the address of it's own pcmcia_link
+ *    structure.
+ *
+ *                             -------------
+ *
+ * The key to all this is the pcmcia_link structure which associates all the 
+ * other structures with each other in the correct configuration.  The
+ * pcmcia_link is the connecting information that allows each part of the 
+ * pcmcia system to find the associated other parts.
+ */
+
+
+struct pcmcia_link;
+struct pcmcia_conf;
+struct pcmcia_adapter;
+
+/*
+ * These entrypoints are called by the high-end drivers to get services from
+ * whatever low-end drivers they are attached to each adapter type has one of
+ * these statically allocated.
+ */
+struct pcmcia_funcs {
+/* 4 map io range */
+       int (*pcmcia_map_io) __P((struct pcmcia_link *, u_int, u_int, int));
+/* 8 map memory window */
+       int (*pcmcia_map_mem) __P((struct pcmcia_link *, caddr_t,
+                                  u_int, u_int, int));
+/*12 map interrupt */
+       int (*pcmcia_map_intr) __P((struct pcmcia_link *, int, int));
+/*26 power on/off etc */
+       int (*pcmcia_service) __P((struct pcmcia_link *, int, void *, int));
+};
+
+struct pcmciabus_link {                        /* Link back to the bus we are on */
+       /* Bus specific configure    */
+       int (*bus_config) __P((struct pcmcia_link *, struct device *,
+                              struct pcmcia_conf *, struct cfdata *));
+       /* Bus specific unconfigure  */
+       int (*bus_unconfig) __P((struct pcmcia_link *));
+       /* Bus specific probe        */
+       int (*bus_probe) __P((struct device *, void *,
+                             void *, struct pcmcia_link *));
+       /* Bus specific search       */
+       int (*bus_search) __P((struct device *, void *, cfprint_t));
+       /* initialize scratch        */
+       int (*bus_init) __P((struct device *, struct cfdata *,
+                            void *, struct pcmcia_adapter *, int));
+};
+struct pcmcia_adapter {
+       struct pcmcia_funcs *chip_link;
+       struct pcmciabus_link *bus_link;
+        void *          adapter_softc;
+       caddr_t scratch_mem;            /* pointer to scratch window */
+       int scratch_memsiz;             /* size of scratch window    */
+       int scratch_inuse;              /* window in use             */
+};
+
+#define PCMCIA_MAP_ATTR                0x0100 /* for memory only */
+#define PCMCIA_MAP_8           0x0100 /* for io only */
+#define PCMCIA_MAP_16          0x0200
+#define PCMCIA_UNMAP           0x0400
+#define PCMCIA_PHYSICAL_ADDR    0x0800
+#define PCMCIA_UNMAP_ALL       0x0c00
+#define PCMCIA_FIXED_WIN       0x1000
+#define PCMCIA_LAST_WIN                0x0010
+#define PCMCIA_FIRST_WIN       0x0020
+#define PCMCIA_ANY_WIN         0x0030
+
+#define        PCMCIA_OP_RESET         0x0000
+#define        PCMCIA_OP_POWER         0x0001
+#define        PCMCIA_OP_STATUS        0x0002
+#define        PCMCIA_OP_GETREGS       0x0003
+#define        PCMCIA_OP_WAIT          0x0004
+
+#define PCMCIA_POWER_ON                0x0001
+#define PCMCIA_POWER_5V                0x0002
+#define PCMCIA_POWER_3V                0x0004
+#define PCMCIA_POWER_AUTO      0x0008
+
+#define PCMCIA_CARD_PRESENT     0x0001
+#define PCMCIA_BATTERY         0x0002
+#define PCMCIA_WRITE_PROT      0x0004
+#define PCMCIA_READY           0x0008
+#define PCMCIA_POWER           0x0010
+#define PCMCIA_POWER_PP                0x0020
+#define PCMCIA_CARD_IS_MAPPED   0x1000
+#define PCMCIA_CARD_INUSE       0x2000
+
+
+/*
+ * This structure describes the connection between an adapter driver and
+ * a device driver, and is used by each to call services provided by
+ * the other, and to allow generic pcmcia glue code to call these services
+ * as well.
+ */
+struct pcmcia_link {
+               char    pcmciabus;              /* the Nth pcmciabus */
+               char    slot;                   /* slot of this dev */
+               char    flags;                  
+#define CARD_IS_MAPPED         0x01
+#define PCMCIA_ATTACH          0x02
+#define PCMCIA_REATTACH        0x04
+#define PCMCIA_SLOT_INUSE      0x08
+#define PCMCIA_ATTACH_TYPE     (PCMCIA_ATTACH|PCMCIA_REATTACH)
+#define PCMCIA_SLOT_EVENT      0x80
+#define PCMCIA_SLOT_OPEN       0x40
+        char   opennings;
+
+       char    iowin;
+       char    memwin;
+       char    intr;
+       char    dummy;
+               struct  pcmcia_adapter *adapter;        /* adapter entry points etc. */
+               struct  pcmciadevs *device;     /* device entry points etc. */
+       void    *devp;                  /* pointer to configured device */
+               void    *fordriver;             /* for private use by the driver */
+       void    *shuthook;              /* shutdown hook handle */
+       struct selinfo  pcmcialink_sel; /* for select users */
+};
+
+/*
+ * One of these is allocated and filled in for each pcmcia bus.
+ * it holds pointers to allow the pcmcia bus to get to the driver
+ * it also has a template entry which is the prototype struct
+ * supplied by the adapter driver, this is used to initialise
+ * the others, before they have the rest of the fields filled in
+ */
+struct pcmciabus_softc {
+       struct device sc_dev;
+       struct pcmcia_link *sc_link[8];
+};
+
+struct pcmcia_conf {
+    int irq_share:1; 
+    int irq_level:1; /* 1 level */
+    int irq_pulse:1; /* 1  pulse */
+    int irq_vend:1;
+    int irq_iock:1;
+    int irq_berr:1;
+    int irq_nmi:1;
+    int iocard:1;
+    u_char iowin;
+    u_char memwin;
+    u_char irq_num;
+    u_char cfgtype;
+#define CFGENTRYID     0x20
+#define CFGENTRYMASK   (CFGENTRYID|(CFGENTRYID-1))
+#define DOSRESET       0x40
+    int cfg_regmask;
+    int irq_mask;
+    int cfg_off;
+    struct iowin {
+       int start;
+       int len;
+       int flags;
+    }io[4];
+    struct memwin {
+       int start; 
+       int caddr;
+       int len;
+       int flags;
+    }mem[4];
+    char driver_name[8][4]; /* up to four different functions on a card */
+    int  unitid;
+    int  cfgid;
+};
+
+struct pcmcia_device {
+    char *name;
+    int (*pcmcia_config) __P((struct pcmcia_link *, struct device *,
+                             struct pcmcia_conf *, struct cfdata *));
+    int (*pcmcia_probe) __P((struct device *, void *,
+                            void *, struct pcmcia_link *));
+    int (*pcmcia_insert) __P((struct pcmcia_link *, struct device *,
+                             struct cfdata *));
+    int        (*pcmcia_remove) __P((struct pcmcia_link *, struct device *));
+};
+
+struct pcmciadevs {
+        char *devname;
+        int flags;              /* 1 show my comparisons during boot(debug) */
+#define PC_SHOWME       0x01
+        char *manufacturer;
+        char *model;
+        char *add_inf1;
+        char *add_inf2;
+        void *param;
+        struct pcmcia_device *dev;
+};
+
+#ifdef _KERNEL
+extern int pcmcia_add_device __P((struct pcmciadevs *));
+extern int pcmcia_get_cf __P((struct pcmcia_link *, u_char *, int, int,
+                             struct pcmcia_conf *));
+extern int pcmcia_targmatch __P((struct device *, struct cfdata *, void *));
+#endif
+
+/* in pcmcia_conf.c, available for user space too: */
+extern int pcmcia_get_cisver1 __P((struct pcmcia_link *, u_char *, int,
+                                  char *, char *, char *, char *));
+int      parse_cfent  __P((u_char *, int, int, struct pcmcia_conf *));
+int      read_cfg_info __P((u_char *, int, struct pcmcia_conf *));
+void   pcmcia_getstr __P((char *buf, u_char **, u_char *));
+
+#endif /* _PCMCIA_PCMCIABUS_H_ */