diff options
author | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 1998-09-11 10:47:16 +0000 |
---|---|---|
committer | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 1998-09-11 10:47:16 +0000 |
commit | 4cccaf7b6e534b99f6c07b76048acfa90e4d8495 (patch) | |
tree | 9485f874b3237996416ecf4fa4d21e3a5c93c57c /sys/dev/pcmcia | |
parent | 27d7305f5dcc8a0f7154c2543c83537e60e654a9 (diff) |
PCMCIA code ported from NetBSD.
Support for aic, ep, pccom and sm.
Diffstat (limited to 'sys/dev/pcmcia')
-rw-r--r-- | sys/dev/pcmcia/Makefile | 10 | ||||
-rw-r--r-- | sys/dev/pcmcia/Makefile.pcmciadevs | 8 | ||||
-rw-r--r-- | sys/dev/pcmcia/aic_pcmcia.c | 160 | ||||
-rw-r--r-- | sys/dev/pcmcia/com_pcmcia.c | 673 | ||||
-rw-r--r-- | sys/dev/pcmcia/devlist2h.awk | 193 | ||||
-rw-r--r-- | sys/dev/pcmcia/files.pcmcia | 63 | ||||
-rw-r--r-- | sys/dev/pcmcia/if_ep_pcmcia.c | 422 | ||||
-rw-r--r-- | sys/dev/pcmcia/if_sm_pcmcia.c | 357 | ||||
-rw-r--r-- | sys/dev/pcmcia/pcmcia.c | 1780 | ||||
-rw-r--r-- | sys/dev/pcmcia/pcmcia_cis.c | 1196 | ||||
-rw-r--r-- | sys/dev/pcmcia/pcmciachip.h | 145 | ||||
-rw-r--r-- | sys/dev/pcmcia/pcmciadevs | 129 | ||||
-rw-r--r-- | sys/dev/pcmcia/pcmciadevs.h | 206 | ||||
-rw-r--r-- | sys/dev/pcmcia/pcmciadevs_data.h | 443 | ||||
-rw-r--r-- | sys/dev/pcmcia/pcmciareg.h | 365 | ||||
-rw-r--r-- | sys/dev/pcmcia/pcmciavar.h | 479 |
16 files changed, 4645 insertions, 1984 deletions
diff --git a/sys/dev/pcmcia/Makefile b/sys/dev/pcmcia/Makefile new file mode 100644 index 00000000000..27986481a40 --- /dev/null +++ b/sys/dev/pcmcia/Makefile @@ -0,0 +1,10 @@ +# $OpenBSD: Makefile,v 1.1 1998/09/11 10:47:13 fgsch Exp $ +# $NetBSD: Makefile,v 1.2 1998/07/19 17:28:15 christos Exp $ + +# use 'make -f Makefile.pcmciadevs' to make pcmciadevs.h and pcmciadevs_data.h + +INCSDIR= /usr/include/dev/pcmcia + +INCS= pcmciachip.h pcmciareg.h pcmciavar.h + +.include <bsd.kinc.mk> diff --git a/sys/dev/pcmcia/Makefile.pcmciadevs b/sys/dev/pcmcia/Makefile.pcmciadevs new file mode 100644 index 00000000000..6b76864c0c4 --- /dev/null +++ b/sys/dev/pcmcia/Makefile.pcmciadevs @@ -0,0 +1,8 @@ +# $OpenBSD: Makefile.pcmciadevs,v 1.1 1998/09/11 10:47:14 fgsch Exp $ +# $NetBSD: Makefile.pcmciadevs,v 1.1 1998/07/19 17:28:15 christos Exp $ + +AWK= awk + +pcmciadevs.h pcmciadevs_data.h: pcmciadevs devlist2h.awk + /bin/rm -f pcmciadevs.h pcmciadevs_data.h + ${AWK} -f devlist2h.awk pcmciadevs diff --git a/sys/dev/pcmcia/aic_pcmcia.c b/sys/dev/pcmcia/aic_pcmcia.c new file mode 100644 index 00000000000..2831f1d84b1 --- /dev/null +++ b/sys/dev/pcmcia/aic_pcmcia.c @@ -0,0 +1,160 @@ +/* $OpenBSD: aic_pcmcia.c,v 1.1 1998/09/11 10:47:14 fgsch Exp $ */ +/* $NetBSD: aic_pcmcia.c,v 1.6 1998/07/19 17:28:15 christos Exp $ */ + +/* + * Copyright (c) 1997 Marc Horowitz. 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 Marc Horowitz. + * 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/select.h> +#include <sys/device.h> + +#include <machine/cpu.h> +#include <machine/bus.h> +#include <machine/intr.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + +#include <dev/isa/isavar.h> + +#include <dev/ic/aic6360var.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmciadevs.h> + +int aic_pcmcia_match __P((struct device *, void *, void *)); +void aic_pcmcia_attach __P((struct device *, struct device *, void *)); + +struct aic_pcmcia_softc { + struct aic_softc sc_aic; /* real "aic" softc */ + + /* PCMCIA-specific goo. */ + struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ + int sc_io_window; /* our i/o window */ + struct pcmcia_function *sc_pf; /* our PCMCIA function */ + void *sc_ih; /* interrupt handler */ +}; + +struct cfattach aic_pcmcia_ca = { + sizeof(struct aic_pcmcia_softc), aic_pcmcia_match, aic_pcmcia_attach +}; + +int +aic_pcmcia_match(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct pcmcia_attach_args *pa = aux; + + if (pa->manufacturer == PCMCIA_VENDOR_ADAPTEC) { + switch (pa->product) { + case PCMCIA_PRODUCT_ADAPTEC_APA1460_1: + case PCMCIA_PRODUCT_ADAPTEC_APA1460_2: + if (pa->pf->number == 0) + return (1); + } + } + + return (0); +} + +void +aic_pcmcia_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct aic_pcmcia_softc *psc = (void *)self; + struct aic_softc *sc = &psc->sc_aic; + struct pcmcia_attach_args *pa = aux; + struct pcmcia_config_entry *cfe; + struct pcmcia_function *pf = pa->pf; + const char *s; + + psc->sc_pf = pf; + + for (cfe = SIMPLEQ_FIRST(&pf->cfe_head); cfe != NULL; + cfe = SIMPLEQ_NEXT(cfe, cfe_list)) { + if (cfe->num_memspace != 0 || + cfe->num_iospace != 1) + continue; + + if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start, + cfe->iospace[0].length, 0, &psc->sc_pcioh) == 0) + break; + } + + if (cfe == 0) { + printf(": can't alloc i/o space\n"); + return; + } + + sc->sc_iot = psc->sc_pcioh.iot; + sc->sc_ioh = psc->sc_pcioh.ioh; + + /* Enable the card. */ + pcmcia_function_init(pf, cfe); + if (pcmcia_function_enable(pf)) { + printf(": function enable failed\n"); + return; + } + + /* Map in the io space */ + if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0, psc->sc_pcioh.size, + &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return; + } + + if (!aic_find(sc->sc_iot, sc->sc_ioh)) + printf(": coundn't find aic\n%s", sc->sc_dev.dv_xname); + + switch (pa->product) { + case PCMCIA_PRODUCT_ADAPTEC_APA1460_1: + s = PCMCIA_STR_ADAPTEC_APA1460_1; + break; + case PCMCIA_PRODUCT_ADAPTEC_APA1460_2: + s = PCMCIA_STR_ADAPTEC_APA1460_2; + break; + default: + s = "Unknown APA1460"; + break; + } + + printf(": %s\n", s); + + aicattach(sc); + + /* Establish the interrupt handler. */ + psc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_BIO, aicintr, sc); + if (psc->sc_ih == NULL) + printf("%s: couldn't establish interrupt\n", + sc->sc_dev.dv_xname); +} diff --git a/sys/dev/pcmcia/com_pcmcia.c b/sys/dev/pcmcia/com_pcmcia.c index cbbe287caa6..02576518c8d 100644 --- a/sys/dev/pcmcia/com_pcmcia.c +++ b/sys/dev/pcmcia/com_pcmcia.c @@ -1,9 +1,43 @@ -/* $OpenBSD: com_pcmcia.c,v 1.3 1998/03/05 14:39:38 niklas Exp $ */ -/* $NetBSD: com.c,v 1.82.4.1 1996/06/02 09:08:00 mrg Exp $ */ +/* $OpenBSD: com_pcmcia.c,v 1.4 1998/09/11 10:47:14 fgsch Exp $ */ +/* $NetBSD: com_pcmcia.c,v 1.15 1998/08/22 17:47:58 msaitoh Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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. + */ /*- - * Copyright (c) 1993, 1994, 1995, 1996 - * Charles M. Hannum. All rights reserved. * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * @@ -34,334 +68,451 @@ * 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. + * + * @(#)com.c 7.5 (Berkeley) 5/16/91 */ #include <sys/param.h> #include <sys/systm.h> -#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/select.h> #include <sys/tty.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/types.h> +#include <sys/device.h> -#include <machine/bus.h> #include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciadevs.h> #include <dev/isa/isavar.h> #include <dev/ic/comreg.h> +#ifdef i386 +#include <i386/isa/pccomvar.h> +#else #include <dev/ic/comvar.h> +#endif #include <dev/ic/ns16550reg.h> -#include <dev/pcmcia/pcmciavar.h> +#include <dev/isa/isareg.h> -/* Macros to clear/set/test flags. */ +#define com_lcr com_cfcr #define SET(t, f) (t) |= (f) -#define CLR(t, f) (t) &= ~(f) -#define ISSET(t, f) ((t) & (f)) -int com_pcmcia_match __P((struct device *, void *, void *)); -void com_pcmcia_attach __P((struct device *, struct device *, void *)); -int com_pcmcia_detach __P((struct device *)); +struct com_dev { + char *name; + char *cis1_info[4]; +}; + +/* Devices that we need to match by CIS strings */ +static struct com_dev com_devs[] = { + { PCMCIA_STR_MEGAHERTZ_XJ2288, + PCMCIA_CIS_MEGAHERTZ_XJ2288 }, +}; + + +static int com_devs_size = sizeof(com_devs) / sizeof(com_devs[0]); +static struct com_dev *com_dev_match __P((struct pcmcia_card *)); + +int com_pcmcia_match __P((struct device *, void *, void *)); +void com_pcmcia_attach __P((struct device *, struct device *, void *)); +void com_pcmcia_cleanup __P((void *)); -int com_pcmcia_mod __P((struct pcmcia_link *pc_link, struct device *self, - struct pcmcia_conf *pc_cf, struct cfdata *cf)); -int com_pcmcia_isa_attach __P((struct device *, void *, void *, - struct pcmcia_link *)); -int com_pcmcia_remove __P((struct pcmcia_link *, struct device *)); -int com_pcmcia_probe __P((struct device *, void *, void *)); +int com_pcmcia_enable __P((struct com_softc *)); +void com_pcmcia_disable __P((struct com_softc *)); +int com_pcmcia_enable1 __P((struct com_softc *)); +void com_pcmcia_disable1 __P((struct com_softc *)); + +void com_attach __P((struct com_softc *)); + +struct com_pcmcia_softc { + struct com_softc sc_com; /* real "com" softc */ + + /* PCMCIA-specific goo */ + struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ + int sc_io_window; /* our i/o window */ + struct pcmcia_function *sc_pf; /* our PCMCIA function */ + void *sc_ih; /* interrupt handler */ +}; struct cfattach com_pcmcia_ca = { - sizeof(struct com_softc), com_pcmcia_match, com_pcmcia_attach, - com_pcmcia_detach + sizeof(struct com_pcmcia_softc), com_pcmcia_match, com_pcmcia_attach }; -/* additional setup needed for pcmcia devices */ -/* modify config entry */ -int -com_pcmcia_mod(pc_link, self, pc_cf, cf) - struct pcmcia_link *pc_link; - struct device *self; - struct pcmcia_conf *pc_cf; - struct cfdata *cf; -{ - int err; - - if (!(err = PCMCIA_BUS_CONFIG(pc_link->adapter, pc_link, self, - pc_cf, cf))) { - pc_cf->memwin = 0; - if (pc_cf->cfgtype == 0) - pc_cf->cfgtype = CFGENTRYID; /* determine from ioaddr */ +/* Look for pcmcia cards with particular CIS strings */ +static struct com_dev * +com_dev_match(card) + struct pcmcia_card *card; +{ + int i, j; + + for (i = 0; i < com_devs_size; i++) { + for (j = 0; j < 4; j++) + if (com_devs[i].cis1_info[j] && + strcmp(com_devs[i].cis1_info[j], + card->cis1_info[j])) + break; + if (j == 4) + return &com_devs[i]; } - return err; + + return NULL; } -static struct pcmcia_com { - struct pcmcia_device pcd; -} pcmcia_com = { - {"PCMCIA Modem card", com_pcmcia_mod, com_pcmcia_isa_attach, - NULL, com_pcmcia_remove} -}; - - -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} -}; -#define ncom_pcmcia_devs sizeof(pcmcia_com_devs)/sizeof(pcmcia_com_devs[0]) int com_pcmcia_match(parent, match, aux) struct device *parent; void *match, *aux; { - return pcmcia_slave_match(parent, match, aux, pcmcia_com_devs, - ncom_pcmcia_devs); + int comportmask; + struct pcmcia_attach_args *pa = aux; + struct pcmcia_config_entry *cfe; + + /* 1. Does it claim to be a serial device? */ + if (pa->pf->function == PCMCIA_FUNCTION_SERIAL) + return 1; + + /* 2. Does it have all four 'standard' port ranges? */ + comportmask = 0; + for (cfe = pa->pf->cfe_head.sqh_first; cfe; + cfe = cfe->cfe_list.sqe_next) { + switch (cfe->iospace[0].start) { + case IO_COM1: + comportmask |= 1; + break; + case IO_COM2: + comportmask |= 2; + break; + case IO_COM3: + comportmask |= 4; + break; + case IO_COM4: + comportmask |= 8; + break; + } + } + + if (comportmask == 15) + return 1; + + /* 3. Is this a card we know about? */ + if (com_dev_match(pa->card) != NULL) + return 1; + + return 0; } -int -com_pcmcia_isa_attach(parent, match, aux, pc_link) - struct device *parent; - void *match; +void +com_pcmcia_attach(parent, self, aux) + struct device *parent, *self; void *aux; - struct pcmcia_link *pc_link; { - struct isa_attach_args *ia = aux; - struct com_softc *sc = match; - int rval; - - if ((rval = com_pcmcia_probe(parent, sc->sc_dev.dv_cfdata, ia))) { - if (ISSET(pc_link->flags, PCMCIA_REATTACH)) { -#ifdef COM_DEBUG - printf("comreattach, hwflags=%x\n", sc->sc_hwflags); + struct com_pcmcia_softc *psc = (void *) self; + struct com_softc *sc = &psc->sc_com; + struct pcmcia_attach_args *pa = aux; + struct pcmcia_config_entry *cfe; + int autoalloc = 0; + + psc->sc_pf = pa->pf; + +retry: + /* find a cfe we can use */ + + for (cfe = pa->pf->cfe_head.sqh_first; cfe; + cfe = cfe->cfe_list.sqe_next) { +#if 0 + /* + * Some modem cards (e.g. Xircom CM33) also have + * mem space. Don't bother with this check. + */ + if (cfe->num_memspace != 0) + continue; #endif - sc->sc_hwflags = COM_HW_REATTACH | (sc->sc_hwflags & - (COM_HW_ABSENT_PENDING|COM_HW_CONSOLE)); - } else - sc->sc_hwflags = 0; - sc->sc_ic = ia->ia_ic; + + if (cfe->num_iospace != 1) + continue; + + if (autoalloc == 1) { + if (cfe->iomask == 3) { + if (!pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length, + cfe->iospace[0].length, + &psc->sc_pcioh)) { + goto found; + } + } + } else { + if (!pcmcia_io_alloc(pa->pf, cfe->iospace[0].start, + cfe->iospace[0].length, 0, &psc->sc_pcioh)) { + goto found; + } + } + } + if (autoalloc == 0) { + autoalloc = 1; + goto retry; + } else if (!cfe) { + printf(": can't allocate i/o space\n"); + return; } - return rval; -} +found: + sc->sc_iot = psc->sc_pcioh.iot; + sc->sc_ioh = psc->sc_pcioh.ioh; -/* - * Called by config_detach attempts, shortly after com_pcmcia_remove - * was called. - */ -int -com_pcmcia_detach(self) - struct device *self; -{ - struct com_softc *sc = (void *)self; + /* Enable the card. */ + pcmcia_function_init(pa->pf, cfe); + if (com_pcmcia_enable1(sc)) + printf(": function enable failed\n"); + +#ifdef notyet + sc->enabled = 1; +#endif - if (ISSET(sc->sc_hwflags, COM_HW_ABSENT_PENDING)) { - /* don't let it really be detached, it is still open */ - return EBUSY; + /* map in the io space */ + + if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? + PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, psc->sc_pcioh.size, + &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return; } - return 0; /* OK! */ + + sc->sc_iobase = -1; +#ifdef notyet + sc->sc_frequency = COM_FREQ; + + sc->enable = com_pcmcia_enable; + sc->disable = com_pcmcia_disable; +#endif + + printf(": serial device"); + +#ifdef notyet + com_attach_subr(sc); +#endif + com_attach(sc); + + /* establish the interrupt. */ + psc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_TTY, comintr, sc); + if (psc->sc_ih == NULL) + printf("%s: couldn't establish interrupt\n", + sc->sc_dev.dv_xname); + +#ifdef notyet + sc->enabled = 0; + + com_pcmcia_disable1(sc); +#endif } -/* - * called by pcmcia framework to accept/reject remove attempts. - * If we return 0, then the detach will proceed. - */ int -com_pcmcia_remove(pc_link, self) - struct pcmcia_link *pc_link; - struct device *self; +com_pcmcia_enable(sc) + struct com_softc *sc; { - struct com_softc *sc = (void *)self; - struct tty *tp; - int s; - - if (!sc->sc_tty) - goto ok; - tp = sc->sc_tty; - - /* not in use ? if so, return "OK" */ - if (!ISSET(tp->t_state, TS_ISOPEN) && - !ISSET(tp->t_state, TS_WOPEN)) { - ttyfree(sc->sc_tty); - sc->sc_tty = NULL; - ok: - isa_intr_disestablish(sc->sc_ic, sc->sc_ih); - sc->sc_ih = NULL; - SET(sc->sc_hwflags, COM_HW_ABSENT); - return 0; /* OK! */ + struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; + struct pcmcia_function *pf = psc->sc_pf; + + /* establish the interrupt. */ + psc->sc_ih = pcmcia_intr_establish(pf, IPL_TTY, comintr, sc); + if (psc->sc_ih == NULL) { + printf("%s: couldn't establish interrupt\n", + sc->sc_dev.dv_xname); + return (1); } - /* - * Not easily removed. Put device into a dead state, clean state - * as best we can. notify all waiters. - */ - SET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING); -#ifdef COM_DEBUG - printf("pending detach flags %x\n", sc->sc_hwflags); -#endif + return com_pcmcia_enable1(sc); +} - s = spltty(); - com_absent_notify(sc); - splx(s); +int +com_pcmcia_enable1(sc) + struct com_softc *sc; +{ + struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; + struct pcmcia_function *pf = psc->sc_pf; + int ret; - return 0; + if ((ret = pcmcia_function_enable(pf))) + return(ret); + + if (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) { + int reg; + + /* turn off the ethernet-disable bit */ + + reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); + if (reg & 0x08) { + reg &= ~0x08; + pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); + } + } + + return(ret); } -#if 0 void -com_pcmcia_attach(parent, self, aux) - struct device *parent, *self; - void *aux; +com_pcmcia_disable(sc) + struct com_softc *sc; { - struct pcmcia_attach_args *paa = aux; - - printf("com_pcmcia_attach %p %p %p\n", parent, self, aux); - delay(2000000); - if (!pcmcia_configure(parent, self, paa->paa_link)) { - struct com_softc *sc = (void *)self; - sc->sc_hwflags |= COM_HW_ABSENT; - printf(": not attached\n"); - } + struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; + + com_pcmcia_disable1(sc); + pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); } -#endif -int -com_pcmcia_probe(parent, match, aux) - struct device *parent; - void *match, *aux; +void +com_pcmcia_disable1(sc) + struct com_softc *sc; { - bus_space_tag_t iot; - bus_space_handle_t ioh; - int iobase, needioh; - int rv = 1; - struct isa_attach_args *ia = aux; - - iot = ia->ia_iot; - iobase = ia->ia_iobase; - needioh = 1; - - /* if it's in use as console, it's there. */ - if (iobase == comconsaddr && !comconsattached) - goto out; - - if (needioh && bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) { - rv = 0; - goto out; - } - rv = comprobe1(iot, ioh); - if (needioh) - bus_space_unmap(iot, ioh, COM_NPORTS); - -out: - ia->ia_iosize = COM_NPORTS; - ia->ia_msize = 0; - return (rv); + struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; + + pcmcia_function_disable(psc->sc_pf); } +/* + * XXX This should be handled by a generic attach + */ void -com_pcmcia_attach(parent, self, aux) - struct device *parent, *self; - void *aux; +com_attach(sc) + struct com_softc *sc; { - struct com_softc *sc = (void *)self; - int iobase, irq; - bus_space_tag_t iot; - bus_space_handle_t ioh; - struct isa_attach_args *ia = aux; - - if (ISSET(sc->sc_hwflags, COM_HW_REATTACH)) { - int s; - s = spltty(); - com_absent_notify(sc); - splx(s); - } else - sc->sc_hwflags = 0; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + u_int8_t lcr; + + sc->sc_hwflags = 0; sc->sc_swflags = 0; /* - * We're living on an isa. + * Probe for all known forms of UART. */ - iobase = ia->ia_iobase; - iot = ia->ia_iot; - if (iobase != comconsaddr) { - if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) - panic("comattach: io mapping failed"); - } else - ioh = comconsioh; - irq = ia->ia_irq; - - sc->sc_iot = iot; - sc->sc_ioh = ioh; - sc->sc_iobase = iobase; - - if (iobase == comconsaddr) { - comconsattached = 1; - - /* - * Need to reset baud rate, etc. of next print so reset - * comconsinit. Also make sure console is always "hardwired". - */ - delay(1000); /* wait for output to finish */ - comconsinit = 0; - SET(sc->sc_hwflags, COM_HW_CONSOLE); - SET(sc->sc_swflags, COM_SW_SOFTCAR); - } + lcr = bus_space_read_1(iot, ioh, com_lcr); - /* look for a NS 16550AF UART with FIFOs */ - bus_space_write_1(iot, ioh, com_fifo, - FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); - delay(100); - if (ISSET(bus_space_read_1(iot, ioh, com_iir), IIR_FIFO_MASK) == - IIR_FIFO_MASK) { - if (ISSET(bus_space_read_1(iot, ioh, com_fifo), - FIFO_TRIGGER_14) == FIFO_TRIGGER_14) { - SET(sc->sc_hwflags, COM_HW_FIFO); - printf(": ns16550a, working fifo\n"); - } else - printf(": ns16550, broken fifo\n"); - } else - printf(": ns8250 or ns16450, no fifo\n"); - bus_space_write_1(iot, ioh, com_fifo, 0); + bus_space_write_1(iot, ioh, com_lcr, LCR_EFR); + bus_space_write_1(iot, ioh, com_efr, 0); + bus_space_write_1(iot, ioh, com_lcr, 0); - /* disable interrupts */ - bus_space_write_1(iot, ioh, com_ier, 0); - bus_space_write_1(iot, ioh, com_mcr, 0); + bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE); + delay(100); - if (irq != IRQUNK) { - struct isa_attach_args *ia = aux; + switch(bus_space_read_1(iot, ioh, com_iir) >> 6) { + case 0: + sc->sc_uarttype = COM_UART_16450; + break; + case 2: + sc->sc_uarttype = COM_UART_16550; + break; + case 3: + sc->sc_uarttype = COM_UART_16550A; + break; + default: + sc->sc_uarttype = COM_UART_UNKNOWN; + break; + } - sc->sc_ih = isa_intr_establish(ia->ia_ic, irq, - IST_EDGE, IPL_TTY, comintr, sc, sc->sc_dev.dv_xname); + if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for ST16650s */ + bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB); + if (bus_space_read_1(iot, ioh, com_efr) == 0) { + sc->sc_uarttype = COM_UART_ST16650; + } else { + bus_space_write_1(iot, ioh, com_lcr, LCR_EFR); + if (bus_space_read_1(iot, ioh, com_efr) == 0) + sc->sc_uarttype = COM_UART_ST16650V2; + } } -#ifdef KGDB - if (kgdb_dev == makedev(commajor, unit)) { - if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) - kgdb_dev = -1; /* can't debug over console port */ - else { - cominit(iot, ioh, kgdb_rate); - if (kgdb_debug_init) { - /* - * Print prefix of device name, - * let kgdb_connect print the rest. - */ - printf("%s: ", sc->sc_dev.dv_xname); - kgdb_connect(1); - } else - printf("%s: kgdb enabled\n", - sc->sc_dev.dv_xname); +#ifdef i386 + if (sc->sc_uarttype == COM_UART_ST16650V2) { /* Probe for XR16850s */ + u_int8_t dlbl, dlbh; + + /* Enable latch access and get the current values. */ + bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB); + dlbl = bus_space_read_1(iot, ioh, com_dlbl); + dlbh = bus_space_read_1(iot, ioh, com_dlbh); + + /* Zero out the latch divisors */ + bus_space_write_1(iot, ioh, com_dlbl, 0); + bus_space_write_1(iot, ioh, com_dlbh, 0); + + if (bus_space_read_1(iot, ioh, com_dlbh) == 0x10) { + sc->sc_uarttype = COM_UART_XR16850; + sc->sc_uartrev = bus_space_read_1(iot, ioh, com_dlbl); } + + /* Reset to original. */ + bus_space_write_1(iot, ioh, com_dlbl, dlbl); + bus_space_write_1(iot, ioh, com_dlbh, dlbh); } #endif + + /* Reset the LCR (latch access is probably enabled). */ + bus_space_write_1(iot, ioh, com_lcr, lcr); + if (sc->sc_uarttype == COM_UART_16450) { /* Probe for 8250 */ + u_int8_t scr0, scr1, scr2; + + scr0 = bus_space_read_1(iot, ioh, com_scratch); + bus_space_write_1(iot, ioh, com_scratch, 0xa5); + scr1 = bus_space_read_1(iot, ioh, com_scratch); + bus_space_write_1(iot, ioh, com_scratch, 0x5a); + scr2 = bus_space_read_1(iot, ioh, com_scratch); + bus_space_write_1(iot, ioh, com_scratch, scr0); + + if ((scr1 != 0xa5) || (scr2 != 0x5a)) + sc->sc_uarttype = COM_UART_8250; + } - /* XXX maybe move up some? */ - if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) - printf("%s: console\n", sc->sc_dev.dv_xname); + /* + * Print UART type and initialize ourself. + */ + sc->sc_fifolen = 1; /* default */ + switch (sc->sc_uarttype) { + case COM_UART_UNKNOWN: + printf(": unknown uart\n"); + break; + case COM_UART_8250: + printf(": ns8250, no fifo\n"); + break; + case COM_UART_16450: + printf(": ns16450, no fifo\n"); + break; + case COM_UART_16550: + printf(": ns16550, no working fifo\n"); + break; + case COM_UART_16550A: + printf(": ns16550a, 16 byte fifo\n"); + SET(sc->sc_hwflags, COM_HW_FIFO); + sc->sc_fifolen = 16; + break; + case COM_UART_ST16650: + printf(": st16650, no working fifo\n"); + break; + case COM_UART_ST16650V2: + printf(": st16650, 32 byte fifo\n"); + SET(sc->sc_hwflags, COM_HW_FIFO); + sc->sc_fifolen = 32; + break; +#ifdef i386 + case COM_UART_XR16850: + printf(": xr16850 (rev %d), 128 byte fifo\n", sc->sc_uartrev); + SET(sc->sc_hwflags, COM_HW_FIFO); + sc->sc_fifolen = 128; + break; +#endif + default: + panic("comattach: bad fifo type\n"); + } + + /* clear and disable fifo */ + bus_space_write_1(iot, ioh, com_fifo, FIFO_RCV_RST | FIFO_XMT_RST); + (void)bus_space_read_1(iot, ioh, com_data); + bus_space_write_1(iot, ioh, com_fifo, 0); } diff --git a/sys/dev/pcmcia/devlist2h.awk b/sys/dev/pcmcia/devlist2h.awk new file mode 100644 index 00000000000..c077fce7736 --- /dev/null +++ b/sys/dev/pcmcia/devlist2h.awk @@ -0,0 +1,193 @@ +#! /usr/bin/awk -f +# $OpenBSD: devlist2h.awk,v 1.1 1998/09/11 10:47:14 fgsch Exp $ +# $NetBSD: devlist2h.awk,v 1.2 1998/07/22 11:47:13 christos Exp $ +# +# Copyright (c) 1998, Christos Zoulas +# Copyright (c) 1995, 1996 Christopher G. Demetriou +# 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 Christopher G. Demetriou. +# This product includes software developed by Christos Zoulas +# 4. The name of the author(s) 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. +# +function collectline(f, line) { + oparen = 0 + line = "" + while (f <= NF) { + if ($f == "#") { + line = line "(" + oparen = 1 + f++ + continue + } + if (oparen) { + line = line $f + if (f < NF) + line = line " " + f++ + continue + } + line = line $f + if (f < NF) + line = line " " + f++ + } + if (oparen) + line = line ")" + return line +} +BEGIN { + nproducts = nvendors = 0 + dfile="pcmciadevs_data.h" + hfile="pcmciadevs.h" +} +NR == 1 { + VERSION = $0 + gsub("\\$", "", VERSION) + + printf("/*\t\$OpenBSD\$\t*/\n\n") > dfile + printf("/*\n") > dfile + printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \ + > dfile + printf(" *\n") > dfile + printf(" * generated from:\n") > dfile + printf(" *\t%s\n", VERSION) > dfile + printf(" */\n") > dfile + + printf("/*\t\$OpenBSD\$\t*/\n\n") > hfile + printf("/*\n") > hfile + printf(" * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.\n") \ + > hfile + printf(" *\n") > hfile + printf(" * generated from:\n") > hfile + printf(" *\t%s\n", VERSION) > hfile + printf(" */\n") > hfile + + next +} +$1 == "vendor" { + nvendors++ + + vendorindex[$2] = nvendors; # record index for this name, for later. + vendors[nvendors, 1] = $2; # name + vendors[nvendors, 2] = $3; # id + printf("#define\tPCMCIA_VENDOR_%s\t%s\t", vendors[nvendors, 1], + vendors[nvendors, 2]) > hfile + vendors[nvendors, 3] = collectline(4, line) + printf("/* %s */\n", vendors[nvendors, 3]) > hfile + next +} +$1 == "product" { + nproducts++ + + products[nproducts, 1] = $2; # vendor name + products[nproducts, 2] = $3; # product id + products[nproducts, 3] = $4; # id + + f = 5; + + if ($4 == "{") { + products[nproducts, 3] = -1 + z = "{ " + for (i = 0; i < 4; i++) { + if (f <= NF) { + gsub("&sp", " ", $f) + gsub("&tab", "\t", $f) + gsub("&nl", "\n", $f) + z = z $f " " + f++ + } + else { + if (i == 3) + z = z "NULL " + else + z = z "NULL, " + } + } + products[nproducts, 4] = z $f + f++ + } + else { + products[nproducts, 4] = "{ NULL, NULL, NULL, NULL }" + } + printf("#define\tPCMCIA_CIS_%s_%s\t%s\n", + products[nproducts, 1], products[nproducts, 2], + products[nproducts, 4]) > hfile + printf("#define\tPCMCIA_PRODUCT_%s_%s\t%s\n", products[nproducts, 1], + products[nproducts, 2], products[nproducts, 3]) > hfile + + products[nproducts, 5] = collectline(f, line) + + printf("#define\tPCMCIA_STR_%s_%s\t\"%s\"\n", + products[nproducts, 1], products[nproducts, 2], + products[nproducts, 5]) > hfile + + next +} +{ + if ($0 == "") + blanklines++ + print $0 > hfile + if (blanklines < 2) + print $0 > dfile +} +END { + # print out the match tables + + printf("\n") > dfile + + printf("struct pcmcia_knowndev pcmcia_knowndevs[] = {\n") > dfile + for (i = 1; i <= nproducts; i++) { + printf("\t{\n") > dfile + if (products[i, 3] == -1) { + printf("\t PCMCIA_VENDOR_UNKNOWN, PCMCIA_PRODUCT_%s_%s,\n", + products[i, 1], products[i, 2]) > dfile + } else { + printf("\t PCMCIA_VENDOR_%s, PCMCIA_PRODUCT_%s_%s,\n", + products[i, 1], products[i, 1], products[i, 2]) > dfile + } + printf("\t PCMCIA_CIS_%s_%s,\n", + products[i, 1], products[i, 2]) > dfile + printf("\t ") > dfile + printf("0") > dfile + printf(",\n") > dfile + + vendi = vendorindex[products[i, 1]]; + printf("\t \"%s\",\n", vendors[vendi, 3]) > dfile + printf("\t \"%s\"\t},\n", products[i, 5]) > dfile + printf("\t},\n") > dfile + } + for (i = 1; i <= nvendors; i++) { + printf("\t{\n") > dfile + printf("\t PCMCIA_VENDOR_%s, 0,\n", vendors[i, 1]) > dfile + printf("\t PCMCIA_KNOWNDEV_NOPROD,\n") > dfile + printf("\t PCMCIA_CIS_INVALID,\n") > dfile + printf("\t \"%s\",\n", vendors[i, 3]) > dfile + printf("\t NULL,\n") > dfile + printf("\t},\n") > dfile + } + printf("\t{ 0, 0, { NULL, NULL, NULL, NULL }, 0, NULL, NULL, }\n") > dfile + printf("};\n") > dfile +} diff --git a/sys/dev/pcmcia/files.pcmcia b/sys/dev/pcmcia/files.pcmcia index 63ea15a0192..b4fdf62187d 100644 --- a/sys/dev/pcmcia/files.pcmcia +++ b/sys/dev/pcmcia/files.pcmcia @@ -1,33 +1,50 @@ -# $OpenBSD: files.pcmcia,v 1.8 1997/08/20 17:09:10 angelos Exp $ -# $Id: files.pcmcia,v 1.8 1997/08/20 17:09:10 angelos Exp $ +# $OpenBSD: files.pcmcia,v 1.9 1998/09/11 10:47:14 fgsch Exp $ +# $NetBSD: files.pcmcia,v 1.9 1998/06/21 18:45:41 christos Exp $ # # Config.new file and device description for machine-independent PCMCIA code. # Included by ports that need it. -# XXX Does this comment hold? -# ports should define their own "device pcmcia" line (like the one below, -# but with the correct bus attachment). +device pcmcia {[function = -1], [irq = -1]} +file dev/pcmcia/pcmcia.c pcmcia +file dev/pcmcia/pcmcia_cis.c pcmcia -# -# needs all the parameters available on isa, so devices can attach here. -# +# device declaration in sys/conf/files +attach pcmcia at pcic -device pcmcia {[port = -1], [size = 0], - [iomem = -1], [iosiz = 0], - [irq = -1], [drq = -1], [slot = -1]} -attach pcmcia at pcmciabus +# 3Com 3c589 Ethernet and 3c562 multifunction Ethernet controllers +# device declaration in sys/conf/files +attach ep at pcmcia with ep_pcmcia +file dev/pcmcia/if_ep_pcmcia.c ep_pcmcia -file dev/pcmcia/pcmcia.c pcmcia needs-flag -file dev/pcmcia/pcmcia_conf.c pcmcia +# National Semiconductor DS8390/WD83C690-based boards +# (NE[12]000, and clones) +#attach ne at pcmcia with ne_pcmcia +#file dev/pcmcia/if_ne_pcmcia.c ne_pcmcia -# 8250/16[45]50-based "com" ports -attach com at pcmcia with com_pcmcia -file dev/pcmcia/com_pcmcia.c com_pcmcia +# Adaptec APA-1460 SCSI Host Adapter +attach aic at pcmcia with aic_pcmcia +file dev/pcmcia/aic_pcmcia.c aic_pcmcia -# 3Com 3c589 Ethernet controllers -# device declaration in sys/conf/files -attach ep at pcmcia with ep_pcmcia -file dev/pcmcia/if_ep_pcmcia.c ep_pcmcia +attach pccom at pcmcia with com_pcmcia +file dev/pcmcia/com_pcmcia.c com_pcmcia + +# Digital RoamAbout / Lucent WaveLAN PCMCIA card +#device wl: arp, ether, ifnet +#attach wl at pcmcia with wl_pcmcia +#file dev/pcmcia/if_wl_pcmcia.c wl_pcmcia + +# PCMCIA IDE controller +#attach wdc at pcmcia with wdc_pcmcia +#file dev/pcmcia/wdc_pcmcia.c wdc_pcmcia + +# SMC91Cxx Ethernet Controllers (i.e. Megahertz X-Jack) +attach sm at pcmcia with sm_pcmcia +file dev/pcmcia/if_sm_pcmcia.c sm_pcmcia + +# MB8696x Ethernet Controllers (i.e. TDK LAK CD021BX) +#attach mbe at pcmcia with mbe_pcmcia +#file dev/pcmcia/if_mbe_pcmcia.c mbe_pcmcia -#attach wlp at pcmcia with wlp_pcmcia -#file dev/pcmcia/if_wlp_pcmcia.c wlp_pcmcia +# PCMCIA Floppy controller +#attach fdc at pcmcia with fdc_pcmcia +#file dev/pcmcia/fdc_pcmcia.c fdc_pcmcia diff --git a/sys/dev/pcmcia/if_ep_pcmcia.c b/sys/dev/pcmcia/if_ep_pcmcia.c index aeaa0937ad3..2f43037a872 100644 --- a/sys/dev/pcmcia/if_ep_pcmcia.c +++ b/sys/dev/pcmcia/if_ep_pcmcia.c @@ -1,9 +1,14 @@ -/* $OpenBSD: if_ep_pcmcia.c,v 1.8 1998/03/17 00:00:57 deraadt Exp $ */ +/* $OpenBSD: if_ep_pcmcia.c,v 1.9 1998/09/11 10:47:14 fgsch Exp $ */ +/* $NetBSD: if_ep_pcmcia.c,v 1.16 1998/08/17 23:20:40 thorpej Exp $ */ -/* - * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca> +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -14,8 +19,40 @@ * 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 Herb Peyerl. - * 4. The name of Herb Peyerl may not be used to endorse or promote products + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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. + */ + +/* + * Copyright (c) 1997 Marc Horowitz. 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 Marc Horowitz. + * 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 @@ -33,6 +70,7 @@ #include "bpfilter.h" #include <sys/param.h> +#include <sys/systm.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/ioctl.h> @@ -40,10 +78,8 @@ #include <sys/syslog.h> #include <sys/select.h> #include <sys/device.h> -#include <sys/systm.h> #include <net/if.h> -#include <net/netisr.h> #include <net/if_dl.h> #include <net/if_types.h> #include <net/netisr.h> @@ -56,6 +92,11 @@ #include <netinet/if_ether.h> #endif +#ifdef NS +#include <netns/ns.h> +#include <netns/ns_if.h> +#endif + #if NBPFILTER > 0 #include <net/bpf.h> #include <net/bpfdesc.h> @@ -63,164 +104,289 @@ #include <machine/cpu.h> #include <machine/bus.h> +#include <machine/intr.h> #include <dev/ic/elink3var.h> #include <dev/ic/elink3reg.h> -#include <dev/isa/isavar.h> /*XXX*/ +#include <dev/pcmcia/pcmciareg.h> #include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmciadevs.h> + +int ep_pcmcia_match __P((struct device *, void *, void *)); +void ep_pcmcia_attach __P((struct device *, struct device *, void *)); -int ep_pcmcia_match __P((struct device *, void *, void *)); -void ep_pcmcia_attach __P((struct device *, struct device *, void *)); -int ep_pcmcia_detach __P((struct device *)); +int ep_pcmcia_get_enaddr __P((struct pcmcia_tuple *, void *)); +int ep_pcmcia_enable __P((struct ep_softc *)); +void ep_pcmcia_disable __P((struct ep_softc *)); -int ep_pcmcia_isasetup __P((struct device *, void *, void *, - struct pcmcia_link *)); -int epmod __P((struct pcmcia_link *, struct device *, struct pcmcia_conf *, - struct cfdata *)); -int ep_remove __P((struct pcmcia_link *, struct device *)); +int ep_pcmcia_enable1 __P((struct ep_softc *)); +void ep_pcmcia_disable1 __P((struct ep_softc *)); + +struct ep_pcmcia_softc { + struct ep_softc sc_ep; /* real "ep" softc */ + + /* PCMCIA-specific goo */ + struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ + int sc_io_window; /* our i/o window */ + struct pcmcia_function *sc_pf; /* our PCMCIA function */ +}; struct cfattach ep_pcmcia_ca = { - sizeof(struct ep_softc), ep_pcmcia_match, ep_pcmcia_attach, - ep_pcmcia_detach + sizeof(struct ep_pcmcia_softc), ep_pcmcia_match, ep_pcmcia_attach +}; + +struct ep_pcmcia_product { + u_int32_t epp_product; /* PCMCIA product ID */ + u_short epp_chipset; /* 3Com chipset used */ + int epp_flags; /* initial softc flags */ + int epp_expfunc; /* expected function */ + const char *epp_name; /* device name */ +} ep_pcmcia_products[] = { + { PCMCIA_PRODUCT_3COM_3C562, EP_CHIPSET_3C509, + 0, 0, + PCMCIA_STR_3COM_3C562 }, + { PCMCIA_PRODUCT_3COM_3C589, EP_CHIPSET_3C509, + 0, 0, + PCMCIA_STR_3COM_3C589 }, + + { PCMCIA_PRODUCT_3COM_3C574, EP_CHIPSET_BOOMERANG, + EP_FLAGS_MII, 0, + PCMCIA_STR_3COM_3C574 }, + + { 0, 0, + 0, 0, + NULL }, }; -/* additional setup needed for pcmcia devices */ +struct ep_pcmcia_product *ep_pcmcia_lookup __P((struct pcmcia_attach_args *)); + +struct ep_pcmcia_product * +ep_pcmcia_lookup(pa) + struct pcmcia_attach_args *pa; +{ + struct ep_pcmcia_product *epp; + + for (epp = ep_pcmcia_products; epp->epp_name != NULL; epp++) + if (pa->product == epp->epp_product && + pa->pf->number == epp->epp_expfunc) + return (epp); + + return (NULL); +} + int -ep_pcmcia_isasetup(parent, match, aux, pc_link) - struct device *parent; - void *match; - void *aux; - struct pcmcia_link *pc_link; +ep_pcmcia_match(parent, match, aux) + struct device *parent; + void *match, *aux; { - struct ep_softc *sc = (void *) match; - struct isa_attach_args *ia = aux; - struct ifnet *ifp = &sc->sc_arpcom.ac_if; - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh = sc->sc_ioh; - extern int ifqmaxlen; - - bus_space_write_2(iot, ioh, EP_COMMAND, WINDOW_SELECT | 0); - bus_space_write_2(iot, ioh, EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); - bus_space_write_2(iot, ioh, EP_W0_RESOURCE_CFG, 0x3f00); - - /* - * ok til here. Now try to figure out which link we have. - * try coax first... - */ -#ifdef EP_COAX_DEFAULT - bus_space_write_2(iot, ioh, EP_W0_ADDRESS_CFG, 0xC000); -#else - /* COAX as default is reported to be a problem */ - bus_space_write_2(iot, ioh, EP_W0_ADDRESS_CFG, 0x0000); -#endif - ifp->if_snd.ifq_maxlen = ifqmaxlen; + struct pcmcia_attach_args *pa = aux; + + if (pa->manufacturer != PCMCIA_VENDOR_3COM) + return (0); - ia->ia_iosize = 0x10; - ia->ia_msize = 0; + if (ep_pcmcia_lookup(pa) != NULL) + return (1); - sc->bustype = EP_BUS_PCMCIA; - sc->pcmcia_flags = (pc_link->flags & PCMCIA_REATTACH) ? EP_REATTACH:0; - return 1; + return (0); } -/* modify config entry */ int -epmod(pc_link, self, pc_cf, cf) - struct pcmcia_link *pc_link; - struct device *self; - struct pcmcia_conf *pc_cf; - struct cfdata *cf; +ep_pcmcia_enable(sc) + struct ep_softc *sc; { - int err; -/* struct pcmciadevs *dev = pc_link->device;*/ -/* struct ep_softc *sc = (void *) self;*/ - - if ((err = PCMCIA_BUS_CONFIG(pc_link->adapter, pc_link, self, pc_cf, - cf)) != 0) { - printf("bus_config failed %d\n", err); - return err; - } + struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; + struct pcmcia_function *pf = psc->sc_pf; - if (pc_cf->io[0].len > 0x10) - pc_cf->io[0].len = 0x10; -#if 0 - pc_cf->cfgtype = DOSRESET; -#endif - pc_cf->cfgtype = 1; + /* establish the interrupt. */ + sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, epintr, sc); + if (sc->sc_ih == NULL) { + printf("%s: couldn't establish interrupt\n", + sc->sc_dev.dv_xname); + return (1); + } - return 0; + return (ep_pcmcia_enable1(sc)); } int -ep_remove(pc_link, self) - struct pcmcia_link *pc_link; - struct device *self; +ep_pcmcia_enable1(sc) + struct ep_softc *sc; { - 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); - sc->pcmcia_flags = EP_ABSENT; - return PCMCIA_BUS_UNCONFIG(pc_link->adapter, pc_link); + struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; + struct pcmcia_function *pf = psc->sc_pf; + int ret; + + if ((ret = pcmcia_function_enable(pf))) + return (ret); + + if (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) { + int reg; + + /* turn off the serial-disable bit */ + + reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); + if (reg & 0x08) { + reg &= ~0x08; + pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); + } + + } + + return (ret); } -static struct pcmcia_3com { - struct pcmcia_device pcd; -} pcmcia_3com = { - { - "PCMCIA 3COM 3C589", epmod, - ep_pcmcia_isasetup, NULL, ep_remove - }, -}; +void +ep_pcmcia_disable(sc) + struct ep_softc *sc; +{ + struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; -struct pcmciadevs pcmcia_ep_devs[] = { - { - "ep", 0, "3Com Corporation", "3C589", - NULL, NULL, - (void *) -1, (void *) &pcmcia_3com - }, -}; + ep_pcmcia_disable1(sc); + pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); +} -int -ep_pcmcia_match(parent, match, aux) - struct device *parent; - void *match, *aux; +void +ep_pcmcia_disable1(sc) + struct ep_softc *sc; { - return pcmcia_slave_match(parent, match, aux, pcmcia_ep_devs, - sizeof(pcmcia_ep_devs)/sizeof(pcmcia_ep_devs[0])); + struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc; + + pcmcia_function_disable(psc->sc_pf); } void ep_pcmcia_attach(parent, self, aux) - struct device *parent, *self; - void *aux; + struct device *parent, *self; + void *aux; { - struct ep_softc *sc = (void *)self; - struct isa_attach_args *ia = aux; - bus_space_tag_t iot = ia->ia_iot; - bus_space_handle_t ioh; - - if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh)) - panic("ep_isa_attach: can't map i/o space"); - - sc->sc_iot = iot; - sc->sc_ioh = ioh; - - epconfig(sc, EP_CHIPSET_3C509); - sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, - IST_EDGE, IPL_NET, epintr, sc, sc->sc_dev.dv_xname); + struct ep_pcmcia_softc *psc = (void *) self; + struct ep_softc *sc = &psc->sc_ep; + struct pcmcia_attach_args *pa = aux; + struct pcmcia_config_entry *cfe; + struct ep_pcmcia_product *epp; + u_int8_t myla[ETHER_ADDR_LEN]; + u_int8_t *enaddr = NULL; + int i; + + psc->sc_pf = pa->pf; + cfe = pa->pf->cfe_head.sqh_first; + + /* Enable the card. */ + pcmcia_function_init(pa->pf, cfe); + if (ep_pcmcia_enable1(sc)) + printf(": function enable failed\n"); + +#ifdef notyet + sc->enabled = 1; +#endif + + if (cfe->num_memspace != 0) + printf(": unexpected number of memory spaces %d should be 0\n", + cfe->num_memspace); + + if (cfe->num_iospace != 1) + printf(": unexpected number of I/O spaces %d should be 1\n", + cfe->num_iospace); + + if (pa->product == PCMCIA_PRODUCT_3COM_3C562) { + bus_addr_t maxaddr = (pa->pf->sc->iobase + pa->pf->sc->iosize); + + for (i = pa->pf->sc->iobase; i < maxaddr; i += 0x10) { + /* + * the 3c562 can only use 0x??00-0x??7f + * according to the Linux driver + */ + if (i & 0x80) + continue; + if (pcmcia_io_alloc(pa->pf, i, cfe->iospace[0].length, + 0, &psc->sc_pcioh) == 0) + break; + } + if (i >= maxaddr) { + printf(": can't allocate i/o space\n"); + return; + } + } else { + if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length, + cfe->iospace[0].length, &psc->sc_pcioh)) + printf(": can't allocate i/o space\n"); + } + + sc->sc_iot = psc->sc_pcioh.iot; + sc->sc_ioh = psc->sc_pcioh.ioh; + + if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? + PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, cfe->iospace[0].length, + &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return; + } + + switch (pa->product) { + case PCMCIA_PRODUCT_3COM_3C562: + /* + * 3c562a-c use this; 3c562d does it in the regular way. + * we might want to check the revision and produce a warning + * in the future. + */ + /* FALLTHROUGH */ + case PCMCIA_PRODUCT_3COM_3C574: + /* + * Apparently, some 3c574s do it this way, as well. + */ + if (pcmcia_scan_cis(parent, ep_pcmcia_get_enaddr, myla)) + enaddr = myla; + break; + } + + sc->bustype = EP_BUS_PCMCIA; + + epp = ep_pcmcia_lookup(pa); + if (epp == NULL) + panic("ep_pcmcia_attach: impossible"); + + printf(": %s\n", epp->epp_name); + +#ifdef notyet + sc->enable = ep_pcmcia_enable; + sc->disable = ep_pcmcia_disable; +#endif + + epconfig(sc, epp->epp_chipset, enaddr); + + /* establish the interrupt. */ + sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, epintr, sc); + if (sc->sc_ih == NULL) + printf("%s: couldn't establish interrupt\n", + sc->sc_dev.dv_xname); + +#ifdef notyet + sc->enabled = 0; + + ep_pcmcia_disable1(sc); +#endif } -/* - * No detach; network devices are too well linked into the rest of the - * kernel. - */ int -ep_pcmcia_detach(self) - struct device *self; +ep_pcmcia_get_enaddr(tuple, arg) + struct pcmcia_tuple *tuple; + void *arg; { - return EBUSY; + u_int8_t *myla = arg; + int i; + + /* this is 3c562a-c magic */ + if (tuple->code == 0x88) { + if (tuple->length < ETHER_ADDR_LEN) + return (0); + + for (i = 0; i < ETHER_ADDR_LEN; i += 2) { + myla[i] = pcmcia_tuple_read_1(tuple, i + 1); + myla[i + 1] = pcmcia_tuple_read_1(tuple, i); + } + + return (1); + } + return (0); } diff --git a/sys/dev/pcmcia/if_sm_pcmcia.c b/sys/dev/pcmcia/if_sm_pcmcia.c new file mode 100644 index 00000000000..b789eef3c51 --- /dev/null +++ b/sys/dev/pcmcia/if_sm_pcmcia.c @@ -0,0 +1,357 @@ +/* $OpenBSD: if_sm_pcmcia.c,v 1.1 1998/09/11 10:47:14 fgsch Exp $ */ +/* $NetBSD: if_sm_pcmcia.c,v 1.11 1998/08/15 20:47:32 thorpej Exp $ */ + +/*- + * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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. + */ + +#include "bpfilter.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/select.h> +#include <sys/device.h> + +#include <net/if.h> +#include <net/if_dl.h> +#ifdef __NetBSD__ +#include <net/if_ether.h> +#include <net/if_media.h> +#endif + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#ifdef __NetBSD__ +#include <netinet/if_inarp.h> +#else +#include <netinet/if_ether.h> +#endif +#endif + +#ifdef NS +#include <netns/ns.h> +#include <netns/ns_if.h> +#endif + +#if NBPFILTER > 0 +#include <net/bpf.h> +#include <net/bpfdesc.h> +#endif + +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/ic/smc91cxxreg.h> +#include <dev/ic/smc91cxxvar.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmciadevs.h> + +int sm_pcmcia_match __P((struct device *, void *, void *)); +void sm_pcmcia_attach __P((struct device *, struct device *, void *)); + +struct sm_pcmcia_softc { + struct smc91cxx_softc sc_smc; /* real "smc" softc */ + + /* PCMCIA-specific goo. */ + struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ + int sc_io_window; /* our i/o window */ + void *sc_ih; /* interrupt cookie */ + struct pcmcia_function *sc_pf; /* our PCMCIA function */ +}; + +struct cfattach sm_pcmcia_ca = { + sizeof(struct sm_pcmcia_softc), sm_pcmcia_match, sm_pcmcia_attach +}; + +int sm_pcmcia_enable __P((struct smc91cxx_softc *)); +void sm_pcmcia_disable __P((struct smc91cxx_softc *)); + +int sm_pcmcia_ascii_enaddr __P((const char *, u_int8_t *)); +int sm_pcmcia_funce_enaddr __P((struct device *, u_int8_t *)); + +int sm_pcmcia_lannid_ciscallback __P((struct pcmcia_tuple *, void *)); + +struct sm_pcmcia_product { + u_int32_t spp_vendor; /* vendor ID */ + u_int32_t spp_product; /* product ID */ + int spp_expfunc; /* expected function */ + const char *spp_name; /* product name */ +} sm_pcmcia_products[] = { + { PCMCIA_VENDOR_MEGAHERTZ2, PCMCIA_PRODUCT_MEGAHERTZ2_XJACK, + 0, PCMCIA_STR_MEGAHERTZ2_XJACK }, + + { PCMCIA_VENDOR_NEWMEDIA, PCMCIA_PRODUCT_NEWMEDIA_BASICS, + 0, PCMCIA_STR_NEWMEDIA_BASICS }, + +#if 0 + { PCMCIA_VENDOR_SMC, PCMCIA_PRODUCT_SMC_8020BT, + 0, PCMCIA_STR_SMC_8020BT }, +#endif + + { 0, 0, + 0, NULL }, +}; + +struct sm_pcmcia_product *sm_pcmcia_lookup __P((struct pcmcia_attach_args *)); + +struct sm_pcmcia_product * +sm_pcmcia_lookup(pa) + struct pcmcia_attach_args *pa; +{ + struct sm_pcmcia_product *spp; + + for (spp = sm_pcmcia_products; spp->spp_name != NULL; spp++) + if (pa->manufacturer == spp->spp_vendor && + pa->product == spp->spp_product && + pa->pf->number == spp->spp_expfunc) + return (spp); + return (NULL); +} + +int +sm_pcmcia_match(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct pcmcia_attach_args *pa = aux; + + if (sm_pcmcia_lookup(pa) != NULL) + return (1); + return (0); +} + +void +sm_pcmcia_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)self; + struct smc91cxx_softc *sc = &psc->sc_smc; + struct pcmcia_attach_args *pa = aux; + struct pcmcia_config_entry *cfe; + u_int8_t myla[ETHER_ADDR_LEN], *enaddr = NULL; + struct sm_pcmcia_product *spp; + + psc->sc_pf = pa->pf; + cfe = pa->pf->cfe_head.sqh_first; + + /* Enable the card. */ + pcmcia_function_init(pa->pf, cfe); + if (pcmcia_function_enable(pa->pf)) { + printf(": function enable failed\n"); + return; + } + + /* XXX sanity check number of mem and i/o spaces */ + + /* Allocate and map i/o space for the card. */ + if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length, + cfe->iospace[0].length, &psc->sc_pcioh)) { + printf(": can't allocate i/o space\n"); + return; + } + + sc->sc_bst = psc->sc_pcioh.iot; + sc->sc_bsh = psc->sc_pcioh.ioh; + + sc->sc_enable = sm_pcmcia_enable; + sc->sc_disable = sm_pcmcia_disable; + + if (pcmcia_io_map(pa->pf, (cfe->flags & PCMCIA_CFE_IO16) ? + PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8, 0, cfe->iospace[0].length, + &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return; + } + + spp = sm_pcmcia_lookup(pa); + if (spp == NULL) + panic("sm_pcmcia_attach: impossible"); + + printf(": %s\n", spp->spp_name); + + /* + * First try to get the Ethernet address from FUNCE/LANNID tuple. + */ + if (sm_pcmcia_funce_enaddr(parent, myla)) + enaddr = myla; + + /* + * If that failed, try one of the CIS info strings. + */ + if (enaddr == NULL) { + char *cisstr = NULL; + + switch (pa->manufacturer) { + case PCMCIA_VENDOR_MEGAHERTZ2: + cisstr = pa->pf->sc->card.cis1_info[3]; + break; + + case PCMCIA_VENDOR_SMC: + cisstr = pa->pf->sc->card.cis1_info[2]; + break; + } + + if (cisstr != NULL && sm_pcmcia_ascii_enaddr(cisstr, myla)) + enaddr = myla; + } + + if (enaddr == NULL) + printf("%s: unable to get Ethernet address\n", + sc->sc_dev.dv_xname); + + /* Perform generic intialization. */ + smc91cxx_attach(sc, enaddr); + + pcmcia_function_disable(pa->pf); +} + +int +sm_pcmcia_ascii_enaddr(cisstr, myla) + const char *cisstr; + u_int8_t *myla; +{ + char enaddr_str[12]; + int i, j; + + if (strlen(cisstr) != 12) { + /* Bogus address! */ + return (0); + } + bcopy(cisstr, enaddr_str, 12); + bzero(myla, sizeof(myla)); + for (i = 0; i < 6; i++) { + for (j = 0; j < 2; j++) { + /* Convert to upper case. */ + if (enaddr_str[(i * 2) + j] >= 'a' && + enaddr_str[(i * 2) + j] <= 'z') + enaddr_str[(i * 2) + j] -= 'a' - 'A'; + + /* Parse the digit. */ + if (enaddr_str[(i * 2) + j] >= '0' && + enaddr_str[(i * 2) + j] <= '9') + myla[i] |= enaddr_str[(i * 2) + j] + - '0'; + else if (enaddr_str[(i * 2) + j] >= 'A' && + enaddr_str[(i * 2) + j] <= 'F') + myla[i] |= enaddr_str[(i * 2) + j] + - 'A' + 10; + else { + /* Bogus digit!! */ + return (0); + } + + /* Compensate for ordering of digits. */ + if (j == 0) + myla[i] <<= 4; + } + } + + return (1); +} + +int +sm_pcmcia_funce_enaddr(parent, myla) + struct device *parent; + u_int8_t *myla; +{ + + return (pcmcia_scan_cis(parent, sm_pcmcia_lannid_ciscallback, myla)); +} + +int +sm_pcmcia_lannid_ciscallback(tuple, arg) + struct pcmcia_tuple *tuple; + void *arg; +{ + u_int8_t *myla = arg; + int i; + + if (tuple->code == PCMCIA_CISTPL_FUNCE) { + /* subcode, length */ + if (tuple->length < 2) + return (0); + + if ((pcmcia_tuple_read_1(tuple, 0) != + PCMCIA_TPLFE_TYPE_LAN_NID) || + (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN)) + return (0); + + for (i = 0; i < ETHER_ADDR_LEN; i++) + myla[i] = pcmcia_tuple_read_1(tuple, i + 2); + return (1); + } + return (0); +} + +int +sm_pcmcia_enable(sc) + struct smc91cxx_softc *sc; +{ + struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)sc; + + /* Establish the interrupt handler. */ + psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, smc91cxx_intr, + sc); + if (psc->sc_ih == NULL) { + printf("%s: couldn't establish interrupt handler\n", + sc->sc_dev.dv_xname); + return (1); + } + + return (pcmcia_function_enable(psc->sc_pf)); +} + +void +sm_pcmcia_disable(sc) + struct smc91cxx_softc *sc; +{ + struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)sc; + + pcmcia_function_disable(psc->sc_pf); + + pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); +} diff --git a/sys/dev/pcmcia/pcmcia.c b/sys/dev/pcmcia/pcmcia.c index 16a80a669bd..c7539c7a1f3 100644 --- a/sys/dev/pcmcia/pcmcia.c +++ b/sys/dev/pcmcia/pcmcia.c @@ -1,8 +1,8 @@ -/* $OpenBSD: pcmcia.c,v 1.10 1997/08/19 21:59:49 angelos Exp $ */ +/* $OpenBSD: pcmcia.c,v 1.11 1998/09/11 10:47:14 fgsch Exp $ */ +/* $NetBSD: pcmcia.c,v 1.9 1998/08/13 02:10:55 eeh Exp $ */ /* - * Copyright (c) 1996 John T. Kohl. All rights reserved. - * Copyright (c) 1994 Stefan Grefen. All rights reserved. + * Copyright (c) 1997 Marc Horowitz. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,8 +14,7 @@ * 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. + * This product includes software developed by Marc Horowitz. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * @@ -29,1340 +28,777 @@ * 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. - * */ -/* - * XXX - these next two lines are just "glue" until the confusion over - * pcmcia vs pcmciabus between the framework and sys/conf/files - * gets resolved - */ -#define pcmciabus_cd pcmcia_cd -#define pcmciabus_ca pcmcia_ca - -/* - * 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 <sys/proc.h> -#include <dev/pcmcia/pcmciavar.h> +/* XXX only needed for intr debugging */ +#include <vm/vm.h> + #include <dev/pcmcia/pcmciareg.h> -#include <dev/pcmcia/pcmcia_ioctl.h> +#include <dev/pcmcia/pcmciachip.h> +#include <dev/pcmcia/pcmciavar.h> -#ifdef IBM_WD -#define PCMCIA_DEBUG -#endif -#ifdef PCMCIA_DEBUG -# define PPRINTF(a) printf a +#ifdef PCMCIADEBUG +int pcmcia_debug = 1; +#define DPRINTF(arg) if (pcmcia_debug) printf arg #else -# define PPRINTF(a) +#define DPRINTF(arg) #endif -#ifdef PCMCIA_DEBUG -void pcmciadumpcf __P((struct pcmcia_conf *)); +#ifdef PCMCIAVERBOSE +int pcmcia_verbose = 1; +#else +int pcmcia_verbose = 0; #endif -static struct old_devs { - struct device *dev; - struct pcmciadevs *pcdev; -} *deldevs; -static int ndeldevs = 0; - -#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)) -/* - * XXX - * this is quite broken in the face of various bus mapping stuff... - * drivers need to cooperate with the pcmcia framework to deal with - * bus mapped memory. Whee. - */ -#define PCMCIA_MAP_MEM(a,b,c,d,e,f,g) ((a)->chip_link->pcmcia_map_mem(b,c,d,e,f,g)) - -#define SCRATCH_MEM(a) ((caddr_t)(a)->scratch_memh) -#define SCRATCH_MEMT(a) ((a)->pa_memt) -#define SCRATCH_SIZE(a) ((a)->scratch_memsiz) -#define SCRATCH_INUSE(a)((a)->scratch_inuse) - -/* - * Declarations - */ -int pcmcia_probedev __P((struct pcmcia_link *, struct pcmcia_cardinfo *)); -int pcmcia_probe_bus __P((int, int)); -int pcmciabusmatch __P((struct device *, void *, void *)); -void pcmciabusattach __P((struct device *, struct device *, void *)); -int pcmcia_mapcard __P((struct pcmcia_link *, int, struct pcmcia_conf *)); -int pcmcia_mapcard_and_configure __P((struct pcmcia_link *, int, - struct pcmcia_conf *)); - -int pcmcia_unconfigure __P((struct pcmcia_link *)); -int pcmcia_unmapcard __P((struct pcmcia_link *)); +int pcmcia_match __P((struct device *, void *, void *)); +int pcmcia_submatch __P((struct device *, void *, void *)); +void pcmcia_attach __P((struct device *, struct device *, void *)); +int pcmcia_print __P((void *, const char *)); -int pcmcia_print __P((void *, const char *)); -int pcmcia_submatch __P((struct device *, void *, void *)); -void pcmcia_probe_link __P((struct pcmcia_link *)); +static inline void pcmcia_socket_enable __P((pcmcia_chipset_tag_t, + pcmcia_chipset_handle_t *)); +static inline void pcmcia_socket_disable __P((pcmcia_chipset_tag_t, + pcmcia_chipset_handle_t *)); -void pcmcia_detach __P((struct device *, void *)); - -struct cfattach pcmcia_ca = { - sizeof(struct pcmciabus_softc), pcmciabusmatch, pcmciabusattach, -}; +int pcmcia_card_intr __P((void *)); struct cfdriver pcmcia_cd = { - NULL, "pcmcia", DV_DULL, 1 + NULL, "pcmcia", DV_DULL }; -int pcmciaopen __P((dev_t, int, int, struct proc *)); -int pcmciaclose __P((dev_t, int, int, struct proc *)); -int pcmciachip_ioctl __P((int, int, caddr_t)); -int pcmciaslot_ioctl __P((struct pcmcia_link *, int, int, caddr_t)); -int pcmciaioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); -int pcmciaselect __P((dev_t, int, struct proc *)); -int pcmciammap __P((dev_t, int, int)); - -#if 0 -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; -} -#endif +struct cfattach pcmcia_ca = { + sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach +}; int -pcmciabusmatch(parent, self, aux) - struct device *parent; - void *self; - void *aux; +pcmcia_ccr_read(pf, ccr) + struct pcmcia_function *pf; + int ccr; { - struct pcmciabus_softc *sc = (void *)self; - struct cfdata *cf = sc->sc_dev.dv_cfdata; - struct pcmciabus_attach_args *pba = aux; - struct pcmcia_adapter *pca = pba->pba_aux; - int found = 0; - PPRINTF(("- pcmciabusmatch %p %p\n", pba, pca)); - - if (pca->bus_link) { - if (PCMCIA_BUS_INIT(pca, parent, cf, aux, pca, 0)) - found++; - } - return found != 0; + return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, + pf->pf_ccr_offset + ccr)); } -/* - * 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; +pcmcia_ccr_write(pf, ccr, val) + struct pcmcia_function *pf; + int ccr; + int val; { - struct pcmciabus_softc *sc = (struct pcmciabus_softc *) self; - struct cfdata *cf = self->dv_cfdata; - struct pcmciabus_attach_args *pba = aux; - struct pcmcia_adapter *pca = pba->pba_aux; - - PPRINTF(("- pcmciabusattach\n")); - if (pca->bus_link) { - PCMCIA_BUS_INIT(pca, parent, cf, aux, pca, 1); - } - printf("\n"); - sc->sc_driver = pca; - sc->sc_iot = pba->pba_iot; - sc->sc_memt = pba->pba_memt; - pcmcia_probe_bus(sc->sc_dev.dv_unit, -1); + if ((pf->ccr_mask) & (1 << (ccr / 2))) { + bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, + pf->pf_ccr_offset + ccr, val); + } } -/* - * Probe the requested pcmcia bus. It must be already set up. - * -1 requests all set up pcmcia busses. - */ -int pcmcia_probe_busses __P((int, int)); - int -pcmcia_probe_busses(bus, slot) - int bus, slot; +pcmcia_match(parent, match, aux) + struct device *parent; + void *match, *aux; { - PPRINTF(("- pcmcia_probe_busses\n")); - if (bus == -1) { - for (bus = 0; bus < pcmciabus_cd.cd_ndevs; bus++) - if (pcmciabus_cd.cd_devs[bus]) - pcmcia_probe_bus(bus, slot); - return 0; - } else { - return pcmcia_probe_bus(bus, slot); - } + /* if the autoconfiguration got this far, there's a socket here */ + return (1); } -/* Macros to clear/set/test flags. */ -#define SET(t, f) (t) |= (f) -#define CLR(t, f) (t) &= ~(f) -#define ISSET(t, f) ((t) & (f)) - -/* - * Probe the requested pcmcia bus. It must be already set up. - */ -int -pcmcia_probe_bus(bus, slot) - int bus, slot; +void +pcmcia_attach(parent, self, aux) + struct device *parent, *self; + void *aux; { - struct pcmciabus_softc *pcmcia; - int maxslot, minslot; - struct pcmcia_link *link; - - PPRINTF(("- pcmcia_probe_bus\n")); - if (bus < 0 || bus >= pcmciabus_cd.cd_ndevs) - return ENXIO; - pcmcia = pcmciabus_cd.cd_devs[bus]; - if (!pcmcia || pcmcia->sc_driver == NULL) /* bus is not configured */ - return ENXIO; - - if (slot == -1) { - maxslot = pcmcia->sc_driver->nslots - 1; - minslot = 0; - } else { - if (slot < 0 || slot >= pcmcia->sc_driver->nslots) - return EINVAL; - maxslot = minslot = slot; - } + struct pcmciabus_attach_args *paa = aux; + struct pcmcia_softc *sc = (struct pcmcia_softc *) self; - for (slot = minslot; slot <= maxslot; slot++) { - if ((link = pcmcia->sc_link[slot])) { - if (link->devp) - continue; - } + printf("\n"); - /* - * 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->sc_driver; - link->bus = pcmcia; - link->slot = slot; - } - (void) pcmcia_probe_link(link); - } - return 0; + sc->pct = paa->pct; + sc->pch = paa->pch; + sc->iobase = paa->iobase; + sc->iosize = paa->iosize; + + sc->ih = NULL; } -void -pcmcia_probe_link(link) - struct pcmcia_link *link; +int +pcmcia_card_attach(dev) + struct device *dev; { - struct pcmcia_cardinfo cardinfo; + struct pcmcia_softc *sc = (struct pcmcia_softc *) dev; + struct pcmcia_function *pf; struct pcmcia_attach_args paa; - struct pcmciabus_softc *pcmcia = link->bus; - int i; + int attached; - PPRINTF(("- pcmcia_probe_link %p\n", link)); /* - * Set up card and fetch card info. + * this is here so that when socket_enable calls gettype, trt happens */ - if (pcmcia_probedev(link, &cardinfo) == 0) { - /* could not fetch its strings, so give up on it. */ - PCMCIA_SERVICE(link->adapter, - link, PCMCIA_OP_POWER, - 0, 0); - return; - } + sc->card.pf_head.sqh_first = NULL; - /* - * See if we can reattach a device. - */ - CLR(link->flags, PCMCIA_ATTACH_TYPE); - SET(link->flags, PCMCIA_REATTACH); - for (i = 0; i < ndeldevs; i++) { - if (deldevs[i].dev) { - PPRINTF(("trying device\n")); - link->device = deldevs[i].pcdev; - if (pcmcia_configure(deldevs[i].dev->dv_parent, - deldevs[i].dev, link)) { - CLR(link->flags, PCMCIA_ATTACH_TYPE); - SET(link->flags, PCMCIA_SLOT_INUSE); - deldevs[i].dev = NULL; - deldevs[i].pcdev = NULL; - return; - } - } - } + pcmcia_chip_socket_enable(sc->pct, sc->pch); + pcmcia_read_cis(sc); - paa.paa_cardinfo = &cardinfo; - paa.paa_link = link; - paa.paa_aux = NULL; - paa.paa_bestmatch = 0; - paa.paa_matchonly = 1; - CLR(link->flags, PCMCIA_ATTACH_TYPE); - SET(link->flags, PCMCIA_ATTACH); + pcmcia_chip_socket_disable(sc->pct, sc->pch); /* - * Run the config matching routines to find us a good match. - * match routines will flag on "matchonly" and fill in stuff - * into the link structure, but not return any match. + * bail now if the card has no functions, or if there was an error in + * the cis. */ - (void) config_found_sm(&pcmcia->sc_dev, - &paa, - pcmcia_print, - pcmcia_submatch); - - if (PCMCIA_BUS_SEARCH(link->adapter, - &pcmcia->sc_dev, - link, NULL)) { - CLR(link->flags, PCMCIA_ATTACH_TYPE); - SET(link->flags, PCMCIA_SLOT_INUSE); - } else { - CLR(link->flags, PCMCIA_ATTACH_TYPE|PCMCIA_SLOT_INUSE); - link->device = NULL; - printf("%s slot %d: No matching config entry.\n", - pcmcia->sc_dev.dv_xname, - link->slot); - PCMCIA_SERVICE(link->adapter, - link, PCMCIA_OP_POWER, - 0, 0); - link->fordriver = NULL; - } - return; -} -/* - * given a target ask the device what - * it is, and find the correct driver table - * entry. - */ -int -pcmcia_probedev(link, cardinfo) - struct pcmcia_link *link; - struct pcmcia_cardinfo *cardinfo; -{ - struct pcmcia_adapter *pca = link->adapter; - u_char scratch[CIS_MAXSIZE]; - int card_stat; - int err; - int pow = 0; - int slot = link->slot; - - PPRINTF(("- pcmcia_probe_dev\n")); - - printf("%s slot %d: ", ((struct device *) link->bus)->dv_xname, slot); - - /* turn off power in case it's on, to get a fresh start on things: */ - PCMCIA_SERVICE(pca, link, PCMCIA_OP_POWER, 0, 0); - if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_STATUS, - &card_stat, 0)) != 0) { - printf("failed to get status %d\n", err); - return NULL; - } + if (sc->card.error) + return (1); + if (sc->card.pf_head.sqh_first == NULL) + return (1); - if (ISSET(card_stat, PCMCIA_CARD_PRESENT) == 0) { - printf("empty\n"); - return NULL; - } + if (pcmcia_verbose) + pcmcia_print_cis(sc); - if (!ISSET(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; - } - } + attached = 0; - if (!ISSET(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; - } - } + for (pf = sc->card.pf_head.sqh_first; pf != NULL; + pf = pf->pf_list.sqe_next) { + if (pf->cfe_head.sqh_first == NULL) + continue; - /* - * 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; + pf->sc = sc; + pf->cfe = NULL; + pf->ih_fct = NULL; + pf->ih_arg = NULL; } - if ((err = pcmcia_get_cisver1(link, scratch, sizeof(scratch), - cardinfo->manufacturer, - cardinfo->model, cardinfo->add_info1, - cardinfo->add_info2)) != 0) { - printf("failed to get cis info %d\n", err); - goto bad; + for (pf = sc->card.pf_head.sqh_first; pf != NULL; + pf = pf->pf_list.sqe_next) { + if (pf->cfe_head.sqh_first == NULL) + continue; + + paa.manufacturer = sc->card.manufacturer; + paa.product = sc->card.product; + paa.card = &sc->card; + paa.pf = pf; + + if (config_found_sm(&sc->dev, &paa, pcmcia_print, + pcmcia_submatch)) { + attached++; + + DPRINTF(("%s: function %d CCR at %d " + "offset %lx: %x %x %x %x, %x %x %x %x, %x\n", + sc->dev.dv_xname, pf->number, + pf->pf_ccr_window, pf->pf_ccr_offset, + pcmcia_ccr_read(pf, 0x00), + pcmcia_ccr_read(pf, 0x02), pcmcia_ccr_read(pf, 0x04), + pcmcia_ccr_read(pf, 0x06), pcmcia_ccr_read(pf, 0x0A), + pcmcia_ccr_read(pf, 0x0C), pcmcia_ccr_read(pf, 0x0E), + pcmcia_ccr_read(pf, 0x10), pcmcia_ccr_read(pf, 0x12))); + } } - printf("<%s, %s", cardinfo->manufacturer, cardinfo->model); - if (cardinfo->add_info1[0]) - printf(", %s", cardinfo->add_info1); - if (cardinfo->add_info2[0]) - printf(", %s", cardinfo->add_info2); - printf(">\n"); - - return 1; -bad: - if (!pow) - PCMCIA_SERVICE(pca, link, PCMCIA_OP_POWER, 0, 0); - return 0; + return (attached ? 0 : 1); +} + +void +pcmcia_card_detach(dev) + struct device *dev; +{ + /* struct pcmcia_softc *sc = (struct pcmcia_softc *) dev; */ + /* don't do anything yet */ } int -pcmcia_configure(parent, self, aux) - struct device *parent; - void *self; - void *aux; +pcmcia_submatch(parent, match, aux) + struct device *parent; + void *match, *aux; { - struct device *dev = self; - struct pcmcia_link *link = aux; - struct cfdata *cf = dev->dv_cfdata; - struct cfdriver *cd = cf->cf_driver; - struct pcmciadevs *pcs = link->device; - struct pcmcia_device *pcd; - struct pcmcia_adapter *pca = link->adapter; - struct pcmcia_conf pc_cf; - char *devname = (char *) link->fordriver; - u_char scratch[CIS_MAXSIZE]; - int mymap = 0; - - PPRINTF(("- pcmcia_configure\n")); - - if ((devname && strcmp(devname, cd->cd_name)) || !pca) - return 0; - - if (link->devp) - return 0; /* something else already attached */ - - if (pcs == NULL) - pcd = NULL; - else - pcd = pcs->dev; - - PPRINTF(("pcmcia_configure: %p\n", pcd)); - if (!ISSET(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 %p %p\n", - pcd, pcd->pcmcia_config)); - 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 + struct cfdata *cf = match; + struct pcmcia_attach_args *paa = aux; - if (pcmcia_mapcard(link, -1, &pc_cf) != 0) - return 0; + if (cf->cf_loc[0 /* PCMCIACF_FUNCTION */] != + -1 /* PCMCIACF_FUNCTION_DEFAULT */ && + cf->cf_loc[0 /* PCMCIACF_FUNCTION */] != paa->pf->number) + return (0); - mymap = 1; - } - link->devp = dev; + return ((*cf->cf_attach->ca_match)(parent, cf, aux)); +} - PPRINTF(("pcmcia_configure: calling bus attach\n")); - if (!(PCMCIA_BUS_PROBE(pca, parent, dev, cf, link))) { - PPRINTF(("pcmcia_configure: bus probe failed\n")); - goto bad; +int +pcmcia_print(arg, pnp) + void *arg; + const char *pnp; +{ + struct pcmcia_attach_args *pa = arg; + struct pcmcia_softc *sc = pa->pf->sc; + struct pcmcia_card *card = &sc->card; + int i; + + if (pnp) { + for (i = 0; i < 4; i++) { + if (card->cis1_info[i] == NULL) + break; + if (i) + printf(", "); + printf("%s", card->cis1_info[i]); + } + if (i) + printf(" "); + printf("(manufacturer 0x%x, product 0x%x)", card->manufacturer, + card->product); } + printf(" function %d", pa->pf->number); - if (pcd && pcd->pcmcia_insert && pcd->pcmcia_insert(link, dev, cf)) { - PPRINTF(("pcmcia_configure: pcmcia_insert failed\n")); - goto bad; - } + return (UNCONF); +} - return 1; +int +pcmcia_card_gettype(dev) + struct device *dev; +{ + struct pcmcia_softc *sc = (struct pcmcia_softc *)dev; + struct pcmcia_function *pf; -bad: - link->devp = NULL; - if (mymap) - pcmcia_unmapcard(link); - PPRINTF(("pcmcia_configure: configuration error\n")); - return 0; + /* + * set the iftype to memory if this card has no functions (not yet + * probed), or only one function, and that is not initialized yet or + * that is memory. + */ + pf = SIMPLEQ_FIRST(&sc->card.pf_head); + if (pf == NULL || + (SIMPLEQ_NEXT(pf, pf_list) == NULL && + (pf->cfe == NULL || pf->cfe->iftype == PCMCIA_IFTYPE_MEMORY))) + return (PCMCIA_IFTYPE_MEMORY); + else + return (PCMCIA_IFTYPE_IO); } +/* + * Initialize a PCMCIA function. May be called as long as the function is + * disabled. + */ void -pcmcia_detach(dev, arg) - struct device *dev; - void *arg; +pcmcia_function_init(pf, cfe) + struct pcmcia_function *pf; + struct pcmcia_config_entry *cfe; { - struct pcmcia_link *link = arg; + if (pf->pf_flags & PFF_ENABLED) + panic("pcmcia_function_init: function is enabled"); - link->devp = NULL; - printf("%s: device %s at slot %d detached/really\n", - dev->dv_parent->dv_xname, - dev->dv_xname, link->slot); + /* Remember which configuration entry we are using. */ + pf->cfe = cfe; } -int -pcmcia_unconfigure(link) - struct pcmcia_link *link; +static inline void pcmcia_socket_enable(pct, pch) + pcmcia_chipset_tag_t pct; + pcmcia_chipset_handle_t *pch; { - int i; - struct device *dev; - struct pcmcia_adapter *pca = link->adapter; - struct pcmcia_device *pcd; + pcmcia_chip_socket_enable(pct, pch); +} - PPRINTF(("- pcmcia_unconfigure\n")); - if (link->devp == NULL) - return ENODEV; +static inline void pcmcia_socket_disable(pct, pch) + pcmcia_chipset_tag_t pct; + pcmcia_chipset_handle_t *pch; +{ + pcmcia_chip_socket_disable(pct, pch); +} - if (link->device) - pcd = link->device->dev; - else - pcd = NULL; +/* Enable a PCMCIA function */ +int +pcmcia_function_enable(pf) + struct pcmcia_function *pf; +{ + struct pcmcia_function *tmp; + int reg; - if (ISSET(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; - } - if (config_detach(link->devp->dv_cfdata, pcmcia_detach, link)) { - /* must be retained */ - for (i = 0; deldevs && deldevs[i].dev && i < ndeldevs; i++) - continue; + if (pf->cfe == NULL) + panic("pcmcia_function_enable: function not initialized"); - if (i >= ndeldevs) { - int sz = ndeldevs ? (ndeldevs * 2) : - (MINALLOCSIZE / sizeof(deldevs[0])); - struct old_devs *ndel = malloc(sz * sizeof(deldevs[0]), - M_DEVBUF, M_NOWAIT); - if (!ndel) { - PPRINTF(("pcmcia_delete: creating dev array")); - return ENOMEM; - } - bzero(ndel, sz * sizeof(ndel[0])); - if (ndeldevs) { - bcopy(deldevs, ndel, - ndeldevs * sizeof(deldevs[0])); - free(deldevs, M_DEVBUF); - } - ndeldevs = sz - 1; - deldevs = ndel; - } - dev = deldevs[i].dev = link->devp; - deldevs[i].pcdev = link->device; - link->devp = NULL; - TAILQ_REMOVE(&alldevs, dev, dv_list); - printf("%s: device %s at slot %d detached/retained\n", - dev->dv_parent->dv_xname, - dev->dv_xname, link->slot); + /* + * Increase the reference count on the socket, enabling power, if + * necessary. + */ + if (pf->sc->sc_enabled_count++ == 0) + pcmcia_chip_socket_enable(pf->sc->pct, pf->sc->pch); + DPRINTF(("%s: ++enabled_count = %d\n", pf->sc->dev.dv_xname, + pf->sc->sc_enabled_count)); + + if (pf->pf_flags & PFF_ENABLED) { /* - * Make this node eligible to probe again. - * Since we're indirectly allocating state, - * this device data will not get trashed later and we - * can hold onto it. + * Don't do anything if we're already enabled. */ -/* dev->dv_cfdata->cf_fstate = FSTATE_NOTFOUND;*/ + return (0); } - return 0; -} -/* - * Map the card into I/O and memory space, using the details provided - * with pc_cf. - */ + /* + * it's possible for different functions' CCRs to be in the same + * underlying page. Check for that. + */ -int -pcmcia_mapcard(link, unit, pc_cf) - struct pcmcia_link *link; - int unit; - 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, pca->pa_memt, - (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; + for (tmp = pf->sc->card.pf_head.sqh_first; tmp != NULL; + tmp = tmp->pf_list.sqe_next) { + if ((tmp->pf_flags & PFF_ENABLED) && + (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && + ((pf->ccr_base + PCMCIA_CCR_SIZE) <= + (tmp->ccr_base - tmp->pf_ccr_offset + + tmp->pf_ccr_realsize))) { + pf->pf_ccrt = tmp->pf_ccrt; + pf->pf_ccrh = tmp->pf_ccrh; + pf->pf_ccr_realsize = tmp->pf_ccr_realsize; + + /* + * pf->pf_ccr_offset = (tmp->pf_ccr_offset - + * tmp->ccr_base) + pf->ccr_base; + */ + pf->pf_ccr_offset = + (tmp->pf_ccr_offset + pf->ccr_base) - + tmp->ccr_base; + pf->pf_ccr_window = tmp->pf_ccr_window; + break; } } - 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; + if (tmp == NULL) { + if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE, &pf->pf_pcmh)) + goto bad; + + if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base, + PCMCIA_CCR_SIZE, &pf->pf_pcmh, &pf->pf_ccr_offset, + &pf->pf_ccr_window)) { + pcmcia_mem_free(pf, &pf->pf_pcmh); + goto bad; } } - /* Now we've mapped everything enable it */ - if ((err = PCMCIA_MAP_MEM(pca, link, SCRATCH_MEMT(pca), - 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; + reg = (pf->cfe->number & PCMCIA_CCR_OPTION_CFINDEX); + reg |= PCMCIA_CCR_OPTION_LEVIREQ; + if (pcmcia_mfc(pf->sc)) { + reg |= (PCMCIA_CCR_OPTION_FUNC_ENABLE | + PCMCIA_CCR_OPTION_ADDR_DECODE); + if (pf->ih_fct) + reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE; + } + pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); -#define GETMEM(x) bus_space_read_1(pca->pa_memt, \ - (bus_space_handle_t)SCRATCH_MEM(pca), \ - (pc_cf->cfg_off & (SCRATCH_SIZE(pca)-1)) + x) -#define PUTMEM(x,v) bus_space_write_1(pca->pa_memt, \ - (bus_space_handle_t)SCRATCH_MEM(pca), \ - (pc_cf->cfg_off & (SCRATCH_SIZE(pca)-1)) + x, v) + reg = 0; - if (ISSET(pc_cf->cfgtype, DOSRESET)) { - PUTMEM(0, PCMCIA_SRESET); - delay(50000); - } + if ((pf->cfe->flags & PCMCIA_CFE_IO16) == 0) + reg |= PCMCIA_CCR_STATUS_IOIS8; + if (pf->cfe->flags & PCMCIA_CFE_AUDIO) + reg |= PCMCIA_CCR_STATUS_AUDIO; + pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg); + pcmcia_ccr_write(pf, PCMCIA_CCR_SOCKETCOPY, 0); - PPRINTF(("CMDR %x\n",(ISSET(pc_cf->cfgtype, CFGENTRYID) ? - pc_cf->cfgid |CFGENTRYID: - (pc_cf->cfgtype & CFGENTRYMASK)|1)| - (pc_cf->irq_level ? PCMCIA_LVLREQ : 0) - )); + if (pcmcia_mfc(pf->sc)) { + long tmp, iosize; - PUTMEM(0, (ISSET(pc_cf->cfgtype, CFGENTRYID) ? - pc_cf->cfgid |CFGENTRYID: - (pc_cf->cfgtype & CFGENTRYMASK)|1)| - (pc_cf->irq_level ? PCMCIA_LVLREQ : 0)); - delay(50000); + tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; + /* round up to nearest (2^n)-1 */ + for (iosize = 1; iosize < tmp; iosize <<= 1) + ; + iosize--; - if (ISSET(pc_cf->cfg_regmask, (1 << (PCMCIA_SCR / 2)))) - PUTMEM(PCMCIA_SCR, (link->slot & 1) | 0x10); + pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0, + pf->pf_mfc_iobase & 0xff); + pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1, + (pf->pf_mfc_iobase >> 8) & 0xff); + pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2, 0); + pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3, 0); -#if 0 - DPRINTF(("CCSR %x\n", GETMEM(PCMCIA_CCSR])); - if (ISSET(GETMEM(PCMCIA_CCSR), PCMCIA_POWER_DOWN)) { - u_char val = GETMEM(PCMCIA_CCSR); - CLR(val, PCMCIA_POWER_DOWN); - PUTMEM(PCMCIA_CCSR, var); - DPRINTF(("CCSR now %x\n", GETMEM(PCMCIA_CCSR))); + pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE, iosize); } -#endif + DPRINTF(("%s: function %d CCR at %d offset %lx: " + "%x %x %x %x, %x %x %x %x, %x\n", + pf->sc->dev.dv_xname, pf->number, + pf->pf_ccr_window, pf->pf_ccr_offset, + pcmcia_ccr_read(pf, 0x00), pcmcia_ccr_read(pf, 0x02), + pcmcia_ccr_read(pf, 0x04), pcmcia_ccr_read(pf, 0x06), - PPRINTF(("pcmcia_mapcard: about to initialize...\n")); + pcmcia_ccr_read(pf, 0x0A), pcmcia_ccr_read(pf, 0x0C), + pcmcia_ccr_read(pf, 0x0E), pcmcia_ccr_read(pf, 0x10), - if ((err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_WAIT, - 1000, 0)) != 0) { - PPRINTF(("failed to initialize %d\n", err)); - err = 0; /* XXX */ - } -error: - PCMCIA_MAP_MEM(pca, link, SCRATCH_MEMT(pca), SCRATCH_MEM(pca), 0, - SCRATCH_SIZE(pca), PCMCIA_LAST_WIN | PCMCIA_UNMAP); - if (err != 0) { - PPRINTF(("pcmcia_mapcard: unmaping\n")); - for (i = 0; i < pc_cf->memwin; i++) { - PCMCIA_MAP_MEM(pca, link, - pca->pa_memt, - (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); - CLR(link->flags, CARD_IS_MAPPED); - link->iowin = 0; - link->memwin = 0; - link->intr = 0; - } else { - SET(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; -} + pcmcia_ccr_read(pf, 0x12))); -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, pca->pa_memt, 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, 50000, 0); - CLR(link->flags, (CARD_IS_MAPPED | PCMCIA_SLOT_INUSE)); - link->iowin = 0; - link->memwin = 0; - link->intr = 0; - return 0; -} + pf->pf_flags |= PFF_ENABLED; + return (0); + bad: + /* + * Decrement the reference count, and power down the socket, if + * necessary. + */ + if (--pf->sc->sc_enabled_count == 0) + pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch); + DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname, + pf->sc->sc_enabled_count)); -int -pcmcia_mapcard_and_configure(link, unit, pc_cf) - struct pcmcia_link *link; - struct pcmcia_conf *pc_cf; - int unit; + return (1); +} + +/* Disable PCMCIA function. */ +void +pcmcia_function_disable(pf) + struct pcmcia_function *pf; { - int mymap = 0; - int err; + struct pcmcia_function *tmp; - PPRINTF(("- pcmcia_mapcard_and_configure\n")); - if (pc_cf->driver_name[0][0]) { - if ((err = pcmcia_mapcard(link, unit, pc_cf)) != 0) { - return err; - } - mymap=1; - link->fordriver = pc_cf->driver_name[0]; - } else - link->fordriver = NULL; - - pcmcia_probe_link(link); - - if (!ISSET(link->flags, PCMCIA_SLOT_INUSE)) { - if (mymap) - pcmcia_unmapcard(link); - return ENODEV; + if (pf->cfe == NULL) + panic("pcmcia_function_enable: function not initialized"); + + if ((pf->pf_flags & PFF_ENABLED) == 0) { + /* + * Don't do anything if we're already disabled. + */ + return; } - return 0; -} + /* + * it's possible for different functions' CCRs to be in the same + * underlying page. Check for that. Note we mark us as disabled + * first to avoid matching ourself. + */ -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); - int pgoff = offs / size; - int toff; - - toff = offs - (pgoff * size); - - PPRINTF(("- pcmcia_read_cis: mem %p size %d\n", p, size)); - if (pca == NULL) - return ENXIO; - - s = splbio(); - while (*inuse) - sleep((caddr_t) inuse, PZERO - 1); - *inuse = 1; - splx(s); - - while (len > 0) { - int tlen = min(len, (size - toff) / 2); - int i; - - if ((err = PCMCIA_MAP_MEM(pca, link, pca->pa_memt, p, pgoff, - size, - PCMCIA_MAP_ATTR | - PCMCIA_LAST_WIN)) != 0) - goto error; - - PPRINTF(("- pcmcia_read_cis: mem mapped\n")); - - for (i = 0; i < tlen; j++, i++) - scratch[j] = p[toff + i * 2]; - - PCMCIA_MAP_MEM(pca, link, pca->pa_memt, p, 0, size, - PCMCIA_LAST_WIN | PCMCIA_UNMAP); - len -= tlen; - pgoff++; - toff = 0; + pf->pf_flags &= ~PFF_ENABLED; + for (tmp = pf->sc->card.pf_head.sqh_first; tmp != NULL; + tmp = tmp->pf_list.sqe_next) { + if ((tmp->pf_flags & PFF_ENABLED) && + (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && + ((pf->ccr_base + PCMCIA_CCR_SIZE) <= + (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize))) + break; } -error: - s = splbio(); - *inuse = 0; - wakeup((caddr_t) inuse); - splx(s); - - PPRINTF(("- pcmcia_read_cis return %d\n", err)); - return err; -} -/* here we start our pseudodev for controlling the slots */ -#define PCMCIABUS_UNIT(a) (minor(a)) -#define PCMCIABUS_SLOT(a) (a&0x3) /* per-controller */ -#define PCMCIABUS_SLOTID(a) (a&0xf) /* system-wide assignment */ -#define PCMCIABUS_CHIPNO(a) ((a&0xf)>>2) -#define PCMCIABUS_CHIPID(a) (a&0x3) -#define PCMCIABUS_CHIP 0x40 -#define PCMCIABUS_BUS 0x80 -#define PCMCIABUS_BUSID(a) (a&0x3) -#define PCMCIABUS_DEVTYPE(a) ((a)&(PCMCIABUS_CHIP|PCMCIABUS_BUS)) -static int busopen = 0; -static int chipopen[4] = {0, 0, 0, 0}; + /* Not used by anyone else; unmap the CCR. */ + if (tmp == NULL) { + pcmcia_mem_unmap(pf, pf->pf_ccr_window); + pcmcia_mem_free(pf, &pf->pf_pcmh); + } + + /* + * Decrement the reference count, and power down the socket, if + * necessary. + */ + if (--pf->sc->sc_enabled_count == 0) + pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch); + DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname, + pf->sc->sc_enabled_count)); +} int -pcmciaopen(dev, flag, mode, p) - dev_t dev; - int flag, mode; - struct proc *p; +pcmcia_io_map(pf, width, offset, size, pcihp, windowp) + struct pcmcia_function *pf; + int width; + bus_addr_t offset; + bus_size_t size; + struct pcmcia_io_handle *pcihp; + int *windowp; { - int unit = PCMCIABUS_UNIT(dev); - int chipid, slot; - struct pcmcia_link *link; - struct pcmciabus_softc *pcmcia; - - PPRINTF(("- pcmciabusopen\n")); - 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_CHIPID(unit); - if (chipid < 0 || chipid >= pcmciabus_cd.cd_ndevs) - return ENXIO; - pcmcia = pcmciabus_cd.cd_devs[chipid]; - if (pcmcia == NULL || pcmcia->sc_driver == NULL) - return ENXIO; - - if (chipopen[chipid]) - return EBUSY; - - chipopen[chipid] = 1; - break; - - case 0: - slot = PCMCIABUS_SLOT(unit); - chipid = PCMCIABUS_CHIPNO(unit); - - if (chipid < 0 || chipid >= pcmciabus_cd.cd_ndevs) - return ENXIO; - - pcmcia = pcmciabus_cd.cd_devs[chipid]; - if (pcmcia == NULL || pcmcia->sc_driver == NULL) - return ENXIO; - link = pcmcia->sc_link[slot]; - if (!link) - return ENXIO; - - if (ISSET(link->flags, PCMCIA_SLOT_OPEN)) - return EBUSY; - - SET(link->flags, PCMCIA_SLOT_OPEN); - break; - - default: - return ENXIO; + int reg; - } - return 0; -} + if (pcmcia_chip_io_map(pf->sc->pct, pf->sc->pch, + width, offset, size, pcihp, windowp)) + return (1); + /* + * XXX in the multifunction multi-iospace-per-function case, this + * needs to cooperate with io_alloc to make sure that the spaces + * don't overlap, and that the ccr's are set correctly + */ -int -pcmciaclose(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; - int s; - - PPRINTF(("- pcmciabusclose\n")); - switch (PCMCIABUS_DEVTYPE(unit)) { - case PCMCIABUS_BUS: - busopen = 0; - break; - - case PCMCIABUS_CHIP: - chipid = PCMCIABUS_CHIPID(unit); - chipopen[chipid] = 0; - break; - - case 0: - slot = PCMCIABUS_SLOT(unit); - chipid = PCMCIABUS_CHIPNO(unit); - pcmcia = pcmciabus_cd.cd_devs[chipid]; - link = pcmcia->sc_link[slot]; - - s = splclock(); - CLR(link->flags, (PCMCIA_SLOT_OPEN|PCMCIA_SLOT_EVENT)); - splx(s); - break; - - default: - return ENXIO; - } - return 0; -} + if (pcmcia_mfc(pf->sc)) { + long tmp, iosize; -int -pcmciachip_ioctl(chipid, cmd, data) - int chipid, cmd; - caddr_t data; -{ - struct pcmciabus_softc *pcmcia = pcmciabus_cd.cd_devs[chipid]; - struct pcmcia_adapter *pca = pcmcia->sc_driver; - 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 = 0; - return PCMCIA_SERVICE(pca, &link, PCMCIA_OP_GETREGS, - pi->chip_data, 0); + if (pf->pf_mfc_iomax == 0) { + pf->pf_mfc_iobase = pcihp->addr + offset; + pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; + } else { + /* this makes the assumption that nothing overlaps */ + if (pf->pf_mfc_iobase > pcihp->addr + offset) + pf->pf_mfc_iobase = pcihp->addr + offset; + if (pf->pf_mfc_iomax < pcihp->addr + offset + size) + pf->pf_mfc_iomax = pcihp->addr + offset + size; + } + + tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; + /* round up to nearest (2^n)-1 */ + for (iosize = 1; iosize >= tmp; iosize <<= 1) + ; + iosize--; + + pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0, + pf->pf_mfc_iobase & 0xff); + pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1, + (pf->pf_mfc_iobase >> 8) & 0xff); + pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2, 0); + pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3, 0); + + pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE, iosize); + + reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); + reg |= PCMCIA_CCR_OPTION_ADDR_DECODE; + pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); } - return ENOTTY; + return (0); } -int -pcmciaslot_ioctl(link, slotid, cmd, data) - struct pcmcia_link *link; - int slotid, cmd; - caddr_t data; +void * +pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg) + struct pcmcia_function *pf; + int ipl; + int (*ih_fct) __P((void *)); + void *ih_arg; { - int err = 0; - struct pcmciabus_softc *pcmcia = - pcmciabus_cd.cd_devs[PCMCIABUS_CHIPNO(slotid)]; - struct pcmcia_adapter *pca = pcmcia->sc_driver; - - 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) { - if (ISSET(link->flags, CARD_IS_MAPPED)) - SET(pi->status, PCMCIA_CARD_IS_MAPPED); - if (ISSET(link->flags, PCMCIA_SLOT_INUSE)) - SET(pi->status, PCMCIA_CARD_INUSE); - } - return err; - } + void *ret; - 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 (!ISSET(status, PCMCIA_CARD_PRESENT)) - return ENODEV; - pi->slot = slotid; - return pcmcia_read_cis(link, pi->cis_data, 0, - CIS_MAXSIZE); - } + /* behave differently if this is a multifunction card */ - case PCMCIAIO_CONFIGURE: - { - struct pcmcia_conf *pc_cf = (void *) data; - return pcmcia_mapcard_and_configure(link, -1, pc_cf); - } + if (pcmcia_mfc(pf->sc)) { + int s, ihcnt, hiipl, reg; + struct pcmcia_function *pf2; + + /* + * mask all the ipl's which are already used by this card, + * and find the highest ipl number (lowest priority) + */ - case PCMCIAIO_UNCONFIGURE: - return pcmcia_unconfigure(link); - - case PCMCIAIO_UNMAP: - if (ISSET(link->flags, PCMCIA_SLOT_INUSE)) - return EBUSY; - 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; + ihcnt = 0; + s = 0; /* this is only here to keep the compiler + happy */ + hiipl = 0; /* this is only here to keep the compiler + happy */ + + for (pf2 = pf->sc->card.pf_head.sqh_first; pf2 != NULL; + pf2 = pf2->pf_list.sqe_next) { + if (pf2->ih_fct) { + DPRINTF(("%s: function %d has ih_fct %p\n", + pf->sc->dev.dv_xname, pf2->number, + pf2->ih_fct)); + + if (ihcnt == 0) { + hiipl = pf2->ih_ipl; + } else { + if (pf2->ih_ipl > hiipl) + hiipl = pf2->ih_ipl; } - return 0; - default: - return EINVAL; + ihcnt++; } } - case PCMCIAIO_READ_COR: - { - struct pcmcia_info *pi = (void *)data; - struct pcmcia_conf pc_cf; - int status,s; + /* + * establish the real interrupt, changing the ipl if + * necessary + */ - err = PCMCIA_SERVICE(pca, link, PCMCIA_OP_STATUS, - &status, 0); - if (err) - return err; - if (!ISSET(status, PCMCIA_CARD_PRESENT)) - return ENODEV; + if (ihcnt == 0) { +#ifdef DIAGNOSTIC + if (pf->sc->ih != NULL) + panic("card has intr handler, but no function does"); +#endif + s = splhigh(); - if ((status = pcmcia_read_cis(link, pi->cis_data, 0, - CIS_MAXSIZE))) - return status; + /* set up the handler for the new function */ - bzero(&pc_cf, sizeof(pc_cf)); - if (pcmcia_get_cf(link, pi->cis_data, - sizeof(pi->cis_data), -1, - &pc_cf) != 0 ) - return EIO; + pf->ih_fct = ih_fct; + pf->ih_arg = ih_arg; + pf->ih_ipl = ipl; - s=splbio(); + pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct, + pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc); + splx(s); + } else if (ipl > hiipl) { +#ifdef DIAGNOSTIC + if (pf->sc->ih == NULL) + panic("functions have ih, but the card does not"); +#endif - while(SCRATCH_INUSE(pca)) - sleep((caddr_t)&SCRATCH_INUSE(pca), PZERO - 1); + /* XXX need #ifdef for splserial on x86 */ + s = splhigh(); + + pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, + pf->sc->ih); + + /* set up the handler for the new function */ + pf->ih_fct = ih_fct; + pf->ih_arg = ih_arg; + pf->ih_ipl = ipl; + + pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct, + pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc); - SCRATCH_INUSE(pca) = 1; splx(s); - if ((err = PCMCIA_MAP_MEM(pca, link, - SCRATCH_MEMT(pca), - 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_MEMT(pca), - SCRATCH_MEM(pca), - 0,SCRATCH_SIZE(pca), - PCMCIA_LAST_WIN|PCMCIA_UNMAP); - } - s = splbio(); - SCRATCH_INUSE(pca)=0; - wakeup((caddr_t)&SCRATCH_INUSE(pca)); + } else { + s = splhigh(); + + /* set up the handler for the new function */ + + pf->ih_fct = ih_fct; + pf->ih_arg = ih_arg; + pf->ih_ipl = ipl; + splx(s); - return err; } - default: - return ENOTTY; + + ret = pf->sc->ih; + + if (ret != NULL) { + reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); + reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE; + pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); + + reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS); + reg |= PCMCIA_CCR_STATUS_INTRACK; + pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg); + } + } else { + ret = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch, + pf, ipl, ih_fct, ih_arg); } - return ENOTTY; + + return (ret); } -int -pcmciaioctl(dev, cmd, data, flag, p) - dev_t dev; - u_long cmd; - caddr_t data; - int flag; - struct proc *p; +void +pcmcia_intr_disestablish(pf, ih) + struct pcmcia_function *pf; + void *ih; { - int unit = PCMCIABUS_UNIT(dev); - int chipid = PCMCIABUS_CHIPNO(unit); - struct pcmciabus_softc *pcmcia; - struct pcmcia_link *link; + /* behave differently if this is a multifunction card */ - PPRINTF(("- pcmciabusioctl\n")); - if (chipid < 0 || chipid >= pcmciabus_cd.cd_ndevs) - return ENXIO; + if (pcmcia_mfc(pf->sc)) { + int s, ihcnt, hiipl; + struct pcmcia_function *pf2; - pcmcia = pcmciabus_cd.cd_devs[chipid]; - if (pcmcia == NULL) - return ENXIO; + /* + * mask all the ipl's which are already used by this card, + * and find the highest ipl number (lowest priority). Skip + * the current function. + */ - switch (PCMCIABUS_DEVTYPE(unit)) { -#if 0 - case PCMCIABUS_BUS: - return pcmciabus_ioctl(PCMCIABUS_BUSID(unit), cmd, data); + ihcnt = 0; + s = 0; /* this is only here to keep the compipler + happy */ + hiipl = 0; /* this is only here to keep the compipler + happy */ + + for (pf2 = pf->sc->card.pf_head.sqh_first; pf2 != NULL; + pf2 = pf2->pf_list.sqe_next) { + if (pf2 == pf) + continue; + + if (pf2->ih_fct) { + if (ihcnt == 0) { + hiipl = pf2->ih_ipl; + } else { + if (pf2->ih_ipl > hiipl) + hiipl = pf2->ih_ipl; + } + ihcnt++; + } + } + + /* + * if the ih being removed is lower priority than the lowest + * priority remaining interrupt, up the priority. + */ + + /* ihcnt is the number of interrupt handlers *not* including + the one about to be removed. */ + + if (ihcnt == 0) { + int reg; + +#ifdef DIAGNOSTIC + if (pf->sc->ih == NULL) + panic("disestablishing last function, but card has no ih"); #endif - case PCMCIABUS_CHIP: - return pcmciachip_ioctl(PCMCIABUS_CHIPID(unit), cmd, data); - case 0: - link = pcmcia->sc_link[PCMCIABUS_SLOT(unit)]; - return pcmciaslot_ioctl(link, PCMCIABUS_SLOTID(unit), - cmd, data); - default: - return ENXIO; - } -} + pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, + pf->sc->ih); -int -pcmciaselect(device, rw, p) - dev_t device; - int rw; - struct proc *p; -{ - int s; - int unit = PCMCIABUS_UNIT(device); - int chipid = PCMCIABUS_CHIPNO(unit); - struct pcmciabus_softc *pcmcia; - struct pcmcia_link *link; - - PPRINTF(("- pcmciabus_select\n")); - pcmcia = pcmciabus_cd.cd_devs[chipid]; - - switch (PCMCIABUS_DEVTYPE(unit)) { - case 0: - link = pcmcia->sc_link[PCMCIABUS_SLOT(unit)]; - break; - case PCMCIABUS_BUS: - case PCMCIABUS_CHIP: - default: - return 0; - } + reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); + reg &= ~PCMCIA_CCR_OPTION_IREQ_ENABLE; + pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); + + pf->ih_fct = NULL; + pf->ih_arg = NULL; + + pf->sc->ih = NULL; + } else if (pf->ih_ipl > hiipl) { +#ifdef DIAGNOSTIC + if (pf->sc->ih == NULL) + panic("changing ih ipl, but card has no ih"); +#endif + /* XXX need #ifdef for splserial on x86 */ + s = splhigh(); + + pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, + pf->sc->ih); + pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct, + pf->sc->pch, pf, hiipl, pcmcia_card_intr, pf->sc); + + /* null out the handler for this function */ + + pf->ih_fct = NULL; + pf->ih_arg = NULL; + + splx(s); + } else { + s = splhigh(); + + pf->ih_fct = NULL; + pf->ih_arg = NULL; - s = splpcmcia(); - switch (rw) { - case FREAD: - case FWRITE: - break; - case 0: - if (ISSET(link->flags, PCMCIA_SLOT_EVENT)) { - CLR(link->flags, PCMCIA_SLOT_EVENT); splx(s); - return 1; } - selrecord(p, &link->pcmcialink_sel); - break; + } else { + pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih); } - splx(s); - return 0; } -int -pcmciammap(dev, offset, nprot) - dev_t dev; - int offset, nprot; +int +pcmcia_card_intr(arg) + void *arg; { - return ENXIO; -} + struct pcmcia_softc *sc = arg; + struct pcmcia_function *pf; + int reg, ret, ret2; + ret = 0; -#ifdef PCMCIA_DEBUG -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("IRQ mask %x\n", cf->irq_mask); - 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); - } -} + for (pf = sc->card.pf_head.sqh_first; pf != NULL; + pf = pf->pf_list.sqe_next) { +#if 0 + printf("%s: intr flags=%x fct=%d physaddr=%lx cor=%02x csr=%02x pin=%02x", + sc->dev.dv_xname, pf->pf_flags, pf->number, + pmap_extract(pmap_kernel(), + (vaddr_t) pf->pf_ccrh) + pf->pf_ccr_offset, + pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION), + pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS), + pcmcia_ccr_read(pf, PCMCIA_CCR_PIN)); #endif - -int -pcmcia_print(aux, pnp) - void *aux; - const char *pnp; -{ + if (pf->ih_fct != NULL && + (pf->ccr_mask & (1 << (PCMCIA_CCR_STATUS / 2)))) { + reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS); + if (reg & PCMCIA_CCR_STATUS_INTR) { + ret2 = (*pf->ih_fct)(pf->ih_arg); + if (ret2 != 0 && ret == 0) + ret = ret2; + reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS); #if 0 - struct pcmcia_attach_args *paa = aux; - printf(" slot %d", paa->paa_link->slot); + printf("; csr %02x->%02x", + reg, reg & ~PCMCIA_CCR_STATUS_INTR); #endif - return (0); /* be silent */ -} - -/* - * Filter out inappropriate configurations before heading off to - * the device match routines. - */ -int -pcmcia_submatch(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct device *self = match; - struct cfdata *cf = self->dv_cfdata; - struct pcmcia_attach_args *paa = aux; - struct pcmcia_link *link = paa->paa_link; - + pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, + reg & ~PCMCIA_CCR_STATUS_INTR); + } + } #if 0 - printf("pcmcia_submatch: paa=%p link=%p, cf=%p\n", paa, link, cf); - delay(2000000); - + printf("\n"); #endif - - if (cf->cf_loc[6] != -1 && link->slot != cf->cf_loc[6]) { - printf("slot mismatch: %d cf_loc %d\n", link->slot, - cf->cf_loc[6]); - return 0; } - return ((*cf->cf_attach->ca_match)(parent, match, aux)); + return (ret); } diff --git a/sys/dev/pcmcia/pcmcia_cis.c b/sys/dev/pcmcia/pcmcia_cis.c new file mode 100644 index 00000000000..1653f1aea6d --- /dev/null +++ b/sys/dev/pcmcia/pcmcia_cis.c @@ -0,0 +1,1196 @@ +/* $OpenBSD: pcmcia_cis.c,v 1.1 1998/09/11 10:47:15 fgsch Exp $ */ +/* $NetBSD: pcmcia_cis.c,v 1.9 1998/08/22 23:41:48 msaitoh Exp $ */ + +/* + * Copyright (c) 1997 Marc Horowitz. 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 Marc Horowitz. + * 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. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciachip.h> +#include <dev/pcmcia/pcmciavar.h> + +#ifdef PCMCIACISDEBUG +int pcmciacis_debug = 1; +#define DPRINTF(arg) if (pcmciacis_debug) printf arg +#else +#define DPRINTF(arg) +#endif + +#define PCMCIA_CIS_SIZE 1024 + +struct cis_state { + int count; + int gotmfc; + struct pcmcia_config_entry temp_cfe; + struct pcmcia_config_entry *default_cfe; + struct pcmcia_card *card; + struct pcmcia_function *pf; +}; + +int pcmcia_parse_cis_tuple __P((struct pcmcia_tuple *, void *)); + +void +pcmcia_read_cis(sc) + struct pcmcia_softc *sc; +{ + struct cis_state state; + + state.count = 0; + state.gotmfc = 0; + + state.card = &sc->card; + + state.card->error = 0; + state.card->cis1_major = -1; + state.card->cis1_minor = -1; + state.card->cis1_info[0] = NULL; + state.card->cis1_info[1] = NULL; + state.card->cis1_info[2] = NULL; + state.card->cis1_info[3] = NULL; + state.card->manufacturer = PCMCIA_VENDOR_INVALID; + state.card->product = PCMCIA_PRODUCT_INVALID; + SIMPLEQ_INIT(&state.card->pf_head); + + state.pf = NULL; + + if (pcmcia_scan_cis((struct device *)sc, pcmcia_parse_cis_tuple, + &state) == -1) + state.card->error++; +} + +int +pcmcia_scan_cis(dev, fct, arg) + struct device *dev; + int (*fct) __P((struct pcmcia_tuple *, void *)); + void *arg; +{ + struct pcmcia_softc *sc = (struct pcmcia_softc *) dev; + pcmcia_chipset_tag_t pct; + pcmcia_chipset_handle_t pch; + int window; + struct pcmcia_mem_handle pcmh; + struct pcmcia_tuple tuple; + int longlink_present; + int longlink_common; + u_long longlink_addr; + int mfc_count; + int mfc_index; + struct { + int common; + u_long addr; + } mfc[256 / 5]; + int ret; + + ret = 0; + + pct = sc->pct; + pch = sc->pch; + + /* allocate some memory */ + + if (pcmcia_chip_mem_alloc(pct, pch, PCMCIA_CIS_SIZE, &pcmh)) { +#ifdef DIAGNOSTIC + printf("%s: can't alloc memory to read attributes\n", + sc->dev.dv_xname); +#endif + return -1; + } + tuple.memt = pcmh.memt; + tuple.memh = pcmh.memh; + + /* initialize state for the primary tuple chain */ + if (pcmcia_chip_mem_map(pct, pch, PCMCIA_MEM_ATTR, 0, + PCMCIA_CIS_SIZE, &pcmh, &tuple.ptr, &window)) { + pcmcia_chip_mem_free(pct, pch, &pcmh); +#ifdef DIAGNOSTIC + printf("%s: can't map memory to read attributes\n", + sc->dev.dv_xname); +#endif + return -1; + } + DPRINTF(("cis mem map %x\n", (unsigned int) tuple.memh)); + + tuple.mult = 2; + + longlink_present = 1; + longlink_common = 1; + longlink_addr = 0; + + mfc_count = 0; + mfc_index = 0; + + DPRINTF(("%s: CIS tuple chain:\n", sc->dev.dv_xname)); + + while (1) { + while (1) { + /* get the tuple code */ + + tuple.code = pcmcia_cis_read_1(&tuple, tuple.ptr); + + /* two special-case tuples */ + + if (tuple.code == PCMCIA_CISTPL_NULL) { + DPRINTF(("CISTPL_NONE\n 00\n")); + tuple.ptr++; + continue; + } else if (tuple.code == PCMCIA_CISTPL_END) { + DPRINTF(("CISTPL_END\n ff\n")); + /* Call the function for the END tuple, since + the CIS semantics depend on it */ + if ((*fct) (&tuple, arg)) { + pcmcia_chip_mem_unmap(pct, pch, + window); + ret = 1; + goto done; + } + tuple.ptr++; + break; + } + /* now all the normal tuples */ + + tuple.length = pcmcia_cis_read_1(&tuple, tuple.ptr + 1); + switch (tuple.code) { + case PCMCIA_CISTPL_LONGLINK_A: + case PCMCIA_CISTPL_LONGLINK_C: + if (tuple.length < 4) { + DPRINTF(("CISTPL_LONGLINK_%s too " + "short %d\n", + longlink_common ? "C" : "A", + tuple.length)); + break; + } + longlink_present = 1; + longlink_common = (tuple.code == + PCMCIA_CISTPL_LONGLINK_C) ? 1 : 0; + longlink_addr = pcmcia_tuple_read_4(&tuple, 0); + DPRINTF(("CISTPL_LONGLINK_%s %lx\n", + longlink_common ? "C" : "A", + longlink_addr)); + break; + case PCMCIA_CISTPL_NO_LINK: + longlink_present = 0; + DPRINTF(("CISTPL_NO_LINK\n")); + break; + case PCMCIA_CISTPL_CHECKSUM: + if (tuple.length < 5) { + DPRINTF(("CISTPL_CHECKSUM too " + "short %d\n", tuple.length)); + break; + } { + int16_t offset; + u_long addr, length; + u_int cksum, sum; + int i; + + *((u_int16_t *) & offset) = + pcmcia_tuple_read_2(&tuple, 0); + length = pcmcia_tuple_read_2(&tuple, 2); + cksum = pcmcia_tuple_read_1(&tuple, 4); + + addr = tuple.ptr + offset; + + DPRINTF(("CISTPL_CHECKSUM addr=%lx " + "len=%lx cksum=%x", + addr, length, cksum)); + + /* + * XXX do more work to deal with + * distant regions + */ + if ((addr >= PCMCIA_CIS_SIZE) || + ((addr + length) < 0) || + ((addr + length) >= + PCMCIA_CIS_SIZE)) { + DPRINTF((" skipped, " + "too distant\n")); + break; + } + sum = 0; + for (i = 0; i < length; i++) + sum += + bus_space_read_1(tuple.memt, + tuple.memh, + addr + tuple.mult * i); + if (cksum != (sum & 0xff)) { + DPRINTF((" failed sum=%x\n", + sum)); + printf("%s: CIS checksum " + "failed\n", + sc->dev.dv_xname); +#if 0 + /* + * XXX Some working cards have + * XXX bad checksums!! + */ + ret = -1; +#endif + } else { + DPRINTF((" ok\n")); + } + } + break; + case PCMCIA_CISTPL_LONGLINK_MFC: + if (tuple.length < 1) { + DPRINTF(("CISTPL_LONGLINK_MFC too " + "short %d\n", tuple.length)); + break; + } + /* + * this is kind of ad hoc, as I don't have + * any real documentation + */ + { + int i; + + mfc_count = + pcmcia_tuple_read_1(&tuple, 0); + DPRINTF(("CISTPL_LONGLINK_MFC %d", + mfc_count)); + for (i = 0; i < mfc_count; i++) { + mfc[i].common = + (pcmcia_tuple_read_1(&tuple, + 1 + 5 * i) == + PCMCIA_MFC_MEM_COMMON) ? + 1 : 0; + mfc[i].addr = + pcmcia_tuple_read_4(&tuple, + 1 + 5 * i + 1); + DPRINTF((" %s:%lx", + mfc[i].common ? "common" : + "attr", mfc[i].addr)); + } + DPRINTF(("\n")); + } + /* + * for LONGLINK_MFC, fall through to the + * function. This tuple has structural and + * semantic content. + */ + default: + { + if ((*fct) (&tuple, arg)) { + pcmcia_chip_mem_unmap(pct, + pch, window); + ret = 1; + goto done; + } + } + break; + } /* switch */ +#ifdef PCMCIACISDEBUG + /* print the tuple */ + { + int i; + + DPRINTF((" %02x %02x", tuple.code, + tuple.length)); + + for (i = 0; i < tuple.length; i++) { + DPRINTF((" %02x", + pcmcia_tuple_read_1(&tuple, i))); + if ((i % 16) == 13) + DPRINTF(("\n")); + } + if ((i % 16) != 14) + DPRINTF(("\n")); + } +#endif + /* skip to the next tuple */ + tuple.ptr += 2 + tuple.length; + } + /* + * the chain is done. Clean up and move onto the next one, + * if any. The loop is here in the case that there is an MFC + * card with no longlink (which defaults to existing, == 0). + * In general, this means that if one pointer fails, it will + * try the next one, instead of just bailing. + */ + + while (1) { + pcmcia_chip_mem_unmap(pct, pch, window); + + if (longlink_present) { + /* + * if the longlink is to attribute memory, + * then it is unindexed. That is, if the + * link value is 0x100, then the actual + * memory address is 0x200. This means that + * we need to multiply by 2 before calling + * mem_map, and then divide the resulting ptr + * by 2 after. + */ + + if (!longlink_common) + longlink_addr *= 2; + + pcmcia_chip_mem_map(pct, pch, longlink_common ? + PCMCIA_MEM_COMMON : PCMCIA_MEM_ATTR, + longlink_addr, PCMCIA_CIS_SIZE, + &pcmh, &tuple.ptr, &window); + + if (!longlink_common) + tuple.ptr /= 2; + + DPRINTF(("cis mem map %x\n", + (unsigned int) tuple.memh)); + + tuple.mult = longlink_common ? 1 : 2; + longlink_present = 0; + longlink_common = 1; + longlink_addr = 0; + } else if (mfc_count && (mfc_index < mfc_count)) { + if (!mfc[mfc_index].common) + mfc[mfc_index].addr *= 2; + + pcmcia_chip_mem_map(pct, pch, + mfc[mfc_index].common ? + PCMCIA_MEM_COMMON : PCMCIA_MEM_ATTR, + mfc[mfc_index].addr, PCMCIA_CIS_SIZE, + &pcmh, &tuple.ptr, &window); + + if (!mfc[mfc_index].common) + tuple.ptr /= 2; + + DPRINTF(("cis mem map %x\n", + (unsigned int) tuple.memh)); + + /* set parse state, and point at the next one */ + + tuple.mult = mfc[mfc_index].common ? 1 : 2; + + mfc_index++; + } else { + goto done; + } + + /* make sure that the link is valid */ + tuple.code = pcmcia_cis_read_1(&tuple, tuple.ptr); + if (tuple.code != PCMCIA_CISTPL_LINKTARGET) { + DPRINTF(("CISTPL_LINKTARGET expected, " + "code %02x observed\n", tuple.code)); + continue; + } + tuple.length = pcmcia_cis_read_1(&tuple, tuple.ptr + 1); + if (tuple.length < 3) { + DPRINTF(("CISTPL_LINKTARGET too short %d\n", + tuple.length)); + continue; + } + if ((pcmcia_tuple_read_1(&tuple, 0) != 'C') || + (pcmcia_tuple_read_1(&tuple, 1) != 'I') || + (pcmcia_tuple_read_1(&tuple, 2) != 'S')) { + DPRINTF(("CISTPL_LINKTARGET magic " + "%02x%02x%02x incorrect\n", + pcmcia_tuple_read_1(&tuple, 0), + pcmcia_tuple_read_1(&tuple, 1), + pcmcia_tuple_read_1(&tuple, 2))); + continue; + } + tuple.ptr += 2 + tuple.length; + + break; + } + } + + pcmcia_chip_mem_unmap(pct, pch, window); + +done: + /* Last, free the allocated memory block */ + pcmcia_chip_mem_free(pct, pch, &pcmh); + + return (ret); +} + +/* XXX this is incredibly verbose. Not sure what trt is */ + +void +pcmcia_print_cis(sc) + struct pcmcia_softc *sc; +{ + struct pcmcia_card *card = &sc->card; + struct pcmcia_function *pf; + struct pcmcia_config_entry *cfe; + int i; + + printf("%s: CIS version ", sc->dev.dv_xname); + if (card->cis1_major == 4) { + if (card->cis1_minor == 0) + printf("PCMCIA 1.0\n"); + else if (card->cis1_minor == 1) + printf("PCMCIA 2.0 or 2.1\n"); + } else if (card->cis1_major >= 5) + printf("PC Card Standard %d.%d\n", card->cis1_major, card->cis1_minor); + else + printf("unknown (major=%d, minor=%d)\n", + card->cis1_major, card->cis1_minor); + + printf("%s: CIS info: ", sc->dev.dv_xname); + for (i = 0; i < 4; i++) { + if (card->cis1_info[i] == NULL) + break; + if (i) + printf(", "); + printf("%s", card->cis1_info[i]); + } + printf("\n"); + + printf("%s: Manufacturer code 0x%x, product 0x%x\n", + sc->dev.dv_xname, card->manufacturer, card->product); + + for (pf = card->pf_head.sqh_first; pf != NULL; + pf = pf->pf_list.sqe_next) { + printf("%s: function %d: ", sc->dev.dv_xname, pf->number); + + switch (pf->function) { + case PCMCIA_FUNCTION_UNSPEC: + printf("unspecified"); + break; + case PCMCIA_FUNCTION_MULTIFUNCTION: + printf("multi-function"); + break; + case PCMCIA_FUNCTION_MEMORY: + printf("memory"); + break; + case PCMCIA_FUNCTION_SERIAL: + printf("serial port"); + break; + case PCMCIA_FUNCTION_PARALLEL: + printf("parallel port"); + break; + case PCMCIA_FUNCTION_DISK: + printf("fixed disk"); + break; + case PCMCIA_FUNCTION_VIDEO: + printf("video adapter"); + break; + case PCMCIA_FUNCTION_NETWORK: + printf("network adapter"); + break; + case PCMCIA_FUNCTION_AIMS: + printf("auto incrementing mass storage"); + break; + case PCMCIA_FUNCTION_SCSI: + printf("SCSI bridge"); + break; + case PCMCIA_FUNCTION_SECURITY: + printf("Security services"); + break; + case PCMCIA_FUNCTION_INSTRUMENT: + printf("Instrument"); + break; + default: + printf("unknown (%d)", pf->function); + break; + } + + printf(", ccr addr %lx mask %lx\n", pf->ccr_base, pf->ccr_mask); + + for (cfe = pf->cfe_head.sqh_first; cfe != NULL; + cfe = cfe->cfe_list.sqe_next) { + printf("%s: function %d, config table entry %d: ", + sc->dev.dv_xname, pf->number, cfe->number); + + switch (cfe->iftype) { + case PCMCIA_IFTYPE_MEMORY: + printf("memory card"); + break; + case PCMCIA_IFTYPE_IO: + printf("I/O card"); + break; + default: + printf("card type unknown"); + break; + } + + printf("; irq mask %x", cfe->irqmask); + + if (cfe->num_iospace) { + printf("; iomask %lx, iospace", cfe->iomask); + + for (i = 0; i < cfe->num_iospace; i++) + printf(" %lx%s%lx", + cfe->iospace[i].start, + cfe->iospace[i].length ? "-" : "", + cfe->iospace[i].start + + cfe->iospace[i].length - 1); + } + if (cfe->num_memspace) { + printf("; memspace"); + + for (i = 0; i < cfe->num_memspace; i++) + printf(" %lx%s%lx%s%lx", + cfe->memspace[i].cardaddr, + cfe->memspace[i].length ? "-" : "", + cfe->memspace[i].cardaddr + + cfe->memspace[i].length - 1, + cfe->memspace[i].hostaddr ? + "@" : "", + cfe->memspace[i].hostaddr); + } + if (cfe->maxtwins) + printf("; maxtwins %d", cfe->maxtwins); + + printf(";"); + + if (cfe->flags & PCMCIA_CFE_MWAIT_REQUIRED) + printf(" mwait_required"); + if (cfe->flags & PCMCIA_CFE_RDYBSY_ACTIVE) + printf(" rdybsy_active"); + if (cfe->flags & PCMCIA_CFE_WP_ACTIVE) + printf(" wp_active"); + if (cfe->flags & PCMCIA_CFE_BVD_ACTIVE) + printf(" bvd_active"); + if (cfe->flags & PCMCIA_CFE_IO8) + printf(" io8"); + if (cfe->flags & PCMCIA_CFE_IO16) + printf(" io16"); + if (cfe->flags & PCMCIA_CFE_IRQSHARE) + printf(" irqshare"); + if (cfe->flags & PCMCIA_CFE_IRQPULSE) + printf(" irqpulse"); + if (cfe->flags & PCMCIA_CFE_IRQLEVEL) + printf(" irqlevel"); + if (cfe->flags & PCMCIA_CFE_POWERDOWN) + printf(" powerdown"); + if (cfe->flags & PCMCIA_CFE_READONLY) + printf(" readonly"); + if (cfe->flags & PCMCIA_CFE_AUDIO) + printf(" audio"); + + printf("\n"); + } + } + + if (card->error) + printf("%s: %d errors found while parsing CIS\n", + sc->dev.dv_xname, card->error); +} + +int +pcmcia_parse_cis_tuple(tuple, arg) + struct pcmcia_tuple *tuple; + void *arg; +{ + /* most of these are educated guesses */ + static struct pcmcia_config_entry init_cfe = { + -1, PCMCIA_CFE_RDYBSY_ACTIVE | PCMCIA_CFE_WP_ACTIVE | + PCMCIA_CFE_BVD_ACTIVE, PCMCIA_IFTYPE_MEMORY, + }; + + struct cis_state *state = arg; + + switch (tuple->code) { + case PCMCIA_CISTPL_END: + /* if we've seen a LONGLINK_MFC, and this is the first + * END after it, reset the function list. + * + * XXX This might also be the right place to start a + * new function, but that assumes that a function + * definition never crosses any longlink, and I'm not + * sure about that. This is probably safe for MFC + * cards, but what we have now isn't broken, so I'd + * rather not change it. + */ + if (state->gotmfc == 1) { + struct pcmcia_function *pf, *pfnext; + + for (pf = state->card->pf_head.sqh_first; pf != NULL; + pf = pfnext) { + pfnext = pf->pf_list.sqe_next; + free(pf, M_DEVBUF); + } + + SIMPLEQ_INIT(&state->card->pf_head); + + state->count = 0; + state->gotmfc = 2; + state->pf = NULL; + } + break; + case PCMCIA_CISTPL_LONGLINK_MFC: + /* + * this tuple's structure was dealt with in scan_cis. here, + * record the fact that the MFC tuple was seen, so that + * functions declared before the MFC link can be cleaned + * up. + */ + state->gotmfc = 1; + break; +#ifdef PCMCIACISDEBUG + case PCMCIA_CISTPL_DEVICE: + case PCMCIA_CISTPL_DEVICE_A: + { + u_int reg, dtype, dspeed; + + reg = pcmcia_tuple_read_1(tuple, 0); + dtype = reg & PCMCIA_DTYPE_MASK; + dspeed = reg & PCMCIA_DSPEED_MASK; + + DPRINTF(("CISTPL_DEVICE%s type=", + (tuple->code == PCMCIA_CISTPL_DEVICE) ? "" : "_A")); + switch (dtype) { + case PCMCIA_DTYPE_NULL: + DPRINTF(("null")); + break; + case PCMCIA_DTYPE_ROM: + DPRINTF(("rom")); + break; + case PCMCIA_DTYPE_OTPROM: + DPRINTF(("otprom")); + break; + case PCMCIA_DTYPE_EPROM: + DPRINTF(("eprom")); + break; + case PCMCIA_DTYPE_EEPROM: + DPRINTF(("eeprom")); + break; + case PCMCIA_DTYPE_FLASH: + DPRINTF(("flash")); + break; + case PCMCIA_DTYPE_SRAM: + DPRINTF(("sram")); + break; + case PCMCIA_DTYPE_DRAM: + DPRINTF(("dram")); + break; + case PCMCIA_DTYPE_FUNCSPEC: + DPRINTF(("funcspec")); + break; + case PCMCIA_DTYPE_EXTEND: + DPRINTF(("extend")); + break; + default: + DPRINTF(("reserved")); + break; + } + DPRINTF((" speed=")); + switch (dspeed) { + case PCMCIA_DSPEED_NULL: + DPRINTF(("null")); + break; + case PCMCIA_DSPEED_250NS: + DPRINTF(("250ns")); + break; + case PCMCIA_DSPEED_200NS: + DPRINTF(("200ns")); + break; + case PCMCIA_DSPEED_150NS: + DPRINTF(("150ns")); + break; + case PCMCIA_DSPEED_100NS: + DPRINTF(("100ns")); + break; + case PCMCIA_DSPEED_EXT: + DPRINTF(("ext")); + break; + default: + DPRINTF(("reserved")); + break; + } + } + DPRINTF(("\n")); + break; +#endif + case PCMCIA_CISTPL_VERS_1: + if (tuple->length < 6) { + DPRINTF(("CISTPL_VERS_1 too short %d\n", + tuple->length)); + break; + } { + int start, i, ch, count; + + state->card->cis1_major = pcmcia_tuple_read_1(tuple, 0); + state->card->cis1_minor = pcmcia_tuple_read_1(tuple, 1); + + for (count = 0, start = 0, i = 0; + (count < 4) && ((i + 4) < 256); i++) { + ch = pcmcia_tuple_read_1(tuple, 2 + i); + if (ch == 0xff) + break; + state->card->cis1_info_buf[i] = ch; + if (ch == 0) { + state->card->cis1_info[count] = + state->card->cis1_info_buf + start; + start = i + 1; + count++; + } + } + DPRINTF(("CISTPL_VERS_1\n")); + } + break; + case PCMCIA_CISTPL_MANFID: + if (tuple->length < 4) { + DPRINTF(("CISTPL_MANFID too short %d\n", + tuple->length)); + break; + } + state->card->manufacturer = pcmcia_tuple_read_2(tuple, 0); + state->card->product = pcmcia_tuple_read_2(tuple, 2); + DPRINTF(("CISTPL_MANFID\n")); + break; + case PCMCIA_CISTPL_FUNCID: + if (tuple->length < 1) { + DPRINTF(("CISTPL_FUNCID too short %d\n", + tuple->length)); + break; + } + if ((state->pf == NULL) || (state->gotmfc == 2)) { + state->pf = malloc(sizeof(*state->pf), M_DEVBUF, + M_NOWAIT); + bzero(state->pf, sizeof(*state->pf)); + state->pf->number = state->count++; + state->pf->last_config_index = -1; + SIMPLEQ_INIT(&state->pf->cfe_head); + + SIMPLEQ_INSERT_TAIL(&state->card->pf_head, state->pf, + pf_list); + } + state->pf->function = pcmcia_tuple_read_1(tuple, 0); + + DPRINTF(("CISTPL_FUNCID\n")); + break; + case PCMCIA_CISTPL_CONFIG: + if (tuple->length < 3) { + DPRINTF(("CISTPL_CONFIG too short %d\n", + tuple->length)); + break; + } { + u_int reg, rasz, rmsz, rfsz; + int i; + + reg = pcmcia_tuple_read_1(tuple, 0); + rasz = 1 + ((reg & PCMCIA_TPCC_RASZ_MASK) >> + PCMCIA_TPCC_RASZ_SHIFT); + rmsz = 1 + ((reg & PCMCIA_TPCC_RMSZ_MASK) >> + PCMCIA_TPCC_RMSZ_SHIFT); + rfsz = ((reg & PCMCIA_TPCC_RFSZ_MASK) >> + PCMCIA_TPCC_RFSZ_SHIFT); + + if (tuple->length < (rasz + rmsz + rfsz)) { + DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too " + "short %d\n", rasz, rmsz, rfsz, + tuple->length)); + break; + } + if (state->pf == NULL) { + state->pf = malloc(sizeof(*state->pf), + M_DEVBUF, M_NOWAIT); + bzero(state->pf, sizeof(*state->pf)); + state->pf->number = state->count++; + state->pf->last_config_index = -1; + SIMPLEQ_INIT(&state->pf->cfe_head); + + SIMPLEQ_INSERT_TAIL(&state->card->pf_head, + state->pf, pf_list); + + state->pf->function = PCMCIA_FUNCTION_UNSPEC; + } + state->pf->last_config_index = + pcmcia_tuple_read_1(tuple, 1); + + state->pf->ccr_base = 0; + for (i = 0; i < rasz; i++) + state->pf->ccr_base |= + ((pcmcia_tuple_read_1(tuple, 2 + i)) << + (i * 8)); + + state->pf->ccr_mask = 0; + for (i = 0; i < rmsz; i++) + state->pf->ccr_mask |= + ((pcmcia_tuple_read_1(tuple, + 2 + rasz + i)) << (i * 8)); + + /* skip the reserved area and subtuples */ + + /* reset the default cfe for each cfe list */ + state->temp_cfe = init_cfe; + state->default_cfe = &state->temp_cfe; + } + DPRINTF(("CISTPL_CONFIG\n")); + break; + case PCMCIA_CISTPL_CFTABLE_ENTRY: + { + int idx, i, j; + u_int reg, reg2; + u_int intface, def, num; + u_int power, timing, iospace, irq, memspace, misc; + struct pcmcia_config_entry *cfe; + + idx = 0; + + reg = pcmcia_tuple_read_1(tuple, idx); + idx++; + intface = reg & PCMCIA_TPCE_INDX_INTFACE; + def = reg & PCMCIA_TPCE_INDX_DEFAULT; + num = reg & PCMCIA_TPCE_INDX_NUM_MASK; + + /* + * this is a little messy. Some cards have only a + * cfentry with the default bit set. So, as we go + * through the list, we add new indexes to the queue, + * and keep a pointer to the last one with the + * default bit set. if we see a record with the same + * index, as the default, we stash the default and + * replace the queue entry. otherwise, we just add + * new entries to the queue, pointing the default ptr + * at them if the default bit is set. if we get to + * the end with the default pointer pointing at a + * record which hasn't had a matching index, that's + * ok; it just becomes a cfentry like any other. + */ + + /* + * if the index in the cis differs from the default + * cis, create new entry in the queue and start it + * with the current default + */ + if (num != state->default_cfe->number) { + cfe = (struct pcmcia_config_entry *) + malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); + + *cfe = *state->default_cfe; + + SIMPLEQ_INSERT_TAIL(&state->pf->cfe_head, + cfe, cfe_list); + + cfe->number = num; + + /* + * if the default bit is set in the cis, then + * point the new default at whatever is being + * filled in + */ + if (def) + state->default_cfe = cfe; + } else { + /* + * the cis index matches the default index, + * fill in the default cfentry. It is + * assumed that the cfdefault index is in the + * queue. For it to be otherwise, the cis + * index would have to be -1 (initial + * condition) which is not possible, or there + * would have to be a preceding cis entry + * which had the same cis index and had the + * default bit unset. Neither condition + * should happen. If it does, this cfentry + * is lost (written into temp space), which + * is an acceptable failure mode. + */ + + cfe = state->default_cfe; + + /* + * if the cis entry does not have the default + * bit set, copy the default out of the way + * first. + */ + if (!def) { + state->temp_cfe = *state->default_cfe; + state->default_cfe = &state->temp_cfe; + } + } + + if (intface) { + reg = pcmcia_tuple_read_1(tuple, idx); + idx++; + if (reg & PCMCIA_TPCE_IF_MWAIT) + cfe->flags |= PCMCIA_CFE_MWAIT_REQUIRED; + if (reg & PCMCIA_TPCE_IF_RDYBSY) + cfe->flags |= PCMCIA_CFE_RDYBSY_ACTIVE; + if (reg & PCMCIA_TPCE_IF_WP) + cfe->flags |= PCMCIA_CFE_WP_ACTIVE; + if (reg & PCMCIA_TPCE_IF_BVD) + cfe->flags |= PCMCIA_CFE_BVD_ACTIVE; + cfe->iftype = reg & PCMCIA_TPCE_IF_IFTYPE; + } + reg = pcmcia_tuple_read_1(tuple, idx); + idx++; + + power = reg & PCMCIA_TPCE_FS_POWER_MASK; + timing = reg & PCMCIA_TPCE_FS_TIMING; + iospace = reg & PCMCIA_TPCE_FS_IOSPACE; + irq = reg & PCMCIA_TPCE_FS_IRQ; + memspace = reg & PCMCIA_TPCE_FS_MEMSPACE_MASK; + misc = reg & PCMCIA_TPCE_FS_MISC; + + if (power) { + /* skip over power, don't save */ + /* for each parameter selection byte */ + for (i = 0; i < power; i++) { + reg = pcmcia_tuple_read_1(tuple, idx); + idx++; + /* for each bit */ + for (j = 0; j < 7; j++) { + /* if the bit is set */ + if ((reg >> j) & 0x01) { + /* skip over bytes */ + do { + reg2 = pcmcia_tuple_read_1(tuple, idx); + idx++; + /* + * until + * non-extensi + * on byte + */ + } while (reg2 & 0x80); + } + } + } + } + if (timing) { + /* skip over timing, don't save */ + reg = pcmcia_tuple_read_1(tuple, idx); + idx++; + + if ((reg & PCMCIA_TPCE_TD_RESERVED_MASK) != + PCMCIA_TPCE_TD_RESERVED_MASK) + idx++; + if ((reg & PCMCIA_TPCE_TD_RDYBSY_MASK) != + PCMCIA_TPCE_TD_RDYBSY_MASK) + idx++; + if ((reg & PCMCIA_TPCE_TD_WAIT_MASK) != + PCMCIA_TPCE_TD_WAIT_MASK) + idx++; + } + if (iospace) { + reg = pcmcia_tuple_read_1(tuple, idx); + idx++; + + if (reg & PCMCIA_TPCE_IO_BUSWIDTH_8BIT) + cfe->flags |= PCMCIA_CFE_IO8; + if (reg & PCMCIA_TPCE_IO_BUSWIDTH_16BIT) + cfe->flags |= PCMCIA_CFE_IO16; + cfe->iomask = + reg & PCMCIA_TPCE_IO_IOADDRLINES_MASK; + + if (reg & PCMCIA_TPCE_IO_HASRANGE) { + reg = pcmcia_tuple_read_1(tuple, idx); + idx++; + + cfe->num_iospace = 1 + (reg & + PCMCIA_TPCE_IO_RANGE_COUNT); + + if (cfe->num_iospace > + (sizeof(cfe->iospace) / + sizeof(cfe->iospace[0]))) { + DPRINTF(("too many io " + "spaces %d", + cfe->num_iospace)); + state->card->error++; + break; + } + for (i = 0; i < cfe->num_iospace; i++) { + switch (reg & PCMCIA_TPCE_IO_RANGE_ADDRSIZE_MASK) { + case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_ONE: + cfe->iospace[i].start = + pcmcia_tuple_read_1(tuple, idx); + idx++; + break; + case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_TWO: + cfe->iospace[i].start = + pcmcia_tuple_read_2(tuple, idx); + idx += 2; + break; + case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_FOUR: + cfe->iospace[i].start = + pcmcia_tuple_read_4(tuple, idx); + idx += 4; + break; + } + switch (reg & + PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_MASK) { + case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_ONE: + cfe->iospace[i].length = + pcmcia_tuple_read_1(tuple, idx); + idx++; + break; + case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_TWO: + cfe->iospace[i].length = + pcmcia_tuple_read_2(tuple, idx); + idx += 2; + break; + case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_FOUR: + cfe->iospace[i].length = + pcmcia_tuple_read_4(tuple, idx); + idx += 4; + break; + } + cfe->iospace[i].length++; + } + } else { + cfe->num_iospace = 1; + cfe->iospace[0].start = 0; + cfe->iospace[0].length = + (1 << cfe->iomask); + } + } + if (irq) { + reg = pcmcia_tuple_read_1(tuple, idx); + idx++; + + if (reg & PCMCIA_TPCE_IR_SHARE) + cfe->flags |= PCMCIA_CFE_IRQSHARE; + if (reg & PCMCIA_TPCE_IR_PULSE) + cfe->flags |= PCMCIA_CFE_IRQPULSE; + if (reg & PCMCIA_TPCE_IR_LEVEL) + cfe->flags |= PCMCIA_CFE_IRQLEVEL; + + if (reg & PCMCIA_TPCE_IR_HASMASK) { + /* + * it's legal to ignore the + * special-interrupt bits, so I will + */ + + cfe->irqmask = + pcmcia_tuple_read_2(tuple, idx); + idx += 2; + } else { + cfe->irqmask = + (1 << (reg & PCMCIA_TPCE_IR_IRQ)); + } + } + if (memspace) { + if (memspace == PCMCIA_TPCE_FS_MEMSPACE_LENGTH) { + cfe->num_memspace = 1; + cfe->memspace[0].length = 256 * + pcmcia_tuple_read_2(tuple, idx); + idx += 2; + cfe->memspace[0].cardaddr = 0; + cfe->memspace[0].hostaddr = 0; + } else if (memspace == + PCMCIA_TPCE_FS_MEMSPACE_LENGTHADDR) { + cfe->num_memspace = 1; + cfe->memspace[0].length = 256 * + pcmcia_tuple_read_2(tuple, idx); + idx += 2; + cfe->memspace[0].cardaddr = 256 * + pcmcia_tuple_read_2(tuple, idx); + idx += 2; + cfe->memspace[0].hostaddr = 0; + } else { + int lengthsize; + int cardaddrsize; + int hostaddrsize; + + reg = pcmcia_tuple_read_1(tuple, idx); + idx++; + + cfe->num_memspace = reg & + PCMCIA_TPCE_MS_COUNT; + + if (cfe->num_memspace > + (sizeof(cfe->memspace) / + sizeof(cfe->memspace[0]))) { + DPRINTF(("too many mem " + "spaces %d", + cfe->num_memspace)); + state->card->error++; + break; + } + lengthsize = + ((reg & PCMCIA_TPCE_MS_LENGTH_SIZE_MASK) >> + PCMCIA_TPCE_MS_LENGTH_SIZE_SHIFT); + cardaddrsize = + ((reg & PCMCIA_TPCE_MS_CARDADDR_SIZE_MASK) >> + PCMCIA_TPCE_MS_CARDADDR_SIZE_SHIFT); + hostaddrsize = + (reg & PCMCIA_TPCE_MS_HOSTADDR) ? cardaddrsize : 0; + + if (lengthsize == 0) { + DPRINTF(("cfe memspace " + "lengthsize == 0")); + state->card->error++; + } + for (i = 0; i < cfe->num_memspace; i++) { + if (lengthsize) { + cfe->memspace[i].length = + 256 * pcmcia_tuple_read_n(tuple, lengthsize, + idx); + idx += lengthsize; + } else { + cfe->memspace[i].length = 0; + } + if (cfe->memspace[i].length == 0) { + DPRINTF(("cfe->memspace[%d].length == 0", + i)); + state->card->error++; + } + if (cardaddrsize) { + cfe->memspace[i].cardaddr = + 256 * pcmcia_tuple_read_n(tuple, cardaddrsize, + idx); + idx += cardaddrsize; + } else { + cfe->memspace[i].cardaddr = 0; + } + if (hostaddrsize) { + cfe->memspace[i].hostaddr = + 256 * pcmcia_tuple_read_n(tuple, hostaddrsize, + idx); + idx += hostaddrsize; + } else { + cfe->memspace[i].hostaddr = 0; + } + } + } + } + if (misc) { + reg = pcmcia_tuple_read_1(tuple, idx); + idx++; + + if (reg & PCMCIA_TPCE_MI_PWRDOWN) + cfe->flags = PCMCIA_CFE_POWERDOWN; + if (reg & PCMCIA_TPCE_MI_READONLY) + cfe->flags = PCMCIA_CFE_READONLY; + if (reg & PCMCIA_TPCE_MI_AUDIO) + cfe->flags = PCMCIA_CFE_AUDIO; + cfe->maxtwins = reg & PCMCIA_TPCE_MI_MAXTWINS; + + while (reg & PCMCIA_TPCE_MI_EXT) { + reg = pcmcia_tuple_read_1(tuple, idx); + idx++; + } + } + /* skip all the subtuples */ + } + DPRINTF(("CISTPL_CFTABLE_ENTRY\n")); + break; + default: + DPRINTF(("unhandled CISTPL %x\n", tuple->code)); + break; + } + + return (0); +} diff --git a/sys/dev/pcmcia/pcmciachip.h b/sys/dev/pcmcia/pcmciachip.h new file mode 100644 index 00000000000..6950c6775e9 --- /dev/null +++ b/sys/dev/pcmcia/pcmciachip.h @@ -0,0 +1,145 @@ +/* $OpenBSD: pcmciachip.h,v 1.1 1998/09/11 10:47:15 fgsch Exp $ */ +/* $NetBSD: pcmciachip.h,v 1.2 1997/10/16 23:27:36 thorpej Exp $ */ + +/* + * Copyright (c) 1997 Marc Horowitz. 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 Marc Horowitz. + * 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. + */ + +#ifndef _PCMCIA_PCMCIACHIP_H_ +#define _PCMCIA_PCMCIACHIP_H_ + +#include <machine/bus.h> + +struct pcmcia_function; +struct pcmcia_mem_handle; +struct pcmcia_io_handle; + +/* interfaces for pcmcia to call the chipset */ + +typedef struct pcmcia_chip_functions *pcmcia_chipset_tag_t; +typedef void *pcmcia_chipset_handle_t; +typedef int pcmcia_mem_handle_t; + +#define PCMCIA_MEM_ATTR 1 +#define PCMCIA_MEM_COMMON 2 + +#define PCMCIA_WIDTH_AUTO 0 +#define PCMCIA_WIDTH_IO8 1 +#define PCMCIA_WIDTH_IO16 2 + +struct pcmcia_chip_functions { + /* memory space allocation */ + int (*mem_alloc) __P((pcmcia_chipset_handle_t, bus_size_t, + struct pcmcia_mem_handle *)); + void (*mem_free) __P((pcmcia_chipset_handle_t, + struct pcmcia_mem_handle *)); + + /* memory space window mapping */ + int (*mem_map) __P((pcmcia_chipset_handle_t, int, bus_addr_t, + bus_size_t, struct pcmcia_mem_handle *, + bus_addr_t *, int *)); + void (*mem_unmap) __P((pcmcia_chipset_handle_t, int)); + + /* I/O space allocation */ + int (*io_alloc) __P((pcmcia_chipset_handle_t, bus_addr_t, + bus_size_t, bus_size_t, struct pcmcia_io_handle *)); + void (*io_free) __P((pcmcia_chipset_handle_t, + struct pcmcia_io_handle *)); + + /* I/O space window mapping */ + int (*io_map) __P((pcmcia_chipset_handle_t, int, bus_addr_t, + bus_size_t, struct pcmcia_io_handle *, int *)); + void (*io_unmap) __P((pcmcia_chipset_handle_t, int)); + + /* interrupt glue */ + void *(*intr_establish) __P((pcmcia_chipset_handle_t, + struct pcmcia_function *, int, int (*)(void *), void *)); + void (*intr_disestablish) __P((pcmcia_chipset_handle_t, void *)); + + /* card enable/disable */ + void (*socket_enable) __P((pcmcia_chipset_handle_t)); + void (*socket_disable) __P((pcmcia_chipset_handle_t)); +}; + +/* Memory space functions. */ +#define pcmcia_chip_mem_alloc(tag, handle, size, pcmhp) \ + ((*(tag)->mem_alloc)((handle), (size), (pcmhp))) + +#define pcmcia_chip_mem_free(tag, handle, pcmhp) \ + ((*(tag)->mem_free)((handle), (pcmhp))) + +#define pcmcia_chip_mem_map(tag, handle, kind, card_addr, size, pcmhp, \ + offsetp, windowp) \ + ((*(tag)->mem_map)((handle), (kind), (card_addr), (size), (pcmhp), \ + (offsetp), (windowp))) + +#define pcmcia_chip_mem_unmap(tag, handle, window) \ + ((*(tag)->mem_unmap)((handle), (window))) + +/* I/O space functions. */ +#define pcmcia_chip_io_alloc(tag, handle, start, size, align, pcihp) \ + ((*(tag)->io_alloc)((handle), (start), (size), (align), (pcihp))) + +#define pcmcia_chip_io_free(tag, handle, pcihp) \ + ((*(tag)->io_free)((handle), (pcihp))) + +#define pcmcia_chip_io_map(tag, handle, width, card_addr, size, pcihp, \ + windowp) \ + ((*(tag)->io_map)((handle), (width), (card_addr), (size), (pcihp), \ + (windowp))) + +#define pcmcia_chip_io_unmap(tag, handle, window) \ + ((*(tag)->io_unmap)((handle), (window))) + +/* Interrupt functions. */ +#define pcmcia_chip_intr_establish(tag, handle, pf, ipl, fct, arg) \ + ((*(tag)->intr_establish)((handle), (pf), (ipl), (fct), (arg))) + +#define pcmcia_chip_intr_disestablish(tag, handle, ih) \ + ((*(tag)->intr_disestablish)((handle), (ih))) + +/* Socket functions. */ +#define pcmcia_chip_socket_enable(tag, handle) \ + ((*(tag)->socket_enable)((handle))) +#define pcmcia_chip_socket_disable(tag, handle) \ + ((*(tag)->socket_disable)((handle))) + +struct pcmciabus_attach_args { + pcmcia_chipset_tag_t pct; + pcmcia_chipset_handle_t pch; + bus_addr_t iobase; /* start i/o space allocation here */ + bus_size_t iosize; /* size of the i/o space range */ +}; + +/* interfaces for the chipset to call pcmcia */ + +int pcmcia_card_attach __P((struct device *)); +void pcmcia_card_detach __P((struct device *)); +int pcmcia_card_gettype __P((struct device *)); + +#endif /* _PCMCIA_PCMCIACHIP_H_ */ diff --git a/sys/dev/pcmcia/pcmciadevs b/sys/dev/pcmcia/pcmciadevs new file mode 100644 index 00000000000..7bbc4091464 --- /dev/null +++ b/sys/dev/pcmcia/pcmciadevs @@ -0,0 +1,129 @@ + $OpenBSD: pcmciadevs,v 1.1 1998/09/11 10:47:15 fgsch Exp $ +/* $NetBSD: pcmciadevs,v 1.13 1998/08/17 23:10:12 thorpej Exp $ */ + +/* + * Copyright (c) 1998, Christos Zoulas + * 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 Christos Zoulas + * for the NetBSD Project. + * 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. + */ + +/* + * List of known PCMCIA vendors + */ + +vendor NEWMEDIA 0x0057 NewMedia Corporation +vendor IBM 0x00a4 IBM Corporation +vendor 3COM 0x0101 3Com Corporation +vendor MEGAHERTZ 0x0102 Megahertz Corporation +vendor SOCKET 0x0104 Socket Communications +vendor TDK 0x0105 TDK Corporation +vendor SMC 0x0108 Standard Microsystems Corporation +vendor MOTOROLA 0x0109 Motorola Corporation +vendor USROBOTICS 0x0115 US Robotics Corporation +vendor MEGAHERTZ2 0x0128 Megahertz Corporation +vendor ADAPTEC 0x012f Adaptec Corporation +vendor LINKSYS 0x0149 Linksys Corporation +vendor SIMPLETECH 0x014d Simple Technology +vendor DAYNA 0x0194 Dayna Corporation +vendor IODATA 0x01bf I-O DATA + +/* + * List of known products. Grouped by vendor. + */ +/* Adaptec Products */ +product ADAPTEC APA1460_1 0x0001 Adaptec APA-1460/A SCSI Host Adapter +product ADAPTEC APA1460_2 0x0002 Adaptec APA-1460/B SCSI Host Adapter + +/* 3COM Products */ +product 3COM 3C562 0x0562 3Com 3c562 33.6 Modem/10Mbps Ethernet +product 3COM 3C589 0x0589 3Com 3c589 10Mbps Ethernet +product 3COM 3C574 0x0574 3Com 3c574-TX 10/100Mbps Ethernet + +/* Dayna Products */ +product DAYNA COMMUNICARD_E 0x002d Dayna CommuniCard E + +/* Motorola Products */ +product MOTOROLA POWER144 0x0105 Motorola Power 14.4 Modem +product MOTOROLA PM100C 0x0302 Motorola Personal Messenger 100C CDPD Modem +product MOTOROLA MONTANA_33.6 0x0505 Motorola Montana 33.6 Fax/Modem + +/* IBM Products */ +product IBM INFOMOVER 0x0002 National Semiconductor InfoMover +product IBM HOME_AND_AWAY 0x002e IBM Home and Away Modem + +/* I-O DATA */ +product IODATA PCLAT 0x2216 I-O DATA PCLA/T + +/* Linksys corporation */ +product LINKSYS ECARD 0x0265 Linksys EthernetCard +product LINKSYS COMBO_ECARD 0xc1ab Linksys Combo EthernetCard +product LINKSYS TRUST_COMBO_ECARD 0x021b Trust (Linksys) Combo EthernetCard + +/* Megahertz Products */ +product MEGAHERTZ XJ4288 0x0023 Megahertz XJ4288 Modem +product MEGAHERTZ2 XJEM1144 0x0101 Megahertz XJEM1144 Ethernet +product MEGAHERTZ2 XJACK 0x0103 Megahertz X-JACK Ethernet + +/* US Robotics Products */ +product USROBOTICS WORLDPORT144 0x3330 US Robotics WorldPort 14.4 Modem + +/* Simple Technology Products */ +product SIMPLETECH COMMUNICATOR288 0x0100 Simple Technology 28.8 Communicator + +/* Socket Communications Products */ +product SOCKET PAGECARD 0x0003 Socket Communications PageCard +product SOCKET DUAL_RS232 0x0012 Socket Communications Dual RS232 + +/* TDK Products */ +product TDK LAK_CD021BX 0x0200 TDK LAK-CD021BX Ethernet +product TDK DFL9610 0x0d0a TDK DFL9610 Ethernet & Digital Cellular + +/* NewMedia Products */ +product NEWMEDIA BASICS 0x0019 NewMedia BASICS Ethernet + +/* Standard Microsystems Corporation Products */ +product SMC 8016 0x0105 SMC 8016 EtherCard + +/* Cards we know only by their cis */ +vendor PREMAX -1 Premax +vendor PLANET -1 Planet +vendor DLINK -1 D-Link +vendor RPTI -1 RPTI +vendor ACCTON -1 ACCTON +vendor YEDATA -1 Y-E DATA +vendor DIGITAL -1 Digital Equipment Corporation + +product MEGAHERTZ XJ2288 { "MEGAHERTZ", "MODEM&spXJ2288", NULL, NULL } Megahertz XJ2288 Modem +product PREMAX PE200 { "PMX&sp&sp&sp", "PE-200", NULL, NULL } PreMax PE-200 +product PLANET SMARTCOM2000 { "PCMCIA", "UE2212", NULL, NULL } Planet SmartCOM 2000 +product DLINK DE650 { "D-Link", "DE-650", NULL, NULL } D-Link DE-650 +product DLINK DE660 { "D-Link", "DE-660", NULL, NULL } D-Link DE-660 +product RPTI EP401 { "RPTI", "EP401&spEthernet&spNE2000&spCompatible", NULL, NULL } RPTI EP401 +product ACCTON EN2212 { "ACCTON", "EN2212", NULL, NULL } Accton EN2212 +product YEDATA EXTERNAL_FDD { "Y-E&spDATA", "External&spFDD", NULL, NULL } Y-E DATA External FDD +product DIGITAL DEPCMXX { "DIGITAL", "DEPCM-XX", NULL, NULL } DEC DEPCM-BA diff --git a/sys/dev/pcmcia/pcmciadevs.h b/sys/dev/pcmcia/pcmciadevs.h new file mode 100644 index 00000000000..d5052d8dd5a --- /dev/null +++ b/sys/dev/pcmcia/pcmciadevs.h @@ -0,0 +1,206 @@ +/* $OpenBSD: pcmciadevs.h,v 1.1 1998/09/11 10:47:15 fgsch Exp $ */ + +/* + * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. + * + * generated from: + * OpenBSD + */ +/* $NetBSD: pcmciadevs,v 1.13 1998/08/17 23:10:12 thorpej Exp $ */ + +/* + * Copyright (c) 1998, Christos Zoulas + * 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 Christos Zoulas + * for the NetBSD Project. + * 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. + */ + +/* + * List of known PCMCIA vendors + */ + +#define PCMCIA_VENDOR_NEWMEDIA 0x0057 /* NewMedia Corporation */ +#define PCMCIA_VENDOR_IBM 0x00a4 /* IBM Corporation */ +#define PCMCIA_VENDOR_3COM 0x0101 /* 3Com Corporation */ +#define PCMCIA_VENDOR_MEGAHERTZ 0x0102 /* Megahertz Corporation */ +#define PCMCIA_VENDOR_SOCKET 0x0104 /* Socket Communications */ +#define PCMCIA_VENDOR_TDK 0x0105 /* TDK Corporation */ +#define PCMCIA_VENDOR_SMC 0x0108 /* Standard Microsystems Corporation */ +#define PCMCIA_VENDOR_MOTOROLA 0x0109 /* Motorola Corporation */ +#define PCMCIA_VENDOR_USROBOTICS 0x0115 /* US Robotics Corporation */ +#define PCMCIA_VENDOR_MEGAHERTZ2 0x0128 /* Megahertz Corporation */ +#define PCMCIA_VENDOR_ADAPTEC 0x012f /* Adaptec Corporation */ +#define PCMCIA_VENDOR_LINKSYS 0x0149 /* Linksys Corporation */ +#define PCMCIA_VENDOR_SIMPLETECH 0x014d /* Simple Technology */ +#define PCMCIA_VENDOR_DAYNA 0x0194 /* Dayna Corporation */ +#define PCMCIA_VENDOR_IODATA 0x01bf /* I-O DATA */ + +/* + * List of known products. Grouped by vendor. + */ +/* Adaptec Products */ +#define PCMCIA_CIS_ADAPTEC_APA1460_1 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_ADAPTEC_APA1460_1 0x0001 +#define PCMCIA_STR_ADAPTEC_APA1460_1 "Adaptec APA-1460/A SCSI Host Adapter" +#define PCMCIA_CIS_ADAPTEC_APA1460_2 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_ADAPTEC_APA1460_2 0x0002 +#define PCMCIA_STR_ADAPTEC_APA1460_2 "Adaptec APA-1460/B SCSI Host Adapter" + +/* 3COM Products */ +#define PCMCIA_CIS_3COM_3C562 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_3COM_3C562 0x0562 +#define PCMCIA_STR_3COM_3C562 "3Com 3c562 33.6 Modem/10Mbps Ethernet" +#define PCMCIA_CIS_3COM_3C589 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_3COM_3C589 0x0589 +#define PCMCIA_STR_3COM_3C589 "3Com 3c589 10Mbps Ethernet" +#define PCMCIA_CIS_3COM_3C574 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_3COM_3C574 0x0574 +#define PCMCIA_STR_3COM_3C574 "3Com 3c574-TX 10/100Mbps Ethernet" + +/* Dayna Products */ +#define PCMCIA_CIS_DAYNA_COMMUNICARD_E { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_DAYNA_COMMUNICARD_E 0x002d +#define PCMCIA_STR_DAYNA_COMMUNICARD_E "Dayna CommuniCard E" + +/* Motorola Products */ +#define PCMCIA_CIS_MOTOROLA_POWER144 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_MOTOROLA_POWER144 0x0105 +#define PCMCIA_STR_MOTOROLA_POWER144 "Motorola Power 14.4 Modem" +#define PCMCIA_CIS_MOTOROLA_PM100C { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_MOTOROLA_PM100C 0x0302 +#define PCMCIA_STR_MOTOROLA_PM100C "Motorola Personal Messenger 100C CDPD Modem" +#define PCMCIA_CIS_MOTOROLA_MONTANA_33.6 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_MOTOROLA_MONTANA_33.6 0x0505 +#define PCMCIA_STR_MOTOROLA_MONTANA_33.6 "Motorola Montana 33.6 Fax/Modem" + +/* IBM Products */ +#define PCMCIA_CIS_IBM_INFOMOVER { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_IBM_INFOMOVER 0x0002 +#define PCMCIA_STR_IBM_INFOMOVER "National Semiconductor InfoMover" +#define PCMCIA_CIS_IBM_HOME_AND_AWAY { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_IBM_HOME_AND_AWAY 0x002e +#define PCMCIA_STR_IBM_HOME_AND_AWAY "IBM Home and Away Modem" + +/* I-O DATA */ +#define PCMCIA_CIS_IODATA_PCLAT { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_IODATA_PCLAT 0x2216 +#define PCMCIA_STR_IODATA_PCLAT "I-O DATA PCLA/T" + +/* Linksys corporation */ +#define PCMCIA_CIS_LINKSYS_ECARD { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_LINKSYS_ECARD 0x0265 +#define PCMCIA_STR_LINKSYS_ECARD "Linksys EthernetCard" +#define PCMCIA_CIS_LINKSYS_COMBO_ECARD { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_LINKSYS_COMBO_ECARD 0xc1ab +#define PCMCIA_STR_LINKSYS_COMBO_ECARD "Linksys Combo EthernetCard" +#define PCMCIA_CIS_LINKSYS_TRUST_COMBO_ECARD { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_LINKSYS_TRUST_COMBO_ECARD 0x021b +#define PCMCIA_STR_LINKSYS_TRUST_COMBO_ECARD "Trust (Linksys) Combo EthernetCard" + +/* Megahertz Products */ +#define PCMCIA_CIS_MEGAHERTZ_XJ4288 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_MEGAHERTZ_XJ4288 0x0023 +#define PCMCIA_STR_MEGAHERTZ_XJ4288 "Megahertz XJ4288 Modem" +#define PCMCIA_CIS_MEGAHERTZ2_XJEM1144 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_MEGAHERTZ2_XJEM1144 0x0101 +#define PCMCIA_STR_MEGAHERTZ2_XJEM1144 "Megahertz XJEM1144 Ethernet" +#define PCMCIA_CIS_MEGAHERTZ2_XJACK { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_MEGAHERTZ2_XJACK 0x0103 +#define PCMCIA_STR_MEGAHERTZ2_XJACK "Megahertz X-JACK Ethernet" + +/* US Robotics Products */ +#define PCMCIA_CIS_USROBOTICS_WORLDPORT144 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_USROBOTICS_WORLDPORT144 0x3330 +#define PCMCIA_STR_USROBOTICS_WORLDPORT144 "US Robotics WorldPort 14.4 Modem" + +/* Simple Technology Products */ +#define PCMCIA_CIS_SIMPLETECH_COMMUNICATOR288 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_SIMPLETECH_COMMUNICATOR288 0x0100 +#define PCMCIA_STR_SIMPLETECH_COMMUNICATOR288 "Simple Technology 28.8 Communicator" + +/* Socket Communications Products */ +#define PCMCIA_CIS_SOCKET_PAGECARD { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_SOCKET_PAGECARD 0x0003 +#define PCMCIA_STR_SOCKET_PAGECARD "Socket Communications PageCard" +#define PCMCIA_CIS_SOCKET_DUAL_RS232 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_SOCKET_DUAL_RS232 0x0012 +#define PCMCIA_STR_SOCKET_DUAL_RS232 "Socket Communications Dual RS232" + +/* TDK Products */ +#define PCMCIA_CIS_TDK_LAK_CD021BX { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_TDK_LAK_CD021BX 0x0200 +#define PCMCIA_STR_TDK_LAK_CD021BX "TDK LAK-CD021BX Ethernet" +#define PCMCIA_CIS_TDK_DFL9610 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_TDK_DFL9610 0x0d0a +#define PCMCIA_STR_TDK_DFL9610 "TDK DFL9610 Ethernet & Digital Cellular" + +/* NewMedia Products */ +#define PCMCIA_CIS_NEWMEDIA_BASICS { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_NEWMEDIA_BASICS 0x0019 +#define PCMCIA_STR_NEWMEDIA_BASICS "NewMedia BASICS Ethernet" + +/* Standard Microsystems Corporation Products */ +#define PCMCIA_CIS_SMC_8016 { NULL, NULL, NULL, NULL } +#define PCMCIA_PRODUCT_SMC_8016 0x0105 +#define PCMCIA_STR_SMC_8016 "SMC 8016 EtherCard" + +/* Cards we know only by their cis */ +#define PCMCIA_VENDOR_PREMAX -1 /* Premax */ +#define PCMCIA_VENDOR_PLANET -1 /* Planet */ +#define PCMCIA_VENDOR_DLINK -1 /* D-Link */ +#define PCMCIA_VENDOR_RPTI -1 /* RPTI */ +#define PCMCIA_VENDOR_ACCTON -1 /* ACCTON */ +#define PCMCIA_VENDOR_YEDATA -1 /* Y-E DATA */ +#define PCMCIA_VENDOR_DIGITAL -1 /* Digital Equipment Corporation */ + +#define PCMCIA_CIS_MEGAHERTZ_XJ2288 { "MEGAHERTZ", "MODEM XJ2288", NULL, NULL } +#define PCMCIA_PRODUCT_MEGAHERTZ_XJ2288 -1 +#define PCMCIA_STR_MEGAHERTZ_XJ2288 "Megahertz XJ2288 Modem" +#define PCMCIA_CIS_PREMAX_PE200 { "PMX ", "PE-200", NULL, NULL } +#define PCMCIA_PRODUCT_PREMAX_PE200 -1 +#define PCMCIA_STR_PREMAX_PE200 "PreMax PE-200" +#define PCMCIA_CIS_PLANET_SMARTCOM2000 { "PCMCIA", "UE2212", NULL, NULL } +#define PCMCIA_PRODUCT_PLANET_SMARTCOM2000 -1 +#define PCMCIA_STR_PLANET_SMARTCOM2000 "Planet SmartCOM 2000" +#define PCMCIA_CIS_DLINK_DE650 { "D-Link", "DE-650", NULL, NULL } +#define PCMCIA_PRODUCT_DLINK_DE650 -1 +#define PCMCIA_STR_DLINK_DE650 "D-Link DE-650" +#define PCMCIA_CIS_DLINK_DE660 { "D-Link", "DE-660", NULL, NULL } +#define PCMCIA_PRODUCT_DLINK_DE660 -1 +#define PCMCIA_STR_DLINK_DE660 "D-Link DE-660" +#define PCMCIA_CIS_RPTI_EP401 { "RPTI", "EP401 Ethernet NE2000 Compatible", NULL, NULL } +#define PCMCIA_PRODUCT_RPTI_EP401 -1 +#define PCMCIA_STR_RPTI_EP401 "RPTI EP401" +#define PCMCIA_CIS_ACCTON_EN2212 { "ACCTON", "EN2212", NULL, NULL } +#define PCMCIA_PRODUCT_ACCTON_EN2212 -1 +#define PCMCIA_STR_ACCTON_EN2212 "Accton EN2212" +#define PCMCIA_CIS_YEDATA_EXTERNAL_FDD { "Y-E DATA", "External FDD", NULL, NULL } +#define PCMCIA_PRODUCT_YEDATA_EXTERNAL_FDD -1 +#define PCMCIA_STR_YEDATA_EXTERNAL_FDD "Y-E DATA External FDD" +#define PCMCIA_CIS_DIGITAL_DEPCMXX { "DIGITAL", "DEPCM-XX", NULL, NULL } +#define PCMCIA_PRODUCT_DIGITAL_DEPCMXX -1 +#define PCMCIA_STR_DIGITAL_DEPCMXX "DEC DEPCM-BA" diff --git a/sys/dev/pcmcia/pcmciadevs_data.h b/sys/dev/pcmcia/pcmciadevs_data.h new file mode 100644 index 00000000000..f1f13e81280 --- /dev/null +++ b/sys/dev/pcmcia/pcmciadevs_data.h @@ -0,0 +1,443 @@ +/* $OpenBSD: pcmciadevs_data.h,v 1.1 1998/09/11 10:47:15 fgsch Exp $ */ + +/* + * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. + * + * generated from: + * OpenBSD + */ +/* $NetBSD: pcmciadevs,v 1.13 1998/08/17 23:10:12 thorpej Exp $ */ + +/* + * Copyright (c) 1998, Christos Zoulas + * 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 Christos Zoulas + * for the NetBSD Project. + * 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_knowndev pcmcia_knowndevs[] = { + { + PCMCIA_VENDOR_ADAPTEC, PCMCIA_PRODUCT_ADAPTEC_APA1460_1, + PCMCIA_CIS_ADAPTEC_APA1460_1, + 0, + "Adaptec Corporation", + "Adaptec APA-1460/A SCSI Host Adapter" }, + }, + { + PCMCIA_VENDOR_ADAPTEC, PCMCIA_PRODUCT_ADAPTEC_APA1460_2, + PCMCIA_CIS_ADAPTEC_APA1460_2, + 0, + "Adaptec Corporation", + "Adaptec APA-1460/B SCSI Host Adapter" }, + }, + { + PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3C562, + PCMCIA_CIS_3COM_3C562, + 0, + "3Com Corporation", + "3Com 3c562 33.6 Modem/10Mbps Ethernet" }, + }, + { + PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3C589, + PCMCIA_CIS_3COM_3C589, + 0, + "3Com Corporation", + "3Com 3c589 10Mbps Ethernet" }, + }, + { + PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3C574, + PCMCIA_CIS_3COM_3C574, + 0, + "3Com Corporation", + "3Com 3c574-TX 10/100Mbps Ethernet" }, + }, + { + PCMCIA_VENDOR_DAYNA, PCMCIA_PRODUCT_DAYNA_COMMUNICARD_E, + PCMCIA_CIS_DAYNA_COMMUNICARD_E, + 0, + "Dayna Corporation", + "Dayna CommuniCard E" }, + }, + { + PCMCIA_VENDOR_MOTOROLA, PCMCIA_PRODUCT_MOTOROLA_POWER144, + PCMCIA_CIS_MOTOROLA_POWER144, + 0, + "Motorola Corporation", + "Motorola Power 14.4 Modem" }, + }, + { + PCMCIA_VENDOR_MOTOROLA, PCMCIA_PRODUCT_MOTOROLA_PM100C, + PCMCIA_CIS_MOTOROLA_PM100C, + 0, + "Motorola Corporation", + "Motorola Personal Messenger 100C CDPD Modem" }, + }, + { + PCMCIA_VENDOR_MOTOROLA, PCMCIA_PRODUCT_MOTOROLA_MONTANA_33.6, + PCMCIA_CIS_MOTOROLA_MONTANA_33.6, + 0, + "Motorola Corporation", + "Motorola Montana 33.6 Fax/Modem" }, + }, + { + PCMCIA_VENDOR_IBM, PCMCIA_PRODUCT_IBM_INFOMOVER, + PCMCIA_CIS_IBM_INFOMOVER, + 0, + "IBM Corporation", + "National Semiconductor InfoMover" }, + }, + { + PCMCIA_VENDOR_IBM, PCMCIA_PRODUCT_IBM_HOME_AND_AWAY, + PCMCIA_CIS_IBM_HOME_AND_AWAY, + 0, + "IBM Corporation", + "IBM Home and Away Modem" }, + }, + { + PCMCIA_VENDOR_IODATA, PCMCIA_PRODUCT_IODATA_PCLAT, + PCMCIA_CIS_IODATA_PCLAT, + 0, + "I-O DATA", + "I-O DATA PCLA/T" }, + }, + { + PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_ECARD, + PCMCIA_CIS_LINKSYS_ECARD, + 0, + "Linksys Corporation", + "Linksys EthernetCard" }, + }, + { + PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_COMBO_ECARD, + PCMCIA_CIS_LINKSYS_COMBO_ECARD, + 0, + "Linksys Corporation", + "Linksys Combo EthernetCard" }, + }, + { + PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_TRUST_COMBO_ECARD, + PCMCIA_CIS_LINKSYS_TRUST_COMBO_ECARD, + 0, + "Linksys Corporation", + "Trust (Linksys) Combo EthernetCard" }, + }, + { + PCMCIA_VENDOR_MEGAHERTZ, PCMCIA_PRODUCT_MEGAHERTZ_XJ4288, + PCMCIA_CIS_MEGAHERTZ_XJ4288, + 0, + "Megahertz Corporation", + "Megahertz XJ4288 Modem" }, + }, + { + PCMCIA_VENDOR_MEGAHERTZ2, PCMCIA_PRODUCT_MEGAHERTZ2_XJEM1144, + PCMCIA_CIS_MEGAHERTZ2_XJEM1144, + 0, + "Megahertz Corporation", + "Megahertz XJEM1144 Ethernet" }, + }, + { + PCMCIA_VENDOR_MEGAHERTZ2, PCMCIA_PRODUCT_MEGAHERTZ2_XJACK, + PCMCIA_CIS_MEGAHERTZ2_XJACK, + 0, + "Megahertz Corporation", + "Megahertz X-JACK Ethernet" }, + }, + { + PCMCIA_VENDOR_USROBOTICS, PCMCIA_PRODUCT_USROBOTICS_WORLDPORT144, + PCMCIA_CIS_USROBOTICS_WORLDPORT144, + 0, + "US Robotics Corporation", + "US Robotics WorldPort 14.4 Modem" }, + }, + { + PCMCIA_VENDOR_SIMPLETECH, PCMCIA_PRODUCT_SIMPLETECH_COMMUNICATOR288, + PCMCIA_CIS_SIMPLETECH_COMMUNICATOR288, + 0, + "Simple Technology", + "Simple Technology 28.8 Communicator" }, + }, + { + PCMCIA_VENDOR_SOCKET, PCMCIA_PRODUCT_SOCKET_PAGECARD, + PCMCIA_CIS_SOCKET_PAGECARD, + 0, + "Socket Communications", + "Socket Communications PageCard" }, + }, + { + PCMCIA_VENDOR_SOCKET, PCMCIA_PRODUCT_SOCKET_DUAL_RS232, + PCMCIA_CIS_SOCKET_DUAL_RS232, + 0, + "Socket Communications", + "Socket Communications Dual RS232" }, + }, + { + PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_LAK_CD021BX, + PCMCIA_CIS_TDK_LAK_CD021BX, + 0, + "TDK Corporation", + "TDK LAK-CD021BX Ethernet" }, + }, + { + PCMCIA_VENDOR_TDK, PCMCIA_PRODUCT_TDK_DFL9610, + PCMCIA_CIS_TDK_DFL9610, + 0, + "TDK Corporation", + "TDK DFL9610 Ethernet & Digital Cellular" }, + }, + { + PCMCIA_VENDOR_NEWMEDIA, PCMCIA_PRODUCT_NEWMEDIA_BASICS, + PCMCIA_CIS_NEWMEDIA_BASICS, + 0, + "NewMedia Corporation", + "NewMedia BASICS Ethernet" }, + }, + { + PCMCIA_VENDOR_SMC, PCMCIA_PRODUCT_SMC_8016, + PCMCIA_CIS_SMC_8016, + 0, + "Standard Microsystems Corporation", + "SMC 8016 EtherCard" }, + }, + { + PCMCIA_VENDOR_UNKNOWN, PCMCIA_PRODUCT_MEGAHERTZ_XJ2288, + PCMCIA_CIS_MEGAHERTZ_XJ2288, + 0, + "Megahertz Corporation", + "Megahertz XJ2288 Modem" }, + }, + { + PCMCIA_VENDOR_UNKNOWN, PCMCIA_PRODUCT_PREMAX_PE200, + PCMCIA_CIS_PREMAX_PE200, + 0, + "Premax", + "PreMax PE-200" }, + }, + { + PCMCIA_VENDOR_UNKNOWN, PCMCIA_PRODUCT_PLANET_SMARTCOM2000, + PCMCIA_CIS_PLANET_SMARTCOM2000, + 0, + "Planet", + "Planet SmartCOM 2000" }, + }, + { + PCMCIA_VENDOR_UNKNOWN, PCMCIA_PRODUCT_DLINK_DE650, + PCMCIA_CIS_DLINK_DE650, + 0, + "D-Link", + "D-Link DE-650" }, + }, + { + PCMCIA_VENDOR_UNKNOWN, PCMCIA_PRODUCT_DLINK_DE660, + PCMCIA_CIS_DLINK_DE660, + 0, + "D-Link", + "D-Link DE-660" }, + }, + { + PCMCIA_VENDOR_UNKNOWN, PCMCIA_PRODUCT_RPTI_EP401, + PCMCIA_CIS_RPTI_EP401, + 0, + "RPTI", + "RPTI EP401" }, + }, + { + PCMCIA_VENDOR_UNKNOWN, PCMCIA_PRODUCT_ACCTON_EN2212, + PCMCIA_CIS_ACCTON_EN2212, + 0, + "ACCTON", + "Accton EN2212" }, + }, + { + PCMCIA_VENDOR_UNKNOWN, PCMCIA_PRODUCT_YEDATA_EXTERNAL_FDD, + PCMCIA_CIS_YEDATA_EXTERNAL_FDD, + 0, + "Y-E DATA", + "Y-E DATA External FDD" }, + }, + { + PCMCIA_VENDOR_UNKNOWN, PCMCIA_PRODUCT_DIGITAL_DEPCMXX, + PCMCIA_CIS_DIGITAL_DEPCMXX, + 0, + "Digital Equipment Corporation", + "DEC DEPCM-BA" }, + }, + { + PCMCIA_VENDOR_NEWMEDIA, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "NewMedia Corporation", + NULL, + }, + { + PCMCIA_VENDOR_IBM, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "IBM Corporation", + NULL, + }, + { + PCMCIA_VENDOR_3COM, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "3Com Corporation", + NULL, + }, + { + PCMCIA_VENDOR_MEGAHERTZ, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Megahertz Corporation", + NULL, + }, + { + PCMCIA_VENDOR_SOCKET, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Socket Communications", + NULL, + }, + { + PCMCIA_VENDOR_TDK, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "TDK Corporation", + NULL, + }, + { + PCMCIA_VENDOR_SMC, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Standard Microsystems Corporation", + NULL, + }, + { + PCMCIA_VENDOR_MOTOROLA, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Motorola Corporation", + NULL, + }, + { + PCMCIA_VENDOR_USROBOTICS, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "US Robotics Corporation", + NULL, + }, + { + PCMCIA_VENDOR_MEGAHERTZ2, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Megahertz Corporation", + NULL, + }, + { + PCMCIA_VENDOR_ADAPTEC, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Adaptec Corporation", + NULL, + }, + { + PCMCIA_VENDOR_LINKSYS, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Linksys Corporation", + NULL, + }, + { + PCMCIA_VENDOR_SIMPLETECH, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Simple Technology", + NULL, + }, + { + PCMCIA_VENDOR_DAYNA, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Dayna Corporation", + NULL, + }, + { + PCMCIA_VENDOR_IODATA, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "I-O DATA", + NULL, + }, + { + PCMCIA_VENDOR_PREMAX, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Premax", + NULL, + }, + { + PCMCIA_VENDOR_PLANET, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Planet", + NULL, + }, + { + PCMCIA_VENDOR_DLINK, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "D-Link", + NULL, + }, + { + PCMCIA_VENDOR_RPTI, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "RPTI", + NULL, + }, + { + PCMCIA_VENDOR_ACCTON, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "ACCTON", + NULL, + }, + { + PCMCIA_VENDOR_YEDATA, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Y-E DATA", + NULL, + }, + { + PCMCIA_VENDOR_DIGITAL, 0, + PCMCIA_KNOWNDEV_NOPROD, + PCMCIA_CIS_INVALID, + "Digital Equipment Corporation", + NULL, + }, + { 0, 0, { NULL, NULL, NULL, NULL }, 0, NULL, NULL, } +}; diff --git a/sys/dev/pcmcia/pcmciareg.h b/sys/dev/pcmcia/pcmciareg.h index 840d745aba3..caa30615ac2 100644 --- a/sys/dev/pcmcia/pcmciareg.h +++ b/sys/dev/pcmcia/pcmciareg.h @@ -1,136 +1,247 @@ -/* $OpenBSD: pcmciareg.h,v 1.2 1997/11/07 08:07:35 niklas Exp $ */ +/* $OpenBSD: pcmciareg.h,v 1.3 1998/09/11 10:47:15 fgsch Exp $ */ +/* $NetBSD: pcmciareg.h,v 1.6 1998/08/13 15:00:02 nathanw Exp $ */ + /* - * This file was apparently first written by Stefan Grefen, although it - * contained no copyright notice at the time. + * Copyright (c) 1997 Marc Horowitz. 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 Marc Horowitz. + * 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. */ -#ifndef __PCMCIAREG_H__ -#define __PCMCIAREG_H__ + +/* most of this is from the PCMCIA PC Card Standard, Release 2.1 */ + +/* Note: the weird indenting here is to make the constants more + readable. Please don't normalize it. --marc */ /* - * Configuration Registers - * - * These are the registers required by Release 2.0 of the standard - * (Section 4.15) + * CIS Tuples */ + +/* Layer 1 Basic Compatibility Tuples */ +#define PCMCIA_CISTPL_NULL 0x00 +#define PCMCIA_CISTPL_DEVICE 0x01 +#define PCMCIA_DTYPE_MASK 0xF0 +#define PCMCIA_DTYPE_NULL 0x00 +#define PCMCIA_DTYPE_ROM 0x10 +#define PCMCIA_DTYPE_OTPROM 0x20 +#define PCMCIA_DTYPE_EPROM 0x30 +#define PCMCIA_DTYPE_EEPROM 0x40 +#define PCMCIA_DTYPE_FLASH 0x50 +#define PCMCIA_DTYPE_SRAM 0x60 +#define PCMCIA_DTYPE_DRAM 0x70 +#define PCMCIA_DTYPE_FUNCSPEC 0xD0 +#define PCMCIA_DTYPE_EXTEND 0xE0 +#define PCMCIA_DSPEED_MASK 0x07 +#define PCMCIA_DSPEED_NULL 0x00 +#define PCMCIA_DSPEED_250NS 0x01 +#define PCMCIA_DSPEED_200NS 0x02 +#define PCMCIA_DSPEED_150NS 0x03 +#define PCMCIA_DSPEED_100NS 0x04 +#define PCMCIA_DSPEED_EXT 0x07 + +/* + * the 2.1 docs have 0x02-0x07 as reserved, but the linux drivers list the + * follwing tuple code values. I have at least one card (3com 3c562 + * lan+modem) which has a code 0x06 tuple, so I'm going to assume that these + * are for real */ -/* 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. */ +#define PCMCIA_CISTPL_LONGLINK_CB 0x02 +#define PCMCIA_CISTPL_INDIRECT 0x03 +#define PCMCIA_CISTPL_CONFIG_CB 0x04 +#define PCMCIA_CISTPL_CFTABLE_ENTRY_CB 0x05 +#define PCMCIA_CISTPL_LONGLINK_MFC 0x06 +#define PCMCIA_MFC_MEM_ATTR 0x00 +#define PCMCIA_MFC_MEM_COMMON 0x01 +#define PCMCIA_CISTPL_BAR 0x07 +#define PCMCIA_CISTPL_PWR_MGMNT 0x08 + +#define PCMCIA_CISTPL_CHECKSUM 0x10 +#define PCMCIA_CISTPL_LONGLINK_A 0x11 +#define PCMCIA_CISTPL_LONGLINK_C 0x12 +#define PCMCIA_CISTPL_LINKTARGET 0x13 +#define PCMCIA_CISTPL_NO_LINK 0x14 +#define PCMCIA_CISTPL_VERS_1 0x15 +#define PCMCIA_CISTPL_ALTSTR 0x16 +#define PCMCIA_CISTPL_DEVICE_A 0x17 +#define PCMCIA_CISTPL_JEDEC_C 0x18 +#define PCMCIA_CISTPL_JEDEC_A 0x19 +#define PCMCIA_CISTPL_CONFIG 0x1A +#define PCMCIA_TPCC_RASZ_MASK 0x03 +#define PCMCIA_TPCC_RASZ_SHIFT 0 +#define PCMCIA_TPCC_RMSZ_MASK 0x3C +#define PCMCIA_TPCC_RMSZ_SHIFT 2 +#define PCMCIA_TPCC_RFSZ_MASK 0xC0 +#define PCMCIA_TPCC_RFSZ_SHIFT 6 +#define PCMCIA_CISTPL_CFTABLE_ENTRY 0x1B +#define PCMCIA_TPCE_INDX_INTFACE 0x80 +#define PCMCIA_TPCE_INDX_DEFAULT 0x40 +#define PCMCIA_TPCE_INDX_NUM_MASK 0x3F +#define PCMCIA_TPCE_IF_MWAIT 0x80 +#define PCMCIA_TPCE_IF_RDYBSY 0x40 +#define PCMCIA_TPCE_IF_WP 0x20 +#define PCMCIA_TPCE_IF_BVD 0x10 +#define PCMCIA_TPCE_IF_IFTYPE 0x0F +#define PCMCIA_IFTYPE_MEMORY 0 +#define PCMCIA_IFTYPE_IO 1 +#define PCMCIA_TPCE_FS_MISC 0x80 +#define PCMCIA_TPCE_FS_MEMSPACE_MASK 0x60 +#define PCMCIA_TPCE_FS_MEMSPACE_NONE 0x00 +#define PCMCIA_TPCE_FS_MEMSPACE_LENGTH 0x20 +#define PCMCIA_TPCE_FS_MEMSPACE_LENGTHADDR 0x40 +#define PCMCIA_TPCE_FS_MEMSPACE_TABLE 0x60 +#define PCMCIA_TPCE_FS_IRQ 0x10 +#define PCMCIA_TPCE_FS_IOSPACE 0x08 +#define PCMCIA_TPCE_FS_TIMING 0x04 +#define PCMCIA_TPCE_FS_POWER_MASK 0x03 +#define PCMCIA_TPCE_FS_POWER_NONE 0x00 +#define PCMCIA_TPCE_FS_POWER_VCC 0x01 +#define PCMCIA_TPCE_FS_POWER_VCCVPP1 0x02 +#define PCMCIA_TPCE_FS_POWER_VCCVPP1VPP2 0x03 +#define PCMCIA_TPCE_TD_RESERVED_MASK 0xE0 +#define PCMCIA_TPCE_TD_RDYBSY_MASK 0x1C +#define PCMCIA_TPCE_TD_WAIT_MASK 0x03 +#define PCMCIA_TPCE_IO_HASRANGE 0x80 +#define PCMCIA_TPCE_IO_BUSWIDTH_16BIT 0x40 +#define PCMCIA_TPCE_IO_BUSWIDTH_8BIT 0x20 +#define PCMCIA_TPCE_IO_IOADDRLINES_MASK 0x1F +#define PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_MASK 0xC0 +#define PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_NONE 0x00 +#define PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_ONE 0x40 +#define PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_TWO 0x80 +#define PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_FOUR 0xC0 +#define PCMCIA_TPCE_IO_RANGE_ADDRSIZE_MASK 0x30 +#define PCMCIA_TPCE_IO_RANGE_ADDRSIZE_NONE 0x00 +#define PCMCIA_TPCE_IO_RANGE_ADDRSIZE_ONE 0x10 +#define PCMCIA_TPCE_IO_RANGE_ADDRSIZE_TWO 0x20 +#define PCMCIA_TPCE_IO_RANGE_ADDRSIZE_FOUR 0x30 +#define PCMCIA_TPCE_IO_RANGE_COUNT 0x0F +#define PCMCIA_TPCE_IR_SHARE 0x80 +#define PCMCIA_TPCE_IR_PULSE 0x40 +#define PCMCIA_TPCE_IR_LEVEL 0x20 +#define PCMCIA_TPCE_IR_HASMASK 0x10 +#define PCMCIA_TPCE_IR_IRQ 0x0F +#define PCMCIA_TPCE_MS_HOSTADDR 0x80 +#define PCMCIA_TPCE_MS_CARDADDR_SIZE_MASK 0x60 +#define PCMCIA_TPCE_MS_CARDADDR_SIZE_SHIFT 5 +#define PCMCIA_TPCE_MS_LENGTH_SIZE_MASK 0x18 +#define PCMCIA_TPCE_MS_LENGTH_SIZE_SHIFT 3 +#define PCMCIA_TPCE_MS_COUNT 0x07 +#define PCMCIA_TPCE_MI_EXT 0x80 +#define PCMCIA_TPCE_MI_RESERVED 0x40 +#define PCMCIA_TPCE_MI_PWRDOWN 0x20 +#define PCMCIA_TPCE_MI_READONLY 0x10 +#define PCMCIA_TPCE_MI_AUDIO 0x08 +#define PCMCIA_TPCE_MI_MAXTWINS 0x07 +#define PCMCIA_CISTPL_DEVICE_OC 0x1C +#define PCMCIA_CISTPL_DEVICE_OA 0x1D +#define PCMCIA_CISTPL_DEVICE_GEO 0x1E +#define PCMCIA_CISTPL_DEVICE_GEO_A 0x1F +#define PCMCIA_CISTPL_MANFID 0x20 +#define PCMCIA_CISTPL_FUNCID 0x21 +#define PCMCIA_FUNCTION_UNSPEC -1 +#define PCMCIA_FUNCTION_MULTIFUNCTION 0 +#define PCMCIA_FUNCTION_MEMORY 1 +#define PCMCIA_FUNCTION_SERIAL 2 +#define PCMCIA_FUNCTION_PARALLEL 3 +#define PCMCIA_FUNCTION_DISK 4 +#define PCMCIA_FUNCTION_VIDEO 5 +#define PCMCIA_FUNCTION_NETWORK 6 +#define PCMCIA_FUNCTION_AIMS 7 +#define PCMCIA_FUNCTION_SCSI 8 +#define PCMCIA_FUNCTION_SECURITY 9 +#define PCMCIA_FUNCTION_INSTRUMENT 10 +#define PCMCIA_CISTPL_FUNCE 0x22 +#define PCMCIA_TPLFE_TYPE_LAN_TECH 0x01 +#define PCMCIA_TPLFE_TYPE_LAN_SPEED 0x02 +#define PCMCIA_TPLFE_TYPE_LAN_MEDIA 0x03 +#define PCMCIA_TPLFE_TYPE_LAN_NID 0x04 +#define PCMCIA_TPLFE_TYPE_LAN_CONN 0x05 +#define PCMCIA_CISTPL_END 0xFF + +/* Layer 2 Data Recording Format Tuples */ + +#define PCMCIA_CISTPL_SWIL 0x23 +/* #define PCMCIA_CISTPL_RESERVED 0x24-0x3F */ +#define PCMCIA_CISTPL_VERS_2 0x40 +#define PCMCIA_CISTPL_FORMAT 0x41 +#define PCMCIA_CISTPL_GEOMETRY 0x42 +#define PCMCIA_CISTPL_BYTEORDER 0x43 +#define PCMCIA_CISTPL_DATE 0x44 +#define PCMCIA_CISTPL_BATTERY 0x45 +#define PCMCIA_CISTPL_FORAMT_A 0x47 + +/* Layer 3 Data Organization Tuples */ + +#define PCMCIA_CISTPL_ORG 0x46 +/* #define PCMCIA_CISTPL_RESERVED 0x47-0x7F */ + +/* Layer 4 System-Specific Standard Tuples */ + +/* #define PCMCIA_CISTPL_RESERVED 0x80-0x8F */ +#define PCMCIA_CISTPL_SPCL 0x90 +/* #define PCMCIA_CISTPL_RESERVED 0x90-0xFE */ /* - * CIS Tuple defines + * Card Configuration Registers */ -#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 */ - -#define splpcmcia spltty -#define IPL_PCMCIA IPL_TTY - -#endif /* __PCMCIAREG_H__ */ + +#define PCMCIA_CCR_OPTION 0x00 +#define PCMCIA_CCR_OPTION_SRESET 0x80 +#define PCMCIA_CCR_OPTION_LEVIREQ 0x40 +#define PCMCIA_CCR_OPTION_CFINDEX 0x3F +#define PCMCIA_CCR_OPTION_IREQ_ENABLE 0x04 +#define PCMCIA_CCR_OPTION_ADDR_DECODE 0x02 +#define PCMCIA_CCR_OPTION_FUNC_ENABLE 0x01 +#define PCMCIA_CCR_STATUS 0x02 +#define PCMCIA_CCR_STATUS_PINCHANGED 0x80 +#define PCMCIA_CCR_STATUS_SIGCHG 0x40 +#define PCMCIA_CCR_STATUS_IOIS8 0x20 +#define PCMCIA_CCR_STATUS_RESERVED1 0x10 +#define PCMCIA_CCR_STATUS_AUDIO 0x08 +#define PCMCIA_CCR_STATUS_PWRDWN 0x04 +#define PCMCIA_CCR_STATUS_INTR 0x02 +#define PCMCIA_CCR_STATUS_INTRACK 0x01 +#define PCMCIA_CCR_PIN 0x04 +#define PCMCIA_CCR_PIN_CBVD1 0x80 +#define PCMCIA_CCR_PIN_CBVD2 0x40 +#define PCMCIA_CCR_PIN_CRDYBSY 0x20 +#define PCMCIA_CCR_PIN_CWPROT 0x10 +#define PCMCIA_CCR_PIN_RBVD1 0x08 +#define PCMCIA_CCR_PIN_RBVD2 0x04 +#define PCMCIA_CCR_PIN_RRDYBSY 0x02 +#define PCMCIA_CCR_PIN_RWPROT 0x01 +#define PCMCIA_CCR_SOCKETCOPY 0x06 +#define PCMCIA_CCR_SOCKETCOPY_RESERVED 0x80 +#define PCMCIA_CCR_SOCKETCOPY_COPY_MASK 0x70 +#define PCMCIA_CCR_SOCKETCOPY_COPY_SHIFT 4 +#define PCMCIA_CCR_SOCKETCOPY_SOCKET_MASK 0x0F +#define PCMCIA_CCR_EXTSTATUS 0x08 +#define PCMCIA_CCR_IOBASE0 0x0A +#define PCMCIA_CCR_IOBASE1 0x0C +#define PCMCIA_CCR_IOBASE2 0x0E +#define PCMCIA_CCR_IOBASE3 0x10 +#define PCMCIA_CCR_IOSIZE 0x12 + +#define PCMCIA_CCR_SIZE 0x14 diff --git a/sys/dev/pcmcia/pcmciavar.h b/sys/dev/pcmcia/pcmciavar.h index 58872f0722c..203fb3ab0b5 100644 --- a/sys/dev/pcmcia/pcmciavar.h +++ b/sys/dev/pcmcia/pcmciavar.h @@ -1,19 +1,20 @@ -/* $OpenBSD: pcmciavar.h,v 1.5 1997/11/07 08:07:36 niklas Exp $ */ +/* $OpenBSD: pcmciavar.h,v 1.6 1998/09/11 10:47:15 fgsch Exp $ */ +/* $NetBSD: pcmciavar.h,v 1.5 1998/07/19 17:28:17 christos Exp $ */ + /* - * Copyright (c) 1995,1996 John T. Kohl. All rights reserved. - * Copyright (c) 1993, 1994 Stefan Grefen. All rights reserved. + * Copyright (c) 1997 Marc Horowitz. 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. + * 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 Marc Horowitz. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * @@ -27,304 +28,236 @@ * 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. - * */ - /* derived from scsicconf.[ch] writenn by Julian Elischer et al */ - -#ifndef _PCMCIA_PCMCIAVAR_H_ -#define _PCMCIA_PCMCIAVAR_H_ 1 +#include <sys/types.h> #include <sys/queue.h> -#include <sys/select.h> -#include <machine/cpu.h> -#include <machine/bus.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. - */ +#include <machine/bus.h> -struct pcmcia_link; -struct pcmcia_conf; -struct pcmcia_adapter; +#include <dev/pcmcia/pcmciachip.h> /* - * 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. + * Contains information about mapped/allocated i/o spaces. */ -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 *, bus_space_tag_t, - caddr_t, u_int, u_int, int)); -/*12 map interrupt */ - int (*pcmcia_map_intr) __P((struct pcmcia_link *, int, int)); -/*16 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_io_handle { + bus_space_tag_t iot; /* bus space tag (from chipset) */ + bus_space_handle_t ioh; /* mapped space handle */ + bus_addr_t addr; /* resulting address in bus space */ + bus_size_t size; /* size of i/o space */ + int flags; /* misc. information */ }; -#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 PCMCIA_IO_ALLOCATED 0x01 /* i/o space was allocated */ /* - * One of these goes at the front of each chip controller's softc, right - * after the struct device. + * Contains information about allocated memory space. */ -struct pcmcia_adapter { - struct pcmcia_funcs *chip_link; - struct pcmciabus_link *bus_link; - bus_space_tag_t pa_memt; /* mem access handle */ - void *adapter_softc; - caddr_t scratch_mem; /* pointer to scratch window */ - int scratch_memsiz; /* size of scratch window */ - bus_space_handle_t scratch_memh;/* bus memory handle */ - int scratch_inuse; /* window in use */ - int nslots; /* # of slots controlled */ +struct pcmcia_mem_handle { + bus_space_tag_t memt; /* bus space tag (from chipset) */ + bus_space_handle_t memh; /* mapped space handle */ + bus_addr_t addr; /* resulting address in bus space */ + bus_size_t size; /* size of mem space */ + pcmcia_mem_handle_t mhandle; /* opaque memory handle */ + bus_size_t realsize; /* how much we really allocated */ }; -#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 +/* pcmcia itself */ +#define PCMCIA_CFE_MWAIT_REQUIRED 0x0001 +#define PCMCIA_CFE_RDYBSY_ACTIVE 0x0002 +#define PCMCIA_CFE_WP_ACTIVE 0x0004 +#define PCMCIA_CFE_BVD_ACTIVE 0x0008 +#define PCMCIA_CFE_IO8 0x0010 +#define PCMCIA_CFE_IO16 0x0020 +#define PCMCIA_CFE_IRQSHARE 0x0040 +#define PCMCIA_CFE_IRQPULSE 0x0080 +#define PCMCIA_CFE_IRQLEVEL 0x0100 +#define PCMCIA_CFE_POWERDOWN 0x0200 +#define PCMCIA_CFE_READONLY 0x0400 +#define PCMCIA_CFE_AUDIO 0x0800 -/* - * 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 { - u_char pcmciabus; /* the Nth pcmciabus */ - u_char slot; /* slot of this dev */ - u_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 - u_char opennings; - - u_char iowin; - u_char memwin; - u_char intr; - u_char dummy; - struct pcmcia_adapter *adapter; /* adapter entry points etc. */ - struct pcmciadevs *device; /* device entry points etc. */ - struct pcmciabus_softc *bus; /* parent pcmcia bus */ - struct device *devp; /* pointer to configured device */ - void *fordriver; /* for private use by the driver */ - struct selinfo pcmcialink_sel; /* for select users */ -}; +struct pcmcia_config_entry { + int number; + u_int32_t flags; + int iftype; + int num_iospace; -/* - * 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; - bus_space_tag_t sc_iot; - bus_space_tag_t sc_memt; - struct pcmcia_link *sc_link[4]; /* up to 4 slots per bus */ - struct pcmcia_adapter *sc_driver; + /* + * The card will only decode this mask in any case, so we can + * do dynamic allocation with this in mind, in case the suggestions + * below are no good. + */ + u_long iomask; + struct { + u_long length; + u_long start; + } iospace[4]; /* XXX this could be as high as 16 */ + u_int16_t irqmask; + int num_memspace; + struct { + u_long length; + u_long cardaddr; + u_long hostaddr; + } memspace[2]; /* XXX this could be as high as 8 */ + int maxtwins; + SIMPLEQ_ENTRY(pcmcia_config_entry) cfe_list; }; -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_function { + /* read off the card */ + int number; + int function; + int last_config_index; + u_long ccr_base; + u_long ccr_mask; + SIMPLEQ_HEAD(, pcmcia_config_entry) cfe_head; + SIMPLEQ_ENTRY(pcmcia_function) pf_list; + /* run-time state */ + struct pcmcia_softc *sc; + struct pcmcia_config_entry *cfe; + struct pcmcia_mem_handle pf_pcmh; +#define pf_ccrt pf_pcmh.memt +#define pf_ccrh pf_pcmh.memh +#define pf_ccr_mhandle pf_pcmh.mhandle +#define pf_ccr_realsize pf_pcmh.realsize + bus_addr_t pf_ccr_offset; + int pf_ccr_window; + long pf_mfc_iobase; + long pf_mfc_iomax; + int (*ih_fct) __P((void *)); + void *ih_arg; + int ih_ipl; + int pf_flags; }; -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 *)); +/* pf_flags */ +#define PFF_ENABLED 0x0001 /* function is enabled */ + +struct pcmcia_card { + int cis1_major; + int cis1_minor; + /* XXX waste of space? */ + char cis1_info_buf[256]; + char *cis1_info[4]; + /* + * Use int32_t for manufacturer and product so that they can + * hold the id value found in card CIS and special value that + * indicates no id was found. + */ + int32_t manufacturer; +#define PCMCIA_VENDOR_INVALID -1 + int32_t product; +#define PCMCIA_PRODUCT_INVALID -1 + u_int16_t error; +#define PCMCIA_CIS_INVALID { NULL, NULL, NULL, NULL } + SIMPLEQ_HEAD(, pcmcia_function) pf_head; }; -#define MAX_CIS_NAMELEN 64 /* version info string len */ +struct pcmcia_softc { + struct device dev; -struct pcmcia_cardinfo { - char manufacturer[MAX_CIS_NAMELEN]; - char model[MAX_CIS_NAMELEN]; - char add_info1[MAX_CIS_NAMELEN]; - char add_info2[MAX_CIS_NAMELEN]; -}; + /* this stuff is for the socket */ + pcmcia_chipset_tag_t pct; + pcmcia_chipset_handle_t pch; -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; + /* this stuff is for the card */ + struct pcmcia_card card; + void *ih; + int sc_enabled_count; /* how many functions are + enabled */ + + /* + * These are passed down from the PCMCIA chip, and exist only + * so that cards with Very Special address allocation needs + * know what range they should be dealing with. + */ + bus_addr_t iobase; /* start i/o space allocation here */ + bus_size_t iosize; /* size of the i/o space range */ }; -/* - * PCMCIA driver attach arguments - */ struct pcmcia_attach_args { - struct pcmcia_cardinfo *paa_cardinfo; /* card that we're looking at */ - struct pcmcia_link *paa_link; /* this nexus */ - int paa_bestmatch; /* best match so far */ - int paa_matchonly; /* only do matches, don't attach */ - void *paa_aux; /* driver specific */ + int32_t manufacturer; + int32_t product; + struct pcmcia_card *card; + struct pcmcia_function *pf; }; -struct pcmciabus_attach_args { - bus_space_tag_t pba_iot; - bus_space_tag_t pba_memt; - bus_space_tag_t pba_memh; - int pba_maddr; - int pba_msize; - void *pba_aux; /* driver specific */ +struct pcmcia_tuple { + unsigned int code; + unsigned int length; + u_long mult; + bus_addr_t ptr; + bus_space_tag_t memt; + bus_space_handle_t memh; }; -#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 *)); -void parse_cfent __P((u_char *, int, int, struct pcmcia_conf *)); -void read_cfg_info __P((u_char *, int, struct pcmcia_conf *)); -void pcmcia_getstr __P((char *buf, u_char **, u_char *)); -extern int pcmcia_configure __P((struct device *, void *, void *)); -extern int pcmcia_register __P((void *, struct pcmciabus_link *, - struct pcmcia_funcs *, int)); -extern int pcmcia_read_cis __P((struct pcmcia_link *, u_char *, int, int)); -extern int pcmcia_strcmp __P((const char *, const char *, int, const char *)); -extern int pcmcia_matchvalue __P((const struct pcmcia_cardinfo *, - struct pcmciadevs *)); -extern int pcmcia_bestvalue __P((struct pcmcia_cardinfo *, - struct pcmciadevs *, - int, - struct pcmciadevs **)); -extern int pcmcia_slave_match __P((struct device *, - void *, - void *aux, - struct pcmciadevs *, - int)); -#endif /* _PCMCIA_PCMCIAVAR_H_ */ +void pcmcia_read_cis __P((struct pcmcia_softc *)); +void pcmcia_print_cis __P((struct pcmcia_softc *)); +int pcmcia_scan_cis __P((struct device * dev, + int (*) (struct pcmcia_tuple *, void *), void *)); + +#define pcmcia_cis_read_1(tuple, idx0) \ + (bus_space_read_1((tuple)->memt, (tuple)->memh, (tuple)->mult*(idx0))) + +#define pcmcia_tuple_read_1(tuple, idx1) \ + (pcmcia_cis_read_1((tuple), ((tuple)->ptr+(2+(idx1))))) + +#define pcmcia_tuple_read_2(tuple, idx2) \ + (pcmcia_tuple_read_1((tuple), (idx2)) | \ + (pcmcia_tuple_read_1((tuple), (idx2)+1)<<8)) + +#define pcmcia_tuple_read_3(tuple, idx3) \ + (pcmcia_tuple_read_1((tuple), (idx3)) | \ + (pcmcia_tuple_read_1((tuple), (idx3)+1)<<8) | \ + (pcmcia_tuple_read_1((tuple), (idx3)+2)<<16)) + +#define pcmcia_tuple_read_4(tuple, idx4) \ + (pcmcia_tuple_read_1((tuple), (idx4)) | \ + (pcmcia_tuple_read_1((tuple), (idx4)+1)<<8) | \ + (pcmcia_tuple_read_1((tuple), (idx4)+2)<<16) | \ + (pcmcia_tuple_read_1((tuple), (idx4)+3)<<24)) + +#define pcmcia_tuple_read_n(tuple, n, idxn) \ + (((n)==1)?pcmcia_tuple_read_1((tuple), (idxn)) : \ + (((n)==2)?pcmcia_tuple_read_2((tuple), (idxn)) : \ + (((n)==3)?pcmcia_tuple_read_3((tuple), (idxn)) : \ + /* n == 4 */ pcmcia_tuple_read_4((tuple), (idxn))))) + +#define PCMCIA_SPACE_MEMORY 1 +#define PCMCIA_SPACE_IO 2 + +int pcmcia_ccr_read __P((struct pcmcia_function *, int)); +void pcmcia_ccr_write __P((struct pcmcia_function *, int, int)); + +#define pcmcia_mfc(sc) ((sc)->card.pf_head.sqh_first && \ + (sc)->card.pf_head.sqh_first->pf_list.sqe_next) + +void pcmcia_function_init __P((struct pcmcia_function *, + struct pcmcia_config_entry *)); +int pcmcia_function_enable __P((struct pcmcia_function *)); +void pcmcia_function_disable __P((struct pcmcia_function *)); + +#define pcmcia_io_alloc(pf, start, size, align, pciop) \ + (pcmcia_chip_io_alloc((pf)->sc->pct, pf->sc->pch, (start), \ + (size), (align), (pciop))) + +int pcmcia_io_map __P((struct pcmcia_function *, int, bus_addr_t, + bus_size_t, struct pcmcia_io_handle *, int *)); + +#define pcmcia_mem_alloc(pf, size, pcmhp) \ + (pcmcia_chip_mem_alloc((pf)->sc->pct, (pf)->sc->pch, (size), (pcmhp))) + +#define pcmcia_mem_free(pf, pcmhp) \ + (pcmcia_chip_mem_free((pf)->sc->pct, (pf)->sc->pch, (pcmhp))) + +#define pcmcia_mem_map(pf, kind, card_addr, size, pcmhp, offsetp, windowp) \ + (pcmcia_chip_mem_map((pf)->sc->pct, (pf)->sc->pch, (kind), \ + (card_addr), (size), (pcmhp), (offsetp), (windowp))) + +#define pcmcia_mem_unmap(pf, window) \ + (pcmcia_chip_mem_unmap((pf)->sc->pct, (pf)->sc->pch, (window))) + +void *pcmcia_intr_establish __P((struct pcmcia_function *, int, + int (*) (void *), void *)); +void pcmcia_intr_disestablish __P((struct pcmcia_function *, void *)); |