Pull marc-pcmcia branch down from trunk.

This commit is contained in:
thorpej 1997-10-16 23:27:16 +00:00
parent 3664382e53
commit c66b8643d1
11 changed files with 3924 additions and 0 deletions

156
sys/dev/pcmcia/aic_pcmcia.c Normal file
View File

@ -0,0 +1,156 @@
/* $NetBSD: aic_pcmcia.c,v 1.2 1997/10/16 23:27:16 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.
*/
#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 <dev/scsipi/scsipi_all.h>
#include <dev/scsipi/scsipiconf.h>
#include <dev/scsipi/scsi_all.h>
#include <dev/ic/aic6360var.h>
#include <dev/pcmcia/pcmciareg.h>
#include <dev/pcmcia/pcmciavar.h>
#define PCMCIA_MANUFACTURER_ADAPTEC 0x012F
#define PCMCIA_PRODUCT_ADAPTEC_APA1460_1 0x0001
#define PCMCIA_PRODUCT_ADAPTEC_APA1460_2 0x0002
#ifdef __BROKEN_INDIRECT_CONFIG
int aic_pcmcia_match __P((struct device *, void *, void *));
#else
int aic_pcmcia_match __P((struct device *, struct cfdata *, void *));
#endif
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;
#ifdef __BROKEN_INDIRECT_CONFIG
void *match;
#else
struct cfdata *cf;
#endif
void *aux;
{
struct pcmcia_attach_args *pa = aux;
if (pa->manufacturer == PCMCIA_MANUFACTURER_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;
psc->sc_pf = pf;
for (cfe = pf->cfe_head.sqh_first; cfe; cfe = cfe->cfe_list.sqe_next) {
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);
printf(": APA-1460 SCSI Host Adapter\n");
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);
}

235
sys/dev/pcmcia/com_pcmcia.c Normal file
View File

@ -0,0 +1,235 @@
/* $NetBSD: com_pcmcia.c,v 1.2 1997/10/16 23:27:18 thorpej Exp $ */
/*-
* 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.
*
* 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 University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*
* @(#)com.c 7.5 (Berkeley) 5/16/91
*/
#include <sys/param.h>
#include <sys/systm.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/intr.h>
#include <machine/bus.h>
#include <dev/pcmcia/pcmciavar.h>
#include <dev/pcmcia/pcmciareg.h>
#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>
#include <dev/isa/isareg.h>
#define PCMCIA_MANUFACTURER_3COM 0x101
#define PCMCIA_PRODUCT_3COM_3C562 0x562
#define PCMCIA_MANUFACTURER_MOTOROLA 0x109
#define PCMCIA_PRODUCT_MOTOROLA_POWER144 0x105
#define PCMCIA_MANUFACTURER_IBM 0xa4
#define PCMCIA_PRODUCT_IBM_HOME_AND_AWAY 0x2e
#ifdef __BROKEN_INDIRECT_CONFIG
int com_pcmcia_match __P((struct device *, void *, void *));
#else
int com_pcmcia_match __P((struct device *, struct cfdata *, void *));
#endif
void com_pcmcia_attach __P((struct device *, struct device *, void *));
void com_pcmcia_cleanup __P((void *));
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_pcmcia_softc), com_pcmcia_match, com_pcmcia_attach
};
int
com_pcmcia_match(parent, match, aux)
struct device *parent;
#ifdef __BROKEN_INDIRECT_CONFIG
void *match;
#else
struct cfdata *match;
#endif
void *aux;
{
struct pcmcia_attach_args *pa = aux;
struct pcmcia_config_entry *cfe;
if ((pa->manufacturer == PCMCIA_MANUFACTURER_3COM) &&
(pa->product == PCMCIA_PRODUCT_3COM_3C562) &&
(pa->pf->number == 1))
return(1);
if ((pa->manufacturer == PCMCIA_MANUFACTURER_MOTOROLA) &&
(pa->product == PCMCIA_PRODUCT_MOTOROLA_POWER144) &&
(pa->pf->number == 0))
return(1);
if ((pa->manufacturer == PCMCIA_MANUFACTURER_IBM) &&
(pa->product == PCMCIA_PRODUCT_IBM_HOME_AND_AWAY) &&
(pa->pf->number == 1))
return(1);
/* find a cfe we can use (if it matches a standard COM port) */
for (cfe = pa->pf->cfe_head.sqh_first; cfe;
cfe = cfe->cfe_list.sqe_next) {
if (cfe->iospace[0].start == IO_COM1 ||
cfe->iospace[0].start == IO_COM2 ||
cfe->iospace[0].start == IO_COM3 ||
cfe->iospace[0].start == IO_COM4)
return(1);
}
return(0);
}
void
com_pcmcia_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
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;
char *model;
psc->sc_pf = pa->pf;
/* find a cfe we can use */
for (cfe = pa->pf->cfe_head.sqh_first; cfe;
cfe = cfe->cfe_list.sqe_next) {
if (cfe->num_memspace != 0)
continue;
if (cfe->num_iospace != 1)
continue;
if (cfe->iomask == 3) {
if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length,
cfe->iospace[0].length, &psc->sc_pcioh)) {
continue;
}
} else {
if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
cfe->iospace[0].length, 0, &psc->sc_pcioh)) {
continue;
}
}
break;
}
if (!cfe) {
printf(": can't allocate 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(pa->pf, cfe);
if (pcmcia_function_enable(pa->pf))
printf(": function enable failed\n");
/* turn off the bit which disables the ethernet */
if (pa->product == PCMCIA_PRODUCT_3COM_3C562) {
int reg;
reg = pcmcia_ccr_read(pa->pf, PCMCIA_CCR_OPTION);
reg &= ~0x08;
pcmcia_ccr_write(pa->pf, PCMCIA_CCR_OPTION, reg);
}
/* 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;
}
sc->sc_iobase = -1;
sc->sc_frequency = COM_FREQ;
com_attach_subr(sc);
switch (pa->product) {
case PCMCIA_PRODUCT_3COM_3C562:
model = "3Com 3C562 Modem";
break;
case PCMCIA_PRODUCT_MOTOROLA_POWER144:
model = "Motorola Power 14.4 Modem";
break;
default:
model = NULL;
break;
}
if (model != NULL)
printf(": %s\n", model);
/* establish the interrupt. */
psc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_SERIAL, comintr, sc);
if (psc->sc_ih == NULL) {
printf("%s: couldn't establish interrupt\n",
sc->sc_dev.dv_xname);
return;
}
}

View File

@ -0,0 +1,41 @@
# Config.new file and device description for machine-independent PCMCIA code.
# Included by ports that need it.
defopt PCMCIAVERBOSE
device pcmcia {[function = -1], [irq = -1]}
file dev/pcmcia/pcmcia.c
file dev/pcmcia/pcmcia_cis.c
# device declaration in sys/conf/files
attach pcmcia at pcic
# 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
# 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
# Adaptec APA-1460 SCSI Host Adapter
attach aic at pcmcia with aic_pcmcia
file dev/pcmcia/aic_pcmcia.c aic_pcmcia
attach com 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 hard drive / cdrom (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

View File

@ -0,0 +1,287 @@
/* $NetBSD: if_ep_pcmcia.c,v 1.2 1997/10/16 23:27:22 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.
*/
#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>
#include <net/if_ether.h>
#include <net/if_media.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_inarp.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>
#endif
#include <machine/cpu.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <dev/ic/elink3var.h>
#include <dev/ic/elink3reg.h>
#include <dev/pcmcia/pcmciareg.h>
#include <dev/pcmcia/pcmciavar.h>
#define PCMCIA_MANUFACTURER_3COM 0x101
#define PCMCIA_PRODUCT_3COM_3C562 0x562
#define PCMCIA_PRODUCT_3COM_3C589 0x589
#ifdef __BROKEN_INDIRECT_CONFIG
int ep_pcmcia_match __P((struct device *, void *, void *));
#else
int ep_pcmcia_match __P((struct device *, struct cfdata *, void *));
#endif
void ep_pcmcia_attach __P((struct device *, struct device *, void *));
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 *));
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_pcmcia_softc), ep_pcmcia_match, ep_pcmcia_attach
};
int
ep_pcmcia_match(parent, match, aux)
struct device *parent;
#ifdef __BROKEN_INDIRECT_CONFIG
void *match;
#else
struct cfdata *cf;
#endif
void *aux;
{
struct pcmcia_attach_args *pa = aux;
if (pa->manufacturer == PCMCIA_MANUFACTURER_3COM) {
switch (pa->product) {
case PCMCIA_PRODUCT_3COM_3C562:
case PCMCIA_PRODUCT_3COM_3C589:
if (pa->pf->number == 0)
return (1);
}
}
return (0);
}
int
ep_pcmcia_enable(sc)
struct ep_softc *sc;
{
struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
/* establish the interrupt. */
sc->sc_ih = pcmcia_intr_establish(psc->sc_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 (pcmcia_function_enable(psc->sc_pf));
}
void
ep_pcmcia_disable(sc)
struct ep_softc *sc;
{
struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
pcmcia_function_disable(psc->sc_pf);
pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
}
void
ep_pcmcia_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
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;
int i;
u_int8_t myla[ETHER_ADDR_LEN];
u_int8_t *enaddr;
char *model;
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");
sc->enabled = 1;
/* turn off the bit which disables the modem */
if (pa->product == PCMCIA_PRODUCT_3COM_3C562) {
int reg;
reg = pcmcia_ccr_read(pa->pf, PCMCIA_CCR_OPTION);
reg &= ~0x08;
pcmcia_ccr_write(pa->pf, PCMCIA_CCR_OPTION, reg);
}
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);
/*
* XXX there's a comment in the linux driver about the io address
* having to be between 0x00 and 0x70 mod 0x100. weird.
*/
if (pa->product == PCMCIA_PRODUCT_3COM_3C562) {
bus_addr_t maxaddr = (pa->pf->sc->iobase + pa->pf->sc->iosize);
for (i = roundup(pa->pf->sc->iobase, 0x100); i < maxaddr;
i += ((i % 0x100) == 0x70) ? 0x90 : 0x10) {
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;
}
if (pa->product == PCMCIA_PRODUCT_3COM_3C562) {
if (pcmcia_scan_cis(parent, ep_pcmcia_get_enaddr, myla)) {
printf(": can't read ethernet address from CIS\n");
return;
}
enaddr = myla;
} else {
enaddr = NULL;
}
sc->bustype = EP_BUS_PCMCIA;
switch (pa->product) {
case PCMCIA_PRODUCT_3COM_3C589:
model = "3Com 3C589 Ethernet";
break;
case PCMCIA_PRODUCT_3COM_3C562:
model = "3Com 3C562 Ethernet";
break;
default:
model = "3Com Ethernet, model unknown";
break;
}
printf(": %s\n", model);
sc->enable = ep_pcmcia_enable;
sc->disable = ep_pcmcia_disable;
epconfig(sc, EP_CHIPSET_3C509, enaddr);
sc->enabled = 0;
pcmcia_function_disable(pa->pf);
}
int
ep_pcmcia_get_enaddr(tuple, arg)
struct pcmcia_tuple *tuple;
void *arg;
{
u_int8_t *myla = arg;
int i;
/* this is 3c562 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);
}

View File

@ -0,0 +1,430 @@
/* $NetBSD: if_ne_pcmcia.c,v 1.2 1997/10/16 23:27:26 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.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/select.h>
#include <sys/device.h>
#include <sys/socket.h>
#include <net/if_types.h>
#include <net/if.h>
#include <net/if_ether.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <dev/pcmcia/pcmciareg.h>
#include <dev/pcmcia/pcmciavar.h>
#include <dev/ic/dp8390reg.h>
#include <dev/ic/dp8390var.h>
#include <dev/ic/ne2000reg.h>
#include <dev/ic/ne2000var.h>
#ifdef __BROKEN_INDIRECT_CONFIG
int ne_pcmcia_match __P((struct device *, void *, void *));
#else
int ne_pcmcia_match __P((struct device *, struct cfdata *, void *));
#endif
void ne_pcmcia_attach __P((struct device *, struct device *, void *));
int ne_pcmcia_enable __P((struct dp8390_softc *));
void ne_pcmcia_disable __P((struct dp8390_softc *));
struct ne_pcmcia_softc {
struct ne2000_softc sc_ne2000; /* real "ne2000" softc */
/* PCMCIA-specific goo */
struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o information */
int sc_asic_io_window; /* i/o window for ASIC */
int sc_nic_io_window; /* i/o window for NIC */
struct pcmcia_function *sc_pf; /* our PCMCIA function */
void *sc_ih; /* interrupt handle */
};
struct cfattach ne_pcmcia_ca = {
sizeof(struct ne_pcmcia_softc), ne_pcmcia_match, ne_pcmcia_attach
};
struct ne2000dev {
char *name;
int manufacturer;
int product;
char *cis1_info0;
char *cis1_info1;
int function;
int enet_maddr;
unsigned char enet_vendor[3];
} ne2000devs[] = {
{ "PreMax PE-200",
0xffff, 0xffff, "PMX ", "PE-200", 0,
0x07f0, { 0x00, 0x20, 0xe0 } },
{ "National Semiconductor InfoMover",
0x00a4, 0x0002, NULL, NULL, 0,
0x0ff0, { 0x08, 0x00, 0x5a } },
{ "DEC DEPCM-BA",
0x0000, 0x0000, "DIGITAL", "DEPCM-XX", 0,
0x0ff0, { 0x00, 0x00, 0xe8 } },
/* this card might need pcic_alloc_iobase < 0x400, and/or
CIRRUS_PD672X on TI TravelMate 5000 needs it: */
{ "Linksys EthernetCard",
0x0149, 0x0265, "LINKSYS", "E-CARD",
0, -1, { 0x00, 0x80, 0xc8 } },
{ "Planet SmartCOM 2000",
0xffffffff, 0xffff, "PCMCIA", "UE2212", 0,
0xff0, { 0x00, 0x00, 0xe8 } },
#if 0
/* the rest of these are stolen from the linux pcnet pcmcia device
driver. Since I don't know the manfid or cis info strings for
any of them, they're not compiled in until I do. */
{ "Accton EN2212",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0x00, 0xe8 } },
{ "Allied Telesis LA-PCM",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0x00, 0xf4 } },
{ "APEX MultiCard",
0x0000, 0x0000, NULL, NULL, 0,
0x03f4, { 0x00, 0x20, 0xe5 } },
{ "ASANTE FriendlyNet",
0x0000, 0x0000, NULL, NULL, 0,
0x4910, { 0x00, 0x00, 0x94 } },
{ "Danpex EN-6200P2",
0x0000, 0x0000, NULL, NULL, 0,
0x0110, { 0x00, 0x40, 0xc7 } },
{ "DataTrek NetCard",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0x20, 0xe8 } },
{ "Dayna CommuniCard E",
0x0000, 0x0000, NULL, NULL, 0,
0x0110, { 0x00, 0x80, 0x19 } },
{ "D-Link DE-650",
0x0000, 0x0000, NULL, NULL, 0,
0x0040, { 0x00, 0x80, 0xc8 } },
{ "EP-210 Ethernet",
0x0000, 0x0000, NULL, NULL, 0,
0x0110, { 0x00, 0x40, 0x33 } },
{ "Epson EEN10B",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0x00, 0x48 } },
{ "ELECOM Laneed LD-CDWA",
0x0000, 0x0000, NULL, NULL, 0,
0x00b8, { 0x08, 0x00, 0x42 } },
{ "Grey Cell GCS2220",
0x0000, 0x0000, NULL, NULL, 0,
0x0000, { 0x00, 0x47, 0x43 } },
{ "Hypertec Ethernet",
0x0000, 0x0000, NULL, NULL, 0,
0x01c0, { 0x00, 0x40, 0x4c } },
{ "IBM CCAE",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x08, 0x00, 0x5a } },
{ "IBM CCAE",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0x04, 0xac } },
{ "IBM CCAE",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0x06, 0x29 } },
{ "IBM FME",
0x0000, 0x0000, NULL, NULL, 0,
0x0374, { 0x00, 0x04, 0xac } },
{ "IBM FME",
0x0000, 0x0000, NULL, NULL, 0,
0x0374, { 0x08, 0x00, 0x5a } },
{ "I-O DATA PCLA/T",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0xa0, 0xb0 } },
{ "Katron PE-520",
0x0000, 0x0000, NULL, NULL, 0,
0x0110, { 0x00, 0x40, 0xf6 } },
{ "Kingston KNE-PCM/x",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0xc0, 0xf0 } },
{ "Kingston KNE-PCM/x",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0xe2, 0x0c, 0x0f } },
{ "Kingston KNE-PC2",
0x0000, 0x0000, NULL, NULL, 0,
0x0180, { 0x00, 0xc0, 0xf0 } },
{ "Longshine LCS-8534",
0x0000, 0x0000, NULL, NULL, 0,
0x0000, { 0x08, 0x00, 0x00 } },
{ "Maxtech PCN2000",
0x0000, 0x0000, NULL, NULL, 0,
0x5000, { 0x00, 0x00, 0xe8 } },
{ "NDC Instant-Link",
0x0000, 0x0000, NULL, NULL, 0,
0x003a, { 0x00, 0x80, 0xc6 } },
{ "NE2000 Compatible",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0xa0, 0x0c } },
{ "Network General Sniffer",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0x00, 0x65 } },
{ "Panasonic VEL211",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0x80, 0x45 } },
{ "RPTI EP400",
0x0000, 0x0000, NULL, NULL, 0,
0x0110, { 0x00, 0x40, 0x95 } },
{ "SCM Ethernet",
0x0000, 0x0000, NULL, NULL, 0,
0x0ff0, { 0x00, 0x20, 0xcb } },
{ "Socket EA",
0x0000, 0x0000, NULL, NULL, 0,
0x4000, { 0x00, 0xc0, 0x1b } },
{ "Volktek NPL-402CT",
0x0000, 0x0000, NULL, NULL, 0,
0x0060, { 0x00, 0x40, 0x05 } },
#endif
};
#define NE2000_NDEVS (sizeof(ne2000devs) / sizeof(ne2000devs[0]))
#define ne2000_match(card, fct, n) \
((((((card)->manufacturer == ne2000devs[(n)].manufacturer) && \
((card)->product == ne2000devs[(n)].product)) || \
((ne2000devs[(n)].cis1_info0) && (ne2000devs[(n)].cis1_info1) && \
(strcmp((card)->cis1_info[0], ne2000devs[(n)].cis1_info0) == 0) && \
(strcmp((card)->cis1_info[1], ne2000devs[(n)].cis1_info1) == 0))) && \
(pa->pf->number == ne2000devs[(n)].function))? \
&ne2000devs[(n)]:NULL)
int
ne_pcmcia_match(parent, match, aux)
struct device *parent;
#ifdef __BROKEN_INDIRECT_CONFIG
void *match;
#else
struct cfdata *cf;
#endif
void *aux;
{
struct pcmcia_attach_args *pa = aux;
int i;
for (i = 0; i < NE2000_NDEVS; i++) {
if (ne2000_match(pa->card, pa->pf->number, i))
return (1);
}
return (0);
}
void
ne_pcmcia_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct ne_pcmcia_softc *psc = (void *) self;
struct ne2000_softc *nsc = &psc->sc_ne2000;
struct dp8390_softc *dsc = &nsc->sc_dp8390;
struct pcmcia_attach_args *pa = aux;
struct pcmcia_config_entry *cfe;
struct ne2000dev *ne_dev;
struct pcmcia_mem_handle pcmh;
bus_addr_t offset;
int i, j, mwindow;
u_int8_t myea[6], *enaddr = NULL;
psc->sc_pf = pa->pf;
cfe = pa->pf->cfe_head.sqh_first;
#if 0
/*
* Some ne2000 driver's claim to have memory; others don't.
* Since I don't care, I don't check.
*/
if (cfe->num_memspace != 1) {
printf(": unexpected number of memory spaces "
" %d should be 1\n", cfe->num_memspace);
return;
}
#endif
if (cfe->num_iospace == 1) {
if (cfe->iospace[0].length != NE2000_NPORTS) {
printf(": unexpected I/O space configuration\n");
return;
}
} else if (cfe->num_iospace == 2) {
/*
* Some cards report a separate space for NIC and ASIC.
* This make some sense, but we must allocate a single
* NE2000_NPORTS-sized chunk, due to brain damaged
* address decoders on some of these cards.
*/
if ((cfe->iospace[0].length + cfe->iospace[1].length) !=
NE2000_NPORTS) {
printf(": unexpected I/O space configuration\n");
return;
}
} else {
printf(": unexpected number of i/o spaces %d"
" should be 1 or 2\n", cfe->num_iospace);
}
if (pcmcia_io_alloc(pa->pf, 0, NE2000_NPORTS, NE2000_NPORTS,
&psc->sc_pcioh)) {
printf(": can't alloc i/o space\n");
return;
}
dsc->sc_regt = psc->sc_pcioh.iot;
dsc->sc_regh = psc->sc_pcioh.ioh;
nsc->sc_asict = psc->sc_pcioh.iot;
if (bus_space_subregion(dsc->sc_regt, dsc->sc_regh,
NE2000_ASIC_OFFSET, NE2000_ASIC_NPORTS,
&nsc->sc_asich)) {
printf(": can't get subregion for asic\n");
return;
}
/* Set up power management hooks. */
dsc->sc_enable = ne_pcmcia_enable;
dsc->sc_disable = ne_pcmcia_disable;
/* Enable the card. */
pcmcia_function_init(pa->pf, cfe);
if (pcmcia_function_enable(pa->pf)) {
printf(": function enable failed\n");
return;
}
/* some cards claim to be io16, but they're lying. */
if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_IO8,
NE2000_NIC_OFFSET, NE2000_NIC_NPORTS,
&psc->sc_pcioh, &psc->sc_nic_io_window)) {
printf(": can't map NIC i/o space\n");
return;
}
if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_IO16,
NE2000_ASIC_OFFSET, NE2000_ASIC_NPORTS,
&psc->sc_pcioh, &psc->sc_asic_io_window)) {
printf(": can't map ASIC i/o space\n");
return;
}
printf("\n");
/*
* Read the station address from the board.
*/
for (i = 0; i < NE2000_NDEVS; i++) {
if ((ne_dev = ne2000_match(pa->card, pa->pf->number, i))
!= NULL) {
if (ne_dev->enet_maddr >= 0) {
if (pcmcia_mem_alloc(pa->pf,
ETHER_ADDR_LEN * 2, &pcmh)) {
printf("%s: can't alloc mem for"
" enet addr\n",
dsc->sc_dev.dv_xname);
return;
}
if (pcmcia_mem_map(pa->pf, PCMCIA_MEM_ATTR,
ne_dev->enet_maddr, ETHER_ADDR_LEN * 2,
&pcmh, &offset, &mwindow)) {
printf("%s: can't map mem for"
" enet addr\n",
dsc->sc_dev.dv_xname);
return;
}
for (j = 0; j < ETHER_ADDR_LEN; j++)
myea[j] = bus_space_read_1(pcmh.memt,
pcmh.memh, offset + (j * 2));
pcmcia_mem_unmap(pa->pf, mwindow);
pcmcia_mem_free(pa->pf, &pcmh);
enaddr = myea;
}
break;
}
}
if (enaddr != NULL) {
/*
* Make sure this is what we expect.
*/
if (enaddr[0] != ne_dev->enet_vendor[0] ||
enaddr[1] != ne_dev->enet_vendor[1] ||
enaddr[2] != ne_dev->enet_vendor[2]) {
printf("\n%s: enet addr has incorrect vendor code\n",
dsc->sc_dev.dv_xname);
printf("%s: (%02x:%02x:%02x should be "
"%02x:%02x:%02x)\n", dsc->sc_dev.dv_xname,
enaddr[0], enaddr[1], enaddr[2],
ne_dev->enet_vendor[0],
ne_dev->enet_vendor[1],
ne_dev->enet_vendor[2]);
return;
}
}
printf("%s: %s Ethernet\n", dsc->sc_dev.dv_xname, ne_dev->name);
ne2000_attach(nsc, enaddr);
pcmcia_function_disable(pa->pf);
}
int
ne_pcmcia_enable(dsc)
struct dp8390_softc *dsc;
{
struct ne_pcmcia_softc *psc = (struct ne_pcmcia_softc *)dsc;
/* set up the interrupt */
psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, dp8390_intr,
dsc);
if (psc->sc_ih == NULL) {
printf("%s: couldn't establish interrupt\n",
dsc->sc_dev.dv_xname);
return (1);
}
return (pcmcia_function_enable(psc->sc_pf));
}
void
ne_pcmcia_disable(dsc)
struct dp8390_softc *dsc;
{
struct ne_pcmcia_softc *psc = (struct ne_pcmcia_softc *)dsc;
pcmcia_function_disable(psc->sc_pf);
pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
}

View File

@ -0,0 +1,273 @@
/* $NetBSD: if_sm_pcmcia.c,v 1.2 1997/10/16 23:27:28 thorpej Exp $ */
/*-
* Copyright (c) 1997 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>
#include <net/if_ether.h>
#include <net/if_media.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_inarp.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>
#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>
#define PCMCIA_MANUFACTURER_MEGAHERTZ 0x128
#define PCMCIA_PRODUCT_MEGAHERTZ_XJACK 0x103
#ifdef __BROKEN_INDIRECT_CONFIG
int sm_pcmcia_match __P((struct device *, void *, void *));
#else
int sm_pcmcia_match __P((struct device *, struct cfdata *, void *));
#endif
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_match(parent, match, aux)
struct device *parent;
#ifdef __BROKEN_INDIRECT_CONFIG
void *match;
#else
struct cfdata *match;
#endif
void *aux;
{
struct pcmcia_attach_args *pa = aux;
if (pa->manufacturer == PCMCIA_MANUFACTURER_MEGAHERTZ) {
switch (pa->product) {
case PCMCIA_PRODUCT_MEGAHERTZ_XJACK:
if (pa->pf->number == 0)
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;
const char *model;
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;
}
switch (pa->product) {
case PCMCIA_PRODUCT_MEGAHERTZ_XJACK:
model = "Megahertz X-JACK Ethernet";
break;
default:
model = "Unknown SMC91Cxx Ethernet";
}
printf(": %s\n", model);
if (pa->product == PCMCIA_PRODUCT_MEGAHERTZ_XJACK) {
char enaddr_str[12];
int i = 0, j;
/*
* The X-JACK's Ethernet address is stored in the fourth
* CIS info string. We need to parse it and pass it to
* the generic layer.
*/
if (strlen(pa->pf->sc->card.cis1_info[3]) != 12) {
/* Bogus address! */
goto out;
}
bcopy(pa->pf->sc->card.cis1_info[3], 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!! */
goto out;
}
/* Compensate for ordering of digits. */
if (j == 0)
myla[i] <<= 4;
}
}
out:
if (i >= 6) {
/* Successfully parsed. */
enaddr = myla;
} else {
printf("%s: unable to read MAC address from CIS\n",
sc->sc_dev.dv_xname);
}
}
/* Perform generic intialization. */
smc91cxx_attach(sc, enaddr);
pcmcia_function_disable(pa->pf);
}
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);
}

727
sys/dev/pcmcia/pcmcia.c Normal file
View File

@ -0,0 +1,727 @@
/* $NetBSD: pcmcia.c,v 1.2 1997/10/16 23:27:30 thorpej Exp $ */
#define PCMCIADEBUG
/*
* 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 "opt_pcmciaverbose.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
/* XXX only needed for intr debugging */
#include <vm/vm.h>
#include <dev/pcmcia/pcmciareg.h>
#include <dev/pcmcia/pcmciachip.h>
#include <dev/pcmcia/pcmciavar.h>
#ifdef PCMCIADEBUG
int pcmcia_debug = 0;
#define DPRINTF(arg) if (pcmcia_debug) printf arg
#else
#define DPRINTF(arg)
#endif
#ifdef PCMCIAVERBOSE
int pcmcia_verbose = 1;
#else
int pcmcia_verbose = 0;
#endif
#ifdef __BROKEN_INDIRECT_CONFIG
int pcmcia_match __P((struct device *, void *, void *));
int pcmcia_submatch __P((struct device *, void *, void *));
#else
int pcmcia_match __P((struct device *, struct cfdata *, void *));
int pcmcia_submatch __P((struct device *, struct cfdata *, void *));
#endif
void pcmcia_attach __P((struct device *, struct device *, void *));
int pcmcia_print __P((void *, const char *));
int pcmcia_card_intr __P((void *));
struct cfdriver pcmcia_cd = {
NULL, "pcmcia", DV_DULL
};
struct cfattach pcmcia_ca = {
sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach
};
int
pcmcia_ccr_read(pf, ccr)
struct pcmcia_function *pf;
int ccr;
{
return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
pf->pf_ccr_offset + ccr));
}
void
pcmcia_ccr_write(pf, ccr, val)
struct pcmcia_function *pf;
int ccr;
int val;
{
if ((pf->ccr_mask) & (1 << (ccr / 2))) {
bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
pf->pf_ccr_offset + ccr, val);
}
}
int
pcmcia_match(parent, match, aux)
struct device *parent;
#ifdef __BROKEN_INDIRECT_CONFIG
void *match;
#else
struct cfdata *match;
#endif
void *aux;
{
/* if the autoconfiguration got this far, there's a socket here */
return (1);
}
void
pcmcia_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct pcmciabus_attach_args *paa = aux;
struct pcmcia_softc *sc = (struct pcmcia_softc *) self;
printf("\n");
sc->pct = paa->pct;
sc->pch = paa->pch;
sc->iobase = paa->iobase;
sc->iosize = paa->iosize;
sc->ih = NULL;
}
int
pcmcia_card_attach(dev)
struct device *dev;
{
struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
struct pcmcia_function *pf;
struct pcmcia_attach_args paa;
int attached;
/*
* this is here so that when socket_enable calls gettype, trt happens
*/
sc->card.pf_head.sqh_first = NULL;
pcmcia_chip_socket_enable(sc->pct, sc->pch);
pcmcia_read_cis(sc);
pcmcia_chip_socket_disable(sc->pct, sc->pch);
/*
* bail now if the card has no functions, or if there was an error in
* the cis.
*/
if (sc->card.error)
return (1);
if (sc->card.pf_head.sqh_first == NULL)
return (1);
if (pcmcia_verbose)
pcmcia_print_cis(sc);
attached = 0;
for (pf = sc->card.pf_head.sqh_first; pf != NULL;
pf = pf->pf_list.sqe_next) {
if (pf->cfe_head.sqh_first == NULL)
continue;
pf->sc = sc;
pf->cfe = NULL;
pf->ih_fct = NULL;
pf->ih_arg = 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;
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)));
}
}
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
#ifdef __BROKEN_INDIRECT_CONFIG
pcmcia_submatch(parent, match, aux)
struct device *parent;
void *match, *aux;
{
struct cfdata *cf = match;
#else
pcmcia_submatch(parent, cf, aux)
struct device *parent;
struct cfdata *cf;
void *aux;
{
#endif
struct pcmcia_attach_args *paa = aux;
if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != paa->pf->number)
return (0);
return ((*cf->cf_attach->ca_match)(parent, cf, aux));
}
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);
return (UNCONF);
}
int
pcmcia_card_gettype(dev)
struct device *dev;
{
struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
/*
* set the iftype to memory if this card has no functions (not yet
* probed), or only one function, and that is memory.
*/
if (sc->card.pf_head.sqh_first == NULL ||
(sc->card.pf_head.sqh_first != NULL &&
sc->card.pf_head.sqh_first->pf_list.sqe_next == NULL &&
(sc->card.pf_head.sqh_first->cfe_head.sqh_first->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_function_init(pf, cfe)
struct pcmcia_function *pf;
struct pcmcia_config_entry *cfe;
{
if (pf->pf_flags & PFF_ENABLED)
panic("pcmcia_function_init: function is enabled");
/* Remember which configuration entry we are using. */
pf->cfe = cfe;
}
/* Enable a PCMCIA function */
int
pcmcia_function_enable(pf)
struct pcmcia_function *pf;
{
struct pcmcia_function *tmp;
int reg;
if (pf->cfe == NULL)
panic("pcmcia_function_enable: function not initialized");
if (pf->pf_flags & PFF_ENABLED) {
/*
* Don't do anything if we're already enabled.
*/
return (0);
}
/*
* 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);
/*
* it's possible for different functions' CCRs to be in the same
* underlying page. Check for that.
*/
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 (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;
}
}
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), 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)));
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_write(pf, PCMCIA_CCR_OPTION, reg);
reg = 0;
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;
/* Not really needed, since we start with 0. */
if (pf->cfe->flags & PCMCIA_CFE_POWERDOWN)
reg &= ~PCMCIA_CCR_STATUS_PWRDWN;
pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
pcmcia_ccr_write(pf, PCMCIA_CCR_SOCKETCOPY, 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-- == 1)
pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
return (1);
}
/* Disable PCMCIA function. */
void
pcmcia_function_disable(pf)
struct pcmcia_function *pf;
{
struct pcmcia_function *tmp;
int reg;
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;
}
/* Power down the function if the card supports it. */
if (pf->cfe->flags & PCMCIA_CFE_POWERDOWN) {
reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
reg |= PCMCIA_CCR_STATUS_PWRDWN;
pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
}
/*
* 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.
*/
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;
}
/* 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);
}
int
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;
{
bus_addr_t ioaddr;
int reg;
if (pcmcia_chip_io_map(pf->sc->pct, pf->sc->pch,
width, offset, size, pcihp, windowp))
return (1);
ioaddr = pcihp->addr + offset;
/*
* 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
*/
if (pcmcia_mfc(pf->sc)) {
pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0, ioaddr & 0xff);
pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1, (ioaddr >> 8) & 0xff);
pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE, size - 1);
reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
}
return (0);
}
void *
pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg)
struct pcmcia_function *pf;
int ipl;
int (*ih_fct) __P((void *));
void *ih_arg;
{
void *ret;
/* behave differently if this is a multifunction card */
if (pcmcia_mfc(pf->sc)) {
int s, ihcnt, hiipl, reg;
struct pcmcia_function *pf2;
/* XXX splraise() use needs to go away! */
/*
* mask all the ipl's which are already used by this card,
* and find the highest ipl number (lowest priority)
*/
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->ih_fct) {
if (ihcnt == 0) {
s = splraise(pf2->ih_ipl);
hiipl = pf2->ih_ipl;
ihcnt++;
} else {
splraise(pf2->ih_ipl);
if (pf2->ih_ipl > hiipl)
hiipl = pf2->ih_ipl;
}
}
}
/* set up the handler for the new function */
pf->ih_fct = ih_fct;
pf->ih_arg = ih_arg;
pf->ih_ipl = ipl;
/*
* establish the real interrupt, changing the ipl if
* necessary
*/
if (ihcnt == 0) {
#ifdef DIAGNOSTIC
if (pf->sc->ih != NULL)
panic("card has intr handler, but no function does");
#endif
pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc);
} else if (ipl > hiipl) {
#ifdef DIAGNOSTIC
if (pf->sc->ih == NULL)
panic("functions have ih, but the card does not");
#endif
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, ipl, pcmcia_card_intr, pf->sc);
}
if (ihcnt)
splx(s);
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 (ret);
}
void
pcmcia_intr_disestablish(pf, ih)
struct pcmcia_function *pf;
void *ih;
{
/* behave differently if this is a multifunction card */
if (pcmcia_mfc(pf->sc)) {
int s, ihcnt, hiipl;
struct pcmcia_function *pf2;
/*
* mask all the ipl's which are already used by this card,
* and find the highest ipl number (lowest priority). Skip
* the current function.
*/
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) {
s = splraise(pf2->ih_ipl);
hiipl = pf2->ih_ipl;
ihcnt++;
} else {
splraise(pf2->ih_ipl);
if (pf2->ih_ipl > hiipl)
hiipl = pf2->ih_ipl;
}
}
}
/* null out the handler for this function */
pf->ih_fct = NULL;
pf->ih_arg = NULL;
/*
* if the ih being removed is lower priority than the lowest
* priority remaining interrupt, up the priority.
*/
#ifdef DIAGNOSTIC
if (ihcnt == 0) {
panic("can't remove a handler from a card which has none");
} else
#endif
if (ihcnt == 1) {
#ifdef DIAGNOSTIC
if (pf->sc->ih == NULL)
panic("disestablishing last function, but card has no ih");
#endif
pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
pf->sc->ih);
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
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);
}
if (ihcnt)
splx(s);
} else {
pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih);
}
}
int
pcmcia_card_intr(arg)
void *arg;
{
struct pcmcia_softc *sc = arg;
struct pcmcia_function *pf;
int reg, ret, ret2;
ret = 0;
for (pf = sc->card.pf_head.sqh_first; pf != NULL;
pf = pf->pf_list.sqe_next) {
#if 0
printf("%s: intr fct=%d physaddr=%lx cor=%02x csr=%02x pin=%02x",
sc->dev.dv_xname, pf->number,
pmap_extract(pmap_kernel(),
(vm_offset_t) pf->ccrh) + pf->ccr_offset,
bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
pf->pf_ccr_offset + PCMCIA_CCR_OPTION),
bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
pf->pf_ccr_offset + PCMCIA_CCR_STATUS),
bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
pf->pf_ccr_offset + PCMCIA_CCR_PIN));
#endif
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
printf("; csr %02x->%02x",
reg, reg & ~PCMCIA_CCR_STATUS_INTR);
#endif
pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
reg & ~PCMCIA_CCR_STATUS_INTR);
}
}
#if 0
printf("\n");
#endif
}
return (ret);
}

1158
sys/dev/pcmcia/pcmcia_cis.c Normal file

File diff suppressed because it is too large Load Diff

144
sys/dev/pcmcia/pcmciachip.h Normal file
View File

@ -0,0 +1,144 @@
/* $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_ */

221
sys/dev/pcmcia/pcmciareg.h Normal file
View File

@ -0,0 +1,221 @@
/* $NetBSD: pcmciareg.h,v 1.2 1997/10/16 23:27:38 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.
*/
/* most of this is from the PCMCIA PC Card Standard, Release 2.1 */
/*
* 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 0x05
/*
* 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
*/
#define PCMCIA_CISTPL_LONGLINK_CB 0x02
#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_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
/* Layer 2 Data Recording Format Tuples */
#define PCMCIA_CISTPL_MANFID 0x20
#define PCMCIA_CISTPL_FUNCID 0x21
#define PCMCIA_CISTPL_FUNCE 0x22
#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
/* 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-0xFE */
#define PCMCIA_CISTPL_END 0xFF
/*
* Card Configuration Registers
*/
#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_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

252
sys/dev/pcmcia/pcmciavar.h Normal file
View File

@ -0,0 +1,252 @@
/* $NetBSD: pcmciavar.h,v 1.2 1997/10/16 23:27:40 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.
*/
#include <sys/types.h>
#include <sys/queue.h>
#include <machine/bus.h>
#include <dev/pcmcia/pcmciachip.h>
/*
* Contains information about mapped/allocated i/o spaces.
*/
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_IO_ALLOCATED 0x01 /* i/o space was allocated */
/*
* Contains information about allocated memory space.
*/
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 */
};
/* 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
struct pcmcia_config_entry {
int number;
u_int32_t flags;
int iftype;
int num_iospace;
/*
* 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_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;
int (*ih_fct) __P((void *));
void *ih_arg;
int ih_ipl;
int pf_flags;
};
/* 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];
int manufacturer;
u_int16_t product;
u_int16_t error;
SIMPLEQ_HEAD(, pcmcia_function) pf_head;
};
struct pcmcia_softc {
struct device dev;
/* this stuff is for the socket */
pcmcia_chipset_tag_t pct;
pcmcia_chipset_handle_t pch;
/* 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 */
};
struct pcmcia_attach_args {
u_int16_t manufacturer;
u_int16_t product;
struct pcmcia_card *card;
struct pcmcia_function *pf;
};
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;
};
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 *));