if_ed_pccard.c revision 113317
1/* 2 * Copyright (c) 1995, David Greenman 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 unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/dev/ed/if_ed_pccard.c 113317 2003-04-10 06:08:27Z imp $ 28 */ 29 30#include "opt_ed.h" 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/socket.h> 35#include <sys/kernel.h> 36#include <sys/conf.h> 37#include <sys/uio.h> 38 39#include <sys/module.h> 40#include <sys/bus.h> 41#include <machine/bus.h> 42#include <sys/rman.h> 43#include <machine/resource.h> 44 45#include <net/ethernet.h> 46#include <net/if.h> 47#include <net/if_arp.h> 48#include <net/if_mib.h> 49#include <net/if_media.h> 50 51#include <dev/ed/if_edreg.h> 52#include <dev/ed/if_edvar.h> 53#include <dev/pccard/pccardvar.h> 54#include <dev/pccard/pccarddevs.h> 55#ifndef ED_NO_MIIBUS 56#include <dev/mii/mii.h> 57#include <dev/mii/miivar.h> 58#endif 59 60#include "card_if.h" 61#ifndef ED_NO_MIIBUS 62/* "device miibus" required. See GENERIC if you get errors here. */ 63#include "miibus_if.h" 64 65MODULE_DEPEND(ed, miibus, 1, 1, 1); 66#endif 67 68/* 69 * PC-Card (PCMCIA) specific code. 70 */ 71static int ed_pccard_match(device_t); 72static int ed_pccard_probe(device_t); 73static int ed_pccard_attach(device_t); 74static int ed_pccard_detach(device_t); 75 76static int ed_pccard_Linksys(device_t dev); 77static int ed_pccard_ax88190(device_t dev); 78 79static void ax88190_geteprom(struct ed_softc *); 80static int ed_pccard_memwrite(device_t dev, off_t offset, u_char byte); 81#ifndef ED_NO_MIIBUS 82static void ed_pccard_dlink_mii_reset(struct ed_softc *sc); 83static u_int ed_pccard_dlink_mii_readbits(struct ed_softc *sc, int nbits); 84static void ed_pccard_dlink_mii_writebits(struct ed_softc *sc, u_int val, 85 int nbits); 86#endif 87 88/* 89 * ed_pccard_detach - unload the driver and clear the table. 90 * XXX TODO: 91 * This is usually called when the card is ejected, but 92 * can be caused by a modunload of a controller driver. 93 * The idea is to reset the driver's view of the device 94 * and ensure that any driver entry points such as 95 * read and write do not hang. 96 */ 97static int 98ed_pccard_detach(device_t dev) 99{ 100 struct ed_softc *sc = device_get_softc(dev); 101 struct ifnet *ifp = &sc->arpcom.ac_if; 102 103 if (sc->gone) { 104 device_printf(dev, "already unloaded\n"); 105 return (0); 106 } 107 ed_stop(sc); 108 ifp->if_flags &= ~IFF_RUNNING; 109 ether_ifdetach(ifp); 110 sc->gone = 1; 111 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 112 ed_release_resources(dev); 113 return (0); 114} 115 116static const struct ed_product { 117 struct pccard_product prod; 118 int enet_maddr; 119 unsigned char enet_vendor[3]; 120 int flags; 121#define NE2000DVF_DL10019 0x0001 /* chip is D-Link DL10019 */ 122#define NE2000DVF_AX88190 0x0002 /* chip is ASIX AX88190 */ 123} ed_pccard_products[] = { 124 { PCMCIA_CARD(EDIMAX, EP4000A, 0), 125 -1, { 0x00, 0xa0, 0x0c } }, 126 { PCMCIA_CARD(SYNERGY21, S21810, 0), 127 -1, { 0x00, 0x48, 0x54} }, 128 { PCMCIA_CARD(AMBICOM, AMB8002T, 0), 129 -1, { 0x00, 0x10, 0x7a } }, 130 { PCMCIA_CARD(PREMAX, PE200, 0), 131 0x07f0, { 0x00, 0x20, 0xe0 } }, 132 { PCMCIA_CARD(DIGITAL, DEPCMXX, 0), 133 0x0ff0, { 0x00, 0x00, 0xe8 } }, 134 { PCMCIA_CARD(PLANET, SMARTCOM2000, 0), 135 0xff0, { 0x00, 0x00, 0xe8 } }, 136 { PCMCIA_CARD(DLINK, DE660, 0), 137 -1, { 0x00, 0x80, 0xc8 } }, 138 { PCMCIA_CARD(DLINK, DE660PLUS, 0), 139 -1, { 0x00, 0x80, 0x08 } }, 140 { PCMCIA_CARD(RPTI, EP400, 0), 141 -1, { 0x00, 0x40, 0x95 } }, 142 { PCMCIA_CARD(RPTI, EP401, 0), 143 -1, { 0x00, 0x40, 0x95 } }, 144 { PCMCIA_CARD(ACCTON, EN2212, 0), 145 0x0ff0, { 0x00, 0x00, 0xe8 } }, 146 { PCMCIA_CARD(SVEC, COMBOCARD, 0), 147 -1, { 0x00, 0xe0, 0x98 } }, 148 { PCMCIA_CARD(SVEC, LANCARD, 0), 149 0x7f0, { 0x00, 0xc0, 0x6c } }, 150 { PCMCIA_CARD(EPSON, EEN10B, 0), 151 0xff0, { 0x00, 0x00, 0x48 } }, 152 { PCMCIA_CARD(CNET, NE2000, 0), 153 -1, { 0x00, 0x80, 0xad } }, 154 { PCMCIA_CARD(ZONET, ZEN, 0), 155 -1, { 0x00, 0x80, 0xad } }, 156 157 /* 158 * You have to add new entries which contains 159 * PCMCIA_VENDOR_INVALID and/or PCMCIA_PRODUCT_INVALID 160 * in front of this comment. 161 */ 162 { PCMCIA_CARD(LANTECH, FASTNETTX, 0), 163 -1, { 0x00, 0x04, 0x1c}, NE2000DVF_AX88190 }, 164 { PCMCIA_CARD(IBM, INFOMOVER, 0), 165 0x0ff0, { 0x08, 0x00, 0x5a } }, 166 { PCMCIA_CARD(IBM, INFOMOVER, 0), 167 0x0ff0, { 0x00, 0x04, 0xac } }, 168 { PCMCIA_CARD(IBM, INFOMOVER, 0), 169 0x0ff0, { 0x00, 0x06, 0x29 } }, 170 { PCMCIA_CARD(KINGSTON, KNE2, 0), 171 -1, { 0, 0, 0 }, 0 }, /* XXX */ 172 { PCMCIA_CARD(LINKSYS, ECARD_1, 0), 173 -1, { 0x00, 0x80, 0xc8 } }, 174 { PCMCIA_CARD(LINKSYS, PCM100, 0), 175 -1, { 0x00, 0x04, 0x5a } }, 176#ifdef BOGUS 177 /* 178 * The next three should be detected as linksys, but might fail 179 * the mac sanity check. 180 */ 181 { PCMCIA_CARD(PLANEX, FNW3600T, 0), 182 -1, { 0x00, 0x90, 0xcc }, NE2000DVF_DL10019 }, 183 { PCMCIA_CARD(PLANEX, FNW3700T, 0), 184 -1, { 0x00, 0x90, 0xcc }, NE2000DVF_DL10019 }, 185 { PCMCIA_CARD(SVEC, PN650TX, 0), 186 -1, { 0x00, 0xe0, 0x98 }, NE2000DVF_DL10019 }, 187#endif 188 189 /* 190 * This entry should be here so that above two cards doesn't 191 * match with this. FNW-3700T won't match above entries due to 192 * MAC address check. 193 */ 194 { PCMCIA_CARD(LINKSYS, COMBO_ECARD, 0), 195 -1, { 0x00, 0x90, 0xcc }, NE2000DVF_DL10019 }, 196 { PCMCIA_CARD(LINKSYS, ETHERFAST, 0), 197 -1, { 0x00, 0x80, 0xc8 }, NE2000DVF_DL10019 }, 198 { PCMCIA_CARD(LINKSYS, ETHERFAST, 0), 199 -1, { 0x00, 0x90, 0xfe }, NE2000DVF_DL10019 }, 200 { PCMCIA_CARD2(LINKSYS, ETHERFAST, DLINK_DE650, 0), 201 -1, { 0x00, 0xe0, 0x98 }, NE2000DVF_DL10019 }, 202 { PCMCIA_CARD2(LINKSYS, ETHERFAST, MELCO_LPC2_TX, 0), 203 -1, { 0x00, 0x40, 0x26 }, NE2000DVF_DL10019 }, 204 { PCMCIA_CARD(LINKSYS, TRUST_COMBO_ECARD, 0), 205 0x0120, { 0x20, 0x04, 0x49 } }, 206 207 /* 208 * Although the comments above say to put VENDOR/PRODUCT 209 * INVALID IDs above this list, we need to keep this one below 210 * the ECARD_1, or else both will match the same more-generic 211 * entry rather than the more specific one above with proper 212 * vendor and product IDs. 213 */ 214 { PCMCIA_CARD(LINKSYS, ECARD_2, 0), 215 -1, { 0x00, 0x80, 0xc8 } }, 216 217 /* 218 * D-Link DE-650 has many minor versions: 219 * 220 * CIS information Manufacturer Product Note 221 * 1 "D-Link, DE-650" INVALID INVALID white card 222 * 2 "D-Link, DE-650, Ver 01.00" INVALID INVALID became bare metal 223 * 3 "D-Link, DE-650, Ver 01.00" 0x149 0x265 minor changed look 224 * 4 "D-Link, DE-650, Ver 01.00" 0x149 0x265 collision LED added 225 * 226 * While the 1st and the 2nd types should use the "D-Link DE-650" 227 * entry, the 3rd and the 4th types should use the "Linksys 228 * EtherCard" entry. Therefore, this enty must be below the 229 * LINKSYS_ECARD_1. --itohy 230 */ 231 { PCMCIA_CARD(DLINK, DE650, 0), 232 0x0040, { 0x00, 0x80, 0xc8 } }, 233 234 /* 235 * IO-DATA PCLA/TE and later version of PCLA/T has valid 236 * vendor/product ID and it is possible to read MAC address 237 * using standard I/O ports. It also read from CIS offset 0x01c0. 238 * On the other hand, earlier version of PCLA/T doesn't have valid 239 * vendor/product ID and MAC address must be read from CIS offset 240 * 0x0ff0 (i.e., usual ne2000 way to read it doesn't work). 241 * And CIS information of earlier and later version of PCLA/T are 242 * same except fourth element. So, for now, we place the entry for 243 * PCLA/TE (and later version of PCLA/T) followed by entry 244 * for the earlier version of PCLA/T (or, modify to match all CIS 245 * information and have three or more individual entries). 246 */ 247 { PCMCIA_CARD(IODATA, PCLATE, 0), 248 -1, { 0x00, 0xa0, 0xb0 } }, 249 250 /* 251 * This entry should be placed after above PCLA-TE entry. 252 * See above comments for detail. 253 */ 254 { PCMCIA_CARD(IODATA, PCLAT, 0), 255 0x0ff0, { 0x00, 0xa0, 0xb0 } }, 256 { PCMCIA_CARD(DAYNA, COMMUNICARD_E_1, 0), 257 0x0110, { 0x00, 0x80, 0x19 } }, 258 { PCMCIA_CARD(DAYNA, COMMUNICARD_E_2, 0), 259 -1, { 0x00, 0x80, 0x19 } }, 260 { PCMCIA_CARD(COREGA, ETHER_PCC_TD, 0), 261 -1, { 0x00, 0x00, 0xf4 } }, 262 { PCMCIA_CARD(COREGA, ETHER_PCC_T, 0), 263 -1, { 0x00, 0x00, 0xf4 } }, 264 { PCMCIA_CARD(COREGA, ETHER_II_PCC_T, 0), 265 -1, { 0x00, 0x00, 0xf4 } }, 266 { PCMCIA_CARD(COREGA, ETHER_II_PCC_TD, 0), 267 -1, { 0x00, 0x00, 0xf4 } }, 268 { PCMCIA_CARD(COREGA, FAST_ETHER_PCC_TX, 0), 269 -1, { 0x00, 0x00, 0xf4 }, NE2000DVF_DL10019 }, 270 { PCMCIA_CARD(COREGA, FETHER_PCC_TXD, 0), 271 -1, { 0x00, 0x90, 0x99 }, NE2000DVF_AX88190 }, 272 { PCMCIA_CARD(COREGA, FETHER_PCC_TXF, 0), 273 -1, { 0x00, 0x90, 0x99 }, NE2000DVF_DL10019 }, 274 { PCMCIA_CARD(COMPEX, LINKPORT_ENET_B, 0), 275 0x01c0, { 0x00, 0xa0, 0x0c } }, 276 { PCMCIA_CARD(DYNALINK, L10C, 0), 277 0x01c0, { 0x00, 0x00, 0x00 } }, 278 { PCMCIA_CARD(SMC, EZCARD, 0), 279 0x01c0, { 0x00, 0xe0, 0x29 } }, 280 { PCMCIA_CARD(SOCKET, EA_ETHER, 0), 281 -1, { 0x00, 0xc0, 0x1b } }, 282 { PCMCIA_CARD(SOCKET, LP_ETHER_CF, 0), 283 -1, { 0x00, 0xc0, 0x1b } }, 284 { PCMCIA_CARD(SOCKET, LP_ETHER, 0), 285 -1, { 0x00, 0xc0, 0x1b } }, 286 { PCMCIA_CARD(KINGSTON, KNE2, 0), 287 -1, { 0x00, 0xc0, 0xf0 } }, 288 { PCMCIA_CARD(XIRCOM, CFE_10, 0), 289 -1, { 0x00, 0x10, 0xa4 } }, 290 { PCMCIA_CARD(MELCO, LPC3_TX, 0), 291 -1, { 0x00, 0x40, 0x26 }, NE2000DVF_AX88190 }, 292 { PCMCIA_CARD(BUFFALO, LPC3_CLT, 0), 293 -1, { 0x00, 0x07, 0x40 } }, 294 { PCMCIA_CARD(BUFFALO, LPC_CF_CLT, 0), 295 -1, { 0x00, 0x07, 0x40 } }, 296 { PCMCIA_CARD(BILLIONTON, LNT10TN, 0), 297 -1, { 0x00, 0x00, 0x00 } }, 298 { PCMCIA_CARD(NDC, ND5100_E, 0), 299 -1, { 0x00, 0x80, 0xc6 } }, 300 { PCMCIA_CARD(TELECOMDEVICE, TCD_HPC100, 0), 301 -1, { 0x00, 0x40, 0x26 }, NE2000DVF_AX88190 }, 302 { PCMCIA_CARD(MACNICA, ME1_JEIDA, 0), 303 0x00b8, { 0x08, 0x00, 0x42 } }, 304 { PCMCIA_CARD(ALLIEDTELESIS, LA_PCM, 0), 305 0x0ff0, { 0x00, 0x00, 0xf4 } }, 306 { PCMCIA_CARD(DLINK, DFE670TXD, 0), 307 -1, { 0x00, 0x50, 0xba}, NE2000DVF_DL10019}, 308 { PCMCIA_CARD(NETGEAR, FA410TXC, 0), 309 -1, { 0x00, 0x48, 0x54 }, NE2000DVF_DL10019}, 310 { PCMCIA_CARD(NETGEAR, FA411, 0), 311 -1, { 0x00, 0x40, 0xf4 }, NE2000DVF_AX88190}, 312 313#if 0 314 /* the rest of these are stolen from the linux pcnet pcmcia device 315 driver. Since I don't know the manfid or cis info strings for 316 any of them, they're not compiled in until I do. */ 317 { "APEX MultiCard", 318 0x0000, 0x0000, NULL, NULL, 0, 319 0x03f4, { 0x00, 0x20, 0xe5 } }, 320 { "ASANTE FriendlyNet", 321 0x0000, 0x0000, NULL, NULL, 0, 322 0x4910, { 0x00, 0x00, 0x94 } }, 323 { "Danpex EN-6200P2", 324 0x0000, 0x0000, NULL, NULL, 0, 325 0x0110, { 0x00, 0x40, 0xc7 } }, 326 { "DataTrek NetCard", 327 0x0000, 0x0000, NULL, NULL, 0, 328 0x0ff0, { 0x00, 0x20, 0xe8 } }, 329 { "Dayna CommuniCard E", 330 0x0000, 0x0000, NULL, NULL, 0, 331 0x0110, { 0x00, 0x80, 0x19 } }, 332 { "EP-210 Ethernet", 333 0x0000, 0x0000, NULL, NULL, 0, 334 0x0110, { 0x00, 0x40, 0x33 } }, 335 { "ELECOM Laneed LD-CDWA", 336 0x0000, 0x0000, NULL, NULL, 0, 337 0x00b8, { 0x08, 0x00, 0x42 } }, 338 { "Grey Cell GCS2220", 339 0x0000, 0x0000, NULL, NULL, 0, 340 0x0000, { 0x00, 0x47, 0x43 } }, 341 { "Hypertec Ethernet", 342 0x0000, 0x0000, NULL, NULL, 0, 343 0x01c0, { 0x00, 0x40, 0x4c } }, 344 { "IBM CCAE", 345 0x0000, 0x0000, NULL, NULL, 0, 346 0x0ff0, { 0x08, 0x00, 0x5a } }, 347 { "IBM CCAE", 348 0x0000, 0x0000, NULL, NULL, 0, 349 0x0ff0, { 0x00, 0x04, 0xac } }, 350 { "IBM CCAE", 351 0x0000, 0x0000, NULL, NULL, 0, 352 0x0ff0, { 0x00, 0x06, 0x29 } }, 353 { "IBM FME", 354 0x0000, 0x0000, NULL, NULL, 0, 355 0x0374, { 0x00, 0x04, 0xac } }, 356 { "IBM FME", 357 0x0000, 0x0000, NULL, NULL, 0, 358 0x0374, { 0x08, 0x00, 0x5a } }, 359 { "Katron PE-520", 360 0x0000, 0x0000, NULL, NULL, 0, 361 0x0110, { 0x00, 0x40, 0xf6 } }, 362 { "Kingston KNE-PCM/x", 363 0x0000, 0x0000, NULL, NULL, 0, 364 0x0ff0, { 0x00, 0xc0, 0xf0 } }, 365 { "Kingston KNE-PCM/x", 366 0x0000, 0x0000, NULL, NULL, 0, 367 0x0ff0, { 0xe2, 0x0c, 0x0f } }, 368 { "Longshine LCS-8534", 369 0x0000, 0x0000, NULL, NULL, 0, 370 0x0000, { 0x08, 0x00, 0x00 } }, 371 { "Maxtech PCN2000", 372 0x0000, 0x0000, NULL, NULL, 0, 373 0x5000, { 0x00, 0x00, 0xe8 } }, 374 { "NDC Instant-Link", 375 0x0000, 0x0000, NULL, NULL, 0, 376 0x003a, { 0x00, 0x80, 0xc6 } }, 377 { "NE2000 Compatible", 378 0x0000, 0x0000, NULL, NULL, 0, 379 0x0ff0, { 0x00, 0xa0, 0x0c } }, 380 { "Network General Sniffer", 381 0x0000, 0x0000, NULL, NULL, 0, 382 0x0ff0, { 0x00, 0x00, 0x65 } }, 383 { "Panasonic VEL211", 384 0x0000, 0x0000, NULL, NULL, 0, 385 0x0ff0, { 0x00, 0x80, 0x45 } }, 386 { "SCM Ethernet", 387 0x0000, 0x0000, NULL, NULL, 0, 388 0x0ff0, { 0x00, 0x20, 0xcb } }, 389 { "Volktek NPL-402CT", 390 0x0000, 0x0000, NULL, NULL, 0, 391 0x0060, { 0x00, 0x40, 0x05 } }, 392#endif 393 { { NULL } } 394 395}; 396 397static int 398ed_pccard_match(device_t dev) 399{ 400 const struct ed_product *pp; 401 402 if ((pp = (const struct ed_product *) pccard_product_lookup(dev, 403 (const struct pccard_product *) ed_pccard_products, 404 sizeof(ed_pccard_products[0]), NULL)) != NULL) { 405 if (pp->prod.pp_name != NULL) 406 device_set_desc(dev, pp->prod.pp_name); 407 if (pp->flags & NE2000DVF_DL10019) 408 device_set_flags(dev, ED_FLAGS_LINKSYS); 409 else if (pp->flags & NE2000DVF_AX88190) 410 device_set_flags(dev, ED_FLAGS_AX88190); 411 return (0); 412 } 413 return (EIO); 414} 415 416/* 417 * Probe framework for pccards. Replicates the standard framework, 418 * minus the pccard driver registration and ignores the ether address 419 * supplied (from the CIS), relying on the probe to find it instead. 420 */ 421static int 422ed_pccard_probe(device_t dev) 423{ 424 int error; 425 int flags = device_get_flags(dev); 426 427 if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_AX88190) { 428 error = ed_pccard_ax88190(dev); 429 goto end2; 430 } 431 432 error = ed_probe_Novell(dev, 0, flags); 433 if (error == 0) 434 goto end; 435 ed_release_resources(dev); 436 437 error = ed_probe_WD80x3(dev, 0, flags); 438 if (error == 0) 439 goto end; 440 ed_release_resources(dev); 441 goto end2; 442 443end: 444 if (ED_FLAGS_GETTYPE(flags) & ED_FLAGS_LINKSYS) 445 ed_pccard_Linksys(dev); 446end2: 447 if (error == 0) 448 error = ed_alloc_irq(dev, 0, 0); 449 450 ed_release_resources(dev); 451 return (error); 452} 453 454static int 455ed_pccard_attach(device_t dev) 456{ 457 int error; 458 int flags = device_get_flags(dev); 459 int i; 460 struct ed_softc *sc = device_get_softc(dev); 461 u_char sum; 462 u_char ether_addr[ETHER_ADDR_LEN]; 463 464 if (sc->port_used > 0) 465 ed_alloc_port(dev, sc->port_rid, sc->port_used); 466 if (sc->mem_used) 467 ed_alloc_memory(dev, sc->mem_rid, sc->mem_used); 468 ed_alloc_irq(dev, sc->irq_rid, 0); 469 470 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, 471 edintr, sc, &sc->irq_handle); 472 if (error) { 473 printf("setup intr failed %d \n", error); 474 ed_release_resources(dev); 475 return (error); 476 } 477 478 if (sc->vendor != ED_VENDOR_LINKSYS) { 479 pccard_get_ether(dev, ether_addr); 480 for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) 481 sum |= ether_addr[i]; 482 if (sum) 483 bcopy(ether_addr, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 484 } 485 486 error = ed_attach(sc, device_get_unit(dev), flags); 487#ifndef ED_NO_MIIBUS 488 if (error == 0 && sc->vendor == ED_VENDOR_LINKSYS) { 489 /* Probe for an MII bus, but ignore errors. */ 490 ed_pccard_dlink_mii_reset(sc); 491 sc->mii_readbits = ed_pccard_dlink_mii_readbits; 492 sc->mii_writebits = ed_pccard_dlink_mii_writebits; 493 mii_phy_probe(dev, &sc->miibus, ed_ifmedia_upd, 494 ed_ifmedia_sts); 495 } 496#endif 497 498 return (error); 499} 500 501static void 502ax88190_geteprom(struct ed_softc *sc) 503{ 504 int prom[16],i; 505 u_char tmp; 506 struct { 507 unsigned char offset, value; 508 } pg_seq[] = { 509 {ED_P0_CR, ED_CR_RD2|ED_CR_STP},/* Select Page0 */ 510 {ED_P0_DCR, 0x01}, 511 {ED_P0_RBCR0, 0x00}, /* Clear the count regs. */ 512 {ED_P0_RBCR1, 0x00}, 513 {ED_P0_IMR, 0x00}, /* Mask completion irq. */ 514 {ED_P0_ISR, 0xff}, 515 {ED_P0_RCR, ED_RCR_MON | ED_RCR_INTT}, /* Set To Monitor */ 516 {ED_P0_TCR, ED_TCR_LB0}, /* loopback mode. */ 517 {ED_P0_RBCR0, 32}, 518 {ED_P0_RBCR1, 0x00}, 519 {ED_P0_RSAR0, 0x00}, 520 {ED_P0_RSAR1, 0x04}, 521 {ED_P0_CR ,ED_CR_RD0 | ED_CR_STA}, 522 }; 523 524 /* Reset Card */ 525 tmp = ed_asic_inb(sc, ED_NOVELL_RESET); 526 ed_asic_outb(sc, ED_NOVELL_RESET, tmp); 527 DELAY(5000); 528 ed_asic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP); 529 DELAY(5000); 530 531 /* Card Settings */ 532 for (i = 0; i < sizeof(pg_seq) / sizeof(pg_seq[0]); i++) 533 ed_nic_outb(sc, pg_seq[i].offset, pg_seq[i].value); 534 535 /* Get Data */ 536 for (i = 0; i < 16; i++) 537 prom[i] = ed_asic_inb(sc, 0); 538 sc->arpcom.ac_enaddr[0] = prom[0] & 0xff; 539 sc->arpcom.ac_enaddr[1] = prom[0] >> 8; 540 sc->arpcom.ac_enaddr[2] = prom[1] & 0xff; 541 sc->arpcom.ac_enaddr[3] = prom[1] >> 8; 542 sc->arpcom.ac_enaddr[4] = prom[2] & 0xff; 543 sc->arpcom.ac_enaddr[5] = prom[2] >> 8; 544} 545 546static int 547ed_pccard_memwrite(device_t dev, off_t offset, u_char byte) 548{ 549 int cis_rid; 550 struct resource *cis; 551 552 cis_rid = 0; 553 cis = bus_alloc_resource(dev, SYS_RES_MEMORY, &cis_rid, 0, ~0, 554 4 << 10, RF_ACTIVE | RF_SHAREABLE); 555 if (cis == NULL) 556 return (ENXIO); 557 CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 558 cis_rid, PCCARD_A_MEM_ATTR); 559 560 bus_space_write_1(rman_get_bustag(cis), rman_get_bushandle(cis), 561 offset, byte); 562 563 bus_deactivate_resource(dev, SYS_RES_MEMORY, cis_rid, cis); 564 bus_release_resource(dev, SYS_RES_MEMORY, cis_rid, cis); 565 566 return (0); 567} 568 569/* 570 * Probe the Ethernet MAC addrees for PCMCIA Linksys EtherFast 10/100 571 * and compatible cards (DL10019C Ethernet controller). 572 * 573 * Note: The PAO patches try to use more memory for the card, but that 574 * seems to fail for my card. A future optimization would add this back 575 * conditionally. 576 */ 577static int 578ed_pccard_Linksys(device_t dev) 579{ 580 struct ed_softc *sc = device_get_softc(dev); 581 u_char sum; 582 int i; 583 584 /* 585 * Linksys registers(offset from ASIC base) 586 * 587 * 0x04-0x09 : Physical Address Register 0-5 (PAR0-PAR5) 588 * 0x0A : Card ID Register (CIR) 589 * 0x0B : Check Sum Register (SR) 590 */ 591 for (sum = 0, i = 0x04; i < 0x0c; i++) 592 sum += ed_asic_inb(sc, i); 593 if (sum != 0xff) 594 return (0); /* invalid DL10019C */ 595 for (i = 0; i < ETHER_ADDR_LEN; i++) { 596 sc->arpcom.ac_enaddr[i] = ed_asic_inb(sc, 0x04 + i); 597 } 598 599 ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); 600 sc->isa16bit = 1; 601 sc->vendor = ED_VENDOR_LINKSYS; 602 sc->type = ED_TYPE_NE2000; 603 sc->type_str = "Linksys"; 604 605 return (1); 606} 607 608/* 609 * Special setup for AX88190 610 */ 611static int 612ed_pccard_ax88190(device_t dev) 613{ 614 int error; 615 int flags = device_get_flags(dev); 616 int iobase; 617 struct ed_softc *sc = device_get_softc(dev); 618 619 /* Allocate the port resource during setup. */ 620 error = ed_alloc_port(dev, 0, ED_NOVELL_IO_PORTS); 621 if (error) 622 return (error); 623 624 sc->asic_offset = ED_NOVELL_ASIC_OFFSET; 625 sc->nic_offset = ED_NOVELL_NIC_OFFSET; 626 sc->chip_type = ED_CHIP_TYPE_AX88190; 627 628 /* 629 * Set Attribute Memory IOBASE Register 630 */ 631 iobase = rman_get_start(sc->port_res); 632 ed_pccard_memwrite(dev, ED_AX88190_IOBASE0, iobase & 0xff); 633 ed_pccard_memwrite(dev, ED_AX88190_IOBASE1, (iobase >> 8) & 0xff); 634 ax88190_geteprom(sc); 635 ed_release_resources(dev); 636 error = ed_probe_Novell(dev, 0, flags); 637 if (error == 0) { 638 sc->vendor = ED_VENDOR_PCCARD; 639 sc->type = ED_TYPE_NE2000; 640 sc->type_str = "AX88190"; 641 } 642 return (error); 643} 644 645#ifndef ED_NO_MIIBUS 646/* MII bit-twiddling routines for cards using Dlink chipset */ 647#define DLINK_MIISET(sc, x) ed_asic_outb(sc, ED_DLINK_MIIBUS, \ 648 ed_asic_inb(sc, ED_DLINK_MIIBUS) | (x)) 649#define DLINK_MIICLR(sc, x) ed_asic_outb(sc, ED_DLINK_MIIBUS, \ 650 ed_asic_inb(sc, ED_DLINK_MIIBUS) & ~(x)) 651 652static void 653ed_pccard_dlink_mii_reset(sc) 654 struct ed_softc *sc; 655{ 656 ed_asic_outb(sc, ED_DLINK_MIIBUS, 0); 657 DELAY(10); 658 DLINK_MIISET(sc, ED_DLINK_MII_RESET2); 659 DELAY(10); 660 DLINK_MIISET(sc, ED_DLINK_MII_RESET1); 661 DELAY(10); 662 DLINK_MIICLR(sc, ED_DLINK_MII_RESET1); 663 DELAY(10); 664 DLINK_MIICLR(sc, ED_DLINK_MII_RESET2); 665 DELAY(10); 666} 667 668static void 669ed_pccard_dlink_mii_writebits(sc, val, nbits) 670 struct ed_softc *sc; 671 u_int val; 672 int nbits; 673{ 674 int i; 675 676 DLINK_MIISET(sc, ED_DLINK_MII_DIROUT); 677 678 for (i = nbits - 1; i >= 0; i--) { 679 if ((val >> i) & 1) 680 DLINK_MIISET(sc, ED_DLINK_MII_DATAOUT); 681 else 682 DLINK_MIICLR(sc, ED_DLINK_MII_DATAOUT); 683 DELAY(10); 684 DLINK_MIISET(sc, ED_DLINK_MII_CLK); 685 DELAY(10); 686 DLINK_MIICLR(sc, ED_DLINK_MII_CLK); 687 DELAY(10); 688 } 689} 690 691static u_int 692ed_pccard_dlink_mii_readbits(sc, nbits) 693 struct ed_softc *sc; 694 int nbits; 695{ 696 int i; 697 u_int val = 0; 698 699 DLINK_MIICLR(sc, ED_DLINK_MII_DIROUT); 700 701 for (i = nbits - 1; i >= 0; i--) { 702 DLINK_MIISET(sc, ED_DLINK_MII_CLK); 703 DELAY(10); 704 val <<= 1; 705 if (ed_asic_inb(sc, ED_DLINK_MIIBUS) & ED_DLINK_MII_DATATIN) 706 val++; 707 DLINK_MIICLR(sc, ED_DLINK_MII_CLK); 708 DELAY(10); 709 } 710 711 return val; 712} 713#endif 714 715static device_method_t ed_pccard_methods[] = { 716 /* Device interface */ 717 DEVMETHOD(device_probe, pccard_compat_probe), 718 DEVMETHOD(device_attach, pccard_compat_attach), 719 DEVMETHOD(device_detach, ed_pccard_detach), 720 721#ifndef ED_NO_MIIBUS 722 /* Bus interface */ 723 DEVMETHOD(bus_child_detached, ed_child_detached), 724 725 /* MII interface */ 726 DEVMETHOD(miibus_readreg, ed_miibus_readreg), 727 DEVMETHOD(miibus_writereg, ed_miibus_writereg), 728#endif 729 730 /* Card interface */ 731 DEVMETHOD(card_compat_match, ed_pccard_match), 732 DEVMETHOD(card_compat_probe, ed_pccard_probe), 733 DEVMETHOD(card_compat_attach, ed_pccard_attach), 734 { 0, 0 } 735}; 736 737static driver_t ed_pccard_driver = { 738 "ed", 739 ed_pccard_methods, 740 sizeof(struct ed_softc) 741}; 742 743DRIVER_MODULE(if_ed, pccard, ed_pccard_driver, ed_devclass, 0, 0); 744#ifndef ED_NO_MIIBUS 745DRIVER_MODULE(miibus, ed, miibus_driver, miibus_devclass, 0, 0); 746#endif 747