summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico G. Schwindt <fgsch@cvs.openbsd.org>2000-05-30 14:36:42 +0000
committerFederico G. Schwindt <fgsch@cvs.openbsd.org>2000-05-30 14:36:42 +0000
commit453a7b8dba7ab24340a472343881325f9e87ef91 (patch)
treefd80460fd8d2ff021ff690aec82a009d20d8d079
parent95e20ed8307bddafac4d8f21791e7c74224c8cd1 (diff)
Changes from NetBSD:
* support for ax88190 cards * instead of using the first cfe entry, go thru the whole list. * change the code so cards with same id but different mac can be allowed (ibm infomover by instance) * on fail, be sure to unmap and/or free all the resources previously allocated; we really need to do this in the rest of the drivers * new products
-rw-r--r--sys/dev/pcmcia/if_ne_pcmcia.c365
1 files changed, 260 insertions, 105 deletions
diff --git a/sys/dev/pcmcia/if_ne_pcmcia.c b/sys/dev/pcmcia/if_ne_pcmcia.c
index a3340e9e1e4..c94320010ee 100644
--- a/sys/dev/pcmcia/if_ne_pcmcia.c
+++ b/sys/dev/pcmcia/if_ne_pcmcia.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ne_pcmcia.c,v 1.28 2000/04/25 04:48:49 fgsch Exp $ */
+/* $OpenBSD: if_ne_pcmcia.c,v 1.29 2000/05/30 14:36:41 fgsch Exp $ */
/* $NetBSD: if_ne_pcmcia.c,v 1.17 1998/08/15 19:00:04 thorpej Exp $ */
/*
@@ -77,6 +77,14 @@ struct ne_pcmcia_softc {
void *sc_ih; /* interrupt handle */
};
+u_int8_t *
+ ne_pcmcia_get_enaddr __P((struct ne_pcmcia_softc *, int,
+ u_int8_t[ETHER_ADDR_LEN]));
+u_int8_t *
+ ne_pcmcia_dl10019_get_enaddr __P((struct ne_pcmcia_softc *,
+ u_int8_t[ETHER_ADDR_LEN]));
+int ne_pcmcia_ax88190_set_iobase __P((struct ne_pcmcia_softc *));
+
struct cfattach ne_pcmcia_ca = {
sizeof(struct ne_pcmcia_softc), ne_pcmcia_match, ne_pcmcia_attach,
ne_pcmcia_detach, ne_pcmcia_activate
@@ -89,6 +97,9 @@ struct ne2000dev {
int function;
int enet_maddr;
unsigned char enet_vendor[3];
+ int flags;
+#define NE2000DVF_DL10019 0x0001 /* chip is D-Link DL10019 */
+#define NE2000DVF_AX88190 0x0002 /* chip is ASIX AX88190 */
} ne2000devs[] = {
{ PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
PCMCIA_CIS_AMBICOM_AMB8002T,
@@ -165,32 +176,42 @@ struct ne2000dev {
PCMCIA_CIS_IBM_INFOMOVER,
0, 0x0ff0, { 0x08, 0x00, 0x5a } },
+ { PCMCIA_VENDOR_IBM, PCMCIA_PRODUCT_IBM_INFOMOVER,
+ PCMCIA_CIS_IBM_INFOMOVER,
+ 0, 0x0ff0, { 0x00, 0x04, 0xac } },
+
+ { PCMCIA_VENDOR_IBM, PCMCIA_PRODUCT_IBM_INFOMOVER,
+ PCMCIA_CIS_IBM_INFOMOVER,
+ 0, 0x0ff0, { 0x00, 0x06, 0x29 } },
+
{ PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_ECARD_1,
PCMCIA_CIS_LINKSYS_ECARD_1,
0, -1, { 0x00, 0x80, 0xc8 } },
{ PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_COMBO_ECARD,
PCMCIA_CIS_PLANEX_FNW3600T,
- 0, -1, { 0x00, 0x90, 0xcc } },
+ 0, -1, { 0x00, 0x90, 0xcc }, NE2000DVF_DL10019 },
{ PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_COMBO_ECARD,
PCMCIA_CIS_SVEC_PN650TX,
- 0, -1, { 0x00, 0xe0, 0x98 } },
+ 0, -1, { 0x00, 0xe0, 0x98 }, NE2000DVF_DL10019 },
/*
* This entry should be here so that above two cards doesn't
* match with this. FNW-3700T won't match above entries due to
* MAC address check.
*/
-#if 0
{ PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_COMBO_ECARD,
PCMCIA_CIS_PLANEX_FNW3700T,
- 0, -1, { 0x00, 0x90, 0xcc } },
-#endif
+ 0, -1, { 0x00, 0x90, 0xcc }, NE2000DVF_AX88190 },
{ PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_ETHERFAST,
PCMCIA_CIS_LINKSYS_ETHERFAST,
- 0, -1, { 0x00, 0x80, 0xc8 } },
+ 0, -1, { 0x00, 0x80, 0xc8 }, NE2000DVF_DL10019 },
+
+ { PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_ETHERFAST,
+ PCMCIA_CIS_DLINK_DE650,
+ 0, -1, { 0x00, 0xe0, 0x98 }, NE2000DVF_DL10019 },
{ PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_COMBO_ECARD,
PCMCIA_CIS_LINKSYS_COMBO_ECARD,
@@ -268,7 +289,7 @@ struct ne2000dev {
{ PCMCIA_VENDOR_COREGA, PCMCIA_PRODUCT_COREGA_FAST_ETHER_PCC_TX,
PCMCIA_CIS_COREGA_FAST_ETHER_PCC_TX,
- 0, -1, { 0x00, 0x00, 0xf4 } },
+ 0, -1, { 0x00, 0x00, 0xf4 }, NE2000DVF_DL10019 },
{ PCMCIA_VENDOR_COMPEX, PCMCIA_PRODUCT_COMPEX_LINKPORT_ENET_B,
PCMCIA_CIS_COMPEX_LINKPORT_ENET_B,
@@ -286,11 +307,9 @@ struct ne2000dev {
PCMCIA_CIS_XIRCOM_CFE_10,
0, -1, { 0x00, 0x10, 0xa4 } },
-#if 0
{ PCMCIA_VENDOR_MELCO, PCMCIA_PRODUCT_MELCO_LPC3_TX,
PCMCIA_CIS_MELCO_LPC3_TX,
- 0, -1, { 0x00, 0x40, 0x26 } },
-#endif
+ 0, -1, { 0x00, 0x40, 0x26 }, NE2000DVF_AX88190 },
{ PCMCIA_VENDOR_DUAL, PCMCIA_PRODUCT_DUAL_NE2000,
PCMCIA_CIS_DUAL_NE2000,
@@ -332,15 +351,6 @@ struct ne2000dev {
{ "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 } },
@@ -423,10 +433,8 @@ ne_pcmcia_attach(parent, self, aux)
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 *enaddr = NULL;
+ int i;
+ u_int8_t myea[6], *enaddr;
void (*npp_init_media) __P((struct dp8390_softc *, int **,
int *, int *));
int *media, nmedia, defmedia;
@@ -436,47 +444,65 @@ ne_pcmcia_attach(parent, self, aux)
nmedia = defmedia = 0;
psc->sc_pf = pa->pf;
- cfe = pa->pf->cfe_head.sqh_first;
+ for (cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); cfe != NULL;
+ cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
#if 0
- /*
- * Some ne2000 driver's claim to have memory; others don't.
- * Since I don't care, I don't check.
- */
+ /*
+ * 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;
- }
+ 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;
+ if (cfe->num_iospace == 1) {
+ if (cfe->iospace[0].length != NE2000_NPORTS) {
+ printf(": unexpected I/O space "
+ "configuration\n");
+ continue;
+ }
+ } 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) {
+#ifdef DIAGNOSTIC
+ printf(": unexpected I/O space "
+ "configuration\n");
+#endif
+ continue;
+ }
+ } else {
+#ifdef DIAGNOSTIC
+ printf(": unexpected number of i/o spaces %d"
+ " should be 1 or 2\n", cfe->num_iospace);
+#endif
+ continue;
}
- } 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;
+
+ if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
+ NE2000_NPORTS, NE2000_NPORTS, &psc->sc_pcioh)) {
+#ifdef DIAGNOSTIC
+ printf(": can't allocate I/O space\n");
+#endif
+ continue;
}
- } else {
- printf(": unexpected number of i/o spaces %d"
- " should be 1 or 2\n", cfe->num_iospace);
+
+ break;
}
- if (pcmcia_io_alloc(pa->pf, 0, NE2000_NPORTS, NE2000_NPORTS,
- &psc->sc_pcioh)) {
- printf(": can't alloc i/o space\n");
- return;
+ if (cfe == NULL) {
+ printf(": no suitable config entry\n");
+ goto fail_1;
}
dsc->sc_regt = psc->sc_pcioh.iot;
@@ -484,13 +510,12 @@ ne_pcmcia_attach(parent, self, aux)
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)) {
+ NE2000_ASIC_OFFSET, NE2000_ASIC_NPORTS, &nsc->sc_asich)) {
printf(": can't get subregion for asic\n");
- return;
+ goto fail_2;
}
-#if 0
+#ifdef notyet
/* Set up power management hooks. */
dsc->sc_enable = ne_pcmcia_enable;
dsc->sc_disable = ne_pcmcia_disable;
@@ -500,24 +525,22 @@ ne_pcmcia_attach(parent, self, aux)
pcmcia_function_init(pa->pf, cfe);
if (pcmcia_function_enable(pa->pf)) {
printf(": function enable failed\n");
- return;
+ goto fail_2;
}
dsc->sc_enabled = 1;
/* 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_IO8, NE2000_NIC_OFFSET,
+ NE2000_NIC_NPORTS, &psc->sc_pcioh, &psc->sc_nic_io_window)) {
+ printf(": can't map NIC I/O space\n");
+ goto fail_3;
}
- 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;
+ 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");
+ goto fail_4;
}
printf(" port 0x%lx/%d", psc->sc_pcioh.addr, NE2000_NIC_NPORTS);
@@ -525,34 +548,35 @@ ne_pcmcia_attach(parent, self, aux)
/*
* 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) {
+ i = 0;
+again:
+ enaddr = NULL; /* Ask ASIC by default */
+ for (; i < NE2000_NDEVS; i++) {
+ ne_dev = ne2000_match(pa->card, pa->pf->number, i);
+ if (ne_dev != NULL) {
if (ne_dev->enet_maddr >= 0) {
- if (pcmcia_mem_alloc(pa->pf,
- ETHER_ADDR_LEN * 2, &pcmh)) {
- printf(": can't alloc mem for"
- " address\n");
- return;
- }
- if (pcmcia_mem_map(pa->pf, PCMCIA_MEM_ATTR,
- ne_dev->enet_maddr, ETHER_ADDR_LEN * 2,
- &pcmh, &offset, &mwindow)) {
- printf(": can't map mem for"
- " address\n");
- return;
- }
- for (j = 0; j < ETHER_ADDR_LEN; j++)
- dsc->sc_arpcom.ac_enaddr[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 = dsc->sc_arpcom.ac_enaddr;
+ enaddr = ne_pcmcia_get_enaddr(psc,
+ ne_dev->enet_maddr, myea);
+ if (enaddr == NULL)
+ continue;
}
break;
}
}
+ if (i == NE2000_NDEVS) {
+ printf("%s: can't match ethernet vendor code\n",
+ dsc->sc_dev.dv_xname);
+ goto fail_5;
+ }
+
+ if ((ne_dev->flags & NE2000DVF_DL10019) != 0) {
+ enaddr = ne_pcmcia_dl10019_get_enaddr(psc, myea);
+ if (enaddr == NULL) {
+ ++i;
+ goto again;
+ }
+ nsc->sc_type = NE2000_TYPE_DL10019;
+ }
if (enaddr != NULL) {
/*
@@ -561,18 +585,18 @@ ne_pcmcia_attach(parent, self, aux)
if (enaddr[0] != ne_dev->enet_vendor[0] ||
enaddr[1] != ne_dev->enet_vendor[1] ||
enaddr[2] != ne_dev->enet_vendor[2]) {
- printf("%s: enet addr has incorrect vendor code\n",
- dsc->sc_dev.dv_xname);
- printf(": (%02x:%02x:%02x should be "
- "%02x:%02x:%02x)\n",
- enaddr[0], enaddr[1], enaddr[2],
- ne_dev->enet_vendor[0],
- ne_dev->enet_vendor[1],
- ne_dev->enet_vendor[2]);
- return;
+ ++i;
+ goto again;
}
}
+ if ((ne_dev->flags & NE2000DVF_AX88190) != 0) {
+ if (ne_pcmcia_ax88190_set_iobase(psc))
+ goto fail_5;
+
+ nsc->sc_type = NE2000_TYPE_AX88190;
+ }
+
/*
* Check for a RealTek 8019.
*/
@@ -600,11 +624,31 @@ ne_pcmcia_attach(parent, self, aux)
if (npp_init_media != NULL)
(*npp_init_media)(dsc, &media, &nmedia, &defmedia);
- ne2000_attach(nsc, enaddr, media, nmedia, defmedia);
+ if (ne2000_attach(nsc, enaddr, media, nmedia, defmedia))
+ goto fail_5;
-#if 0
+#if notyet
pcmcia_function_disable(pa->pf);
#endif
+ return;
+
+fail_5:
+ /* Unmap ASIC I/O windows. */
+ pcmcia_io_unmap(psc->sc_pf, psc->sc_asic_io_window);
+
+fail_4:
+ /* Unmap NIC I/O windows. */
+ pcmcia_io_unmap(psc->sc_pf, psc->sc_nic_io_window);
+
+fail_3:
+ pcmcia_function_disable(pa->pf);
+
+fail_2:
+ /* Free our I/O space. */
+ pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
+
+fail_1:
+ psc->sc_nic_io_window = -1;
}
int
@@ -617,6 +661,10 @@ ne_pcmcia_detach(dev, flags)
struct ifnet *ifp = &dsc->sc_arpcom.ac_if;
int rv = 0;
+ if (psc->sc_nic_io_window == -1)
+ /* Nothing to detach. */
+ return (0);
+
pcmcia_io_unmap(psc->sc_pf, psc->sc_asic_io_window);
pcmcia_io_unmap(psc->sc_pf, psc->sc_nic_io_window);
pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
@@ -687,3 +735,110 @@ ne_pcmcia_disable(dsc)
pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
pcmcia_function_disable(psc->sc_pf);
}
+
+u_int8_t *
+ne_pcmcia_get_enaddr(psc, maddr, myea)
+ struct ne_pcmcia_softc *psc;
+ int maddr;
+ u_int8_t myea[ETHER_ADDR_LEN];
+{
+ struct ne2000_softc *nsc = &psc->sc_ne2000;
+ struct dp8390_softc *dsc = &nsc->sc_dp8390;
+ struct pcmcia_mem_handle pcmh;
+ bus_addr_t offset;
+ u_int8_t *enaddr = NULL;
+ int j, mwindow;
+
+ if (maddr < 0)
+ return (NULL);
+
+ if (pcmcia_mem_alloc(psc->sc_pf, ETHER_ADDR_LEN * 2, &pcmh)) {
+ printf("%s: can't alloc mem for enet addr\n",
+ dsc->sc_dev.dv_xname);
+ goto fail_1;
+ }
+ if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR, maddr,
+ ETHER_ADDR_LEN * 2, &pcmh, &offset, &mwindow)) {
+ printf("%s: can't map mem for enet addr\n",
+ dsc->sc_dev.dv_xname);
+ goto fail_2;
+ }
+ for (j = 0; j < ETHER_ADDR_LEN; j++)
+ myea[j] = bus_space_read_1(pcmh.memt, pcmh.memh,
+ offset + (j * 2));
+ enaddr = myea;
+
+ pcmcia_mem_unmap(psc->sc_pf, mwindow);
+ fail_2:
+ pcmcia_mem_free(psc->sc_pf, &pcmh);
+ fail_1:
+ return (enaddr);
+}
+
+u_int8_t *
+ne_pcmcia_dl10019_get_enaddr(psc, myea)
+ struct ne_pcmcia_softc *psc;
+ u_int8_t myea[ETHER_ADDR_LEN];
+{
+ struct ne2000_softc *nsc = &psc->sc_ne2000;
+ u_int8_t sum;
+ int j;
+
+#define PAR0 0x04
+ for (j = 0, sum = 0; j < 8; j++)
+ sum += bus_space_read_1(nsc->sc_asict, nsc->sc_asich,
+ PAR0 + j);
+ if (sum != 0xff)
+ return (NULL);
+ for (j = 0; j < ETHER_ADDR_LEN; j++)
+ myea[j] = bus_space_read_1(nsc->sc_asict,
+ nsc->sc_asich, PAR0 + j);
+#undef PAR0
+ return (myea);
+}
+
+int
+ne_pcmcia_ax88190_set_iobase(psc)
+ struct ne_pcmcia_softc *psc;
+{
+ struct ne2000_softc *nsc = &psc->sc_ne2000;
+ struct dp8390_softc *dsc = &nsc->sc_dp8390;
+ struct pcmcia_mem_handle pcmh;
+ bus_addr_t offset;
+ int rv = 1, mwindow;
+
+ if (pcmcia_mem_alloc(psc->sc_pf, NE2000_AX88190_LAN_IOSIZE, &pcmh)) {
+ printf("%s: can't alloc mem for LAN iobase\n",
+ dsc->sc_dev.dv_xname);
+ goto fail_1;
+ }
+ if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR,
+ NE2000_AX88190_LAN_IOBASE, NE2000_AX88190_LAN_IOSIZE,
+ &pcmh, &offset, &mwindow)) {
+ printf("%s: can't map mem for LAN iobase\n",
+ dsc->sc_dev.dv_xname);
+ goto fail_2;
+ }
+
+#ifdef DIAGNOSTIC
+ printf("%s: LAN iobase 0x%x (0x%x) ->", dsc->sc_dev.dv_xname,
+ bus_space_read_1(pcmh.memt, pcmh.memh, offset + 0) |
+ bus_space_read_1(pcmh.memt, pcmh.memh, offset + 2) << 8,
+ (u_int)psc->sc_pcioh.addr);
+#endif
+ bus_space_write_1(pcmh.memt, pcmh.memh, offset,
+ psc->sc_pcioh.addr & 0xff);
+ bus_space_write_1(pcmh.memt, pcmh.memh, offset + 2,
+ psc->sc_pcioh.addr >> 8);
+#ifdef DIAGNOSTIC
+ printf(" 0x%x\n", bus_space_read_1(pcmh.memt, pcmh.memh, offset + 0) |
+ bus_space_read_1(pcmh.memt, pcmh.memh, offset + 2) << 8);
+#endif
+ rv = 0;
+
+ pcmcia_mem_unmap(psc->sc_pf, mwindow);
+ fail_2:
+ pcmcia_mem_free(psc->sc_pf, &pcmh);
+ fail_1:
+ return (rv);
+}