if_ep.c revision 1264
1234370Sjasone/* 2234370Sjasone * Copyright (c) 1993 Herb Peyerl <hpeyerl@novatel.ca> 3234370Sjasone * All rights reserved. 4234370Sjasone * 5234370Sjasone * Redistribution and use in source and binary forms, with or without 6234370Sjasone * modification, are permitted provided that the following conditions 7234370Sjasone * are met: 8234370Sjasone * 1. Redistributions of source code must retain the above copyright 9234370Sjasone * notice, this list of conditions and the following disclaimer. 10234370Sjasone * 2. The name of the author may not be used to endorse or promote products 11234658Sdim * derived from this software withough specific prior written permission 12234658Sdim * 13234370Sjasone * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14234370Sjasone * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15234370Sjasone * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16235238Sjasone * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17234370Sjasone * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18234370Sjasone * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19234370Sjasone * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20234370Sjasone * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21234370Sjasone * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22234370Sjasone * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23234370Sjasone * 24234370Sjasone * From: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp $ 25234370Sjasone * $Id: if_ep.c,v 1.7 1994/02/03 11:51:06 davidg Exp $ 26234370Sjasone */ 27234370Sjasone/* 28234370Sjasone * TODO: 29234370Sjasone * Multi-509 configs. 30234370Sjasone * don't pass unit into epstop. 31234370Sjasone * epintr returns an int for magnum. 0=not for me. 1=for me. -1=whoknows? 32234370Sjasone * deallocate mbufs when ifconfig'd down. 33234370Sjasone */ 34234370Sjasone#include "ep.h" 35234370Sjasone#if NEP > 0 36234370Sjasone 37234370Sjasone#include "bpfilter.h" 38234370Sjasone 39234370Sjasone#include "sys/param.h" 40242844Sjasone#if defined(__FreeBSD__) 41242844Sjasone#include "sys/systm.h" 42234370Sjasone#include "sys/kernel.h" 43234370Sjasone#endif 44234370Sjasone#include "sys/mbuf.h" 45234370Sjasone#include "sys/socket.h" 46234370Sjasone#include "sys/ioctl.h" 47234370Sjasone#include "sys/errno.h" 48234370Sjasone#include "sys/syslog.h" 49234370Sjasone#if defined(__NetBSD__) 50234370Sjasone#include "sys/select.h" 51234370Sjasone#endif 52234370Sjasone 53234370Sjasone#include "net/if.h" 54234370Sjasone#include "net/if_dl.h" 55234370Sjasone#include "net/if_types.h" 56234370Sjasone 57234370Sjasone#ifdef INET 58234370Sjasone#include "netinet/in.h" 59234370Sjasone#include "netinet/in_systm.h" 60235238Sjasone#include "netinet/in_var.h" 61235238Sjasone#include "netinet/ip.h" 62235238Sjasone#include "netinet/if_ether.h" 63235238Sjasone#endif 64235238Sjasone 65235238Sjasone#ifdef NS 66235238Sjasone#include "netns/ns.h" 67235238Sjasone#include "netns/ns_if.h" 68235238Sjasone#endif 69235238Sjasone 70235238Sjasone#if NBPFILTER > 0 71235238Sjasone#include "net/bpf.h" 72235238Sjasone#include "net/bpfdesc.h" 73235238Sjasone#endif 74235238Sjasone 75235238Sjasone#include "machine/pio.h" 76235238Sjasone 77235238Sjasone#include "i386/isa/isa.h" 78234370Sjasone#include "i386/isa/isa_device.h" 79235238Sjasone#include "i386/isa/icu.h" 80234370Sjasone#include "i386/isa/if_epreg.h" 81234370Sjasone 82234370Sjasone#define ETHER_MIN_LEN 64 83234370Sjasone#define ETHER_MAX_LEN 1518 84234370Sjasone#define ETHER_ADDR_LEN 6 85234370Sjasone 86234370Sjasone/* 87234370Sjasone * Ethernet software status per interface. 88234370Sjasone */ 89234370Sjasonestruct ep_softc { 90234370Sjasone struct arpcom arpcom; /* Ethernet common part */ 91234370Sjasone short ep_io_addr; /* i/o bus address */ 92234370Sjasone char ep_connectors; /* Connectors on this card. */ 93234370Sjasone#define MAX_MBS 4 /* # of mbufs we keep around */ 94234370Sjasone struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */ 95234370Sjasone int next_mb; /* Which mbuf to use next. */ 96234370Sjasone int last_mb; /* Last mbuf. */ 97234370Sjasone int tx_start_thresh; /* Current TX_start_thresh. */ 98234370Sjasone caddr_t bpf; /* BPF "magic cookie" */ 99234370Sjasone} ep_softc[NEP]; 100234370Sjasone 101234370Sjasonestatic int epprobe __P((struct isa_device *)); 102234370Sjasonestatic int epattach __P((struct isa_device *)); 103234370Sjasonestatic int epioctl __P((struct ifnet * ifp, int, caddr_t)); 104234370Sjasone 105234370Sjasonevoid epinit __P((int)); 106234370Sjasonevoid epintr __P((int)); 107234370Sjasonevoid epmbufqueue __P((caddr_t, int)); 108234370Sjasonevoid epread __P((struct ep_softc *)); 109234370Sjasonevoid epreset __P((int)); 110234370Sjasonevoid epstart __P((struct ifnet *)); 111234370Sjasonevoid epstop __P((int)); 112234370Sjasonevoid epwatchdog __P((int)); 113234370Sjasone 114234370Sjasonestruct isa_driver epdriver = { 115234370Sjasone epprobe, 116234370Sjasone epattach, 117234370Sjasone "ep" 118234370Sjasone}; 119234370Sjasone 120234370Sjasonestatic int send_ID_sequence __P((u_short)); 121234370Sjasonestatic u_short get_eeprom_data __P((int, int)); 122234370Sjasonestatic int is_eeprom_busy __P((struct isa_device *)); 123234370Sjasone 124234370Sjasone/* 125234370Sjasone * Rudimentary support for multiple cards is here but is not 126234370Sjasone * currently handled. In the future we will have to add code 127234370Sjasone * for tagging the cards for later activation. We wanna do something 128234370Sjasone * about the id_port. We're limited due to current config procedure. 129234370Sjasone * Magnum config holds promise of a fix but we'll have to wait a bit. 130234370Sjasone */ 131234370Sjasoneint 132234370Sjasoneepprobe(is) 133234370Sjasone struct isa_device *is; 134234370Sjasone{ 135234370Sjasone struct ep_softc *sc = &ep_softc[is->id_unit]; 136234370Sjasone u_short k; 137234370Sjasone int id_port = 0x100; /* XXX */ 138234370Sjasone 139234370Sjasone outw(BASE + EP_COMMAND, GLOBAL_RESET); 140234370Sjasone DELAY(1000); 141234370Sjasone outb(id_port, 0xc0); /* Global reset to id_port. */ 142234370Sjasone DELAY(1000); 143234370Sjasone send_ID_sequence(id_port); 144234370Sjasone DELAY(1000); 145234370Sjasone 146234370Sjasone /* 147234370Sjasone * MFG_ID should have 0x6d50. 148234370Sjasone * PROD_ID should be 0x9[0-f]50 149234370Sjasone */ 150234370Sjasone k = get_eeprom_data(id_port, EEPROM_MFG_ID); 151234370Sjasone if (k != MFG_ID) 152242844Sjasone return (0); 153234370Sjasone k = get_eeprom_data(id_port, EEPROM_PROD_ID); 154234370Sjasone if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) 155234370Sjasone return (0); 156242844Sjasone 157234370Sjasone k = get_eeprom_data(id_port, EEPROM_ADDR_CFG); /* get addr cfg */ 158234370Sjasone k = (k & 0x1f) * 0x10 + 0x200; /* decode base addr. */ 159242844Sjasone if (k != (u_short)is->id_iobase) 160234370Sjasone return (0); 161234370Sjasone 162234370Sjasone k = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG); 163234370Sjasone k >>= 12; 164234370Sjasone if (is->id_irq != (1 << ((k == 2) ? 9 : k))) 165234370Sjasone return (0); 166234370Sjasone 167234370Sjasone outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); 168242844Sjasone 169234370Sjasone return (0x10); /* 16 bytes of I/O space used. */ 170234370Sjasone} 171234370Sjasone 172234370Sjasonestatic int 173234370Sjasoneepattach(is) 174234370Sjasone struct isa_device *is; 175234370Sjasone{ 176234370Sjasone struct ep_softc *sc = &ep_softc[is->id_unit]; 177234370Sjasone struct ifnet *ifp = &sc->arpcom.ac_if; 178234370Sjasone u_short i; 179234370Sjasone struct ifaddr *ifa; 180234370Sjasone struct sockaddr_dl *sdl; 181234370Sjasone 182242844Sjasone sc->ep_io_addr = is->id_iobase; 183242844Sjasone 184234370Sjasone printf("ep%d: ", is->id_unit); 185234370Sjasone 186234370Sjasone sc->ep_connectors = 0; 187234370Sjasone i = inw(is->id_iobase + EP_W0_CONFIG_CTRL); 188234370Sjasone if (i & IS_AUI) { 189234370Sjasone printf("aui"); 190234370Sjasone sc->ep_connectors |= AUI; 191234370Sjasone } 192234370Sjasone if (i & IS_BNC) { 193234370Sjasone if (sc->ep_connectors) 194234370Sjasone printf("/"); 195234370Sjasone printf("bnc"); 196234370Sjasone sc->ep_connectors |= BNC; 197234370Sjasone } 198234370Sjasone if (i & IS_UTP) { 199234370Sjasone if (sc->ep_connectors) 200234370Sjasone printf("/"); 201234370Sjasone printf("utp"); 202234370Sjasone sc->ep_connectors |= UTP; 203234370Sjasone } 204234370Sjasone if (!sc->ep_connectors) 205234370Sjasone printf("no connectors!"); 206234370Sjasone 207234370Sjasone /* 208234370Sjasone * Read the station address from the eeprom 209234370Sjasone */ 210234370Sjasone for (i = 0; i < 3; i++) { 211234370Sjasone u_short *p; 212242844Sjasone GO_WINDOW(0); 213234370Sjasone if (is_eeprom_busy(is)) 214234370Sjasone return(0); 215234370Sjasone outw(BASE + EP_W0_EEPROM_COMMAND, READ_EEPROM | i); 216234370Sjasone if (is_eeprom_busy(is)) 217234370Sjasone return(0); 218234370Sjasone p =(u_short *)&sc->arpcom.ac_enaddr[i*2]; 219234370Sjasone *p = htons(inw(BASE + EP_W0_EEPROM_DATA)); 220234370Sjasone GO_WINDOW(2); 221242844Sjasone outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(*p)); 222234370Sjasone } 223234370Sjasone printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr)); 224234370Sjasone 225234370Sjasone ifp->if_unit = is->id_unit; 226234370Sjasone ifp->if_name = "ep"; 227234370Sjasone ifp->if_mtu = ETHERMTU; 228234370Sjasone ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; 229234370Sjasone ifp->if_init = epinit; 230234370Sjasone ifp->if_output = ether_output; 231234370Sjasone ifp->if_start = epstart; 232234370Sjasone ifp->if_ioctl = epioctl; 233234370Sjasone ifp->if_watchdog = epwatchdog; 234234370Sjasone 235234370Sjasone if_attach(ifp); 236234370Sjasone 237234370Sjasone /* 238234370Sjasone * Fill the hardware address into ifa_addr if we find an 239234370Sjasone * AF_LINK entry. We need to do this so bpf's can get the hardware 240234370Sjasone * addr of this card. netstat likes this too! 241234370Sjasone */ 242234370Sjasone ifa = ifp->if_addrlist; 243234370Sjasone while ((ifa != 0) && (ifa->ifa_addr != 0) && 244234370Sjasone (ifa->ifa_addr->sa_family != AF_LINK)) 245234370Sjasone ifa = ifa->ifa_next; 246234370Sjasone 247234370Sjasone if ((ifa != 0) && (ifa->ifa_addr != 0)) { 248234370Sjasone sdl = (struct sockaddr_dl *) ifa->ifa_addr; 249234370Sjasone sdl->sdl_type = IFT_ETHER; 250234370Sjasone sdl->sdl_alen = ETHER_ADDR_LEN; 251234370Sjasone sdl->sdl_slen = 0; 252234370Sjasone bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN); 253234370Sjasone } 254234370Sjasone#if NBPFILTER > 0 255234370Sjasone bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 256234370Sjasone#endif 257235238Sjasone return 1; 258235238Sjasone} 259235238Sjasone 260235238Sjasone 261235238Sjasone/* 262234370Sjasone * The order in here seems important. Otherwise we may not receive 263242844Sjasone * interrupts. ?! 264234370Sjasone */ 265234370Sjasonevoid 266234370Sjasoneepinit(unit) 267242844Sjasone int unit; 268242844Sjasone{ 269242844Sjasone register struct ep_softc *sc = &ep_softc[unit]; 270234370Sjasone register struct ifnet *ifp = &sc->arpcom.ac_if; 271234370Sjasone int s, i; 272234370Sjasone 273234370Sjasone if (ifp->if_addrlist == (struct ifaddr *) 0) 274234370Sjasone return; 275234370Sjasone 276234370Sjasone s = splimp(); 277234370Sjasone while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) 278234370Sjasone ; 279234370Sjasone 280234370Sjasone GO_WINDOW(0); 281234370Sjasone 282234370Sjasone /* Disable the card */ 283234370Sjasone outw(BASE + EP_W0_CONFIG_CTRL, 0); 284234370Sjasone 285234370Sjasone /* Enable the card */ 286234370Sjasone outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); 287234370Sjasone 288234370Sjasone GO_WINDOW(2); 289234370Sjasone 290234370Sjasone /* Reload the ether_addr. */ 291234370Sjasone for (i = 0; i < 6; i++) 292234370Sjasone outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]); 293234370Sjasone 294234370Sjasone outw(BASE + EP_COMMAND, RX_RESET); 295234370Sjasone outw(BASE + EP_COMMAND, TX_RESET); 296234370Sjasone 297234370Sjasone /* Window 1 is operating window */ 298234370Sjasone GO_WINDOW(1); 299234370Sjasone for (i = 0; i < 31; i++) 300234370Sjasone inb(BASE + EP_W1_TX_STATUS); 301234370Sjasone 302234370Sjasone /* get rid of stray intr's */ 303234370Sjasone outw(BASE + EP_COMMAND, ACK_INTR | 0xff); 304234370Sjasone 305234370Sjasone outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE | 306234370Sjasone S_TX_COMPLETE | S_TX_AVAIL); 307234370Sjasone outw(BASE + EP_COMMAND, SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE | 308234370Sjasone S_TX_COMPLETE | S_TX_AVAIL); 309234370Sjasone 310234370Sjasone outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | 311234370Sjasone FIL_GROUP | FIL_BRDCST); 312234370Sjasone 313234370Sjasone /* 314234370Sjasone * you can `ifconfig (link0|-link0) ep0' to get the following 315234370Sjasone * behaviour: 316234370Sjasone * -link0 disable AUI/UTP. enable BNC. 317234370Sjasone * link0 disable BNC. enable AUI. if the card has a UTP 318234370Sjasone * connector, that is enabled too. not sure, but it 319234370Sjasone * seems you have to be careful to not plug things 320234370Sjasone * into both AUI & UTP. 321234370Sjasone */ 322234370Sjasone#if defined(__NetBSD__) 323234370Sjasone if (!(ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & BNC)) { 324234370Sjasone#else 325234370Sjasone if (!(ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & BNC)) { 326234370Sjasone#endif 327234370Sjasone outw(BASE + EP_COMMAND, START_TRANSCEIVER); 328234370Sjasone DELAY(1000); 329234370Sjasone } 330234370Sjasone#if defined(__NetBSD__) 331234370Sjasone if ((ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & UTP)) { 332234370Sjasone#else 333234370Sjasone if ((ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & UTP)) { 334234370Sjasone#endif 335234370Sjasone GO_WINDOW(4); 336234370Sjasone outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP); 337234370Sjasone GO_WINDOW(1); 338234370Sjasone } 339234370Sjasone 340234370Sjasone outw(BASE + EP_COMMAND, RX_ENABLE); 341234370Sjasone outw(BASE + EP_COMMAND, TX_ENABLE); 342234370Sjasone 343234370Sjasone ifp->if_flags |= IFF_RUNNING; 344234370Sjasone ifp->if_flags &= ~IFF_OACTIVE; /* just in case */ 345234370Sjasone sc->tx_start_thresh = 20; /* probably a good starting point. */ 346234370Sjasone /* 347234370Sjasone * Store up a bunch of mbuf's for use later. (MAX_MBS). First we 348234370Sjasone * free up any that we had in case we're being called from intr or 349234370Sjasone * somewhere else. 350234370Sjasone */ 351234370Sjasone sc->last_mb = 0; 352234370Sjasone sc->next_mb = 0; 353234370Sjasone epmbufqueue((caddr_t)sc, 0); 354234370Sjasone 355234370Sjasone epstart(ifp); 356234370Sjasone 357234370Sjasone splx(s); 358234370Sjasone} 359234370Sjasone 360234370Sjasonestatic const char padmap[] = {0, 3, 2, 1}; 361234370Sjasone 362234370Sjasonevoid 363234370Sjasoneepstart(ifp) 364234370Sjasone struct ifnet *ifp; 365234370Sjasone{ 366234370Sjasone register struct ep_softc *sc = &ep_softc[ifp->if_unit]; 367234370Sjasone struct mbuf *m, *top; 368234370Sjasone int s, len, pad; 369234370Sjasone 370234370Sjasone s = splimp(); 371234370Sjasone if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) { 372234370Sjasone splx(s); 373234370Sjasone return; 374234370Sjasone } 375234370Sjasone 376234370Sjasonestartagain: 377234370Sjasone /* Sneak a peek at the next packet */ 378234370Sjasone m = sc->arpcom.ac_if.if_snd.ifq_head; 379234370Sjasone if (m == 0) { 380234370Sjasone splx(s); 381234370Sjasone return; 382234370Sjasone } 383234370Sjasone#if 0 384234370Sjasone len = m->m_pkthdr.len; 385234370Sjasone#else 386234370Sjasone for (len = 0, top = m; m; m = m->m_next) 387242844Sjasone len += m->m_len; 388242844Sjasone#endif 389242844Sjasone 390242844Sjasone pad = padmap[len & 3]; 391242844Sjasone 392242844Sjasone /* 393242844Sjasone * The 3c509 automatically pads short packets to minimum ethernet 394242844Sjasone * length, but we drop packets that are too large. Perhaps we should 395242844Sjasone * truncate them instead? 396242844Sjasone */ 397242844Sjasone if (len + pad > ETHER_MAX_LEN) { 398242844Sjasone /* packet is obviously too large: toss it */ 399242844Sjasone ++sc->arpcom.ac_if.if_oerrors; 400242844Sjasone IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); 401242844Sjasone m_freem(m); 402242844Sjasone goto readcheck; 403234370Sjasone } 404234370Sjasone 405234370Sjasone if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) { 406234370Sjasone /* no room in FIFO */ 407234370Sjasone outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4)); 408234370Sjasone sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; 409234370Sjasone splx(s); 410234370Sjasone return; 411234370Sjasone } 412234370Sjasone IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); 413234370Sjasone if (m == 0) { /* not really needed */ 414234370Sjasone splx(s); 415234370Sjasone return; 416234370Sjasone } 417234370Sjasone outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 418234370Sjasone (len / 4 + sc->tx_start_thresh)); 419234370Sjasone 420235238Sjasone outw(BASE + EP_W1_TX_PIO_WR_1, len); 421234370Sjasone outw(BASE + EP_W1_TX_PIO_WR_1, 0xffff); /* Second dword meaningless */ 422234370Sjasone 423235238Sjasone for (top = m; m != 0; m = m->m_next) { 424234370Sjasone outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2); 425235238Sjasone if (m->m_len & 1) 426234370Sjasone outb(BASE + EP_W1_TX_PIO_WR_1, 427235238Sjasone *(mtod(m, caddr_t) + m->m_len - 1)); 428234370Sjasone } 429234370Sjasone while (pad--) 430234370Sjasone outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */ 431234370Sjasone 432234370Sjasone#if NBPFILTER > 0 433234370Sjasone if (sc->bpf) { 434234370Sjasone u_short etype; 435234370Sjasone int off, datasize, resid; 436234370Sjasone struct ether_header *eh; 437234370Sjasone struct trailer_header { 438235238Sjasone u_short ether_type; 439235238Sjasone u_short ether_residual; 440235238Sjasone } trailer_header; 441234370Sjasone char ether_packet[ETHER_MAX_LEN]; 442234370Sjasone char *ep; 443234370Sjasone 444234370Sjasone ep = ether_packet; 445234370Sjasone 446234370Sjasone /* 447234370Sjasone * We handle trailers below: 448234370Sjasone * Copy ether header first, then residual data, 449234370Sjasone * then data. Put all this in a temporary buffer 450234370Sjasone * 'ether_packet' and send off to bpf. Since the 451234370Sjasone * system has generated this packet, we assume 452234370Sjasone * that all of the offsets in the packet are 453234370Sjasone * correct; if they're not, the system will almost 454234370Sjasone * certainly crash in m_copydata. 455234370Sjasone * We make no assumptions about how the data is 456234370Sjasone * arranged in the mbuf chain (i.e. how much 457234370Sjasone * data is in each mbuf, if mbuf clusters are 458234370Sjasone * used, etc.), which is why we use m_copydata 459234370Sjasone * to get the ether header rather than assume 460234370Sjasone * that this is located in the first mbuf. 461234370Sjasone */ 462234370Sjasone /* copy ether header */ 463234370Sjasone m_copydata(top, 0, sizeof(struct ether_header), ep); 464234370Sjasone eh = (struct ether_header *) ep; 465234370Sjasone ep += sizeof(struct ether_header); 466234370Sjasone eh->ether_type = etype = ntohs(eh->ether_type); 467234370Sjasone if (etype >= ETHERTYPE_TRAIL && 468234370Sjasone etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) { 469234370Sjasone datasize = ((etype - ETHERTYPE_TRAIL) << 9); 470234370Sjasone off = datasize + sizeof(struct ether_header); 471234370Sjasone 472234370Sjasone /* copy trailer_header into a data structure */ 473234370Sjasone m_copydata(top, off, sizeof(struct trailer_header), 474234370Sjasone (caddr_t)&trailer_header.ether_type); 475234370Sjasone 476234370Sjasone /* copy residual data */ 477234370Sjasone resid = trailer_header.ether_residual - 478234543Sjasone sizeof(struct trailer_header); 479234370Sjasone resid = ntohs(resid); 480234370Sjasone m_copydata(top, off + sizeof(struct trailer_header), 481234370Sjasone resid, ep); 482234370Sjasone ep += resid; 483234370Sjasone 484234370Sjasone /* copy data */ 485234370Sjasone m_copydata(top, sizeof(struct ether_header), 486234370Sjasone datasize, ep); 487234370Sjasone ep += datasize; 488234370Sjasone 489234370Sjasone /* restore original ether packet type */ 490234370Sjasone eh->ether_type = trailer_header.ether_type; 491234370Sjasone 492234370Sjasone bpf_tap(sc->bpf, ether_packet, ep - ether_packet); 493234370Sjasone } else 494234370Sjasone bpf_mtap(sc->bpf, top); 495234370Sjasone } 496234370Sjasone#endif 497234370Sjasone 498234370Sjasone m_freem(top); 499234370Sjasone ++sc->arpcom.ac_if.if_opackets; 500234370Sjasone 501234543Sjasone /* 502234370Sjasone * Is another packet coming in? We don't want to overflow the 503234370Sjasone * tiny RX fifo. 504234370Sjasone */ 505234370Sjasonereadcheck: 506235238Sjasone if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) { 507234370Sjasone splx(s); 508235238Sjasone return; 509234370Sjasone } 510234370Sjasone goto startagain; 511234370Sjasone} 512234370Sjasone 513234370Sjasonevoid 514234370Sjasoneepintr(unit) 515234370Sjasone int unit; 516234370Sjasone{ 517234370Sjasone int status, i; 518234370Sjasone register struct ep_softc *sc = &ep_softc[unit]; 519234370Sjasone struct ifnet *ifp = &sc->arpcom.ac_if; 520234370Sjasone struct mbuf *m; 521234370Sjasone 522234543Sjasone status = 0; 523234370Sjasonecheckintr: 524234370Sjasone status = inw(BASE + EP_STATUS) & 525234370Sjasone (S_TX_COMPLETE | S_TX_AVAIL | S_RX_COMPLETE | S_CARD_FAILURE); 526234370Sjasone if (status == 0) { 527235238Sjasone /* No interrupts. */ 528234370Sjasone outw(BASE + EP_COMMAND, C_INTR_LATCH); 529235238Sjasone return; 530234370Sjasone } 531234370Sjasone /* important that we do this first. */ 532234370Sjasone outw(BASE + EP_COMMAND, ACK_INTR | status); 533234370Sjasone 534234370Sjasone if (status & S_TX_AVAIL) { 535234370Sjasone status &= ~S_TX_AVAIL; 536234370Sjasone inw(BASE + EP_W1_FREE_TX); 537234370Sjasone sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 538234370Sjasone epstart(&sc->arpcom.ac_if); 539234370Sjasone } 540234370Sjasone if (status & S_RX_COMPLETE) { 541234370Sjasone status &= ~S_RX_COMPLETE; 542234370Sjasone epread(sc); 543234370Sjasone } 544234543Sjasone if (status & S_CARD_FAILURE) { 545234370Sjasone printf("ep%d: reset (status: %x)\n", unit, status); 546234370Sjasone outw(BASE + EP_COMMAND, C_INTR_LATCH); 547234370Sjasone epinit(unit); 548234370Sjasone return; 549234370Sjasone } 550234370Sjasone if (status & S_TX_COMPLETE) { 551234370Sjasone status &= ~S_TX_COMPLETE; 552234370Sjasone /* 553234370Sjasone * We need to read TX_STATUS until we get a 0 status in 554234543Sjasone * order to turn off the interrupt flag. 555234370Sjasone */ 556234370Sjasone while ((i = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) { 557234370Sjasone outw(BASE + EP_W1_TX_STATUS, 0x0); 558234370Sjasone if (i & (TXS_MAX_COLLISION | TXS_JABBER | TXS_UNDERRUN)) { 559234370Sjasone if (i & TXS_MAX_COLLISION) 560234370Sjasone ++sc->arpcom.ac_if.if_collisions; 561234370Sjasone if (i & (TXS_JABBER | TXS_UNDERRUN)) { 562234543Sjasone outw(BASE + EP_COMMAND, TX_RESET); 563234370Sjasone if (i & TXS_UNDERRUN) { 564242844Sjasone if (sc->tx_start_thresh < ETHER_MAX_LEN) { 565242844Sjasone sc->tx_start_thresh += 20; 566242844Sjasone outw(BASE + EP_COMMAND, 567242844Sjasone SET_TX_START_THRESH | 568242844Sjasone sc->tx_start_thresh); 569242844Sjasone } 570242844Sjasone } 571242844Sjasone } 572242844Sjasone outw(BASE + EP_COMMAND, TX_ENABLE); 573242844Sjasone ++sc->arpcom.ac_if.if_oerrors; 574242844Sjasone } 575242844Sjasone } 576242844Sjasone epstart(ifp); 577242844Sjasone } 578242844Sjasone goto checkintr; 579242844Sjasone} 580242844Sjasone 581242844Sjasonevoid 582242844Sjasoneepread(sc) 583242844Sjasone register struct ep_softc *sc; 584242844Sjasone{ 585242844Sjasone struct ether_header *eh; 586242844Sjasone struct mbuf *mcur, *m, *m0, *top; 587242844Sjasone int totlen, lenthisone; 588234543Sjasone int save_totlen; 589234543Sjasone u_short etype; 590234543Sjasone int off, resid; 591234370Sjasone int count, spinwait; 592234543Sjasone int i; 593234370Sjasone 594234543Sjasone totlen = inw(BASE + EP_W1_RX_STATUS); 595234543Sjasone off = 0; 596234370Sjasone top = 0; 597234543Sjasone 598234543Sjasone if (totlen & ERR_RX) { 599234370Sjasone ++sc->arpcom.ac_if.if_ierrors; 600234370Sjasone goto out; 601234543Sjasone } 602234370Sjasone save_totlen = totlen &= RX_BYTES_MASK; /* Lower 11 bits = RX bytes. */ 603234370Sjasone 604242844Sjasone m = sc->mb[sc->next_mb]; 605234370Sjasone sc->mb[sc->next_mb] = 0; 606234370Sjasone 607234543Sjasone if (m == 0) { 608234370Sjasone MGETHDR(m, M_DONTWAIT, MT_DATA); 609234370Sjasone if (m == 0) 610234543Sjasone goto out; 611234370Sjasone } else { 612234543Sjasone /* Convert one of our saved mbuf's */ 613234370Sjasone sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 614234370Sjasone m->m_data = m->m_pktdat; 615234370Sjasone m->m_flags = M_PKTHDR; 616234543Sjasone } 617234543Sjasone 618234543Sjasone top = m0 = m; /* We assign top so we can "goto out" */ 619234543Sjasone#define EROUND ((sizeof(struct ether_header) + 3) & ~3) 620234370Sjasone#define EOFF (EROUND - sizeof(struct ether_header)) 621234543Sjasone m0->m_data += EOFF; 622234370Sjasone /* Read what should be the header. */ 623234543Sjasone insw(BASE + EP_W1_RX_PIO_RD_1, 624234370Sjasone mtod(m0, caddr_t), sizeof(struct ether_header) / 2); 625234543Sjasone m->m_len = sizeof(struct ether_header); 626234370Sjasone totlen -= sizeof(struct ether_header); 627234543Sjasone /* 628234543Sjasone * mostly deal with trailer here. (untested) 629234543Sjasone * We do this in a couple of parts. First we check for a trailer, if 630234370Sjasone * we have one we convert the mbuf back to a regular mbuf and set the offset and 631234370Sjasone * subtract sizeof(struct ether_header) from the pktlen. 632234370Sjasone * After we've read the packet off the interface (all except for the trailer 633234370Sjasone * header, we then get a header mbuf, read the trailer into it, and fix up 634234370Sjasone * the mbuf pointer chain. 635234370Sjasone */ 636234370Sjasone eh = mtod(m, struct ether_header *); 637234370Sjasone eh->ether_type = etype = ntohs((u_short) eh->ether_type); 638234370Sjasone if (etype >= ETHERTYPE_TRAIL && 639234370Sjasone etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) { 640234370Sjasone m->m_data = m->m_dat; /* Convert back to regular mbuf. */ 641234370Sjasone m->m_flags = 0; /* This sucks but non-trailers are the norm */ 642234370Sjasone off = (etype - ETHERTYPE_TRAIL) * 512; 643234370Sjasone if (off >= ETHERMTU) { 644234370Sjasone m_freem(m); 645234370Sjasone return; /* sanity */ 646234370Sjasone } 647234370Sjasone totlen -= sizeof(struct ether_header); /* We don't read the trailer */ 648234370Sjasone m->m_data += 2 * sizeof(u_short); /* Get rid of type & len */ 649234370Sjasone } 650234370Sjasone while (totlen > 0) { 651234370Sjasone lenthisone = min(totlen, M_TRAILINGSPACE(m)); 652234370Sjasone if (lenthisone == 0) { /* no room in this one */ 653234370Sjasone mcur = m; 654234370Sjasone m = sc->mb[sc->next_mb]; 655234370Sjasone sc->mb[sc->next_mb] = 0; 656234370Sjasone if (!m) { 657234370Sjasone MGET(m, M_DONTWAIT, MT_DATA); 658234370Sjasone if (m == 0) 659234370Sjasone goto out; 660234370Sjasone } else { 661234370Sjasone timeout(epmbufqueue, (caddr_t)sc, 0); 662234370Sjasone sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 663234370Sjasone } 664234370Sjasone if (totlen >= MINCLSIZE) 665234370Sjasone MCLGET(m, M_DONTWAIT); 666234370Sjasone m->m_len = 0; 667234370Sjasone mcur->m_next = m; 668234370Sjasone lenthisone = min(totlen, M_TRAILINGSPACE(m)); 669234370Sjasone } 670234370Sjasone insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, 671234370Sjasone lenthisone / 2); 672234370Sjasone m->m_len += lenthisone; 673234370Sjasone if (lenthisone & 1) 674234370Sjasone *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1); 675234370Sjasone totlen -= lenthisone; 676235238Sjasone } 677235238Sjasone if (off) { 678234370Sjasone top = sc->mb[sc->next_mb]; 679234370Sjasone sc->mb[sc->next_mb] = 0; 680234370Sjasone if (top == 0) { 681234370Sjasone MGETHDR(m, M_DONTWAIT, MT_DATA); 682234370Sjasone if (top == 0) 683234370Sjasone goto out; 684234370Sjasone } else { 685234370Sjasone /* Convert one of our saved mbuf's */ 686234370Sjasone sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 687234370Sjasone top->m_data = top->m_pktdat; 688234370Sjasone top->m_flags = M_PKTHDR; 689234370Sjasone } 690234370Sjasone insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, 691234370Sjasone sizeof(struct ether_header)); 692234370Sjasone top->m_next = m0; 693234370Sjasone top->m_len = sizeof(struct ether_header); 694234370Sjasone /* XXX Accomodate for type and len from beginning of trailer */ 695234370Sjasone top->m_pkthdr.len = save_totlen - (2 * sizeof(u_short)); 696234370Sjasone } else { 697234370Sjasone top = m0; 698234370Sjasone top->m_pkthdr.len = save_totlen; 699234370Sjasone } 700234370Sjasone 701234569Sjasone top->m_pkthdr.rcvif = &sc->arpcom.ac_if; 702234370Sjasone outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); 703234370Sjasone while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) 704234370Sjasone ; 705234370Sjasone ++sc->arpcom.ac_if.if_ipackets; 706234370Sjasone#if NBPFILTER > 0 707234370Sjasone if (sc->bpf) { 708234370Sjasone bpf_mtap(sc->bpf, top); 709234370Sjasone 710234370Sjasone /* 711234370Sjasone * Note that the interface cannot be in promiscuous mode if 712234370Sjasone * there are no BPF listeners. And if we are in promiscuous 713234370Sjasone * mode, we have to check if this packet is really ours. 714234370Sjasone */ 715234370Sjasone if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && 716234370Sjasone (eh->ether_dhost[0] & 1) == 0 && 717234370Sjasone bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 718234370Sjasone sizeof(eh->ether_dhost)) != 0 && 719234370Sjasone bcmp(eh->ether_dhost, etherbroadcastaddr, 720234370Sjasone sizeof(eh->ether_dhost)) != 0) { 721234370Sjasone m_freem(top); 722234370Sjasone return; 723234370Sjasone } 724234370Sjasone } 725234370Sjasone#endif 726234370Sjasone m_adj(top, sizeof(struct ether_header)); 727234370Sjasone ether_input(&sc->arpcom.ac_if, eh, top); 728234370Sjasone return; 729234370Sjasone 730234370Sjasoneout: outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); 731234370Sjasone while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) 732234370Sjasone ; 733242844Sjasone if (top) 734234370Sjasone m_freem(top); 735242844Sjasone 736234370Sjasone return; 737234370Sjasone} 738234370Sjasone 739234370Sjasone 740234370Sjasone/* 741234370Sjasone * Look familiar? 742234370Sjasone */ 743234370Sjasonestatic int 744234370Sjasoneepioctl(ifp, cmd, data) 745234370Sjasone register struct ifnet *ifp; 746234370Sjasone int cmd; 747234370Sjasone caddr_t data; 748234370Sjasone{ 749234370Sjasone register struct ifaddr *ifa = (struct ifaddr *) data; 750234370Sjasone struct ep_softc *sc = &ep_softc[ifp->if_unit]; 751234370Sjasone struct ifreq *ifr = (struct ifreq *) data; 752234370Sjasone int s, error = 0; 753234370Sjasone 754234370Sjasone switch (cmd) { 755234370Sjasone case SIOCSIFADDR: 756234370Sjasone ifp->if_flags |= IFF_UP; 757234370Sjasone switch (ifa->ifa_addr->sa_family) { 758234370Sjasone#ifdef INET 759234370Sjasone case AF_INET: 760234370Sjasone epinit(ifp->if_unit); /* before arpwhohas */ 761234370Sjasone ((struct arpcom *) ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; 762234370Sjasone arpwhohas((struct arpcom *) ifp, &IA_SIN(ifa)->sin_addr); 763234370Sjasone break; 764234370Sjasone#endif 765234370Sjasone#ifdef NS 766234370Sjasone case AF_NS: 767234370Sjasone { 768234370Sjasone register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 769234370Sjasone 770234370Sjasone if (ns_nullhost(*ina)) 771234370Sjasone ina->x_host = 772234370Sjasone *(union ns_host *)(sc->arpcom.ac_enaddr); 773234370Sjasone else { 774234370Sjasone ifp->if_flags &= ~IFF_RUNNING; 775234370Sjasone bcopy((caddr_t) ina->x_host.c_host, 776234370Sjasone (caddr_t)sc->arpcom.ac_enaddr, 777234370Sjasone sizeof(sc->arpcom.ac_enaddr)); 778234370Sjasone } 779234370Sjasone epinit(ifp->if_unit); 780234370Sjasone break; 781234370Sjasone } 782234370Sjasone#endif 783234370Sjasone default: 784234370Sjasone epinit(ifp->if_unit); 785234370Sjasone break; 786234370Sjasone } 787234370Sjasone break; 788234370Sjasone case SIOCSIFFLAGS: 789234370Sjasone if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { 790234370Sjasone ifp->if_flags &= ~IFF_RUNNING; 791234370Sjasone epstop(ifp->if_unit); 792234370Sjasone break; 793242844Sjasone } 794234370Sjasone if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) 795234370Sjasone epinit(ifp->if_unit); 796234370Sjasone break; 797234370Sjasone#ifdef notdef 798234370Sjasone case SIOCGHWADDR: 799242844Sjasone bcopy((caddr_t) sc->sc_addr, (caddr_t) &ifr->ifr_data, 800242844Sjasone sizeof(sc->sc_addr)); 801234370Sjasone break; 802242844Sjasone#endif 803234370Sjasone default: 804242844Sjasone error = EINVAL; 805234370Sjasone } 806234370Sjasone return (error); 807242844Sjasone} 808234370Sjasone 809234370Sjasonevoid 810234370Sjasoneepreset(unit) 811234370Sjasone int unit; 812234370Sjasone{ 813234370Sjasone int s = splimp(); 814234370Sjasone 815234370Sjasone epstop(unit); 816242844Sjasone epinit(unit); 817234370Sjasone splx(s); 818234370Sjasone return; 819234370Sjasone} 820234370Sjasone 821234370Sjasonevoid 822234370Sjasoneepwatchdog(unit) 823234370Sjasone int unit; 824234370Sjasone{ 825234370Sjasone struct ep_softc *sc = &ep_softc[unit]; 826234370Sjasone 827234370Sjasone log(LOG_ERR, "ep%d: watchdog\n", unit); 828234370Sjasone ++sc->arpcom.ac_if.if_oerrors; 829234370Sjasone 830234370Sjasone epreset(unit); 831234370Sjasone} 832234370Sjasone 833234370Sjasonevoid 834234370Sjasoneepstop(unit) 835234370Sjasone int unit; 836234370Sjasone{ 837235238Sjasone struct ep_softc *sc = &ep_softc[unit]; 838234370Sjasone 839234370Sjasone outw(BASE + EP_COMMAND, RX_DISABLE); 840234370Sjasone outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); 841234370Sjasone while (inb(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) 842234370Sjasone ; 843234370Sjasone outw(BASE + EP_COMMAND, TX_DISABLE); 844234370Sjasone outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); 845234370Sjasone outw(BASE + EP_COMMAND, RX_RESET); 846234370Sjasone outw(BASE + EP_COMMAND, TX_RESET); 847234370Sjasone outw(BASE + EP_COMMAND, C_INTR_LATCH); 848234370Sjasone outw(BASE + EP_COMMAND, SET_RD_0_MASK); 849234370Sjasone outw(BASE + EP_COMMAND, SET_INTR_MASK); 850234370Sjasone outw(BASE + EP_COMMAND, SET_RX_FILTER); 851234370Sjasone return; 852234370Sjasone} 853234370Sjasone 854234370Sjasone 855234370Sjasone/* 856234370Sjasone * This is adapted straight from the book. There's probably a better way. 857234370Sjasone */ 858234370Sjasonestatic int 859234370Sjasonesend_ID_sequence(port) 860234370Sjasone u_short port; 861234370Sjasone{ 862234370Sjasone char cx, al; 863234370Sjasone 864234370Sjasone cx = 0x0ff; 865234370Sjasone al = 0x0ff; 866234370Sjasone 867234370Sjasone outb(port, 0x0); 868234370Sjasone DELAY(1000); 869234370Sjasone outb(port, 0x0); 870234370Sjasone DELAY(1000); 871234370Sjasone 872234370Sjasoneloop1: cx--; 873234370Sjasone outb(port, al); 874234370Sjasone if (!(al & 0x80)) { 875235238Sjasone al = al << 1; 876234370Sjasone goto loop1; 877234370Sjasone } 878234370Sjasone al = al << 1; 879234370Sjasone al ^= 0xcf; 880234370Sjasone if (cx) 881234370Sjasone goto loop1; 882234370Sjasone 883234370Sjasone return(1); 884234370Sjasone} 885234370Sjasone 886234370Sjasone 887234370Sjasone/* 888234370Sjasone * We get eeprom data from the id_port given an offset into the 889234370Sjasone * eeprom. Basically; after the ID_sequence is sent to all of 890234370Sjasone * the cards; they enter the ID_CMD state where they will accept 891234370Sjasone * command requests. 0x80-0xbf loads the eeprom data. We then 892234370Sjasone * read the port 16 times and with every read; the cards check 893234370Sjasone * for contention (ie: if one card writes a 0 bit and another 894234370Sjasone * writes a 1 bit then the host sees a 0. At the end of the cycle; 895234370Sjasone * each card compares the data on the bus; if there is a difference 896234370Sjasone * then that card goes into ID_WAIT state again). In the meantime; 897234370Sjasone * one bit of data is returned in the AX register which is conveniently 898234370Sjasone * returned to us by inb(). Hence; we read 16 times getting one 899234370Sjasone * bit of data with each read. 900234370Sjasone */ 901234370Sjasonestatic u_short 902234370Sjasoneget_eeprom_data(id_port, offset) 903234370Sjasone int id_port; 904234370Sjasone int offset; 905234370Sjasone{ 906234370Sjasone int i, data = 0; 907234370Sjasone outb(id_port, 0x80 + offset); 908234370Sjasone DELAY(1000); 909234370Sjasone for (i = 0; i < 16; i++) 910234370Sjasone data = (data << 1) | (inw(id_port) & 1); 911234370Sjasone return (data); 912234370Sjasone} 913234370Sjasone 914234370Sjasonestatic int 915234370Sjasoneis_eeprom_busy(is) 916234370Sjasone struct isa_device *is; 917234370Sjasone{ 918234370Sjasone int i = 0, j; 919234370Sjasone register struct ep_softc *sc = &ep_softc[is->id_unit]; 920234370Sjasone 921234370Sjasone while (i++ < 100) { 922234370Sjasone j = inw(BASE + EP_W0_EEPROM_COMMAND); 923234370Sjasone if (j & EEPROM_BUSY) 924234370Sjasone DELAY(100); 925234370Sjasone else 926234370Sjasone break; 927234370Sjasone } 928234370Sjasone if (i >= 100) { 929234370Sjasone printf("\nep%d: eeprom failed to come ready.\n", is->id_unit); 930234370Sjasone return (1); 931234370Sjasone } 932234370Sjasone if (j & EEPROM_TST_MODE) { 933234370Sjasone printf("\nep%d: 3c509 in test mode. Erase pencil mark!\n", is->id_unit); 934234370Sjasone return (1); 935234370Sjasone } 936234370Sjasone return (0); 937234370Sjasone} 938234370Sjasone 939234370Sjasonevoid 940234370Sjasoneepmbufqueue(sp, dummy_arg) 941234370Sjasone caddr_t sp; 942234370Sjasone int dummy_arg; 943234370Sjasone{ 944234370Sjasone struct ep_softc *sc = (struct ep_softc *)sp; 945234370Sjasone int i; 946234370Sjasone 947234370Sjasone if (sc->mb[sc->last_mb]) 948234370Sjasone return; 949234370Sjasone i = sc->last_mb; 950234370Sjasone do { 951234370Sjasone MGET(sc->mb[i], M_DONTWAIT, MT_DATA); 952234370Sjasone if (!sc->mb[i]) 953234370Sjasone break; 954234370Sjasone i = (i + 1) % MAX_MBS; 955234370Sjasone } while (i != sc->next_mb); 956234370Sjasone sc->last_mb = i; 957234370Sjasone return; 958234370Sjasone} 959234370Sjasone 960234370Sjasone#endif /* NEP > 0 */ 961234370Sjasone