if_ep.c revision 963
1/* 2 * Copyright (c) 1993 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. The name of the author may not be used to endorse or promote products 11 * derived from this software withough specific prior written permission 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * $Id: if_ep.c,v 1.5 1993/12/20 09:05:55 mycroft Exp $ 25 */ 26/* 27 * TODO: 28 * Multi-509 configs. 29 * don't pass unit into epstop. 30 * epintr returns an int for magnum. 0=not for me. 1=for me. -1=whoknows? 31 */ 32#include "ep.h" 33#if NEP > 0 34#include "bpfilter.h" 35 36#include <sys/param.h> 37#include <sys/mbuf.h> 38#include <sys/socket.h> 39#include <sys/ioctl.h> 40#include <sys/errno.h> 41#include <sys/syslog.h> 42#include <sys/select.h> 43 44#include <net/if.h> 45#include <net/netisr.h> 46#include <net/if_dl.h> 47#include <net/if_types.h> 48#include <net/netisr.h> 49 50#ifdef INET 51#include <netinet/in.h> 52#include <netinet/in_systm.h> 53#include <netinet/in_var.h> 54#include <netinet/ip.h> 55#include <netinet/if_ether.h> 56#endif 57 58#ifdef NS 59#include <netns/ns.h> 60#include <netns/ns_if.h> 61#endif 62 63#if NBPFILTER > 0 64#include <net/bpf.h> 65#include <net/bpfdesc.h> 66#endif 67 68#include <machine/pio.h> 69 70#include <i386/isa/isa.h> 71#include <i386/isa/isa_device.h> 72#include <i386/isa/icu.h> 73#include <i386/isa/if_epreg.h> 74 75#define ETHER_MIN_LEN 64 76#define ETHER_MAX_LEN 1518 77#define ETHER_ADDR_LEN 6 78/* 79 * Ethernet software status per interface. 80 */ 81struct ep_softc { 82 struct arpcom ep_ac; /* Ethernet common part */ 83#define ep_if ep_ac.ac_if /* network-visible interface */ 84#define ep_addr ep_ac.ac_enaddr /* hardware Ethernet address */ 85 short ep_io_addr; /* i/o bus address */ 86 char ep_connectors; /* Connectors on this card. */ 87#define MAX_MBS 8 /* # of mbufs we keep around */ 88 struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */ 89 int next_mb; /* Which mbuf to use next. */ 90 int last_mb; /* Last mbuf. */ 91 int tx_start_thresh; /* Current TX_start_thresh. */ 92 caddr_t bpf; /* BPF "magic cookie" */ 93} ep_softc[NEP]; 94 95 96int ether_output(), 97 epprobe(), 98 epattach(), 99 epintr(), 100 epinit(), 101 epioctl(), 102 epreset(), 103 epwatchdog(), 104 epstart(), 105 fill_mbuf_queue(); 106 107struct isa_driver epdriver = { 108 epprobe, 109 epattach, 110 "ep" 111}; 112 113extern u_short get_eeprom_data(int id_port, int offset); 114extern int is_eeprom_busy(struct isa_device *is); 115 116/* 117 * Rudimentary support for multiple cards is here but is not 118 * currently handled. In the future we will have to add code 119 * for tagging the cards for later activation. We wanna do something 120 * about the id_port. We're limited due to current config procedure. 121 * Magnum config holds promise of a fix but we'll have to wait a bit. 122 */ 123epprobe(is) 124 struct isa_device *is; 125{ 126 struct ep_softc *sc = &ep_softc[is->id_unit]; 127 u_short k; 128 char buf[8]; 129 int id_port = 0x100; /* XXX */ 130 131 outw(BASE+EP_COMMAND, GLOBAL_RESET); 132 DELAY(1000); 133 outb(id_port, 0xc0); /* Global reset to id_port. */ 134 DELAY(1000); 135 send_ID_sequence(id_port); 136 DELAY(1000); 137/* 138 * MFG_ID should have 0x6d50. 139 * PROD_ID should be 0x9[0-f]50 140 */ 141 k = get_eeprom_data(id_port, EEPROM_MFG_ID); 142 if (k != MFG_ID) 143 return(0); 144 k = get_eeprom_data(id_port, EEPROM_PROD_ID); 145 if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) 146 return(0); 147 148 k = get_eeprom_data(id_port, EEPROM_ADDR_CFG); /* get addr cfg */ 149 k = (k & 0x1f)*0x10+0x200; /* decode base addr. */ 150 if (k != is->id_iobase) 151 return(0); 152 153 k = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG); 154 k >>= 12; 155 if (is->id_irq != (1<<((k==2) ? 9 : k))) 156 return(0); 157 158 outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); 159 160 return(0x10); /* 16 bytes of I/O space used. */ 161} 162 163epattach(is) 164 struct isa_device *is; 165{ 166 struct ep_softc *sc = &ep_softc[is->id_unit]; 167 struct ifnet *ifp = &sc->ep_if; 168 u_short i; 169 struct ifaddr *ifa; 170 struct sockaddr_dl *sdl; 171 172 sc->ep_io_addr = is->id_iobase; 173 174 sc->ep_connectors = 0; 175 i=inw(is->id_iobase+EP_W0_CONFIG_CTRL); 176 177 printf("ep%d: ", is->id_unit); 178 179 if (i & IS_AUI) { 180 if (sc->ep_connectors) 181 printf("/"); 182 printf("aui"); 183 sc->ep_connectors |= AUI; 184 } 185 if (i & IS_BNC) { 186 if (sc->ep_connectors) 187 printf("/"); 188 printf("bnc"); 189 sc->ep_connectors |= BNC; 190 } 191 if (i & IS_UTP) { 192 if (sc->ep_connectors) 193 printf("/"); 194 printf("utp"); 195 sc->ep_connectors |= UTP; 196 } 197 if (!sc->ep_connectors) 198 printf("!no connectors!"); 199 200/* 201 * Read the station address from the eeprom 202 */ 203 for (i=0; i<3; i++) { 204 u_short *p; 205 GO_WINDOW(0); 206 if (is_eeprom_busy(is)) 207 return; 208 outw(BASE+EP_W0_EEPROM_COMMAND, READ_EEPROM | i); 209 if (is_eeprom_busy(is)) 210 return; 211 p =(u_short *)&sc->ep_addr[i*2]; 212 *p=htons(inw(BASE+EP_W0_EEPROM_DATA)); 213 GO_WINDOW(2); 214 outw(BASE+EP_W2_ADDR_0+(i*2), ntohs(*p)); 215 } 216 printf(" address %s\n", ether_sprintf(sc->ep_addr)); 217 218 ifp->if_unit = is->id_unit; 219 ifp->if_name = "ep" ; 220 ifp->if_mtu = ETHERMTU; 221 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; 222 ifp->if_init = epinit; 223 ifp->if_output = ether_output; 224 ifp->if_start = epstart; 225 ifp->if_ioctl = epioctl; 226 ifp->if_watchdog = epwatchdog; 227 228 if_attach(ifp); 229 230/* 231 * Fill the hardware address into ifa_addr if we find an AF_LINK entry. 232 * We need to do this so bpf's can get the hardware addr of this card. 233 * netstat likes this too! 234 */ 235 ifa = ifp->if_addrlist; 236 while ((ifa != 0) && (ifa->ifa_addr != 0) && 237 (ifa->ifa_addr->sa_family != AF_LINK)) 238 ifa = ifa->ifa_next; 239 240 if ((ifa != 0) && (ifa->ifa_addr != 0)) { 241 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 242 sdl->sdl_type = IFT_ETHER; 243 sdl->sdl_alen = ETHER_ADDR_LEN; 244 sdl->sdl_slen = 0; 245 bcopy(sc->ep_addr, LLADDR(sdl), ETHER_ADDR_LEN); 246 } 247#if NBPFILTER > 0 248 bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 249#endif 250} 251 252/* The order in here seems important. Otherwise we may not receive interrupts. ?! */ 253epinit(unit) 254 int unit; 255{ 256 register struct ep_softc *sc = &ep_softc[unit]; 257 register struct ifnet *ifp = &sc->ep_if; 258 int s,i; 259 260 s=splnet(); 261 262 if (ifp->if_addrlist == (struct ifaddr *) 0) { 263 printf("ep: address not known...\n"); 264 splx(s); 265 return; 266 } 267 268 while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS) 269 ; 270 271 GO_WINDOW(0); 272 outw(BASE+EP_W0_CONFIG_CTRL, 0); /* Disable the card */ 273 274 outw(BASE+EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); /* Enable the card */ 275 276 GO_WINDOW(2); 277 for(i=0;i<6;i++) /* Reload the ether_addr. */ 278 outb(BASE+EP_W2_ADDR_0+i, sc->ep_addr[i]); 279 280 outw(BASE+EP_COMMAND, RX_RESET); 281 outw(BASE+EP_COMMAND, TX_RESET); 282 283 GO_WINDOW(1); /* Window 1 is operating window */ 284 for(i=0;i<31;i++) 285 inb(BASE+EP_W1_TX_STATUS); 286 287 outw(BASE+EP_COMMAND, ACK_INTR | 0xff); /* get rid of stray intr's */ 288 289 outw(BASE+EP_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE | 290 S_TX_COMPLETE | S_TX_AVAIL); 291 outw(BASE+EP_COMMAND, SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE | 292 S_TX_COMPLETE | S_TX_AVAIL); 293 294 outw(BASE+EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | 295 FIL_GROUP | FIL_BRDCST); 296 297 if (!(ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & BNC)) { /* Want BNC? */ 298 outw(BASE+EP_COMMAND, START_TRANSCEIVER); 299 DELAY(1000); 300 } 301 if ((sc->ep_connectors & UTP) & !(ifp->if_flags & IFF_LINK0)) { /* Want UTP? */ 302 GO_WINDOW(4); 303 outw(BASE+EP_W4_MEDIA_TYPE, ENABLE_UTP); 304 GO_WINDOW(1); 305 } 306 307 outw(BASE+EP_COMMAND, RX_ENABLE); 308 outw(BASE+EP_COMMAND, TX_ENABLE); 309 310 ifp->if_flags |= IFF_RUNNING; 311 ifp->if_flags &= ~IFF_OACTIVE; /* just in case */ 312 sc->tx_start_thresh = 20; /* probably a good starting point. */ 313 /* 314 * Store up a bunch of mbuf's for use later. (MAX_MBS). First we 315 * free up any that we had in case we're being called from intr or 316 * somewhere else. 317 */ 318 sc->last_mb = 0; 319 sc->next_mb = 0; 320 fill_mbuf_queue(sc); 321 322 epstart(ifp); 323 324 splx(s); 325} 326 327epstart(ifp) 328 struct ifnet *ifp; 329{ 330 register struct ep_softc *sc = &ep_softc[ifp->if_unit]; 331 struct mbuf *m, *top; 332 int s, len, pad; 333 334 s=splnet(); 335 if (sc->ep_if.if_flags & IFF_OACTIVE) { 336 splx(s); 337 return; 338 } 339 340startagain: 341 m = sc->ep_if.if_snd.ifq_head; /* Sneak a peek at the next packet */ 342 if (m == 0) { 343 splx(s); 344 return; 345 } 346 pad = (4-(m->m_pkthdr.len%4)+4)%4; /* icky pooh!! */ 347 348 if ((inw(BASE+EP_W1_FREE_TX)) < (m->m_pkthdr.len)+pad+4) { /* no room in FIFO */ 349 outw(BASE+EP_COMMAND, SET_TX_AVAIL_THRESH | (m->m_pkthdr.len)+pad+4); 350 sc->ep_if.if_flags |= IFF_OACTIVE; 351 splx(s); 352 return; 353 } 354 355 IF_DEQUEUE(&sc->ep_if.if_snd, m); 356 if (m == 0) { /* Could make this go away. */ 357 splx(s); 358 return; 359 } 360 361 outw(BASE+EP_COMMAND, SET_TX_START_THRESH | 362 (m->m_pkthdr.len/4 + sc->tx_start_thresh)); 363 364 outw(BASE+EP_W1_TX_PIO_WR_1, m->m_pkthdr.len); 365 outw(BASE+EP_W1_TX_PIO_WR_1, 0xffff); /* Second dword meaningless */ 366 367 for(top = m; m != 0; m = m->m_next) { 368 outsw(BASE+EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2); 369 if(m->m_len & 1) 370 outb(BASE+EP_W1_TX_PIO_WR_1, 371 *(mtod(m, caddr_t)+m->m_len-1)); 372 } 373 374 while (pad--) 375 outb(BASE+EP_W1_TX_PIO_WR_1, 0); /* Padding */ 376#if NBPFILTER > 0 377 if (sc->bpf) { 378 u_short etype; 379 int off, datasize, resid; 380 struct ether_header *eh; 381 struct trailer_header { 382 u_short ether_type; 383 u_short ether_residual; 384 } trailer_header; 385 char ether_packet[ETHER_MAX_LEN]; 386 char *ep; 387 388 ep = ether_packet; 389 390 /* 391 * We handle trailers below: 392 * Copy ether header first, then residual data, 393 * then data. Put all this in a temporary buffer 394 * 'ether_packet' and send off to bpf. Since the 395 * system has generated this packet, we assume 396 * that all of the offsets in the packet are 397 * correct; if they're not, the system will almost 398 * certainly crash in m_copydata. 399 * We make no assumptions about how the data is 400 * arranged in the mbuf chain (i.e. how much 401 * data is in each mbuf, if mbuf clusters are 402 * used, etc.), which is why we use m_copydata 403 * to get the ether header rather than assume 404 * that this is located in the first mbuf. 405 */ 406 /* copy ether header */ 407 m_copydata(top, 0, sizeof(struct ether_header), ep); 408 eh = (struct ether_header *) ep; 409 ep += sizeof(struct ether_header); 410 etype = ntohs(eh->ether_type); 411 if (etype >= ETHERTYPE_TRAIL && 412 etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 413 datasize = ((etype - ETHERTYPE_TRAIL) << 9); 414 off = datasize + sizeof(struct ether_header); 415 416 /* copy trailer_header into a data structure */ 417 m_copydata(top, off, sizeof(struct trailer_header), 418 &trailer_header.ether_type); 419 420 /* copy residual data */ 421 resid = trailer_header.ether_residual - 422 sizeof(struct trailer_header); 423 resid = ntohs(resid); 424 m_copydata(top, off+sizeof(struct trailer_header), 425 resid, ep); 426 ep += resid; 427 428 /* copy data */ 429 m_copydata(top, sizeof(struct ether_header), 430 datasize, ep); 431 ep += datasize; 432 433 /* restore original ether packet type */ 434 eh->ether_type = trailer_header.ether_type; 435 436 bpf_tap(sc->bpf, ether_packet, ep - ether_packet); 437 } else 438 bpf_mtap(sc->bpf, top); 439 } 440#endif 441 442 m_freem(top); 443 ++sc->ep_if.if_opackets; 444 /* 445 * Is another packet coming in? We don't want to overflow the 446 * tiny RX fifo. 447 */ 448 if (inw(BASE+EP_W1_RX_STATUS) & RX_BYTES_MASK) { 449 splx(s); 450 return; 451 } 452 goto startagain; 453} 454 455epintr(unit) 456 int unit; 457{ 458 int status, i; 459 register struct ep_softc *sc = &ep_softc[unit]; 460 struct ifnet *ifp = &sc->ep_if; 461 struct mbuf *m; 462 463 status=0; 464checkintr: 465 status = inw(BASE + EP_STATUS) & (S_TX_COMPLETE|S_TX_AVAIL|S_RX_COMPLETE|S_CARD_FAILURE); 466 if (status == 0) { /* No interrupts. */ 467 outw(BASE+EP_COMMAND, C_INTR_LATCH); 468 return; 469 } 470 outw(BASE+EP_COMMAND, ACK_INTR | status); /* important that we do this first. */ 471 472 if (status & S_TX_AVAIL) { 473 status &= ~S_TX_AVAIL; 474 inw(BASE+EP_W1_FREE_TX); 475 sc->ep_if.if_flags &= ~IFF_OACTIVE; 476 epstart(&sc->ep_if); 477 } 478 if (status & S_RX_COMPLETE) { 479 status &= ~S_RX_COMPLETE; 480 epread(sc); 481 } 482 if (status & S_CARD_FAILURE) { 483 printf("ep%d: reset (status: %x)\n", unit, status); 484 outw(BASE+EP_COMMAND, C_INTR_LATCH); 485 epinit(unit); 486 return; 487 } 488 if (status & S_TX_COMPLETE) { 489 status &= ~S_TX_COMPLETE; 490 /* 491 * We need to read TX_STATUS until we get a 0 status in 492 * order to turn off the interrupt flag. 493 */ 494 while ((i=inb(BASE+EP_W1_TX_STATUS)) & TXS_COMPLETE) { 495 outw(BASE+EP_W1_TX_STATUS, 0x0); 496 if (i & (TXS_MAX_COLLISION|TXS_JABBER|TXS_UNDERRUN)) { 497 if (i & TXS_MAX_COLLISION) 498 ++sc->ep_if.if_collisions; 499 if (i & (TXS_JABBER|TXS_UNDERRUN)) { 500 outw(BASE+EP_COMMAND, TX_RESET); 501 if(i & TXS_UNDERRUN) { 502 if (sc->tx_start_thresh < ETHER_MAX_LEN) { 503 sc->tx_start_thresh += 20; 504 outw(BASE+EP_COMMAND, 505 SET_TX_START_THRESH | 506 sc->tx_start_thresh); 507 } 508 } 509 } 510 outw(BASE+EP_COMMAND, TX_ENABLE); 511 ++sc->ep_if.if_oerrors; 512 } 513 } 514 epstart(ifp); 515 } 516 goto checkintr; 517} 518 519epread(sc) 520 register struct ep_softc *sc; 521{ 522 struct ether_header *eh; 523 struct mbuf *mcur, *m, *m0, *top; 524 int totlen, lenthisone; 525 int save_totlen; 526 u_short etype; 527 int off, resid; 528 int count, spinwait; 529 int i; 530 531 totlen = inw(BASE + EP_W1_RX_STATUS); 532 off = 0; 533 top = 0; 534 535 if (totlen & ERR_RX) { 536 ++sc->ep_if.if_ierrors; 537 goto out; 538 } 539 save_totlen = totlen &= RX_BYTES_MASK; /* Lower 10 bits = RX bytes. */ 540 541 m = sc->mb[sc->next_mb]; 542 sc->mb[sc->next_mb] = 0; 543 544 if (m == 0) { 545 MGETHDR(m, M_DONTWAIT, MT_DATA); 546 if (m == 0) 547 goto out; 548 } else { /* Convert one of our saved mbuf's */ 549 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 550 m->m_data = m->m_pktdat; 551 m->m_flags = M_PKTHDR; 552 } 553 554 top = m0 = m; /* We assign top so we can "goto out" */ 555# define EROUND ((sizeof(struct ether_header) + 3) & ~3) 556# define EOFF (EROUND - sizeof(struct ether_header)) 557 m0->m_data += EOFF; 558 /* Read what should be the header. */ 559 insw(BASE+EP_W1_RX_PIO_RD_1, mtod(m0, caddr_t), sizeof(struct ether_header)/2); 560 m->m_len = sizeof(struct ether_header); 561 totlen -= sizeof(struct ether_header); 562 /* 563 * mostly deal with trailer here. (untested) 564 * We do this in a couple of parts. First we check for a trailer, if 565 * we have one we convert the mbuf back to a regular mbuf and set the offset and 566 * subtract sizeof(struct ether_header) from the pktlen. 567 * After we've read the packet off the interface (all except for the trailer 568 * header, we then get a header mbuf, read the trailer into it, and fix up 569 * the mbuf pointer chain. 570 */ 571 eh=mtod(m, struct ether_header *); 572 eh->ether_type = ntohs((u_short)eh->ether_type); 573 if (eh->ether_type >= ETHERTYPE_TRAIL && 574 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 575 m->m_data = m->m_dat; /* Convert back to regular mbuf. */ 576 m->m_flags = 0; /* This sucks but non-trailers are the norm */ 577 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 578 if (off >= ETHERMTU) { 579 m_freem(m); 580 return; /* sanity */ 581 } 582 totlen -= sizeof(struct ether_header); /* We don't read the trailer */ 583 m->m_data += 2 * sizeof(u_short); /* Get rid of type & len*/ 584 } 585 while (totlen>0) { 586 lenthisone=min(totlen, M_TRAILINGSPACE(m)); 587 if (lenthisone == 0) { /* no room in this one */ 588 mcur = m; 589 m = sc->mb[sc->next_mb]; 590 sc->mb[sc->next_mb] = 0; 591 if (!m) { 592 MGET(m, M_DONTWAIT, MT_DATA); 593 if (m==0) 594 goto out; 595 } else { 596 timeout(fill_mbuf_queue, sc, 1); 597 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 598 } 599 if (totlen >= MINCLSIZE) 600 MCLGET(m, M_DONTWAIT); 601 m->m_len = 0; 602 mcur->m_next = m; 603 lenthisone = min(totlen, M_TRAILINGSPACE(m)); 604 } 605 insw(BASE+EP_W1_RX_PIO_RD_1, mtod(m, caddr_t)+m->m_len, lenthisone/2); 606 m->m_len += lenthisone; 607 if (lenthisone & 1) 608 *(mtod(m, caddr_t)+m->m_len-1) = inb(BASE+EP_W1_RX_PIO_RD_1); 609 totlen -= lenthisone; 610 } 611 if (off) { 612 top = sc->mb[sc->next_mb]; 613 sc->mb[sc->next_mb] = 0; 614 if (top == 0) { 615 MGETHDR(m, M_DONTWAIT, MT_DATA); 616 if (top == 0) 617 goto out; 618 } else { /* Convert one of our saved mbuf's */ 619 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 620 top->m_data = top->m_pktdat; 621 top->m_flags = M_PKTHDR; 622 } 623 insw(BASE+EP_W1_RX_PIO_RD_1, mtod(m, caddr_t)+m->m_len, 624 sizeof(struct ether_header)); 625 eh->ether_type = ntohs(eh->ether_type); 626 top->m_next = m0; 627 top->m_len = sizeof(struct ether_header); 628 /* XXX Accomodate for type and len from beginning of trailer data */ 629 top->m_pkthdr.len = save_totlen - (2 * sizeof(u_short)); 630 } else { 631 top = m0; 632 top->m_pkthdr.len = save_totlen; 633 } 634 635 top->m_pkthdr.rcvif = &sc->ep_if; 636 outw(BASE+EP_COMMAND, RX_DISCARD_TOP_PACK); 637 while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS) 638 ; 639 ++sc->ep_if.if_ipackets; 640 m_adj(top, sizeof(struct ether_header)); 641 ether_input(&sc->ep_if, eh, top); 642 return; 643 644out: outw(BASE+EP_COMMAND, RX_DISCARD_TOP_PACK); 645 while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS) 646 ; 647 if (top) 648 m_freem(top); 649} 650 651/* 652 * Look familiar? 653 */ 654epioctl(ifp, cmd, data) 655 register struct ifnet *ifp; 656 int cmd; 657 caddr_t data; 658{ 659 register struct ifaddr *ifa = (struct ifaddr *)data; 660 struct ep_softc *sc = &ep_softc[ifp->if_unit]; 661 struct ifreq *ifr = (struct ifreq *)data; 662 int s, error=0; 663 664 switch(cmd){ 665 case SIOCSIFADDR: 666 ifp->if_flags |= IFF_UP; 667 switch (ifa->ifa_addr->sa_family) { 668#ifdef INET 669 case AF_INET: 670 epinit(ifp->if_unit); /* before arpwhohas */ 671 ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; 672 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 673 break; 674#endif 675#ifdef NS 676 case AF_NS: 677 { 678 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 679 680 if (ns_nullhost(*ina)) 681 ina->x_host = *(union ns_host *)(sc->ep_ac.ac_enaddr); 682 else { 683 ifp->if_flags &= ~IFF_RUNNING; 684 bcopy((caddr_t)ina->x_host.c_host, 685 (caddr_t)sc->ns_addr, 686 sizeof(sc->ep_ac.ac_enaddr)); 687 } 688 epinit(ifp->if_unit); 689 break; 690 } 691#endif 692 default: 693 epinit(ifp->if_unit); 694 break; 695 } 696 break; 697 case SIOCSIFFLAGS: 698 if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { 699 ifp->if_flags &= ~IFF_RUNNING; 700 epstop(ifp->if_unit); 701 } else if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) 702 epinit(ifp->if_unit); 703 break; 704 705#ifdef notdef 706 case SIOCGHWADDR: 707 bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data, sizeof(sc->sc_addr)); 708 break; 709#endif 710 711 default: 712 error = EINVAL; 713 } 714 return (error); 715} 716 717epreset(unit) 718 int unit; 719{ 720 int s; 721 722 epstop(unit); 723 epinit(unit); 724 return; 725} 726 727epwatchdog(unit) 728 int unit; 729{ 730 return; 731} 732 733epstop(unit) 734 int unit; 735{ 736 register struct ep_softc *sc = &ep_softc[unit]; 737 738 outw(BASE+EP_COMMAND, RX_DISABLE); 739 outw(BASE+EP_COMMAND, RX_DISCARD_TOP_PACK); 740 while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS) 741 ; 742 outw(BASE+EP_COMMAND, TX_DISABLE); 743 outw(BASE+EP_COMMAND, STOP_TRANSCEIVER); 744 outw(BASE+EP_COMMAND, RX_RESET); 745 outw(BASE+EP_COMMAND, TX_RESET); 746 outw(BASE+EP_COMMAND, C_INTR_LATCH); 747 outw(BASE+EP_COMMAND, SET_RD_0_MASK); 748 outw(BASE+EP_COMMAND, SET_INTR_MASK); 749 outw(BASE+EP_COMMAND, SET_RX_FILTER); 750 return; 751} 752 753/* 754 * This is adapted straight from the book. There's probably a better way. 755 */ 756send_ID_sequence(port) 757 u_short port; 758{ 759 char cx, al; 760 761 cx=0x0ff; 762 al=0x0ff; 763 764 outb(port, 0x0); 765 DELAY(1000); 766 outb(port, 0x0); 767 DELAY(1000); 768 769loop1: cx--; 770 outb(port, al); 771 if (!(al & 0x80)) { 772 al=al<<1; 773 goto loop1; 774 } 775 al=al<<1; 776 al^=0xcf; 777 if (cx) 778 goto loop1; 779 780} 781 782/* 783 * We get eeprom data from the id_port given an offset into the 784 * eeprom. Basically; after the ID_sequence is sent to all of 785 * the cards; they enter the ID_CMD state where they will accept 786 * command requests. 0x80-0xbf loads the eeprom data. We then 787 * read the port 16 times and with every read; the cards check 788 * for contention (ie: if one card writes a 0 bit and another 789 * writes a 1 bit then the host sees a 0. At the end of the cycle; 790 * each card compares the data on the bus; if there is a difference 791 * then that card goes into ID_WAIT state again). In the meantime; 792 * one bit of data is returned in the AX register which is conveniently 793 * returned to us by inb(). Hence; we read 16 times getting one 794 * bit of data with each read. 795 */ 796u_short get_eeprom_data(id_port, offset) 797 int id_port; 798 int offset; 799{ 800 int i, data=0; 801 outb(id_port, 0x80+offset); 802 DELAY(1000); 803 for (i=0; i<16; i++) 804 data = (data<<1) | (inw(id_port) & 1); 805 return(data); 806} 807 808int 809is_eeprom_busy(is) 810 struct isa_device *is; 811{ 812 int i=0, j; 813 register struct ep_softc *sc = &ep_softc[is->id_unit]; 814 815 while (i++<100) { 816 j=inw(BASE+EP_W0_EEPROM_COMMAND); 817 if (j & EEPROM_BUSY) 818 DELAY(100); 819 else 820 break; 821 } 822 if (i>=100) { 823 printf("\nep%d: eeprom failed to come ready.\n", is->id_unit); 824 return(1); 825 } 826 if (j & EEPROM_TST_MODE) { 827 printf("\nep%d: 3c509 in test mode. Erase pencil mark!\n", is->id_unit); 828 return(1); 829 } 830 return(0); 831} 832 833int 834fill_mbuf_queue(sc) 835 struct ep_softc *sc; 836{ 837 int i=0; 838 if (sc->mb[sc->last_mb]) 839 return; 840 i=sc->last_mb; 841 do { 842 MGET(sc->mb[i], M_DONTWAIT, MT_DATA); 843 if (!sc->mb[i]) 844 break; 845 i = (i+1) % MAX_MBS; 846 } while(i != sc->next_mb); 847 sc->last_mb = i; 848} 849#endif /* NEP > 0 */ 850