if_ep_pccard.c revision 51673
1/* 2 * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Herb Peyerl. 16 * 4. The name of Herb Peyerl may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * $FreeBSD: head/sys/dev/ep/if_ep_pccard.c 51673 1999-09-26 06:42:36Z mdodd $ 31 */ 32 33/* 34 * Pccard support for 3C589 by: 35 * HAMADA Naoki 36 * nao@tom-yam.or.jp 37 */ 38 39#include <sys/param.h> 40#include <sys/kernel.h> 41#include <sys/systm.h> 42#include <sys/malloc.h> 43#include <sys/mbuf.h> 44#include <sys/socket.h> 45#include <sys/sockio.h> 46 47#include <net/ethernet.h> 48#include <net/if.h> 49#include <netinet/in.h> 50#include <netinet/if_ether.h> 51 52#include <machine/clock.h> 53 54#include <sys/select.h> 55#include <sys/module.h> 56#include <pccard/cardinfo.h> 57#include <pccard/slot.h> 58 59#include <dev/ep/if_epreg.h> 60#include <dev/ep/if_epvar.h> 61 62/* 63 * PC-Card (PCMCIA) specific code. 64 */ 65static int ep_pccard_init (struct pccard_devinfo *); 66static int ep_pccard_attach ((struct pccard_devinfo *); 67static void ep_pccard_unload (struct pccard_devinfo *); 68static int ep_pccard_intr (struct pccard_devinfo *); 69static int ep_pccard_identify (struct ep_board *epb, int unit); 70 71PCCARD_MODULE(ep, ep_pccard_init, ep_pccard_unload, ep_pccard_intr, 0, net_imask); 72 73/* 74 * Initialize the device - called from Slot manager. 75 */ 76static int 77ep_pccard_init(devi) 78 struct pccard_devinfo *devi; 79{ 80 struct isa_device *is = &devi->isahd; 81 struct ep_softc *sc = ep_softc[is->id_unit]; 82 struct ep_board *epb; 83 int i; 84 85 epb = &ep_board[is->id_unit]; 86 87 if (sc == 0) { 88 if ((sc = ep_alloc(is->id_unit, epb)) == 0) { 89 return (ENXIO); 90 } 91 ep_unit++; 92 } 93 94 /* get_e() requires these. */ 95 sc->ep_io_addr = is->id_iobase; 96 sc->unit = is->id_unit; 97 epb->epb_addr = is->id_iobase; 98 epb->epb_used = 1; 99 100 /* 101 * XXX - Certain (newer?) 3Com cards need epb->cmd_off == 2. Sadly, 102 * you need to have a correct cmd_off in order to identify the card. 103 * So we have to hit it with both and cross our virtual fingers. There's 104 * got to be a better way to do this. jyoung@accessus.net 09/11/1999 105 */ 106 107 epb->cmd_off = 0; 108 epb->prod_id = get_e(sc, EEPROM_PROD_ID); 109 if (!ep_pccard_identify(epb, is->id_unit)) { 110 if (bootverbose) printf("ep%d: Pass 1 of 2 detection failed (nonfatal)\n", is->id_unit); 111 epb->cmd_off = 2; 112 epb->prod_id = get_e(sc, EEPROM_PROD_ID); 113 if (!ep_pccard_identify(epb, is->id_unit)) { 114 if (bootverbose) printf("ep%d: Pass 2 of 2 detection failed (fatal!)\n", is->id_unit); 115 printf("ep%d: Unit failed to come ready or product ID unknown! (id 0x%x)\n", is->id_unit, epb->prod_id); 116 return (ENXIO); 117 } 118 } 119 120 epb->res_cfg = get_e(sc, EEPROM_RESOURCE_CFG); 121 for (i = 0; i < 3; i++) 122 sc->epb->eth_addr[i] = get_e(sc, EEPROM_NODE_ADDR_0 + i); 123 124 if (ep_pccard_attach(devi) == 0) 125 return (ENXIO); 126 127 sc->arpcom.ac_if.if_snd.ifq_maxlen = ifqmaxlen; 128 return (0); 129} 130 131static int 132ep_pccard_identify(epb, unit) 133 struct ep_board *epb; 134 int unit; 135{ 136 /* Determine device type and associated MII capabilities */ 137 switch (epb->prod_id) { 138 case 0x6055: /* 3C556 */ 139 if (bootverbose) printf("ep%d: 3Com 3C556\n", unit); 140 epb->mii_trans = 1; 141 return (1); 142 break; /* NOTREACHED */ 143 case 0x4057: /* 3C574 */ 144 if (bootverbose) printf("ep%d: 3Com 3C574\n", unit); 145 epb->mii_trans = 1; 146 return (1); 147 break; /* NOTREACHED */ 148 case 0x4b57: /* 3C574B */ 149 if (bootverbose) printf("ep%d: 3Com 3C574B, Megahertz 3CCFE574BT or Fast Etherlink 3C574-TX\n", unit); 150 epb->mii_trans = 1; 151 return (1); 152 break; /* NOTREACHED */ 153 case 0x9058: /* 3C589 */ 154 if (bootverbose) printf("ep%d: 3Com Etherlink III 3C589[B/C/D]\n", unit); 155 epb->mii_trans = 0; 156 return (1); 157 break; /* NOTREACHED */ 158 } 159 return (0); 160} 161 162static int 163ep_pccard_attach(devi) 164 struct pccard_devinfo *devi; 165{ 166 struct isa_device *is = &devi->isahd; 167 struct ep_softc *sc = ep_softc[is->id_unit]; 168 u_short config; 169 170 sc->ep_connectors = 0; 171 config = inw(IS_BASE + EP_W0_CONFIG_CTRL); 172 if (config & IS_BNC) { 173 sc->ep_connectors |= BNC; 174 } 175 if (config & IS_UTP) { 176 sc->ep_connectors |= UTP; 177 } 178 if (!(sc->ep_connectors & 7)) 179 /* (Apparently) non-fatal */ 180 if(bootverbose) printf("ep%d: No connectors or MII.\n", is->id_unit); 181 182 sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; 183 184 /* ROM size = 0, ROM base = 0 */ 185 /* For now, ignore AUTO SELECT feature of 3C589B and later. */ 186 outw(BASE + EP_W0_ADDRESS_CFG, get_e(sc, EEPROM_ADDR_CFG) & 0xc000); 187 188 /* Fake IRQ must be 3 */ 189 outw(BASE + EP_W0_RESOURCE_CFG, (sc->epb->res_cfg & 0x0fff) | 0x3000); 190 191 outw(BASE + EP_W0_PRODUCT_ID, sc->epb->prod_id); 192 193 if (sc->epb->mii_trans) { 194 /* 195 * turn on the MII transciever 196 */ 197 GO_WINDOW(3); 198 outw(BASE + EP_W3_OPTIONS, 0x8040); 199 DELAY(1000); 200 outw(BASE + EP_W3_OPTIONS, 0xc040); 201 outw(BASE + EP_COMMAND, RX_RESET); 202 outw(BASE + EP_COMMAND, TX_RESET); 203 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 204 DELAY(1000); 205 outw(BASE + EP_W3_OPTIONS, 0x8040); 206 } 207 208 ep_attach(sc); 209 210 return 1; 211} 212 213static void 214ep_pccard_unload(devi) 215 struct pccard_devinfo *devi; 216{ 217 struct ep_softc *sc = ep_softc[devi->isahd.id_unit]; 218 219 if (sc->gone) { 220 printf("ep%d: already unloaded\n", devi->isahd.id_unit); 221 return; 222 } 223 sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; 224 sc->gone = 1; 225 printf("ep%d: unload\n", devi->isahd.id_unit); 226} 227 228/* 229 * card_intr - Shared interrupt called from 230 * front end of PC-Card handler. 231 */ 232static int 233ep_pccard_intr(devi) 234 struct pccard_devinfo *devi; 235{ 236 struct ep_softc *sc = ep_softc[devi->isahd.id_unit]; 237 238 if (sc->gone) { 239 return; 240 } 241 242 ep_intr((void *)sc); 243 244 return(1); 245} 246