summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorhvozda <hvozda@cvs.openbsd.org>1996-01-16 20:13:03 +0000
committerhvozda <hvozda@cvs.openbsd.org>1996-01-16 20:13:03 +0000
commit4a5d9e1303da71da06ea2645813f7c002266c89b (patch)
tree470578a3ec97c70b17d6ef8d58020ba6a7eb46df /sys
parent063928ca0f66cdb779c3d891eed893aac5cf55d9 (diff)
Last of the glue and devices for for PCMCIA support from Stefan Grefen
<grefen@convex.com> with modifications by John Kohl <jtk@kolvir.blrc.ma.us>
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/com.c57
-rw-r--r--sys/dev/isa/com.c57
-rw-r--r--sys/dev/isa/files.isa12
-rw-r--r--sys/dev/isa/if_ed.c164
-rw-r--r--sys/dev/isa/if_ep.c140
-rw-r--r--sys/dev/isa/pcmcia_isa.c287
-rw-r--r--sys/dev/isa/pcmcia_pcic.c733
7 files changed, 1440 insertions, 10 deletions
diff --git a/sys/dev/ic/com.c b/sys/dev/ic/com.c
index ad63516f0ff..c0003debb79 100644
--- a/sys/dev/ic/com.c
+++ b/sys/dev/ic/com.c
@@ -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;
}
diff --git a/sys/dev/isa/com.c b/sys/dev/isa/com.c
index ad63516f0ff..c0003debb79 100644
--- a/sys/dev/isa/com.c
+++ b/sys/dev/isa/com.c
@@ -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;
}
diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa
index 99ac2a0ed60..63981d69dea 100644
--- a/sys/dev/isa/files.isa
+++ b/sys/dev/isa/files.isa
@@ -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
diff --git a/sys/dev/isa/if_ed.c b/sys/dev/isa/if_ed.c
index a3617cd6685..06c0142a9ca 100644
--- a/sys/dev/isa/if_ed.c
+++ b/sys/dev/isa/if_ed.c
@@ -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) {
diff --git a/sys/dev/isa/if_ep.c b/sys/dev/isa/if_ep.c
index 50c9a636677..4ee4dcc4135 100644
--- a/sys/dev/isa/if_ep.c
+++ b/sys/dev/isa/if_ep.c
@@ -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
index 00000000000..d2fd46ee66f
--- /dev/null
+++ b/sys/dev/isa/pcmcia_isa.c
@@ -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
index 00000000000..30e4d84707d
--- /dev/null
+++ b/sys/dev/isa/pcmcia_pcic.c
@@ -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;
+ }
+}