if_ep.c revision 30398
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 * if_ep.c,v 1.19 1995/01/24 20:53:45 davidg Exp 31 */ 32 33/* 34 * Modified from the FreeBSD 1.1.5.1 version by: 35 * Andres Vega Garcia 36 * INRIA - Sophia Antipolis, France 37 * avega@sophia.inria.fr 38 */ 39 40/* 41 * $Id: if_ep.c,v 1.60 1997/09/02 01:18:13 bde Exp $ 42 * 43 * Promiscuous mode added and interrupt logic slightly changed 44 * to reduce the number of adapter failures. Transceiver select 45 * logic changed to use value from EEPROM. Autoconfiguration 46 * features added. 47 * Done by: 48 * Serge Babkin 49 * Chelindbank (Chelyabinsk, Russia) 50 * babkin@hq.icb.chel.su 51 */ 52 53/* 54 * Pccard support for 3C589 by: 55 * HAMADA Naoki 56 * nao@tom-yam.or.jp 57 */ 58 59#include "ep.h" 60#if NEP > 0 61 62#include "bpfilter.h" 63 64#include <sys/param.h> 65#if defined(__FreeBSD__) 66#include <sys/systm.h> 67#include <sys/conf.h> 68#endif 69#include <sys/malloc.h> 70#include <sys/mbuf.h> 71#include <sys/socket.h> 72#include <sys/sockio.h> 73#if defined(__NetBSD__) 74#include <sys/select.h> 75#endif 76 77#include <net/if.h> 78 79#ifdef INET 80#include <netinet/in.h> 81#include <netinet/if_ether.h> 82#endif 83 84#ifdef IPX 85#include <netipx/ipx.h> 86#include <netipx/ipx_if.h> 87#endif 88 89#ifdef NS 90#include <netns/ns.h> 91#include <netns/ns_if.h> 92#endif 93 94#if NBPFILTER > 0 95#include <net/bpf.h> 96#endif 97 98#if defined(__FreeBSD__) 99#include <machine/clock.h> 100#endif 101 102#include <i386/isa/isa_device.h> 103#include <i386/isa/if_epreg.h> 104#include <i386/isa/elink.h> 105 106/* Exported variables */ 107u_long ep_unit; 108int ep_boards; 109struct ep_board ep_board[EP_MAX_BOARDS + 1]; 110 111static int eeprom_rdy __P((struct ep_softc *sc)); 112 113static int ep_isa_probe __P((struct isa_device *)); 114static struct ep_board * ep_look_for_board_at __P((struct isa_device *is)); 115static int ep_isa_attach __P((struct isa_device *)); 116static int epioctl __P((struct ifnet * ifp, int, caddr_t)); 117 118static void epinit __P((struct ep_softc *)); 119static void epread __P((struct ep_softc *)); 120void epreset __P((int)); 121static void epstart __P((struct ifnet *)); 122static void epstop __P((struct ep_softc *)); 123static void epwatchdog __P((struct ifnet *)); 124 125#if 0 126static int send_ID_sequence __P((int)); 127#endif 128static int get_eeprom_data __P((int, int)); 129 130static struct ep_softc* ep_softc[NEP]; 131static int ep_current_tag = EP_LAST_TAG + 1; 132static char *ep_conn_type[] = {"UTP", "AUI", "???", "BNC"}; 133 134#define ep_ftst(f) (sc->stat&(f)) 135#define ep_fset(f) (sc->stat|=(f)) 136#define ep_frst(f) (sc->stat&=~(f)) 137 138struct isa_driver epdriver = { 139 ep_isa_probe, 140 ep_isa_attach, 141 "ep", 142 0 143}; 144 145#include "crd.h" 146 147#if NCRD > 0 148#include <sys/select.h> 149#include <pccard/card.h> 150#include <pccard/driver.h> 151#include <pccard/slot.h> 152 153/* 154 * PC-Card (PCMCIA) specific code. 155 */ 156static int card_intr __P((struct pccard_dev *)); 157static void ep_unload __P((struct pccard_dev *)); 158static void ep_suspend __P((struct pccard_dev *)); 159static int ep_pccard_init __P((struct pccard_dev *, int)); 160static int ep_pccard_attach __P((struct pccard_dev *)); 161 162static struct pccard_drv ep_info = { 163 "ep", 164 card_intr, 165 ep_unload, 166 ep_suspend, 167 ep_pccard_init, 168 0, /* Attributes - presently unused */ 169 &net_imask 170}; 171 172/* Resume is done by executing ep_pccard_init(dp, 0). */ 173static void 174ep_suspend(dp) 175 struct pccard_dev *dp; 176{ 177 struct ep_softc *sc = ep_softc[dp->isahd.id_unit]; 178 179 printf("ep%d: suspending\n", dp->isahd.id_unit); 180 sc->gone = 1; 181} 182 183/* 184 * 185 */ 186static int 187ep_pccard_init(dp, first) 188 struct pccard_dev *dp; 189 int first; 190{ 191 struct isa_device *is = &dp->isahd; 192 struct ep_softc *sc = ep_softc[is->id_unit]; 193 struct ep_board *epb; 194 int i; 195 196 epb = &ep_board[is->id_unit]; 197 198 if (sc == 0) { 199 if ((sc = ep_alloc(is->id_unit, epb)) == 0) { 200 return (ENXIO); 201 } 202 ep_unit++; 203 } 204 205 /* get_e() requires these. */ 206 sc->ep_io_addr = is->id_iobase; 207 sc->unit = is->id_unit; 208 209 epb->epb_addr = is->id_iobase; 210 epb->epb_used = 1; 211 epb->prod_id = get_e(sc, EEPROM_PROD_ID); 212 213 if (epb->prod_id != 0x9058) { /* 3C589's product id */ 214 if (first) { 215 printf("ep%d: failed to come ready.\n", is->id_unit); 216 } else { 217 printf("ep%d: failed to resume.\n", is->id_unit); 218 } 219 return (ENXIO); 220 } 221 222 epb->res_cfg = get_e(sc, EEPROM_RESOURCE_CFG); 223 for (i = 0; i < 3; i++) { 224 sc->epb->eth_addr[i] = get_e(sc, EEPROM_NODE_ADDR_0 + i); 225 } 226 227 if (first) { 228 if (ep_pccard_attach(dp) == 0) { 229 return (ENXIO); 230 } 231 sc->arpcom.ac_if.if_snd.ifq_maxlen = ifqmaxlen; 232 } 233 234 if (!first) { 235 sc->gone = 0; 236 printf("ep%d: resumed.\n", is->id_unit); 237 epinit(sc); 238 } 239 240 return (0); 241} 242 243static int 244ep_pccard_attach(dp) 245 struct pccard_dev *dp; 246{ 247 struct isa_device *is = &dp->isahd; 248 struct ep_softc *sc = ep_softc[is->id_unit]; 249 u_short config; 250 251 sc->ep_connectors = 0; 252 config = inw(IS_BASE + EP_W0_CONFIG_CTRL); 253 if (config & IS_BNC) { 254 sc->ep_connectors |= BNC; 255 } 256 if (config & IS_UTP) { 257 sc->ep_connectors |= UTP; 258 } 259 if (!(sc->ep_connectors & 7)) 260 printf("no connectors!"); 261 sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; 262 263 /* ROM size = 0, ROM base = 0 */ 264 /* For now, ignore AUTO SELECT feature of 3C589B and later. */ 265 outw(BASE + EP_W0_ADDRESS_CFG, get_e(sc, EEPROM_ADDR_CFG) & 0xc000); 266 267 /* Fake IRQ must be 3 */ 268 outw(BASE + EP_W0_RESOURCE_CFG, (sc->epb->res_cfg & 0x0fff) | 0x3000); 269 270 outw(BASE + EP_W0_PRODUCT_ID, sc->epb->prod_id); 271 272 ep_attach(sc); 273 274 return 1; 275} 276 277static void 278ep_unload(dp) 279 struct pccard_dev *dp; 280{ 281 struct ep_softc *sc = ep_softc[dp->isahd.id_unit]; 282 283 if (sc->gone) { 284 printf("ep%d: already unloaded\n", dp->isahd.id_unit); 285 return; 286 } 287 sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; 288 sc->gone = 1; 289 printf("ep%d: unload\n", dp->isahd.id_unit); 290} 291 292/* 293 * card_intr - Shared interrupt called from 294 * front end of PC-Card handler. 295 */ 296static int 297card_intr(dp) 298 struct pccard_dev *dp; 299{ 300 epintr(dp->isahd.id_unit); 301 return(1); 302} 303 304#endif /* NCRD > 0 */ 305 306static int 307eeprom_rdy(sc) 308 struct ep_softc *sc; 309{ 310 int i; 311 312 for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++); 313 if (i >= MAX_EEPROMBUSY) { 314 printf("ep%d: eeprom failed to come ready.\n", sc->unit); 315 return (0); 316 } 317 return (1); 318} 319 320static struct ep_board * 321ep_look_for_board_at(is) 322 struct isa_device *is; 323{ 324 int data, i, j, id_port = ELINK_ID_PORT; 325 int count = 0; 326 327 if (ep_current_tag == (EP_LAST_TAG + 1)) { 328 /* Come here just one time */ 329 330 ep_current_tag--; 331 332 /* Look for the ISA boards. Init and leave them actived */ 333 outb(id_port, 0); 334 outb(id_port, 0); 335 336 elink_idseq(0xCF); 337 338 elink_reset(); 339 DELAY(10000); 340 for (i = 0; i < EP_MAX_BOARDS; i++) { 341 outb(id_port, 0); 342 outb(id_port, 0); 343 elink_idseq(0xCF); 344 345 data = get_eeprom_data(id_port, EEPROM_MFG_ID); 346 if (data != MFG_ID) 347 break; 348 349 /* resolve contention using the Ethernet address */ 350 351 for (j = 0; j < 3; j++) 352 get_eeprom_data(id_port, j); 353 354 /* and save this address for later use */ 355 356 for (j = 0; j < 3; j++) 357 ep_board[ep_boards].eth_addr[j] = get_eeprom_data(id_port, j); 358 359 ep_board[ep_boards].res_cfg = 360 get_eeprom_data(id_port, EEPROM_RESOURCE_CFG); 361 362 ep_board[ep_boards].prod_id = 363 get_eeprom_data(id_port, EEPROM_PROD_ID); 364 365 ep_board[ep_boards].epb_used = 0; 366#ifdef PC98 367 ep_board[ep_boards].epb_addr = 368 (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x100 + 0x40d0; 369#else 370 ep_board[ep_boards].epb_addr = 371 (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200; 372 373 if (ep_board[ep_boards].epb_addr > 0x3E0) 374 /* Board in EISA configuration mode */ 375 continue; 376#endif /* PC98 */ 377 378 outb(id_port, ep_current_tag); /* tags board */ 379 outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); 380 ep_boards++; 381 count++; 382 ep_current_tag--; 383 } 384 385 ep_board[ep_boards].epb_addr = 0; 386 if (count) { 387 printf("%d 3C5x9 board(s) on ISA found at", count); 388 for (j = 0; ep_board[j].epb_addr; j++) 389 if (ep_board[j].epb_addr <= 0x3E0) 390 printf(" 0x%x", ep_board[j].epb_addr); 391 printf("\n"); 392 } 393 } 394 395 /* we have two cases: 396 * 397 * 1. Device was configured with 'port ?' 398 * In this case we search for the first unused card in list 399 * 400 * 2. Device was configured with 'port xxx' 401 * In this case we search for the unused card with that address 402 * 403 */ 404 405 if (IS_BASE == -1) { /* port? */ 406 for (i = 0; ep_board[i].epb_addr && ep_board[i].epb_used; i++) 407 ; 408 if (ep_board[i].epb_addr == 0) 409 return 0; 410 411 IS_BASE = ep_board[i].epb_addr; 412 ep_board[i].epb_used = 1; 413 414 return &ep_board[i]; 415 } else { 416 for (i = 0; 417 ep_board[i].epb_addr && ep_board[i].epb_addr != IS_BASE; 418 i++) 419 ; 420 421 if (ep_board[i].epb_used || ep_board[i].epb_addr != IS_BASE) 422 return 0; 423 424 if (inw(IS_BASE + EP_W0_EEPROM_COMMAND) & EEPROM_TST_MODE) { 425 printf("ep%d: 3c5x9 at 0x%x in PnP mode. Disable PnP mode!\n", 426 is->id_unit, IS_BASE); 427 } 428 ep_board[i].epb_used = 1; 429 430 return &ep_board[i]; 431 } 432} 433 434/* 435 * get_e: gets a 16 bits word from the EEPROM. we must have set the window 436 * before 437 */ 438u_int16_t 439get_e(sc, offset) 440 struct ep_softc *sc; 441 int offset; 442{ 443 if (!eeprom_rdy(sc)) 444 return (0xffff); 445 outw(BASE + EP_W0_EEPROM_COMMAND, EEPROM_CMD_RD | offset); 446 if (!eeprom_rdy(sc)) 447 return (0xffff); 448 return (inw(BASE + EP_W0_EEPROM_DATA)); 449} 450 451struct ep_softc * 452ep_alloc(unit, epb) 453 int unit; 454 struct ep_board *epb; 455{ 456 struct ep_softc *sc; 457 458 if (unit >= NEP) { 459 printf("ep: unit number (%d) too high\n", unit); 460 return NULL; 461 } 462 463 /* 464 * Allocate a storage area for us 465 */ 466 if (ep_softc[unit]) { 467 printf("ep%d: unit number already allocated to another " 468 "adaptor\n", unit); 469 return NULL; 470 } 471 472 sc = malloc(sizeof(struct ep_softc), M_DEVBUF, M_NOWAIT); 473 if (!sc) { 474 printf("ep%d: cannot malloc!\n", unit); 475 return NULL; 476 } 477 bzero(sc, sizeof(struct ep_softc)); 478 ep_softc[unit] = sc; 479 sc->unit = unit; 480 sc->ep_io_addr = epb->epb_addr; 481 sc->epb = epb; 482 483 return(sc); 484} 485 486void 487ep_free(sc) 488 struct ep_softc *sc; 489{ 490 ep_softc[sc->unit] = NULL; 491 free(sc, M_DEVBUF); 492 return; 493} 494 495int 496ep_isa_probe(is) 497 struct isa_device *is; 498{ 499 struct ep_softc *sc; 500 struct ep_board *epb; 501 u_short k; 502 503#if NCRD > 0 504 pccard_add_driver(&ep_info); 505#endif /* NCRD > 0 */ 506 507 if ((epb = ep_look_for_board_at(is)) == 0) 508 return (0); 509 510 /* 511 * Allocate a storage area for us 512 */ 513 sc = ep_alloc(ep_unit, epb); 514 if (!sc) 515 return (0); 516 517 is->id_unit = ep_unit++; 518 519 /* 520 * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be 521 * 0x9[0-f]50 522 */ 523 GO_WINDOW(0); 524 k = sc->epb->prod_id; 525 if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) { 526 printf("ep_isa_probe: ignoring model %04x\n", k); 527 ep_free(sc); 528 return (0); 529 } 530 531 k = sc->epb->res_cfg; 532 533 k >>= 12; 534 535 /* Now we have two cases again: 536 * 537 * 1. Device was configured with 'irq?' 538 * In this case we use irq read from the board 539 * 540 * 2. Device was configured with 'irq xxx' 541 * In this case we set up the board to use specified interrupt 542 * 543 */ 544 545 if (is->id_irq == 0) { /* irq? */ 546 is->id_irq = 1 << ((k == 2) ? 9 : k); 547 } 548 549 sc->stat = 0; /* 16 bit access */ 550 551 /* By now, the adapter is already activated */ 552 553 return (EP_IOSIZE); /* 16 bytes of I/O space used. */ 554} 555 556static int 557ep_isa_attach(is) 558 struct isa_device *is; 559{ 560 struct ep_softc *sc = ep_softc[is->id_unit]; 561 u_short config; 562 int irq; 563 564 sc->ep_connectors = 0; 565 config = inw(IS_BASE + EP_W0_CONFIG_CTRL); 566 if (config & IS_AUI) { 567 sc->ep_connectors |= AUI; 568 } 569 if (config & IS_BNC) { 570 sc->ep_connectors |= BNC; 571 } 572 if (config & IS_UTP) { 573 sc->ep_connectors |= UTP; 574 } 575 if (!(sc->ep_connectors & 7)) 576 printf("no connectors!"); 577 sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; 578 /* 579 * Write IRQ value to board 580 */ 581 582 irq = ffs(is->id_irq) - 1; 583 if (irq == -1) { 584 printf(" invalid irq... cannot attach\n"); 585 return 0; 586 } 587 588 GO_WINDOW(0); 589 SET_IRQ(BASE, irq); 590 591 ep_attach(sc); 592 return 1; 593} 594 595int 596ep_attach(sc) 597 struct ep_softc *sc; 598{ 599 struct ifaddr *ifa; 600 struct ifnet *ifp = &sc->arpcom.ac_if; 601 struct sockaddr_dl *sdl; 602 u_short *p; 603 int i; 604 int attached; 605 606 sc->gone = 0; 607 attached = (ifp->if_softc != 0); 608 609 printf("ep%d: ", sc->unit); 610 /* 611 * Current media type 612 */ 613 if (sc->ep_connectors & AUI) { 614 printf("aui"); 615 if (sc->ep_connectors & ~AUI) 616 printf("/"); 617 } 618 if (sc->ep_connectors & UTP) { 619 printf("utp"); 620 if (sc->ep_connectors & BNC) 621 printf("/"); 622 } 623 if (sc->ep_connectors & BNC) { 624 printf("bnc"); 625 } 626 627 printf("[*%s*]", ep_conn_type[sc->ep_connector]); 628 629 /* 630 * Setup the station address 631 */ 632 p = (u_short *) & sc->arpcom.ac_enaddr; 633 GO_WINDOW(2); 634 for (i = 0; i < 3; i++) { 635 p[i] = htons(sc->epb->eth_addr[i]); 636 outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i])); 637 } 638 printf(" address %6D\n", sc->arpcom.ac_enaddr, ":"); 639 640 ifp->if_softc = sc; 641 ifp->if_unit = sc->unit; 642 ifp->if_name = "ep"; 643 ifp->if_mtu = ETHERMTU; 644 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 645 ifp->if_output = ether_output; 646 ifp->if_start = epstart; 647 ifp->if_ioctl = epioctl; 648 ifp->if_watchdog = epwatchdog; 649 650 if (!attached) { 651 if_attach(ifp); 652 ether_ifattach(ifp); 653 } 654 655#ifdef EP_LOCAL_STATS 656 sc->rx_no_first = sc->rx_no_mbuf = 657 sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = 658 sc->tx_underrun = 0; 659#endif 660 ep_fset(F_RX_FIRST); 661 sc->top = sc->mcur = 0; 662 663#if NBPFILTER > 0 664 if (!attached) { 665 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 666 } 667#endif 668 return 0; 669} 670 671 672/* 673 * The order in here seems important. Otherwise we may not receive 674 * interrupts. ?! 675 */ 676static void 677epinit(sc) 678 struct ep_softc *sc; 679{ 680 register struct ifnet *ifp = &sc->arpcom.ac_if; 681 int s, i, j; 682 683 if (sc->gone) 684 return; 685 686 /* 687 if (ifp->if_addrlist == (struct ifaddr *) 0) 688 return; 689 */ 690 691 s = splimp(); 692 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 693 694 GO_WINDOW(0); 695 outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); 696 GO_WINDOW(4); 697 outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP); 698 GO_WINDOW(0); 699 700 /* Disable the card */ 701 outw(BASE + EP_W0_CONFIG_CTRL, 0); 702 703 /* Enable the card */ 704 outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); 705 706 GO_WINDOW(2); 707 708 /* Reload the ether_addr. */ 709 for (i = 0; i < 6; i++) 710 outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]); 711 712 outw(BASE + EP_COMMAND, RX_RESET); 713 outw(BASE + EP_COMMAND, TX_RESET); 714 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 715 716 /* Window 1 is operating window */ 717 GO_WINDOW(1); 718 for (i = 0; i < 31; i++) 719 inb(BASE + EP_W1_TX_STATUS); 720 721 /* get rid of stray intr's */ 722 outw(BASE + EP_COMMAND, ACK_INTR | 0xff); 723 724 outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS); 725 726 outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); 727 728 if (ifp->if_flags & IFF_PROMISC) 729 outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | 730 FIL_GROUP | FIL_BRDCST | FIL_ALL); 731 else 732 outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | 733 FIL_GROUP | FIL_BRDCST); 734 735 /* 736 * S.B. 737 * 738 * Now behavior was slightly changed: 739 * 740 * if any of flags link[0-2] is used and its connector is 741 * physically present the following connectors are used: 742 * 743 * link0 - AUI * highest precedence 744 * link1 - BNC 745 * link2 - UTP * lowest precedence 746 * 747 * If none of them is specified then 748 * connector specified in the EEPROM is used 749 * (if present on card or AUI if not). 750 * 751 */ 752 753 /* Set the xcvr. */ 754 if (ifp->if_flags & IFF_LINK0 && sc->ep_connectors & AUI) { 755 i = ACF_CONNECTOR_AUI; 756 } else if (ifp->if_flags & IFF_LINK1 && sc->ep_connectors & BNC) { 757 i = ACF_CONNECTOR_BNC; 758 } else if (ifp->if_flags & IFF_LINK2 && sc->ep_connectors & UTP) { 759 i = ACF_CONNECTOR_UTP; 760 } else { 761 i = sc->ep_connector; 762 } 763 GO_WINDOW(0); 764 j = inw(BASE + EP_W0_ADDRESS_CFG) & 0x3fff; 765 outw(BASE + EP_W0_ADDRESS_CFG, j | (i << ACF_CONNECTOR_BITS)); 766 767 switch(i) { 768 case ACF_CONNECTOR_UTP: 769 if (sc->ep_connectors & UTP) { 770 GO_WINDOW(4); 771 outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP); 772 } 773 break; 774 case ACF_CONNECTOR_BNC: 775 if (sc->ep_connectors & BNC) { 776 outw(BASE + EP_COMMAND, START_TRANSCEIVER); 777 DELAY(1000); 778 } 779 break; 780 case ACF_CONNECTOR_AUI: 781 /* nothing to do */ 782 break; 783 default: 784 printf("ep%d: strange connector type in EEPROM: assuming AUI\n", 785 sc->unit); 786 break; 787 } 788 789 outw(BASE + EP_COMMAND, RX_ENABLE); 790 outw(BASE + EP_COMMAND, TX_ENABLE); 791 792 ifp->if_flags |= IFF_RUNNING; 793 ifp->if_flags &= ~IFF_OACTIVE; /* just in case */ 794 795#ifdef EP_LOCAL_STATS 796 sc->rx_no_first = sc->rx_no_mbuf = 797 sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = 798 sc->tx_underrun = 0; 799#endif 800 ep_fset(F_RX_FIRST); 801 if (sc->top) { 802 m_freem(sc->top); 803 sc->top = sc->mcur = 0; 804 } 805 outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); 806 outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16); 807 808 /* 809 * Store up a bunch of mbuf's for use later. (MAX_MBS). First we free up 810 * any that we had in case we're being called from intr or somewhere 811 * else. 812 */ 813 814 GO_WINDOW(1); 815 epstart(ifp); 816 817 splx(s); 818} 819 820static const char padmap[] = {0, 3, 2, 1}; 821 822static void 823epstart(ifp) 824 struct ifnet *ifp; 825{ 826 register struct ep_softc *sc = ifp->if_softc; 827 register u_int len; 828 register struct mbuf *m; 829 struct mbuf *top; 830 int s, pad; 831 832 if (sc->gone) { 833 return; 834 } 835 836 s = splimp(); 837 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 838 if (ifp->if_flags & IFF_OACTIVE) { 839 splx(s); 840 return; 841 } 842startagain: 843 /* Sneak a peek at the next packet */ 844 m = ifp->if_snd.ifq_head; 845 if (m == 0) { 846 splx(s); 847 return; 848 } 849 for (len = 0, top = m; m; m = m->m_next) 850 len += m->m_len; 851 852 pad = padmap[len & 3]; 853 854 /* 855 * The 3c509 automatically pads short packets to minimum ethernet length, 856 * but we drop packets that are too large. Perhaps we should truncate 857 * them instead? 858 */ 859 if (len + pad > ETHER_MAX_LEN) { 860 /* packet is obviously too large: toss it */ 861 ++ifp->if_oerrors; 862 IF_DEQUEUE(&ifp->if_snd, m); 863 m_freem(m); 864 goto readcheck; 865 } 866 if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) { 867 /* no room in FIFO */ 868 outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4)); 869 /* make sure */ 870 if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) { 871 ifp->if_flags |= IFF_OACTIVE; 872 splx(s); 873 return; 874 } 875 } 876 IF_DEQUEUE(&ifp->if_snd, m); 877 878 outw(BASE + EP_W1_TX_PIO_WR_1, len); 879 outw(BASE + EP_W1_TX_PIO_WR_1, 0x0); /* Second dword meaningless */ 880 881 for (top = m; m != 0; m = m->m_next) 882 if (ep_ftst(F_ACCESS_32_BITS)) { 883 outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), 884 m->m_len / 4); 885 if (m->m_len & 3) 886 outsb(BASE + EP_W1_TX_PIO_WR_1, 887 mtod(m, caddr_t) + (m->m_len & (~3)), 888 m->m_len & 3); 889 } else { 890 outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 2); 891 if (m->m_len & 1) 892 outb(BASE + EP_W1_TX_PIO_WR_1, 893 *(mtod(m, caddr_t) + m->m_len - 1)); 894 } 895 896 while (pad--) 897 outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */ 898 899#if NBPFILTER > 0 900 if (ifp->if_bpf) { 901 bpf_mtap(ifp, top); 902 } 903#endif 904 905 ifp->if_timer = 2; 906 ifp->if_opackets++; 907 m_freem(top); 908 909 /* 910 * Is another packet coming in? We don't want to overflow the tiny RX 911 * fifo. 912 */ 913readcheck: 914 if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) { 915 /* 916 * we check if we have packets left, in that case we prepare to come 917 * back later 918 */ 919 if (ifp->if_snd.ifq_head) { 920 outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8); 921 } 922 splx(s); 923 return; 924 } 925 goto startagain; 926} 927 928void 929epintr(unit) 930 int unit; 931{ 932 register struct ep_softc *sc = ep_softc[unit]; 933 934 if (sc->gone) { 935 return; 936 } 937 938 ep_intr(sc); 939} 940 941void 942ep_intr(arg) 943 void *arg; 944{ 945 struct ep_softc *sc; 946 register int status; 947 struct ifnet *ifp; 948 int x; 949 950 x = splbio(); 951 952 sc = (struct ep_softc *)arg; 953 954 ifp = &sc->arpcom.ac_if; 955 956 outw(BASE + EP_COMMAND, SET_INTR_MASK); /* disable all Ints */ 957 958rescan: 959 960 while ((status = inw(BASE + EP_STATUS)) & S_5_INTS) { 961 962 /* first acknowledge all interrupt sources */ 963 outw(BASE + EP_COMMAND, ACK_INTR | (status & S_MASK)); 964 965 if (status & (S_RX_COMPLETE | S_RX_EARLY)) { 966 epread(sc); 967 continue; 968 } 969 if (status & S_TX_AVAIL) { 970 /* we need ACK */ 971 ifp->if_timer = 0; 972 ifp->if_flags &= ~IFF_OACTIVE; 973 GO_WINDOW(1); 974 inw(BASE + EP_W1_FREE_TX); 975 epstart(ifp); 976 } 977 if (status & S_CARD_FAILURE) { 978 ifp->if_timer = 0; 979#ifdef EP_LOCAL_STATS 980 printf("\nep%d:\n\tStatus: %x\n", sc->unit, status); 981 GO_WINDOW(4); 982 printf("\tFIFO Diagnostic: %x\n", inw(BASE + EP_W4_FIFO_DIAG)); 983 printf("\tStat: %x\n", sc->stat); 984 printf("\tIpackets=%d, Opackets=%d\n", 985 ifp->if_ipackets, ifp->if_opackets); 986 printf("\tNOF=%d, NOMB=%d, BPFD=%d, RXOF=%d, RXOL=%d, TXU=%d\n", 987 sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf, 988 sc->rx_overrunl, sc->tx_underrun); 989#else 990 991#ifdef DIAGNOSTIC 992 printf("ep%d: Status: %x (input buffer overflow)\n", sc->unit, status); 993#else 994 ++ifp->if_ierrors; 995#endif 996 997#endif 998 epinit(sc); 999 splx(x); 1000 return; 1001 } 1002 if (status & S_TX_COMPLETE) { 1003 ifp->if_timer = 0; 1004 /* we need ACK. we do it at the end */ 1005 /* 1006 * We need to read TX_STATUS until we get a 0 status in order to 1007 * turn off the interrupt flag. 1008 */ 1009 while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) { 1010 if (status & TXS_SUCCES_INTR_REQ); 1011 else if (status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION)) { 1012 outw(BASE + EP_COMMAND, TX_RESET); 1013 if (status & TXS_UNDERRUN) { 1014#ifdef EP_LOCAL_STATS 1015 sc->tx_underrun++; 1016#endif 1017 } else { 1018 if (status & TXS_JABBER); 1019 else /* TXS_MAX_COLLISION - we shouldn't get here */ 1020 ++ifp->if_collisions; 1021 } 1022 ++ifp->if_oerrors; 1023 outw(BASE + EP_COMMAND, TX_ENABLE); 1024 /* 1025 * To have a tx_avail_int but giving the chance to the 1026 * Reception 1027 */ 1028 if (ifp->if_snd.ifq_head) { 1029 outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8); 1030 } 1031 } 1032 outb(BASE + EP_W1_TX_STATUS, 0x0); /* pops up the next 1033 * status */ 1034 } /* while */ 1035 ifp->if_flags &= ~IFF_OACTIVE; 1036 GO_WINDOW(1); 1037 inw(BASE + EP_W1_FREE_TX); 1038 epstart(ifp); 1039 } /* end TX_COMPLETE */ 1040 } 1041 1042 outw(BASE + EP_COMMAND, C_INTR_LATCH); /* ACK int Latch */ 1043 1044 if ((status = inw(BASE + EP_STATUS)) & S_5_INTS) 1045 goto rescan; 1046 1047 /* re-enable Ints */ 1048 outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); 1049 1050 splx(x); 1051} 1052 1053static void 1054epread(sc) 1055 register struct ep_softc *sc; 1056{ 1057 struct ether_header *eh; 1058 struct mbuf *top, *mcur, *m; 1059 struct ifnet *ifp; 1060 int lenthisone; 1061 1062 short rx_fifo2, status; 1063 register short delta; 1064 register short rx_fifo; 1065 1066 ifp = &sc->arpcom.ac_if; 1067 status = inw(BASE + EP_W1_RX_STATUS); 1068 1069read_again: 1070 1071 if (status & ERR_RX) { 1072 ++ifp->if_ierrors; 1073 if (status & ERR_RX_OVERRUN) { 1074 /* 1075 * we can think the rx latency is actually greather than we 1076 * expect 1077 */ 1078#ifdef EP_LOCAL_STATS 1079 if (ep_ftst(F_RX_FIRST)) 1080 sc->rx_overrunf++; 1081 else 1082 sc->rx_overrunl++; 1083#endif 1084 } 1085 goto out; 1086 } 1087 rx_fifo = rx_fifo2 = status & RX_BYTES_MASK; 1088 1089 if (ep_ftst(F_RX_FIRST)) { 1090 MGETHDR(m, M_DONTWAIT, MT_DATA); 1091 if (!m) 1092 goto out; 1093 if (rx_fifo >= MINCLSIZE) 1094 MCLGET(m, M_DONTWAIT); 1095 sc->top = sc->mcur = top = m; 1096#define EROUND ((sizeof(struct ether_header) + 3) & ~3) 1097#define EOFF (EROUND - sizeof(struct ether_header)) 1098 top->m_data += EOFF; 1099 1100 /* Read what should be the header. */ 1101 insw(BASE + EP_W1_RX_PIO_RD_1, 1102 mtod(top, caddr_t), sizeof(struct ether_header) / 2); 1103 top->m_len = sizeof(struct ether_header); 1104 rx_fifo -= sizeof(struct ether_header); 1105 sc->cur_len = rx_fifo2; 1106 } else { 1107 /* come here if we didn't have a complete packet last time */ 1108 top = sc->top; 1109 m = sc->mcur; 1110 sc->cur_len += rx_fifo2; 1111 } 1112 1113 /* Reads what is left in the RX FIFO */ 1114 while (rx_fifo > 0) { 1115 lenthisone = min(rx_fifo, M_TRAILINGSPACE(m)); 1116 if (lenthisone == 0) { /* no room in this one */ 1117 mcur = m; 1118 MGET(m, M_DONTWAIT, MT_DATA); 1119 if (!m) 1120 goto out; 1121 if (rx_fifo >= MINCLSIZE) 1122 MCLGET(m, M_DONTWAIT); 1123 m->m_len = 0; 1124 mcur->m_next = m; 1125 lenthisone = min(rx_fifo, M_TRAILINGSPACE(m)); 1126 } 1127 if (ep_ftst(F_ACCESS_32_BITS)) { /* default for EISA configured cards*/ 1128 insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, 1129 lenthisone / 4); 1130 m->m_len += (lenthisone & ~3); 1131 if (lenthisone & 3) 1132 insb(BASE + EP_W1_RX_PIO_RD_1, 1133 mtod(m, caddr_t) + m->m_len, 1134 lenthisone & 3); 1135 m->m_len += (lenthisone & 3); 1136 } else { 1137 insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, 1138 lenthisone / 2); 1139 m->m_len += lenthisone; 1140 if (lenthisone & 1) 1141 *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1); 1142 } 1143 rx_fifo -= lenthisone; 1144 } 1145 1146 if (status & ERR_RX_INCOMPLETE) { /* we haven't received the complete 1147 * packet */ 1148 sc->mcur = m; 1149#ifdef EP_LOCAL_STATS 1150 sc->rx_no_first++; /* to know how often we come here */ 1151#endif 1152 ep_frst(F_RX_FIRST); 1153 if (!((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE)) { 1154 /* we see if by now, the packet has completly arrived */ 1155 goto read_again; 1156 } 1157 outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_NEXT_EARLY_THRESH); 1158 return; 1159 } 1160all_pkt: 1161 outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); 1162 ++ifp->if_ipackets; 1163 ep_fset(F_RX_FIRST); 1164 top->m_pkthdr.rcvif = &sc->arpcom.ac_if; 1165 top->m_pkthdr.len = sc->cur_len; 1166 1167#if NBPFILTER > 0 1168 if (ifp->if_bpf) { 1169 bpf_mtap(ifp, top); 1170 1171 /* 1172 * Note that the interface cannot be in promiscuous mode if there are 1173 * no BPF listeners. And if we are in promiscuous mode, we have to 1174 * check if this packet is really ours. 1175 */ 1176 eh = mtod(top, struct ether_header *); 1177 if ((ifp->if_flags & IFF_PROMISC) && 1178 (eh->ether_dhost[0] & 1) == 0 && 1179 bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 1180 sizeof(eh->ether_dhost)) != 0 && 1181 bcmp(eh->ether_dhost, etherbroadcastaddr, 1182 sizeof(eh->ether_dhost)) != 0) { 1183 if (sc->top) { 1184 m_freem(sc->top); 1185 sc->top = 0; 1186 } 1187 ep_fset(F_RX_FIRST); 1188#ifdef EP_LOCAL_STATS 1189 sc->rx_bpf_disc++; 1190#endif 1191 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 1192 outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); 1193 return; 1194 } 1195 } 1196#endif 1197 1198 eh = mtod(top, struct ether_header *); 1199 m_adj(top, sizeof(struct ether_header)); 1200 ether_input(ifp, eh, top); 1201 sc->top = 0; 1202 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 1203 outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); 1204 return; 1205 1206out: 1207 outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); 1208 if (sc->top) { 1209 m_freem(sc->top); 1210 sc->top = 0; 1211#ifdef EP_LOCAL_STATS 1212 sc->rx_no_mbuf++; 1213#endif 1214 } 1215 ep_fset(F_RX_FIRST); 1216 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 1217 outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); 1218} 1219 1220/* 1221 * Look familiar? 1222 */ 1223static int 1224epioctl(ifp, cmd, data) 1225 register struct ifnet *ifp; 1226 int cmd; 1227 caddr_t data; 1228{ 1229 register struct ifaddr *ifa = (struct ifaddr *) data; 1230 struct ep_softc *sc = ifp->if_softc; 1231 struct ifreq *ifr = (struct ifreq *) data; 1232 int s, error = 0; 1233 1234 s = splimp(); 1235 1236 switch (cmd) { 1237 case SIOCSIFADDR: 1238 ifp->if_flags |= IFF_UP; 1239 1240 /* netifs are BUSY when UP */ 1241 1242 switch (ifa->ifa_addr->sa_family) { 1243#ifdef INET 1244 case AF_INET: 1245 epinit(sc); /* before arpwhohas */ 1246 arp_ifinit((struct arpcom *)ifp, ifa); 1247 break; 1248#endif 1249#ifdef IPX 1250 case AF_IPX: 1251 { 1252 register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 1253 1254 if (ipx_nullhost(*ina)) 1255 ina->x_host = 1256 *(union ipx_host *) (sc->arpcom.ac_enaddr); 1257 else { 1258 ifp->if_flags &= ~IFF_RUNNING; 1259 bcopy((caddr_t) ina->x_host.c_host, 1260 (caddr_t) sc->arpcom.ac_enaddr, 1261 sizeof(sc->arpcom.ac_enaddr)); 1262 } 1263 epinit(sc); 1264 break; 1265 } 1266#endif 1267#ifdef NS 1268 case AF_NS: 1269 { 1270 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 1271 1272 if (ns_nullhost(*ina)) 1273 ina->x_host = 1274 *(union ns_host *) (sc->arpcom.ac_enaddr); 1275 else { 1276 ifp->if_flags &= ~IFF_RUNNING; 1277 bcopy((caddr_t) ina->x_host.c_host, 1278 (caddr_t) sc->arpcom.ac_enaddr, 1279 sizeof(sc->arpcom.ac_enaddr)); 1280 } 1281 epinit(sc); 1282 break; 1283 } 1284#endif 1285 default: 1286 epinit(sc); 1287 break; 1288 } 1289 break; 1290 case SIOCGIFADDR: 1291 { 1292 struct sockaddr *sa; 1293 1294 sa = (struct sockaddr *) & ifr->ifr_data; 1295 bcopy((caddr_t) sc->arpcom.ac_enaddr, 1296 (caddr_t) sa->sa_data, ETHER_ADDR_LEN); 1297 } 1298 break; 1299 case SIOCSIFFLAGS: 1300 1301 if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { 1302 ifp->if_flags &= ~IFF_RUNNING; 1303 epstop(sc); 1304 break; 1305 } else { 1306 /* reinitialize card on any parameter change */ 1307 epinit(sc); 1308 break; 1309 } 1310 1311 /* NOTREACHED */ 1312 break; 1313#ifdef notdef 1314 case SIOCGHWADDR: 1315 bcopy((caddr_t) sc->sc_addr, (caddr_t) & ifr->ifr_data, 1316 sizeof(sc->sc_addr)); 1317 break; 1318#endif 1319 case SIOCSIFMTU: 1320 1321 /* 1322 * Set the interface MTU. 1323 */ 1324 if (ifr->ifr_mtu > ETHERMTU) { 1325 error = EINVAL; 1326 } else { 1327 ifp->if_mtu = ifr->ifr_mtu; 1328 } 1329 break; 1330 case SIOCADDMULTI: 1331 case SIOCDELMULTI: 1332 /* Now this driver has no support for programmable 1333 * multicast filters. If some day it will gain this 1334 * support this part of code must be extended. 1335 */ 1336 error = 0; 1337 break; 1338 default: 1339 error = EINVAL; 1340 } 1341 1342 splx(s); 1343 1344 return (error); 1345} 1346 1347static void 1348epwatchdog(ifp) 1349 struct ifnet *ifp; 1350{ 1351 struct ep_softc *sc = ifp->if_softc; 1352 1353 /* 1354 printf("ep: watchdog\n"); 1355 1356 log(LOG_ERR, "ep%d: watchdog\n", ifp->if_unit); 1357 ifp->if_oerrors++; 1358 */ 1359 1360 if (sc->gone) { 1361 return; 1362 } 1363 1364 ifp->if_flags &= ~IFF_OACTIVE; 1365 epstart(ifp); 1366 ep_intr(ifp->if_softc); 1367} 1368 1369static void 1370epstop(sc) 1371 struct ep_softc *sc; 1372{ 1373 if (sc->gone) { 1374 return; 1375 } 1376 1377 outw(BASE + EP_COMMAND, RX_DISABLE); 1378 outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); 1379 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 1380 outw(BASE + EP_COMMAND, TX_DISABLE); 1381 outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); 1382 outw(BASE + EP_COMMAND, RX_RESET); 1383 outw(BASE + EP_COMMAND, TX_RESET); 1384 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); 1385 outw(BASE + EP_COMMAND, C_INTR_LATCH); 1386 outw(BASE + EP_COMMAND, SET_RD_0_MASK); 1387 outw(BASE + EP_COMMAND, SET_INTR_MASK); 1388 outw(BASE + EP_COMMAND, SET_RX_FILTER); 1389} 1390 1391 1392#if 0 1393static int 1394send_ID_sequence(port) 1395 int port; 1396{ 1397 int cx, al; 1398 1399 for (al = 0xff, cx = 0; cx < 255; cx++) { 1400 outb(port, al); 1401 al <<= 1; 1402 if (al & 0x100) 1403 al ^= 0xcf; 1404 } 1405 return (1); 1406} 1407#endif 1408 1409 1410/* 1411 * We get eeprom data from the id_port given an offset into the eeprom. 1412 * Basically; after the ID_sequence is sent to all of the cards; they enter 1413 * the ID_CMD state where they will accept command requests. 0x80-0xbf loads 1414 * the eeprom data. We then read the port 16 times and with every read; the 1415 * cards check for contention (ie: if one card writes a 0 bit and another 1416 * writes a 1 bit then the host sees a 0. At the end of the cycle; each card 1417 * compares the data on the bus; if there is a difference then that card goes 1418 * into ID_WAIT state again). In the meantime; one bit of data is returned in 1419 * the AX register which is conveniently returned to us by inb(). Hence; we 1420 * read 16 times getting one bit of data with each read. 1421 */ 1422static int 1423get_eeprom_data(id_port, offset) 1424 int id_port; 1425 int offset; 1426{ 1427 int i, data = 0; 1428 outb(id_port, 0x80 + offset); 1429 DELAY(1000); 1430 for (i = 0; i < 16; i++) 1431 data = (data << 1) | (inw(id_port) & 1); 1432 return (data); 1433} 1434 1435#endif /* NEP > 0 */ 1436