if_ed_pccard.c revision 113080
1117395Skan/* 2117395Skan * Copyright (c) 1995, David Greenman 390075Sobrien * All rights reserved. 490075Sobrien * 590075Sobrien * Redistribution and use in source and binary forms, with or without 690075Sobrien * modification, are permitted provided that the following conditions 790075Sobrien * are met: 890075Sobrien * 1. Redistributions of source code must retain the above copyright 990075Sobrien * notice unmodified, this list of conditions, and the following 1090075Sobrien * disclaimer. 1190075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1290075Sobrien * notice, this list of conditions and the following disclaimer in the 13117395Skan * documentation and/or other materials provided with the distribution. 14117395Skan * 1590075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1690075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1790075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1890075Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1990075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2090075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2190075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2290075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2390075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24107590Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25107590Sobrien * SUCH DAMAGE. 2696263Sobrien * 2796263Sobrien * $FreeBSD: head/sys/dev/ed/if_ed_pccard.c 113080 2003-04-04 14:46:50Z sanpei $ 2890075Sobrien */ 2990075Sobrien 3090075Sobrien#include "opt_ed.h" 3190075Sobrien 32117395Skan#include <sys/param.h> 3390075Sobrien#include <sys/systm.h> 3490075Sobrien#include <sys/socket.h> 35122180Skan#include <sys/kernel.h> 36122180Skan#include <sys/conf.h> 37122180Skan#include <sys/uio.h> 3890075Sobrien 3990075Sobrien#include <sys/module.h> 4090075Sobrien#include <sys/bus.h> 41107590Sobrien#include <machine/bus.h> 42107590Sobrien#include <sys/rman.h> 43107590Sobrien#include <machine/resource.h> 44107590Sobrien 45107590Sobrien#include <net/ethernet.h> 46107590Sobrien#include <net/if.h> 47117395Skan#include <net/if_arp.h> 48107590Sobrien#include <net/if_mib.h> 49107590Sobrien#include <net/if_media.h> 50117395Skan 51117395Skan#include <dev/ed/if_edreg.h> 52117395Skan#include <dev/ed/if_edvar.h> 53117395Skan#include <dev/pccard/pccardvar.h> 54117395Skan#include <dev/pccard/pccarddevs.h> 55117395Skan#ifndef ED_NO_MIIBUS 56117395Skan#include <dev/mii/mii.h> 57107590Sobrien#include <dev/mii/miivar.h> 58107590Sobrien#endif 59107590Sobrien 60107590Sobrien#include "card_if.h" 61107590Sobrien#ifndef ED_NO_MIIBUS 62107590Sobrien/* "device miibus" required. See GENERIC if you get errors here. */ 63107590Sobrien#include "miibus_if.h" 64117395Skan 65117395SkanMODULE_DEPEND(ed, miibus, 1, 1, 1); 66117395Skan#endif 67107590Sobrien 68107590Sobrien/* 69107590Sobrien * PC-Card (PCMCIA) specific code. 70107590Sobrien */ 71102780Skanstatic int ed_pccard_match(device_t); 72102780Skanstatic int ed_pccard_probe(device_t); 7390075Sobrienstatic int ed_pccard_attach(device_t); 7490075Sobrienstatic int ed_pccard_detach(device_t); 75117395Skan 76117395Skanstatic int ed_pccard_Linksys(device_t dev); 77117395Skanstatic int ed_pccard_ax88190(device_t dev); 7890075Sobrien 7990075Sobrienstatic void ax88190_geteprom(struct ed_softc *); 80107590Sobrienstatic int ed_pccard_memwrite(device_t dev, off_t offset, u_char byte); 81107590Sobrien#ifndef ED_NO_MIIBUS 82107590Sobrienstatic void ed_pccard_dlink_mii_reset(struct ed_softc *sc); 8390075Sobrienstatic u_int ed_pccard_dlink_mii_readbits(struct ed_softc *sc, int nbits); 8490075Sobrienstatic void ed_pccard_dlink_mii_writebits(struct ed_softc *sc, u_int val, 8590075Sobrien int nbits); 8690075Sobrien#endif 8790075Sobrien 8890075Sobrien/* 8990075Sobrien * ed_pccard_detach - unload the driver and clear the table. 9090075Sobrien * XXX TODO: 9190075Sobrien * This is usually called when the card is ejected, but 9290075Sobrien * can be caused by a modunload of a controller driver. 9390075Sobrien * The idea is to reset the driver's view of the device 9490075Sobrien * and ensure that any driver entry points such as 9590075Sobrien * read and write do not hang. 9690075Sobrien */ 9790075Sobrienstatic int 9890075Sobriened_pccard_detach(device_t dev) 9990075Sobrien{ 10090075Sobrien struct ed_softc *sc = device_get_softc(dev); 10190075Sobrien struct ifnet *ifp = &sc->arpcom.ac_if; 10290075Sobrien 103107590Sobrien if (sc->gone) { 104107590Sobrien device_printf(dev, "already unloaded\n"); 105107590Sobrien return (0); 10690075Sobrien } 10790075Sobrien ed_stop(sc); 10890075Sobrien ifp->if_flags &= ~IFF_RUNNING; 10990075Sobrien ether_ifdetach(ifp); 11090075Sobrien sc->gone = 1; 11190075Sobrien bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 112107590Sobrien ed_release_resources(dev); 11396263Sobrien return (0); 11496263Sobrien} 115107590Sobrien 116107590Sobrienstatic const struct ed_product { 117107590Sobrien struct pccard_product prod; 118107590Sobrien int enet_maddr; 119107590Sobrien unsigned char enet_vendor[3]; 12090075Sobrien int flags; 12190075Sobrien#define NE2000DVF_DL10019 0x0001 /* chip is D-Link DL10019 */ 12290075Sobrien#define NE2000DVF_AX88190 0x0002 /* chip is ASIX AX88190 */ 12390075Sobrien} ed_pccard_products[] = { 124117395Skan { PCMCIA_CARD(EDIMAX, EP4000A, 0), 125117395Skan -1, { 0x00, 0xa0, 0x0c } }, 126117395Skan { PCMCIA_CARD(SYNERGY21, S21810, 0), 127117395Skan -1, { 0x00, 0x48, 0x54} }, 128107590Sobrien { PCMCIA_CARD(AMBICOM, AMB8002T, 0), 12990075Sobrien -1, { 0x00, 0x10, 0x7a } }, 13090075Sobrien { PCMCIA_CARD(PREMAX, PE200, 0), 131107590Sobrien 0x07f0, { 0x00, 0x20, 0xe0 } }, 132107590Sobrien { PCMCIA_CARD(DIGITAL, DEPCMXX, 0), 133107590Sobrien 0x0ff0, { 0x00, 0x00, 0xe8 } }, 134107590Sobrien { PCMCIA_CARD(PLANET, SMARTCOM2000, 0), 135107590Sobrien 0xff0, { 0x00, 0x00, 0xe8 } }, 136107590Sobrien { PCMCIA_CARD(DLINK, DE660, 0), 13796263Sobrien -1, { 0x00, 0x80, 0xc8 } }, 13890075Sobrien { PCMCIA_CARD(DLINK, DE660PLUS, 0), 13990075Sobrien -1, { 0x00, 0x80, 0x08 } }, 140107590Sobrien { PCMCIA_CARD(RPTI, EP400, 0), 141107590Sobrien -1, { 0x00, 0x40, 0x95 } }, 142107590Sobrien { PCMCIA_CARD(RPTI, EP401, 0), 14390075Sobrien -1, { 0x00, 0x40, 0x95 } }, 14490075Sobrien { PCMCIA_CARD(ACCTON, EN2212, 0), 14590075Sobrien 0x0ff0, { 0x00, 0x00, 0xe8 } }, 146107590Sobrien { PCMCIA_CARD(SVEC, COMBOCARD, 0), 147107590Sobrien -1, { 0x00, 0xe0, 0x98 } }, 14890075Sobrien { PCMCIA_CARD(SVEC, LANCARD, 0), 14990075Sobrien 0x7f0, { 0x00, 0xc0, 0x6c } }, 150107590Sobrien { PCMCIA_CARD(EPSON, EEN10B, 0), 151107590Sobrien 0xff0, { 0x00, 0x00, 0x48 } }, 152107590Sobrien { PCMCIA_CARD(CNET, NE2000, 0), 153107590Sobrien -1, { 0x00, 0x80, 0xad } }, 154107590Sobrien { PCMCIA_CARD(ZONET, ZEN, 0), 155107590Sobrien -1, { 0x00, 0x80, 0xad } }, 156107590Sobrien 15790075Sobrien /* 15890075Sobrien * You have to add new entries which contains 15990075Sobrien * PCMCIA_VENDOR_INVALID and/or PCMCIA_PRODUCT_INVALID 16090075Sobrien * in front of this comment. 16190075Sobrien */ 16290075Sobrien { PCMCIA_CARD(LANTECH, FASTNETTX, 0), 16390075Sobrien -1, { 0x00, 0x04, 0x1c}, NE2000DVF_AX88190 }, 16490075Sobrien { PCMCIA_CARD(IBM, INFOMOVER, 0), 16590075Sobrien 0x0ff0, { 0x08, 0x00, 0x5a } }, 16690075Sobrien { PCMCIA_CARD(IBM, INFOMOVER, 0), 16790075Sobrien 0x0ff0, { 0x00, 0x04, 0xac } }, 16890075Sobrien { PCMCIA_CARD(IBM, INFOMOVER, 0), 16990075Sobrien 0x0ff0, { 0x00, 0x06, 0x29 } }, 17090075Sobrien { PCMCIA_CARD(KINGSTON, KNE2, 0), 17190075Sobrien -1, { 0, 0, 0 }, 0 }, /* XXX */ 17290075Sobrien { PCMCIA_CARD(LINKSYS, ECARD_1, 0), 17390075Sobrien -1, { 0x00, 0x80, 0xc8 } }, 174107590Sobrien { PCMCIA_CARD(LINKSYS, PCM100, 0), 17590075Sobrien -1, { 0x00, 0x04, 0x5a } }, 17690075Sobrien#ifdef BOGUS 177107590Sobrien /* 178107590Sobrien * The next three should be detected as linksys, but might fail 179107590Sobrien * the mac sanity check. 180117395Skan */ 181117395Skan { PCMCIA_CARD(PLANEX, FNW3600T, 0), 182117395Skan -1, { 0x00, 0x90, 0xcc }, NE2000DVF_DL10019 }, 183117395Skan { PCMCIA_CARD(PLANEX, FNW3700T, 0), 184107590Sobrien -1, { 0x00, 0x90, 0xcc }, NE2000DVF_DL10019 }, 185107590Sobrien { PCMCIA_CARD(SVEC, PN650TX, 0), 186107590Sobrien -1, { 0x00, 0xe0, 0x98 }, NE2000DVF_DL10019 }, 187107590Sobrien#endif 188107590Sobrien 189107590Sobrien /* 190107590Sobrien * This entry should be here so that above two cards doesn't 191107590Sobrien * match with this. FNW-3700T won't match above entries due to 192107590Sobrien * MAC address check. 193107590Sobrien */ 194107590Sobrien { PCMCIA_CARD(LINKSYS, COMBO_ECARD, 0), 195107590Sobrien -1, { 0x00, 0x90, 0xcc }, NE2000DVF_DL10019 }, 196107590Sobrien { PCMCIA_CARD(LINKSYS, ETHERFAST, 0), 197107590Sobrien -1, { 0x00, 0x80, 0xc8 }, NE2000DVF_DL10019 }, 198117395Skan { PCMCIA_CARD(LINKSYS, ETHERFAST, 0), 199117395Skan -1, { 0x00, 0x90, 0xfe }, NE2000DVF_DL10019 }, 200117395Skan { PCMCIA_CARD2(LINKSYS, ETHERFAST, DLINK_DE650, 0), 20190075Sobrien -1, { 0x00, 0xe0, 0x98 }, NE2000DVF_DL10019 }, 20290075Sobrien { PCMCIA_CARD2(LINKSYS, ETHERFAST, MELCO_LPC2_TX, 0), 20390075Sobrien -1, { 0x00, 0x40, 0x26 }, NE2000DVF_DL10019 }, 204107590Sobrien { PCMCIA_CARD(LINKSYS, TRUST_COMBO_ECARD, 0), 205117395Skan 0x0120, { 0x20, 0x04, 0x49 } }, 206117395Skan 207117395Skan /* 20890075Sobrien * Although the comments above say to put VENDOR/PRODUCT 20990075Sobrien * INVALID IDs above this list, we need to keep this one below 210107590Sobrien * the ECARD_1, or else both will match the same more-generic 211107590Sobrien * entry rather than the more specific one above with proper 212107590Sobrien * vendor and product IDs. 213107590Sobrien */ 214107590Sobrien { PCMCIA_CARD(LINKSYS, ECARD_2, 0), 215107590Sobrien -1, { 0x00, 0x80, 0xc8 } }, 216117395Skan 217107590Sobrien /* 218107590Sobrien * D-Link DE-650 has many minor versions: 21990075Sobrien * 22090075Sobrien * CIS information Manufacturer Product Note 22190075Sobrien * 1 "D-Link, DE-650" INVALID INVALID white card 222107590Sobrien * 2 "D-Link, DE-650, Ver 01.00" INVALID INVALID became bare metal 223107590Sobrien * 3 "D-Link, DE-650, Ver 01.00" 0x149 0x265 minor changed look 22490075Sobrien * 4 "D-Link, DE-650, Ver 01.00" 0x149 0x265 collision LED added 22590075Sobrien * 226107590Sobrien * While the 1st and the 2nd types should use the "D-Link DE-650" 227107590Sobrien * entry, the 3rd and the 4th types should use the "Linksys 228107590Sobrien * EtherCard" entry. Therefore, this enty must be below the 229117395Skan * LINKSYS_ECARD_1. --itohy 230117395Skan */ 231117395Skan { PCMCIA_CARD(DLINK, DE650, 0), 23290075Sobrien 0x0040, { 0x00, 0x80, 0xc8 } }, 23390075Sobrien 23490075Sobrien /* 23590075Sobrien * IO-DATA PCLA/TE and later version of PCLA/T has valid 23690075Sobrien * vendor/product ID and it is possible to read MAC address 23790075Sobrien * using standard I/O ports. It also read from CIS offset 0x01c0. 23890075Sobrien * On the other hand, earlier version of PCLA/T doesn't have valid 23990075Sobrien * vendor/product ID and MAC address must be read from CIS offset 24090075Sobrien * 0x0ff0 (i.e., usual ne2000 way to read it doesn't work). 24190075Sobrien * And CIS information of earlier and later version of PCLA/T are 24290075Sobrien * same except fourth element. So, for now, we place the entry for 243117395Skan * PCLA/TE (and later version of PCLA/T) followed by entry 244117395Skan * for the earlier version of PCLA/T (or, modify to match all CIS 245117395Skan * information and have three or more individual entries). 246117395Skan */ 24790075Sobrien { PCMCIA_CARD(IODATA, PCLATE, 0), 24890075Sobrien -1, { 0x00, 0xa0, 0xb0 } }, 24990075Sobrien 250107590Sobrien /* 251107590Sobrien * This entry should be placed after above PCLA-TE entry. 252107590Sobrien * See above comments for detail. 253117395Skan */ 25490075Sobrien { PCMCIA_CARD(IODATA, PCLAT, 0), 25590075Sobrien 0x0ff0, { 0x00, 0xa0, 0xb0 } }, 256117395Skan { PCMCIA_CARD(DAYNA, COMMUNICARD_E_1, 0), 257117395Skan 0x0110, { 0x00, 0x80, 0x19 } }, 258117395Skan { PCMCIA_CARD(DAYNA, COMMUNICARD_E_2, 0), 25990075Sobrien -1, { 0x00, 0x80, 0x19 } }, 26090075Sobrien { PCMCIA_CARD(COREGA, ETHER_PCC_TD, 0), 261107590Sobrien -1, { 0x00, 0x00, 0xf4 } }, 262107590Sobrien { PCMCIA_CARD(COREGA, ETHER_PCC_T, 0), 263107590Sobrien -1, { 0x00, 0x00, 0xf4 } }, 26490075Sobrien { PCMCIA_CARD(COREGA, ETHER_II_PCC_T, 0), 26590075Sobrien -1, { 0x00, 0x00, 0xf4 } }, 26690075Sobrien { PCMCIA_CARD(COREGA, ETHER_II_PCC_TD, 0), 26790075Sobrien -1, { 0x00, 0x00, 0xf4 } }, 26890075Sobrien { PCMCIA_CARD(COREGA, FAST_ETHER_PCC_TX, 0), 26990075Sobrien -1, { 0x00, 0x00, 0xf4 }, NE2000DVF_DL10019 }, 27090075Sobrien { PCMCIA_CARD(COREGA, FETHER_PCC_TXD, 0), 27190075Sobrien -1, { 0x00, 0x90, 0x99 }, NE2000DVF_AX88190 }, 27290075Sobrien { PCMCIA_CARD(COREGA, FETHER_PCC_TXF, 0), 27390075Sobrien -1, { 0x00, 0x90, 0x99 }, NE2000DVF_DL10019 }, 27490075Sobrien { PCMCIA_CARD(COMPEX, LINKPORT_ENET_B, 0), 27590075Sobrien 0x01c0, { 0x00, 0xa0, 0x0c } }, 276107590Sobrien { PCMCIA_CARD(DYNALINK, L10C, 0), 277107590Sobrien 0x01c0, { 0x00, 0x00, 0x00 } }, 278107590Sobrien { PCMCIA_CARD(SMC, EZCARD, 0), 27990075Sobrien 0x01c0, { 0x00, 0xe0, 0x29 } }, 28090075Sobrien { PCMCIA_CARD(SOCKET, EA_ETHER, 0), 28190075Sobrien -1, { 0x00, 0xc0, 0x1b } }, 28290075Sobrien { PCMCIA_CARD(SOCKET, LP_ETHER_CF, 0), 28390075Sobrien -1, { 0x00, 0xc0, 0x1b } }, 28490075Sobrien { PCMCIA_CARD(SOCKET, LP_ETHER, 0), 28590075Sobrien -1, { 0x00, 0xc0, 0x1b } }, 28690075Sobrien { PCMCIA_CARD(KINGSTON, KNE2, 0), 28790075Sobrien -1, { 0x00, 0xc0, 0xf0 } }, 28890075Sobrien { PCMCIA_CARD(XIRCOM, CFE_10, 0), 289117395Skan -1, { 0x00, 0x10, 0xa4 } }, 29090075Sobrien { PCMCIA_CARD(MELCO, LPC3_TX, 0), 29190075Sobrien -1, { 0x00, 0x40, 0x26 }, NE2000DVF_AX88190 }, 292107590Sobrien { PCMCIA_CARD(BUFFALO, LPC3_CLT, 0), 29390075Sobrien -1, { 0x00, 0x07, 0x40 } }, 29490075Sobrien { PCMCIA_CARD(BUFFALO, LPC_CF_CLT, 0), 29590075Sobrien -1, { 0x00, 0x07, 0x40 } }, 29690075Sobrien { PCMCIA_CARD(BILLIONTON, LNT10TN, 0), 29790075Sobrien -1, { 0x00, 0x00, 0x00 } }, 29890075Sobrien { PCMCIA_CARD(NDC, ND5100_E, 0), 29990075Sobrien -1, { 0x00, 0x80, 0xc6 } }, 30090075Sobrien { PCMCIA_CARD(TELECOMDEVICE, TCD_HPC100, 0), 30190075Sobrien -1, { 0x00, 0x40, 0x26 }, NE2000DVF_AX88190 }, 30290075Sobrien { PCMCIA_CARD(MACNICA, ME1_JEIDA, 0), 303122180Skan 0x00b8, { 0x08, 0x00, 0x42 } }, 304122180Skan { PCMCIA_CARD(ALLIEDTELESIS, LA_PCM, 0), 305122180Skan 0x0ff0, { 0x00, 0x00, 0xf4 } }, 30690075Sobrien { PCMCIA_CARD(DLINK, DFE670TXD, 0), 30790075Sobrien -1, { 0x00, 0x50, 0xba}, NE2000DVF_DL10019}, 30890075Sobrien { PCMCIA_CARD(NETGEAR, FA410TXC, 0), 309117395Skan -1, { 0x00, 0x48, 0x54 }, NE2000DVF_DL10019}, 31096263Sobrien { PCMCIA_CARD(NETGEAR, FA411, 0), 31196263Sobrien -1, { 0x00, 0x40, 0xf4 }, NE2000DVF_AX88190}, 31296263Sobrien 31390075Sobrien#if 0 31490075Sobrien /* the rest of these are stolen from the linux pcnet pcmcia device 315117395Skan driver. Since I don't know the manfid or cis info strings for 316117395Skan any of them, they're not compiled in until I do. */ 317117395Skan { "APEX MultiCard", 318117395Skan 0x0000, 0x0000, NULL, NULL, 0, 31990075Sobrien 0x03f4, { 0x00, 0x20, 0xe5 } }, 32090075Sobrien { "ASANTE FriendlyNet", 32190075Sobrien 0x0000, 0x0000, NULL, NULL, 0, 32290075Sobrien 0x4910, { 0x00, 0x00, 0x94 } }, 323117395Skan { "Danpex EN-6200P2", 324117395Skan 0x0000, 0x0000, NULL, NULL, 0, 325117395Skan 0x0110, { 0x00, 0x40, 0xc7 } }, 32690075Sobrien { "DataTrek NetCard", 327117395Skan 0x0000, 0x0000, NULL, NULL, 0, 32890075Sobrien 0x0ff0, { 0x00, 0x20, 0xe8 } }, 32990075Sobrien { "Dayna CommuniCard E", 33090075Sobrien 0x0000, 0x0000, NULL, NULL, 0, 33190075Sobrien 0x0110, { 0x00, 0x80, 0x19 } }, 33290075Sobrien { "EP-210 Ethernet", 33390075Sobrien 0x0000, 0x0000, NULL, NULL, 0, 33490075Sobrien 0x0110, { 0x00, 0x40, 0x33 } }, 33590075Sobrien { "ELECOM Laneed LD-CDWA", 336122180Skan 0x0000, 0x0000, NULL, NULL, 0, 337122180Skan 0x00b8, { 0x08, 0x00, 0x42 } }, 338122180Skan { "Grey Cell GCS2220", 339117395Skan 0x0000, 0x0000, NULL, NULL, 0, 34090075Sobrien 0x0000, { 0x00, 0x47, 0x43 } }, 34190075Sobrien { "Hypertec Ethernet", 34290075Sobrien 0x0000, 0x0000, NULL, NULL, 0, 34390075Sobrien 0x01c0, { 0x00, 0x40, 0x4c } }, 34490075Sobrien { "IBM CCAE", 34596263Sobrien 0x0000, 0x0000, NULL, NULL, 0, 34690075Sobrien 0x0ff0, { 0x08, 0x00, 0x5a } }, 34790075Sobrien { "IBM CCAE", 348117395Skan 0x0000, 0x0000, NULL, NULL, 0, 34990075Sobrien 0x0ff0, { 0x00, 0x04, 0xac } }, 35090075Sobrien { "IBM CCAE", 35196263Sobrien 0x0000, 0x0000, NULL, NULL, 0, 352107590Sobrien 0x0ff0, { 0x00, 0x06, 0x29 } }, 353107590Sobrien { "IBM FME", 35490075Sobrien 0x0000, 0x0000, NULL, NULL, 0, 35590075Sobrien 0x0374, { 0x00, 0x04, 0xac } }, 356117395Skan { "IBM FME", 357117395Skan 0x0000, 0x0000, NULL, NULL, 0, 35896263Sobrien 0x0374, { 0x08, 0x00, 0x5a } }, 35996263Sobrien { "Katron PE-520", 360117395Skan 0x0000, 0x0000, NULL, NULL, 0, 36190075Sobrien 0x0110, { 0x00, 0x40, 0xf6 } }, 36290075Sobrien { "Kingston KNE-PCM/x", 363107590Sobrien 0x0000, 0x0000, NULL, NULL, 0, 364107590Sobrien 0x0ff0, { 0x00, 0xc0, 0xf0 } }, 365107590Sobrien { "Kingston KNE-PCM/x", 366107590Sobrien 0x0000, 0x0000, NULL, NULL, 0, 367107590Sobrien 0x0ff0, { 0xe2, 0x0c, 0x0f } }, 368107590Sobrien { "Longshine LCS-8534", 369107590Sobrien 0x0000, 0x0000, NULL, NULL, 0, 37090075Sobrien 0x0000, { 0x08, 0x00, 0x00 } }, 37190075Sobrien { "Maxtech PCN2000", 37290075Sobrien 0x0000, 0x0000, NULL, NULL, 0, 37390075Sobrien 0x5000, { 0x00, 0x00, 0xe8 } }, 37490075Sobrien { "NDC Instant-Link", 37590075Sobrien 0x0000, 0x0000, NULL, NULL, 0, 376117395Skan 0x003a, { 0x00, 0x80, 0xc6 } }, 377107590Sobrien { "NE2000 Compatible", 378107590Sobrien 0x0000, 0x0000, NULL, NULL, 0, 379107590Sobrien 0x0ff0, { 0x00, 0xa0, 0x0c } }, 38096263Sobrien { "Network General Sniffer", 38196263Sobrien 0x0000, 0x0000, NULL, NULL, 0, 38290075Sobrien 0x0ff0, { 0x00, 0x00, 0x65 } }, 38390075Sobrien { "Panasonic VEL211", 384107590Sobrien 0x0000, 0x0000, NULL, NULL, 0, 385107590Sobrien 0x0ff0, { 0x00, 0x80, 0x45 } }, 38690075Sobrien { "SCM Ethernet", 38790075Sobrien 0x0000, 0x0000, NULL, NULL, 0, 38890075Sobrien 0x0ff0, { 0x00, 0x20, 0xcb } }, 38990075Sobrien { "Volktek NPL-402CT", 39090075Sobrien 0x0000, 0x0000, NULL, NULL, 0, 39190075Sobrien 0x0060, { 0x00, 0x40, 0x05 } }, 39290075Sobrien#endif 39390075Sobrien { { NULL } } 39490075Sobrien 39590075Sobrien}; 39690075Sobrien 39790075Sobrienstatic int 39890075Sobriened_pccard_match(device_t dev) 39990075Sobrien{ 40090075Sobrien const struct ed_product *pp; 40190075Sobrien 40290075Sobrien if ((pp = (const struct ed_product *) pccard_product_lookup(dev, 403107590Sobrien (const struct pccard_product *) ed_pccard_products, 404107590Sobrien sizeof(ed_pccard_products[0]), NULL)) != NULL) { 405107590Sobrien device_set_desc(dev, pp->prod.pp_name); 40690075Sobrien if (pp->flags & NE2000DVF_DL10019) 40790075Sobrien device_set_flags(dev, ED_FLAGS_LINKSYS); 40890075Sobrien else if (pp->flags & NE2000DVF_AX88190) 40990075Sobrien device_set_flags(dev, ED_FLAGS_AX88190); 41090075Sobrien return (0); 41190075Sobrien } 41290075Sobrien return (EIO); 41390075Sobrien} 414117395Skan 41590075Sobrien/* 41690075Sobrien * Probe framework for pccards. Replicates the standard framework, 41790075Sobrien * minus the pccard driver registration and ignores the ether address 41890075Sobrien * supplied (from the CIS), relying on the probe to find it instead. 41990075Sobrien */ 42096263Sobrienstatic int 42190075Sobriened_pccard_probe(device_t dev) 42290075Sobrien{ 42390075Sobrien int error; 42490075Sobrien int flags = device_get_flags(dev); 42590075Sobrien 42690075Sobrien if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_AX88190) { 42790075Sobrien error = ed_pccard_ax88190(dev); 42890075Sobrien goto end2; 42990075Sobrien } 43090075Sobrien 43190075Sobrien error = ed_probe_Novell(dev, 0, flags); 43290075Sobrien if (error == 0) 43390075Sobrien goto end; 43490075Sobrien ed_release_resources(dev); 43590075Sobrien 43690075Sobrien error = ed_probe_WD80x3(dev, 0, flags); 43790075Sobrien if (error == 0) 43890075Sobrien goto end; 43990075Sobrien ed_release_resources(dev); 440117395Skan goto end2; 441117395Skan 44290075Sobrienend: 44390075Sobrien if (ED_FLAGS_GETTYPE(flags) & ED_FLAGS_LINKSYS) 444107590Sobrien ed_pccard_Linksys(dev); 445107590Sobrienend2: 44690075Sobrien if (error == 0) 44790075Sobrien error = ed_alloc_irq(dev, 0, 0); 44896263Sobrien 44990075Sobrien ed_release_resources(dev); 45090075Sobrien return (error); 451107590Sobrien} 452107590Sobrien 453107590Sobrienstatic int 454107590Sobriened_pccard_attach(device_t dev) 45590075Sobrien{ 45690075Sobrien int error; 45790075Sobrien int flags = device_get_flags(dev); 458117395Skan int i; 45990075Sobrien struct ed_softc *sc = device_get_softc(dev); 46090075Sobrien u_char sum; 46190075Sobrien u_char ether_addr[ETHER_ADDR_LEN]; 46290075Sobrien 46390075Sobrien if (sc->port_used > 0) 46490075Sobrien ed_alloc_port(dev, sc->port_rid, sc->port_used); 46590075Sobrien if (sc->mem_used) 466107590Sobrien ed_alloc_memory(dev, sc->mem_rid, sc->mem_used); 467107590Sobrien ed_alloc_irq(dev, sc->irq_rid, 0); 46890075Sobrien 46990075Sobrien error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, 47090075Sobrien edintr, sc, &sc->irq_handle); 47196263Sobrien if (error) { 47290075Sobrien printf("setup intr failed %d \n", error); 47390075Sobrien ed_release_resources(dev); 47490075Sobrien return (error); 47590075Sobrien } 47690075Sobrien 47790075Sobrien if (sc->vendor != ED_VENDOR_LINKSYS) { 47890075Sobrien pccard_get_ether(dev, ether_addr); 47990075Sobrien for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) 48090075Sobrien sum |= ether_addr[i]; 481107590Sobrien if (sum) 482107590Sobrien bcopy(ether_addr, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 483107590Sobrien } 484107590Sobrien 48590075Sobrien error = ed_attach(sc, device_get_unit(dev), flags); 48690075Sobrien#ifndef ED_NO_MIIBUS 48790075Sobrien if (error == 0 && sc->vendor == ED_VENDOR_LINKSYS) { 48890075Sobrien /* Probe for an MII bus, but ignore errors. */ 48990075Sobrien ed_pccard_dlink_mii_reset(sc); 490107590Sobrien sc->mii_readbits = ed_pccard_dlink_mii_readbits; 491107590Sobrien sc->mii_writebits = ed_pccard_dlink_mii_writebits; 492107590Sobrien mii_phy_probe(dev, &sc->miibus, ed_ifmedia_upd, 493107590Sobrien ed_ifmedia_sts); 494107590Sobrien } 495107590Sobrien#endif 496107590Sobrien 497107590Sobrien return (error); 498107590Sobrien} 499107590Sobrien 500107590Sobrienstatic void 501107590Sobrienax88190_geteprom(struct ed_softc *sc) 502117395Skan{ 503107590Sobrien int prom[16],i; 504107590Sobrien u_char tmp; 50596263Sobrien struct { 50696263Sobrien unsigned char offset, value; 50790075Sobrien } pg_seq[] = { 50890075Sobrien {ED_P0_CR, ED_CR_RD2|ED_CR_STP},/* Select Page0 */ 50990075Sobrien {ED_P0_DCR, 0x01}, 51090075Sobrien {ED_P0_RBCR0, 0x00}, /* Clear the count regs. */ 51190075Sobrien {ED_P0_RBCR1, 0x00}, 51290075Sobrien {ED_P0_IMR, 0x00}, /* Mask completion irq. */ 51390075Sobrien {ED_P0_ISR, 0xff}, 51490075Sobrien {ED_P0_RCR, ED_RCR_MON | ED_RCR_INTT}, /* Set To Monitor */ 51590075Sobrien {ED_P0_TCR, ED_TCR_LB0}, /* loopback mode. */ 51690075Sobrien {ED_P0_RBCR0, 32}, 51790075Sobrien {ED_P0_RBCR1, 0x00}, 51890075Sobrien {ED_P0_RSAR0, 0x00}, 51990075Sobrien {ED_P0_RSAR1, 0x04}, 52090075Sobrien {ED_P0_CR ,ED_CR_RD0 | ED_CR_STA}, 521117395Skan }; 522107590Sobrien 523107590Sobrien /* Reset Card */ 524107590Sobrien tmp = ed_asic_inb(sc, ED_NOVELL_RESET); 52590075Sobrien ed_asic_outb(sc, ED_NOVELL_RESET, tmp); 52690075Sobrien DELAY(5000); 52796263Sobrien ed_asic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP); 52890075Sobrien DELAY(5000); 52990075Sobrien 53096263Sobrien /* Card Settings */ 53190075Sobrien for (i = 0; i < sizeof(pg_seq) / sizeof(pg_seq[0]); i++) 53290075Sobrien ed_nic_outb(sc, pg_seq[i].offset, pg_seq[i].value); 53390075Sobrien 53490075Sobrien /* Get Data */ 53590075Sobrien for (i = 0; i < 16; i++) 53690075Sobrien prom[i] = ed_asic_inb(sc, 0); 53790075Sobrien sc->arpcom.ac_enaddr[0] = prom[0] & 0xff; 53890075Sobrien sc->arpcom.ac_enaddr[1] = prom[0] >> 8; 539107590Sobrien sc->arpcom.ac_enaddr[2] = prom[1] & 0xff; 540107590Sobrien sc->arpcom.ac_enaddr[3] = prom[1] >> 8; 54190075Sobrien sc->arpcom.ac_enaddr[4] = prom[2] & 0xff; 54290075Sobrien sc->arpcom.ac_enaddr[5] = prom[2] >> 8; 54390075Sobrien} 54496263Sobrien 54596263Sobrienstatic int 54690075Sobriened_pccard_memwrite(device_t dev, off_t offset, u_char byte) 54790075Sobrien{ 548107590Sobrien int cis_rid; 549107590Sobrien struct resource *cis; 550107590Sobrien 55190075Sobrien cis_rid = 0; 55290075Sobrien cis = bus_alloc_resource(dev, SYS_RES_MEMORY, &cis_rid, 0, ~0, 55390075Sobrien 4 << 10, RF_ACTIVE | RF_SHAREABLE); 55490075Sobrien if (cis == NULL) 55590075Sobrien return (ENXIO); 55690075Sobrien CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 55790075Sobrien cis_rid, PCCARD_A_MEM_ATTR); 55890075Sobrien 55990075Sobrien bus_space_write_1(rman_get_bustag(cis), rman_get_bushandle(cis), 56090075Sobrien offset, byte); 56190075Sobrien 56290075Sobrien bus_deactivate_resource(dev, SYS_RES_MEMORY, cis_rid, cis); 56390075Sobrien bus_release_resource(dev, SYS_RES_MEMORY, cis_rid, cis); 56490075Sobrien 56590075Sobrien return (0); 56690075Sobrien} 56790075Sobrien 56890075Sobrien/* 569107590Sobrien * Probe the Ethernet MAC addrees for PCMCIA Linksys EtherFast 10/100 570107590Sobrien * and compatible cards (DL10019C Ethernet controller). 571107590Sobrien * 572107590Sobrien * Note: The PAO patches try to use more memory for the card, but that 573107590Sobrien * seems to fail for my card. A future optimization would add this back 57490075Sobrien * conditionally. 57590075Sobrien */ 576107590Sobrienstatic int 577107590Sobriened_pccard_Linksys(device_t dev) 578107590Sobrien{ 579117395Skan struct ed_softc *sc = device_get_softc(dev); 580117395Skan u_char sum; 581117395Skan int i; 58290075Sobrien 58390075Sobrien /* 58490075Sobrien * Linksys registers(offset from ASIC base) 58590075Sobrien * 58690075Sobrien * 0x04-0x09 : Physical Address Register 0-5 (PAR0-PAR5) 58790075Sobrien * 0x0A : Card ID Register (CIR) 58890075Sobrien * 0x0B : Check Sum Register (SR) 58990075Sobrien */ 59090075Sobrien for (sum = 0, i = 0x04; i < 0x0c; i++) 59190075Sobrien sum += ed_asic_inb(sc, i); 59290075Sobrien if (sum != 0xff) 593117395Skan return (0); /* invalid DL10019C */ 594117395Skan for (i = 0; i < ETHER_ADDR_LEN; i++) { 595117395Skan sc->arpcom.ac_enaddr[i] = ed_asic_inb(sc, 0x04 + i); 596117395Skan } 59796263Sobrien 59896263Sobrien ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); 59996263Sobrien sc->isa16bit = 1; 60096263Sobrien sc->vendor = ED_VENDOR_LINKSYS; 60196263Sobrien sc->type = ED_TYPE_NE2000; 60290075Sobrien sc->type_str = "Linksys"; 603107590Sobrien 60490075Sobrien return (1); 60590075Sobrien} 60690075Sobrien 60790075Sobrien/* 60890075Sobrien * Special setup for AX88190 60990075Sobrien */ 610107590Sobrienstatic int 611107590Sobriened_pccard_ax88190(device_t dev) 61290075Sobrien{ 61390075Sobrien int error; 614117395Skan int flags = device_get_flags(dev); 615117395Skan int iobase; 616117395Skan struct ed_softc *sc = device_get_softc(dev); 61790075Sobrien 61890075Sobrien /* Allocate the port resource during setup. */ 61990075Sobrien error = ed_alloc_port(dev, 0, ED_NOVELL_IO_PORTS); 620107590Sobrien if (error) 621107590Sobrien return (error); 62290075Sobrien 62390075Sobrien sc->asic_offset = ED_NOVELL_ASIC_OFFSET; 62490075Sobrien sc->nic_offset = ED_NOVELL_NIC_OFFSET; 62590075Sobrien sc->chip_type = ED_CHIP_TYPE_AX88190; 62690075Sobrien 62790075Sobrien /* 62890075Sobrien * Set Attribute Memory IOBASE Register 62990075Sobrien */ 63090075Sobrien iobase = rman_get_start(sc->port_res); 63190075Sobrien ed_pccard_memwrite(dev, ED_AX88190_IOBASE0, iobase & 0xff); 632122180Skan ed_pccard_memwrite(dev, ED_AX88190_IOBASE1, (iobase >> 8) & 0xff); 633122180Skan ax88190_geteprom(sc); 634122180Skan ed_release_resources(dev); 63596263Sobrien error = ed_probe_Novell(dev, 0, flags); 63696263Sobrien if (error == 0) { 63790075Sobrien sc->vendor = ED_VENDOR_PCCARD; 63890075Sobrien sc->type = ED_TYPE_NE2000; 63996263Sobrien sc->type_str = "AX88190"; 64090075Sobrien } 64190075Sobrien return (error); 64290075Sobrien} 643107590Sobrien 644107590Sobrien#ifndef ED_NO_MIIBUS 645107590Sobrien/* MII bit-twiddling routines for cards using Dlink chipset */ 64690075Sobrien#define DLINK_MIISET(sc, x) ed_asic_outb(sc, ED_DLINK_MIIBUS, \ 64790075Sobrien ed_asic_inb(sc, ED_DLINK_MIIBUS) | (x)) 64896263Sobrien#define DLINK_MIICLR(sc, x) ed_asic_outb(sc, ED_DLINK_MIIBUS, \ 64990075Sobrien ed_asic_inb(sc, ED_DLINK_MIIBUS) & ~(x)) 650117395Skan 651117395Skanstatic void 652117395Skaned_pccard_dlink_mii_reset(sc) 65390075Sobrien struct ed_softc *sc; 65490075Sobrien{ 65590075Sobrien ed_asic_outb(sc, ED_DLINK_MIIBUS, 0); 65690075Sobrien DELAY(10); 657107590Sobrien DLINK_MIISET(sc, ED_DLINK_MII_RESET2); 658107590Sobrien DELAY(10); 659117395Skan DLINK_MIISET(sc, ED_DLINK_MII_RESET1); 660117395Skan DELAY(10); 66196263Sobrien DLINK_MIICLR(sc, ED_DLINK_MII_RESET1); 66296263Sobrien DELAY(10); 66396263Sobrien DLINK_MIICLR(sc, ED_DLINK_MII_RESET2); 66496263Sobrien DELAY(10); 66596263Sobrien} 66690075Sobrien 66790075Sobrienstatic void 66890075Sobriened_pccard_dlink_mii_writebits(sc, val, nbits) 66990075Sobrien struct ed_softc *sc; 67090075Sobrien u_int val; 67190075Sobrien int nbits; 67290075Sobrien{ 67390075Sobrien int i; 67490075Sobrien 675107590Sobrien DLINK_MIISET(sc, ED_DLINK_MII_DIROUT); 676107590Sobrien 677107590Sobrien for (i = nbits - 1; i >= 0; i--) { 678107590Sobrien if ((val >> i) & 1) 67990075Sobrien DLINK_MIISET(sc, ED_DLINK_MII_DATAOUT); 68090075Sobrien else 68190075Sobrien DLINK_MIICLR(sc, ED_DLINK_MII_DATAOUT); 68290075Sobrien DELAY(10); 68390075Sobrien DLINK_MIISET(sc, ED_DLINK_MII_CLK); 68490075Sobrien DELAY(10); 685117395Skan DLINK_MIICLR(sc, ED_DLINK_MII_CLK); 686117395Skan DELAY(10); 687117395Skan } 688117395Skan} 689107590Sobrien 690107590Sobrienstatic u_int 691107590Sobriened_pccard_dlink_mii_readbits(sc, nbits) 69290075Sobrien struct ed_softc *sc; 69390075Sobrien int nbits; 69490075Sobrien{ 69590075Sobrien int i; 69690075Sobrien u_int val = 0; 69790075Sobrien 69890075Sobrien DLINK_MIICLR(sc, ED_DLINK_MII_DIROUT); 69990075Sobrien 70090075Sobrien for (i = nbits - 1; i >= 0; i--) { 70190075Sobrien DLINK_MIISET(sc, ED_DLINK_MII_CLK); 70290075Sobrien DELAY(10); 703107590Sobrien val <<= 1; 704107590Sobrien if (ed_asic_inb(sc, ED_DLINK_MIIBUS) & ED_DLINK_MII_DATATIN) 705107590Sobrien val++; 706107590Sobrien DLINK_MIICLR(sc, ED_DLINK_MII_CLK); 707107590Sobrien DELAY(10); 708107590Sobrien } 709107590Sobrien 710107590Sobrien return val; 71190075Sobrien} 71290075Sobrien#endif 71390075Sobrien 71490075Sobrienstatic device_method_t ed_pccard_methods[] = { 71590075Sobrien /* Device interface */ 71690075Sobrien DEVMETHOD(device_probe, pccard_compat_probe), 71790075Sobrien DEVMETHOD(device_attach, pccard_compat_attach), 71890075Sobrien DEVMETHOD(device_detach, ed_pccard_detach), 71990075Sobrien 72090075Sobrien#ifndef ED_NO_MIIBUS 72190075Sobrien /* Bus interface */ 72290075Sobrien DEVMETHOD(bus_child_detached, ed_child_detached), 72390075Sobrien 72490075Sobrien /* MII interface */ 72590075Sobrien DEVMETHOD(miibus_readreg, ed_miibus_readreg), 726107590Sobrien DEVMETHOD(miibus_writereg, ed_miibus_writereg), 727107590Sobrien#endif 728107590Sobrien 729107590Sobrien /* Card interface */ 73090075Sobrien DEVMETHOD(card_compat_match, ed_pccard_match), 73190075Sobrien DEVMETHOD(card_compat_probe, ed_pccard_probe), 73290075Sobrien DEVMETHOD(card_compat_attach, ed_pccard_attach), 73390075Sobrien { 0, 0 } 73490075Sobrien}; 73590075Sobrien 73690075Sobrienstatic driver_t ed_pccard_driver = { 73790075Sobrien "ed", 73890075Sobrien ed_pccard_methods, 73990075Sobrien sizeof(struct ed_softc) 740117395Skan}; 741117395Skan 742117395SkanDRIVER_MODULE(if_ed, pccard, ed_pccard_driver, ed_devclass, 0, 0); 74390075Sobrien#ifndef ED_NO_MIIBUS 74490075SobrienDRIVER_MODULE(miibus, ed, miibus_driver, miibus_devclass, 0, 0); 74590075Sobrien#endif 746107590Sobrien