1 1.103 thorpej /* $NetBSD: if_eg.c,v 1.103 2022/09/17 17:00:02 thorpej Exp $ */ 2 1.4 cgd 3 1.1 deraadt /* 4 1.1 deraadt * Copyright (c) 1993 Dean Huxley <dean (at) fsa.ca> 5 1.1 deraadt * All rights reserved. 6 1.1 deraadt * 7 1.1 deraadt * Redistribution and use in source and binary forms, with or without 8 1.1 deraadt * modification, are permitted provided that the following conditions 9 1.1 deraadt * are met: 10 1.1 deraadt * 1. Redistributions of source code must retain the above copyright 11 1.1 deraadt * notice, this list of conditions and the following disclaimer. 12 1.1 deraadt * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 deraadt * notice, this list of conditions and the following disclaimer in the 14 1.1 deraadt * documentation and/or other materials provided with the distribution. 15 1.1 deraadt * 3. All advertising materials mentioning features or use of this software 16 1.1 deraadt * must display the following acknowledgement: 17 1.1 deraadt * This product includes software developed by Dean Huxley. 18 1.1 deraadt * 4. The name of Dean Huxley may not be used to endorse or promote products 19 1.1 deraadt * derived from this software without specific prior written permission. 20 1.1 deraadt * 21 1.1 deraadt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 1.1 deraadt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 1.1 deraadt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 1.1 deraadt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 1.1 deraadt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 1.1 deraadt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 1.1 deraadt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 1.1 deraadt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 1.1 deraadt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 1.1 deraadt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 1.22 hpeyerl */ 32 1.22 hpeyerl /* 33 1.22 hpeyerl * Support for 3Com 3c505 Etherlink+ card. 34 1.1 deraadt */ 35 1.1 deraadt 36 1.57 thorpej /* 37 1.57 thorpej * To do: 38 1.1 deraadt * - multicast 39 1.1 deraadt * - promiscuous 40 1.1 deraadt */ 41 1.55 lukem 42 1.55 lukem #include <sys/cdefs.h> 43 1.103 thorpej __KERNEL_RCSID(0, "$NetBSD: if_eg.c,v 1.103 2022/09/17 17:00:02 thorpej Exp $"); 44 1.55 lukem 45 1.42 jonathan #include "opt_inet.h" 46 1.1 deraadt 47 1.1 deraadt #include <sys/param.h> 48 1.31 thorpej #include <sys/systm.h> 49 1.98 thorpej #include <sys/kmem.h> 50 1.1 deraadt #include <sys/mbuf.h> 51 1.1 deraadt #include <sys/socket.h> 52 1.1 deraadt #include <sys/ioctl.h> 53 1.1 deraadt #include <sys/errno.h> 54 1.1 deraadt #include <sys/syslog.h> 55 1.1 deraadt #include <sys/select.h> 56 1.1 deraadt #include <sys/device.h> 57 1.88 riastrad #include <sys/rndsource.h> 58 1.1 deraadt 59 1.1 deraadt #include <net/if.h> 60 1.1 deraadt #include <net/if_dl.h> 61 1.1 deraadt #include <net/if_types.h> 62 1.93 msaitoh #include <net/bpf.h> 63 1.33 is 64 1.33 is #include <net/if_ether.h> 65 1.1 deraadt 66 1.1 deraadt #ifdef INET 67 1.1 deraadt #include <netinet/in.h> 68 1.1 deraadt #include <netinet/in_systm.h> 69 1.1 deraadt #include <netinet/in_var.h> 70 1.1 deraadt #include <netinet/ip.h> 71 1.33 is #include <netinet/if_inarp.h> 72 1.1 deraadt #endif 73 1.1 deraadt 74 1.73 ad #include <sys/cpu.h> 75 1.73 ad #include <sys/intr.h> 76 1.73 ad #include <sys/bus.h> 77 1.1 deraadt 78 1.12 cgd #include <dev/isa/isavar.h> 79 1.10 cgd #include <dev/isa/if_egreg.h> 80 1.10 cgd #include <dev/isa/elink.h> 81 1.1 deraadt 82 1.1 deraadt /* for debugging convenience */ 83 1.1 deraadt #ifdef EGDEBUG 84 1.30 christos #define DPRINTF(x) printf x 85 1.1 deraadt #else 86 1.29 christos #define DPRINTF(x) 87 1.1 deraadt #endif 88 1.1 deraadt 89 1.1 deraadt #define EG_INLEN 10 90 1.1 deraadt #define EG_BUFLEN 0x0670 91 1.1 deraadt 92 1.40 drochner #define EG_PCBLEN 64 93 1.40 drochner 94 1.1 deraadt /* 95 1.1 deraadt * Ethernet software status per interface. 96 1.1 deraadt */ 97 1.1 deraadt struct eg_softc { 98 1.85 chs device_t sc_dev; 99 1.12 cgd void *sc_ih; 100 1.33 is struct ethercom sc_ethercom; /* Ethernet common part */ 101 1.32 thorpej bus_space_tag_t sc_iot; /* bus space identifier */ 102 1.32 thorpej bus_space_handle_t sc_ioh; /* i/o handle */ 103 1.100 thorpej uint8_t eg_rom_major; /* Cards ROM version (major number) */ 104 1.100 thorpej uint8_t eg_rom_minor; /* Cards ROM version (minor number) */ 105 1.27 thorpej short eg_ram; /* Amount of RAM on the card */ 106 1.100 thorpej uint8_t eg_pcb[EG_PCBLEN]; /* Primary Command Block buffer */ 107 1.100 thorpej uint8_t eg_incount; /* Number of buffers currently used */ 108 1.101 thorpej bool eg_txbusy; /* transmitter is busy */ 109 1.72 christos void * eg_inbuf; /* Incoming packet buffer */ 110 1.72 christos void * eg_outbuf; /* Outgoing packet buffer */ 111 1.37 explorer 112 1.83 tls krndsource_t rnd_source; 113 1.1 deraadt }; 114 1.1 deraadt 115 1.99 thorpej static int egprobe(device_t, cfdata_t, void *); 116 1.99 thorpej static void egattach(device_t, device_t, void *); 117 1.1 deraadt 118 1.85 chs CFATTACH_DECL_NEW(eg, sizeof(struct eg_softc), 119 1.60 thorpej egprobe, egattach, NULL, NULL); 120 1.1 deraadt 121 1.99 thorpej static int egintr(void *); 122 1.99 thorpej static void eginit(struct eg_softc *); 123 1.99 thorpej static int egioctl(struct ifnet *, u_long, void *); 124 1.99 thorpej static void egrecv(struct eg_softc *); 125 1.99 thorpej static void egstart(struct ifnet *); 126 1.99 thorpej static void egwatchdog(struct ifnet *); 127 1.99 thorpej static void egreset(struct eg_softc *); 128 1.99 thorpej static void egread(struct eg_softc *, void *, int); 129 1.99 thorpej static struct mbuf *egget(struct eg_softc *, void *, int); 130 1.99 thorpej static void egstop(struct eg_softc *); 131 1.64 perry 132 1.100 thorpej static inline void egprintpcb(uint8_t *); 133 1.100 thorpej static int egoutPCB(bus_space_tag_t, bus_space_handle_t, uint8_t); 134 1.100 thorpej static int egreadPCBstat(bus_space_tag_t, bus_space_handle_t, uint8_t); 135 1.64 perry static int egreadPCBready(bus_space_tag_t, bus_space_handle_t); 136 1.100 thorpej static int egwritePCB(bus_space_tag_t, bus_space_handle_t, uint8_t *); 137 1.100 thorpej static int egreadPCB(bus_space_tag_t, bus_space_handle_t, uint8_t *); 138 1.31 thorpej 139 1.1 deraadt /* 140 1.1 deraadt * Support stuff 141 1.1 deraadt */ 142 1.65 perry 143 1.1 deraadt static inline void 144 1.100 thorpej egprintpcb(uint8_t *pcb) 145 1.1 deraadt { 146 1.1 deraadt int i; 147 1.65 perry 148 1.40 drochner for (i = 0; i < pcb[1] + 2; i++) 149 1.40 drochner DPRINTF(("pcb[%2d] = %x\n", i, pcb[i])); 150 1.1 deraadt } 151 1.1 deraadt 152 1.1 deraadt static int 153 1.100 thorpej egoutPCB(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t b) 154 1.1 deraadt { 155 1.1 deraadt int i; 156 1.1 deraadt 157 1.1 deraadt for (i=0; i < 4000; i++) { 158 1.32 thorpej if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HCRE) { 159 1.32 thorpej bus_space_write_1(iot, ioh, EG_COMMAND, b); 160 1.1 deraadt return 0; 161 1.1 deraadt } 162 1.1 deraadt delay(10); 163 1.1 deraadt } 164 1.29 christos DPRINTF(("egoutPCB failed\n")); 165 1.1 deraadt return 1; 166 1.1 deraadt } 167 1.65 perry 168 1.1 deraadt static int 169 1.100 thorpej egreadPCBstat(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t statb) 170 1.1 deraadt { 171 1.1 deraadt int i; 172 1.1 deraadt 173 1.1 deraadt for (i=0; i < 5000; i++) { 174 1.32 thorpej if ((bus_space_read_1(iot, ioh, EG_STATUS) & 175 1.65 perry EG_PCB_STAT) != EG_PCB_NULL) 176 1.1 deraadt break; 177 1.1 deraadt delay(10); 178 1.1 deraadt } 179 1.65 perry if ((bus_space_read_1(iot, ioh, EG_STATUS) & EG_PCB_STAT) == statb) 180 1.1 deraadt return 0; 181 1.1 deraadt return 1; 182 1.1 deraadt } 183 1.1 deraadt 184 1.1 deraadt static int 185 1.78 dsl egreadPCBready(bus_space_tag_t iot, bus_space_handle_t ioh) 186 1.1 deraadt { 187 1.1 deraadt int i; 188 1.1 deraadt 189 1.1 deraadt for (i=0; i < 10000; i++) { 190 1.32 thorpej if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_ACRF) 191 1.1 deraadt return 0; 192 1.1 deraadt delay(5); 193 1.1 deraadt } 194 1.29 christos DPRINTF(("PCB read not ready\n")); 195 1.1 deraadt return 1; 196 1.1 deraadt } 197 1.65 perry 198 1.1 deraadt static int 199 1.100 thorpej egwritePCB(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t *pcb) 200 1.1 deraadt { 201 1.1 deraadt int i; 202 1.100 thorpej uint8_t len; 203 1.1 deraadt 204 1.32 thorpej bus_space_write_1(iot, ioh, EG_CONTROL, 205 1.32 thorpej (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_NULL); 206 1.1 deraadt 207 1.40 drochner len = pcb[1] + 2; 208 1.1 deraadt for (i = 0; i < len; i++) 209 1.40 drochner egoutPCB(iot, ioh, pcb[i]); 210 1.27 thorpej 211 1.1 deraadt for (i=0; i < 4000; i++) { 212 1.32 thorpej if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HCRE) 213 1.1 deraadt break; 214 1.1 deraadt delay(10); 215 1.1 deraadt } 216 1.17 mycroft 217 1.32 thorpej bus_space_write_1(iot, ioh, EG_CONTROL, 218 1.32 thorpej (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_DONE); 219 1.17 mycroft 220 1.40 drochner egoutPCB(iot, ioh, len); 221 1.1 deraadt 222 1.40 drochner if (egreadPCBstat(iot, ioh, EG_PCB_ACCEPT)) 223 1.1 deraadt return 1; 224 1.1 deraadt return 0; 225 1.65 perry } 226 1.65 perry 227 1.1 deraadt static int 228 1.100 thorpej egreadPCB(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t *pcb) 229 1.1 deraadt { 230 1.1 deraadt int i; 231 1.27 thorpej 232 1.32 thorpej bus_space_write_1(iot, ioh, EG_CONTROL, 233 1.32 thorpej (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_NULL); 234 1.1 deraadt 235 1.53 thorpej memset(pcb, 0, EG_PCBLEN); 236 1.1 deraadt 237 1.40 drochner if (egreadPCBready(iot, ioh)) 238 1.1 deraadt return 1; 239 1.1 deraadt 240 1.40 drochner pcb[0] = bus_space_read_1(iot, ioh, EG_COMMAND); 241 1.27 thorpej 242 1.40 drochner if (egreadPCBready(iot, ioh)) 243 1.1 deraadt return 1; 244 1.1 deraadt 245 1.40 drochner pcb[1] = bus_space_read_1(iot, ioh, EG_COMMAND); 246 1.1 deraadt 247 1.40 drochner if (pcb[1] > 62) { 248 1.40 drochner DPRINTF(("len %d too large\n", pcb[1])); 249 1.1 deraadt return 1; 250 1.1 deraadt } 251 1.27 thorpej 252 1.40 drochner for (i = 0; i < pcb[1]; i++) { 253 1.40 drochner if (egreadPCBready(iot, ioh)) 254 1.1 deraadt return 1; 255 1.40 drochner pcb[2+i] = bus_space_read_1(iot, ioh, EG_COMMAND); 256 1.1 deraadt } 257 1.40 drochner if (egreadPCBready(iot, ioh)) 258 1.1 deraadt return 1; 259 1.40 drochner if (egreadPCBstat(iot, ioh, EG_PCB_DONE)) 260 1.1 deraadt return 1; 261 1.62 simonb if (bus_space_read_1(iot, ioh, EG_COMMAND) != pcb[1] + 2) { 262 1.1 deraadt return 1; 263 1.1 deraadt } 264 1.17 mycroft 265 1.32 thorpej bus_space_write_1(iot, ioh, EG_CONTROL, 266 1.32 thorpej (bus_space_read_1(iot, ioh, EG_CONTROL) & 267 1.27 thorpej ~EG_PCB_STAT) | EG_PCB_ACCEPT); 268 1.17 mycroft 269 1.1 deraadt return 0; 270 1.65 perry } 271 1.1 deraadt 272 1.1 deraadt /* 273 1.1 deraadt * Real stuff 274 1.1 deraadt */ 275 1.1 deraadt 276 1.99 thorpej static int 277 1.80 cegger egprobe(device_t parent, cfdata_t match, void *aux) 278 1.1 deraadt { 279 1.1 deraadt struct isa_attach_args *ia = aux; 280 1.32 thorpej bus_space_tag_t iot = ia->ia_iot; 281 1.32 thorpej bus_space_handle_t ioh; 282 1.27 thorpej int i, rval; 283 1.100 thorpej static uint8_t pcb[EG_PCBLEN]; 284 1.27 thorpej 285 1.27 thorpej rval = 0; 286 1.1 deraadt 287 1.75 ad /* 288 1.75 ad * XXX This probe is slow. If there are no ISA expansion slots, 289 1.75 ad * then skip it. 290 1.75 ad */ 291 1.75 ad if (isa_get_slotcount() == 0) 292 1.75 ad return (0); 293 1.75 ad 294 1.57 thorpej if (ia->ia_nio < 1) 295 1.57 thorpej return (0); 296 1.57 thorpej if (ia->ia_nirq < 1) 297 1.57 thorpej return (0); 298 1.57 thorpej 299 1.57 thorpej if (ISA_DIRECT_CONFIG(ia)) 300 1.57 thorpej return (0); 301 1.38 thorpej 302 1.38 thorpej /* Disallow wildcarded i/o address. */ 303 1.63 drochner if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 304 1.38 thorpej return (0); 305 1.27 thorpej 306 1.57 thorpej /* Disallow wildcarded IRQ. */ 307 1.63 drochner if (ia->ia_irq[0].ir_irq == ISA_UNKNOWN_IRQ) 308 1.57 thorpej return (0); 309 1.57 thorpej 310 1.57 thorpej if ((ia->ia_io[0].ir_addr & ~0x07f0) != 0) { 311 1.57 thorpej DPRINTF(("Weird iobase %x\n", ia->ia_io[0].ir_addr)); 312 1.57 thorpej return 0; 313 1.57 thorpej } 314 1.57 thorpej 315 1.27 thorpej /* Map i/o space. */ 316 1.57 thorpej if (bus_space_map(iot, ia->ia_io[0].ir_addr, 0x08, 0, &ioh)) { 317 1.29 christos DPRINTF(("egprobe: can't map i/o space in probe\n")); 318 1.27 thorpej return 0; 319 1.27 thorpej } 320 1.27 thorpej 321 1.1 deraadt /* hard reset card */ 322 1.65 perry bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_RESET); 323 1.32 thorpej bus_space_write_1(iot, ioh, EG_CONTROL, 0); 324 1.74 ad for (i = 0; i < 500; i++) { 325 1.1 deraadt delay(1000); 326 1.32 thorpej if ((bus_space_read_1(iot, ioh, EG_STATUS) & 327 1.65 perry EG_PCB_STAT) == EG_PCB_NULL) 328 1.1 deraadt break; 329 1.1 deraadt } 330 1.32 thorpej if ((bus_space_read_1(iot, ioh, EG_STATUS) & EG_PCB_STAT) != EG_PCB_NULL) { 331 1.29 christos DPRINTF(("egprobe: Reset failed\n")); 332 1.27 thorpej goto out; 333 1.1 deraadt } 334 1.40 drochner pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */ 335 1.40 drochner pcb[1] = 0; 336 1.40 drochner if (egwritePCB(iot, ioh, pcb) != 0) 337 1.27 thorpej goto out; 338 1.27 thorpej 339 1.40 drochner if ((egreadPCB(iot, ioh, pcb) != 0) || 340 1.40 drochner pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */ 341 1.40 drochner pcb[1] != 0x0a) { 342 1.40 drochner egprintpcb(pcb); 343 1.27 thorpej goto out; 344 1.1 deraadt } 345 1.27 thorpej 346 1.57 thorpej ia->ia_nio = 1; 347 1.57 thorpej ia->ia_io[0].ir_size = 0x08; 348 1.57 thorpej 349 1.57 thorpej ia->ia_nirq = 1; 350 1.57 thorpej 351 1.57 thorpej ia->ia_niomem = 0; 352 1.57 thorpej ia->ia_ndrq = 0; 353 1.57 thorpej 354 1.27 thorpej rval = 1; 355 1.27 thorpej 356 1.27 thorpej out: 357 1.32 thorpej bus_space_unmap(iot, ioh, 0x08); 358 1.27 thorpej return rval; 359 1.1 deraadt } 360 1.1 deraadt 361 1.99 thorpej static void 362 1.80 cegger egattach(device_t parent, device_t self, void *aux) 363 1.1 deraadt { 364 1.85 chs struct eg_softc *sc = device_private(self); 365 1.2 mycroft struct isa_attach_args *ia = aux; 366 1.32 thorpej bus_space_tag_t iot = ia->ia_iot; 367 1.32 thorpej bus_space_handle_t ioh; 368 1.33 is struct ifnet *ifp = &sc->sc_ethercom.ec_if; 369 1.100 thorpej uint8_t myaddr[ETHER_ADDR_LEN]; 370 1.27 thorpej 371 1.85 chs sc->sc_dev = self; 372 1.85 chs 373 1.30 christos printf("\n"); 374 1.27 thorpej 375 1.27 thorpej /* Map i/o space. */ 376 1.57 thorpej if (bus_space_map(iot, ia->ia_io[0].ir_addr, 0x08, 0, &ioh)) { 377 1.76 cegger aprint_error_dev(self, "can't map i/o space\n"); 378 1.27 thorpej return; 379 1.27 thorpej } 380 1.27 thorpej 381 1.32 thorpej sc->sc_iot = iot; 382 1.27 thorpej sc->sc_ioh = ioh; 383 1.27 thorpej 384 1.40 drochner sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */ 385 1.40 drochner sc->eg_pcb[1] = 0; 386 1.40 drochner if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) { 387 1.76 cegger aprint_error_dev(self, "error requesting adapter info\n"); 388 1.40 drochner return; 389 1.40 drochner } 390 1.40 drochner if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) { 391 1.40 drochner egprintpcb(sc->eg_pcb); 392 1.76 cegger aprint_error_dev(self, "error reading adapter info\n"); 393 1.40 drochner return; 394 1.40 drochner } 395 1.40 drochner 396 1.40 drochner if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */ 397 1.40 drochner sc->eg_pcb[1] != 0x0a) { 398 1.40 drochner egprintpcb(sc->eg_pcb); 399 1.76 cegger aprint_error_dev(self, "bogus adapter info\n"); 400 1.40 drochner return; 401 1.40 drochner } 402 1.40 drochner 403 1.40 drochner sc->eg_rom_major = sc->eg_pcb[3]; 404 1.40 drochner sc->eg_rom_minor = sc->eg_pcb[2]; 405 1.40 drochner sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8); 406 1.40 drochner 407 1.2 mycroft egstop(sc); 408 1.1 deraadt 409 1.1 deraadt sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */ 410 1.1 deraadt sc->eg_pcb[1] = 0; 411 1.40 drochner if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) { 412 1.76 cegger aprint_error_dev(self, "can't send Get Station Address\n"); 413 1.1 deraadt return; 414 1.65 perry } 415 1.40 drochner if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) { 416 1.76 cegger aprint_error_dev(self, "can't read station address\n"); 417 1.40 drochner egprintpcb(sc->eg_pcb); 418 1.1 deraadt return; 419 1.1 deraadt } 420 1.1 deraadt 421 1.1 deraadt /* check Get station address response */ 422 1.65 perry if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) { 423 1.76 cegger aprint_error_dev(self, "card responded with garbage (1)\n"); 424 1.40 drochner egprintpcb(sc->eg_pcb); 425 1.1 deraadt return; 426 1.1 deraadt } 427 1.54 thorpej memcpy(myaddr, &sc->eg_pcb[2], ETHER_ADDR_LEN); 428 1.1 deraadt 429 1.91 msaitoh aprint_normal_dev(self, "ROM v%d.%02d %dk address %s\n", 430 1.2 mycroft sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram, 431 1.33 is ether_sprintf(myaddr)); 432 1.1 deraadt 433 1.1 deraadt sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */ 434 1.40 drochner if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) { 435 1.91 msaitoh aprint_error_dev(self, "can't send Set Station Address\n"); 436 1.1 deraadt return; 437 1.1 deraadt } 438 1.40 drochner if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) { 439 1.91 msaitoh aprint_error_dev(self, 440 1.91 msaitoh "can't read Set Station Address status\n"); 441 1.40 drochner egprintpcb(sc->eg_pcb); 442 1.1 deraadt return; 443 1.1 deraadt } 444 1.2 mycroft if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 || 445 1.7 mycroft sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) { 446 1.76 cegger aprint_error_dev(self, "card responded with garbage (2)\n"); 447 1.40 drochner egprintpcb(sc->eg_pcb); 448 1.1 deraadt return; 449 1.1 deraadt } 450 1.1 deraadt 451 1.2 mycroft /* Initialize ifnet structure. */ 452 1.85 chs strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); 453 1.25 thorpej ifp->if_softc = sc; 454 1.1 deraadt ifp->if_start = egstart; 455 1.1 deraadt ifp->if_ioctl = egioctl; 456 1.1 deraadt ifp->if_watchdog = egwatchdog; 457 1.96 msaitoh ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 458 1.52 thorpej IFQ_SET_READY(&ifp->if_snd); 459 1.52 thorpej 460 1.1 deraadt /* Now we can attach the interface. */ 461 1.1 deraadt if_attach(ifp); 462 1.33 is ether_ifattach(ifp, myaddr); 463 1.65 perry 464 1.57 thorpej sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq, 465 1.57 thorpej IST_EDGE, IPL_NET, egintr, sc); 466 1.37 explorer 467 1.85 chs rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 468 1.87 tls RND_TYPE_NET, RND_FLAG_DEFAULT); 469 1.1 deraadt } 470 1.1 deraadt 471 1.99 thorpej static void 472 1.78 dsl eginit(struct eg_softc *sc) 473 1.1 deraadt { 474 1.49 augustss struct ifnet *ifp = &sc->sc_ethercom.ec_if; 475 1.32 thorpej bus_space_tag_t iot = sc->sc_iot; 476 1.32 thorpej bus_space_handle_t ioh = sc->sc_ioh; 477 1.1 deraadt 478 1.1 deraadt /* soft reset the board */ 479 1.32 thorpej bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_FLSH); 480 1.1 deraadt delay(100); 481 1.32 thorpej bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_ATTN); 482 1.1 deraadt delay(100); 483 1.32 thorpej bus_space_write_1(iot, ioh, EG_CONTROL, 0); 484 1.1 deraadt delay(200); 485 1.1 deraadt 486 1.1 deraadt sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */ 487 1.1 deraadt sc->eg_pcb[1] = 2; 488 1.1 deraadt sc->eg_pcb[2] = 3; /* receive broadcast & multicast */ 489 1.1 deraadt sc->eg_pcb[3] = 0; 490 1.40 drochner if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) 491 1.85 chs aprint_error_dev(sc->sc_dev, "can't send Configure 82586\n"); 492 1.1 deraadt 493 1.40 drochner if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) { 494 1.91 msaitoh aprint_error_dev(sc->sc_dev, 495 1.91 msaitoh "can't read Configure 82586 status\n"); 496 1.40 drochner egprintpcb(sc->eg_pcb); 497 1.1 deraadt } else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) 498 1.91 msaitoh aprint_error_dev(sc->sc_dev,"configure card command failed\n"); 499 1.1 deraadt 500 1.27 thorpej if (sc->eg_inbuf == NULL) { 501 1.98 thorpej sc->eg_inbuf = kmem_alloc(EG_BUFLEN, KM_NOSLEEP); 502 1.27 thorpej if (sc->eg_inbuf == NULL) { 503 1.85 chs aprint_error_dev(sc->sc_dev, "can't allocate inbuf\n"); 504 1.27 thorpej panic("eginit"); 505 1.27 thorpej } 506 1.27 thorpej } 507 1.1 deraadt sc->eg_incount = 0; 508 1.1 deraadt 509 1.27 thorpej if (sc->eg_outbuf == NULL) { 510 1.98 thorpej sc->eg_outbuf = kmem_alloc(EG_BUFLEN, KM_NOSLEEP); 511 1.27 thorpej if (sc->eg_outbuf == NULL) { 512 1.91 msaitoh aprint_error_dev(sc->sc_dev,"can't allocate outbuf\n"); 513 1.27 thorpej panic("eginit"); 514 1.27 thorpej } 515 1.27 thorpej } 516 1.15 mycroft 517 1.32 thorpej bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_CMDE); 518 1.16 mycroft 519 1.16 mycroft sc->eg_incount = 0; 520 1.16 mycroft egrecv(sc); 521 1.16 mycroft 522 1.16 mycroft /* Interface is now `running', with no output active. */ 523 1.1 deraadt ifp->if_flags |= IFF_RUNNING; 524 1.101 thorpej sc->eg_txbusy = false; 525 1.1 deraadt 526 1.16 mycroft /* Attempt to start output, if any. */ 527 1.1 deraadt egstart(ifp); 528 1.1 deraadt } 529 1.1 deraadt 530 1.99 thorpej static void 531 1.78 dsl egrecv(struct eg_softc *sc) 532 1.1 deraadt { 533 1.2 mycroft 534 1.1 deraadt while (sc->eg_incount < EG_INLEN) { 535 1.1 deraadt sc->eg_pcb[0] = EG_CMD_RECVPACKET; 536 1.1 deraadt sc->eg_pcb[1] = 0x08; 537 1.1 deraadt sc->eg_pcb[2] = 0; /* address not used.. we send zero */ 538 1.1 deraadt sc->eg_pcb[3] = 0; 539 1.1 deraadt sc->eg_pcb[4] = 0; 540 1.1 deraadt sc->eg_pcb[5] = 0; 541 1.25 thorpej sc->eg_pcb[6] = EG_BUFLEN & 0xff; /* our buffer size */ 542 1.25 thorpej sc->eg_pcb[7] = (EG_BUFLEN >> 8) & 0xff; 543 1.1 deraadt sc->eg_pcb[8] = 0; /* timeout, 0 == none */ 544 1.1 deraadt sc->eg_pcb[9] = 0; 545 1.40 drochner if (egwritePCB(sc->sc_iot, sc->sc_ioh, sc->eg_pcb) != 0) 546 1.1 deraadt break; 547 1.16 mycroft sc->eg_incount++; 548 1.1 deraadt } 549 1.1 deraadt } 550 1.1 deraadt 551 1.99 thorpej static void 552 1.78 dsl egstart(struct ifnet *ifp) 553 1.1 deraadt { 554 1.49 augustss struct eg_softc *sc = ifp->if_softc; 555 1.32 thorpej bus_space_tag_t iot = sc->sc_iot; 556 1.32 thorpej bus_space_handle_t ioh = sc->sc_ioh; 557 1.103 thorpej struct mbuf *m0; 558 1.1 deraadt int len; 559 1.100 thorpej uint16_t *ptr; 560 1.1 deraadt 561 1.1 deraadt /* Don't transmit if interface is busy or not running */ 562 1.101 thorpej if ((ifp->if_flags & IFF_RUNNING) == 0) 563 1.101 thorpej return; 564 1.101 thorpej 565 1.101 thorpej if (sc->eg_txbusy) 566 1.14 mycroft return; 567 1.1 deraadt 568 1.15 mycroft loop: 569 1.1 deraadt /* Dequeue the next datagram. */ 570 1.52 thorpej IFQ_DEQUEUE(&ifp->if_snd, m0); 571 1.15 mycroft if (m0 == 0) 572 1.14 mycroft return; 573 1.65 perry 574 1.101 thorpej sc->eg_txbusy = true; 575 1.15 mycroft 576 1.15 mycroft /* We need to use m->m_pkthdr.len, so require the header */ 577 1.102 thorpej KASSERT(m0->m_flags & M_PKTHDR); 578 1.95 riastrad len = uimax(m0->m_pkthdr.len, ETHER_MIN_LEN - ETHER_CRC_LEN); 579 1.1 deraadt 580 1.94 msaitoh bpf_mtap(ifp, m0, BPF_D_OUT); 581 1.1 deraadt 582 1.1 deraadt sc->eg_pcb[0] = EG_CMD_SENDPACKET; 583 1.1 deraadt sc->eg_pcb[1] = 0x06; 584 1.1 deraadt sc->eg_pcb[2] = 0; /* address not used, we send zero */ 585 1.1 deraadt sc->eg_pcb[3] = 0; 586 1.1 deraadt sc->eg_pcb[4] = 0; 587 1.1 deraadt sc->eg_pcb[5] = 0; 588 1.15 mycroft sc->eg_pcb[6] = len; /* length of packet */ 589 1.15 mycroft sc->eg_pcb[7] = len >> 8; 590 1.40 drochner if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) { 591 1.91 msaitoh aprint_error_dev(sc->sc_dev, 592 1.91 msaitoh "can't send Send Packet command\n"); 593 1.97 thorpej if_statinc(ifp, if_oerrors); 594 1.101 thorpej sc->eg_txbusy = false; 595 1.27 thorpej m_freem(m0); 596 1.15 mycroft goto loop; 597 1.15 mycroft } 598 1.15 mycroft 599 1.103 thorpej m_copydata(m0, 0, m0->m_pkthdr.len, sc->eg_outbuf); 600 1.103 thorpej if (len > m0->m_pkthdr.len) { 601 1.103 thorpej memset((uint8_t *)sc->eg_outbuf + m0->m_pkthdr.len, 0, 602 1.103 thorpej len - m0->m_pkthdr.len); 603 1.1 deraadt } 604 1.15 mycroft 605 1.16 mycroft /* set direction bit: host -> adapter */ 606 1.32 thorpej bus_space_write_1(iot, ioh, EG_CONTROL, 607 1.65 perry bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_CTL_DIR); 608 1.65 perry 609 1.100 thorpej for (ptr = (uint16_t *) sc->eg_outbuf; len > 0; len -= 2) { 610 1.32 thorpej bus_space_write_2(iot, ioh, EG_DATA, *ptr++); 611 1.32 thorpej while (!(bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HRDY)) 612 1.15 mycroft ; /* XXX need timeout here */ 613 1.15 mycroft } 614 1.65 perry 615 1.15 mycroft m_freem(m0); 616 1.1 deraadt } 617 1.1 deraadt 618 1.99 thorpej static int 619 1.78 dsl egintr(void *arg) 620 1.1 deraadt { 621 1.49 augustss struct eg_softc *sc = arg; 622 1.97 thorpej struct ifnet *ifp = &sc->sc_ethercom.ec_if; 623 1.32 thorpej bus_space_tag_t iot = sc->sc_iot; 624 1.32 thorpej bus_space_handle_t ioh = sc->sc_ioh; 625 1.27 thorpej int i, len, serviced; 626 1.100 thorpej uint16_t *ptr; 627 1.1 deraadt 628 1.27 thorpej serviced = 0; 629 1.27 thorpej 630 1.32 thorpej while (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_ACRF) { 631 1.40 drochner egreadPCB(iot, ioh, sc->eg_pcb); 632 1.2 mycroft switch (sc->eg_pcb[0]) { 633 1.1 deraadt case EG_RSP_RECVPACKET: 634 1.7 mycroft len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8); 635 1.65 perry 636 1.16 mycroft /* Set direction bit : Adapter -> host */ 637 1.32 thorpej bus_space_write_1(iot, ioh, EG_CONTROL, 638 1.65 perry bus_space_read_1(iot, ioh, EG_CONTROL) | EG_CTL_DIR); 639 1.16 mycroft 640 1.100 thorpej for (ptr = (uint16_t *) sc->eg_inbuf; 641 1.27 thorpej len > 0; len -= 2) { 642 1.32 thorpej while (!(bus_space_read_1(iot, ioh, EG_STATUS) & 643 1.27 thorpej EG_STAT_HRDY)) 644 1.1 deraadt ; 645 1.32 thorpej *ptr++ = bus_space_read_2(iot, ioh, EG_DATA); 646 1.1 deraadt } 647 1.16 mycroft 648 1.7 mycroft len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8); 649 1.1 deraadt egread(sc, sc->eg_inbuf, len); 650 1.16 mycroft 651 1.1 deraadt sc->eg_incount--; 652 1.16 mycroft egrecv(sc); 653 1.27 thorpej serviced = 1; 654 1.1 deraadt break; 655 1.1 deraadt 656 1.1 deraadt case EG_RSP_SENDPACKET: 657 1.1 deraadt if (sc->eg_pcb[6] || sc->eg_pcb[7]) { 658 1.29 christos DPRINTF(("%s: packet dropped\n", 659 1.85 chs device_xname(sc->sc_dev))); 660 1.97 thorpej if_statinc(ifp, if_oerrors); 661 1.2 mycroft } else 662 1.97 thorpej if_statinc(ifp, if_opackets); 663 1.97 thorpej if (sc->eg_pcb[8] & 0xf) 664 1.97 thorpej if_statadd(ifp, if_collisions, 665 1.97 thorpej sc->eg_pcb[8] & 0xf); 666 1.101 thorpej sc->eg_txbusy = false; 667 1.33 is egstart(&sc->sc_ethercom.ec_if); 668 1.27 thorpej serviced = 1; 669 1.1 deraadt break; 670 1.1 deraadt 671 1.27 thorpej /* XXX byte-order and type-size bugs here... */ 672 1.1 deraadt case EG_RSP_GETSTATS: 673 1.29 christos DPRINTF(("%s: Card Statistics\n", 674 1.85 chs device_xname(sc->sc_dev))); 675 1.54 thorpej memcpy(&i, &sc->eg_pcb[2], sizeof(i)); 676 1.29 christos DPRINTF(("Receive Packets %d\n", i)); 677 1.54 thorpej memcpy(&i, &sc->eg_pcb[6], sizeof(i)); 678 1.29 christos DPRINTF(("Transmit Packets %d\n", i)); 679 1.29 christos DPRINTF(("CRC errors %d\n", 680 1.27 thorpej *(short *) &sc->eg_pcb[10])); 681 1.29 christos DPRINTF(("alignment errors %d\n", 682 1.27 thorpej *(short *) &sc->eg_pcb[12])); 683 1.29 christos DPRINTF(("no resources errors %d\n", 684 1.27 thorpej *(short *) &sc->eg_pcb[14])); 685 1.29 christos DPRINTF(("overrun errors %d\n", 686 1.27 thorpej *(short *) &sc->eg_pcb[16])); 687 1.27 thorpej serviced = 1; 688 1.1 deraadt break; 689 1.65 perry 690 1.1 deraadt default: 691 1.30 christos printf("%s: egintr: Unknown response %x??\n", 692 1.85 chs device_xname(sc->sc_dev), sc->eg_pcb[0]); 693 1.40 drochner egprintpcb(sc->eg_pcb); 694 1.1 deraadt break; 695 1.1 deraadt } 696 1.37 explorer 697 1.37 explorer rnd_add_uint32(&sc->rnd_source, sc->eg_pcb[0]); 698 1.1 deraadt } 699 1.1 deraadt 700 1.27 thorpej return serviced; 701 1.1 deraadt } 702 1.1 deraadt 703 1.1 deraadt /* 704 1.1 deraadt * Pass a packet up to the higher levels. 705 1.1 deraadt */ 706 1.99 thorpej static void 707 1.78 dsl egread(struct eg_softc *sc, void *buf, int len) 708 1.1 deraadt { 709 1.33 is struct ifnet *ifp = &sc->sc_ethercom.ec_if; 710 1.1 deraadt struct mbuf *m; 711 1.65 perry 712 1.1 deraadt if (len <= sizeof(struct ether_header) || 713 1.1 deraadt len > ETHER_MAX_LEN) { 714 1.91 msaitoh aprint_error_dev(sc->sc_dev, 715 1.91 msaitoh "invalid packet size %d; dropping\n", len); 716 1.97 thorpej if_statinc(ifp, if_ierrors); 717 1.1 deraadt return; 718 1.1 deraadt } 719 1.1 deraadt 720 1.2 mycroft /* Pull packet off interface. */ 721 1.18 mycroft m = egget(sc, buf, len); 722 1.1 deraadt if (m == 0) { 723 1.97 thorpej if_statinc(ifp, if_ierrors); 724 1.1 deraadt return; 725 1.1 deraadt } 726 1.1 deraadt 727 1.89 ozaki if_percpuq_enqueue(ifp->if_percpuq, m); 728 1.1 deraadt } 729 1.1 deraadt 730 1.1 deraadt /* 731 1.1 deraadt * convert buf into mbufs 732 1.1 deraadt */ 733 1.99 thorpej static struct mbuf * 734 1.78 dsl egget(struct eg_softc *sc, void *buf, int totlen) 735 1.2 mycroft { 736 1.33 is struct ifnet *ifp = &sc->sc_ethercom.ec_if; 737 1.44 mycroft struct mbuf *m, *m0, *newm; 738 1.2 mycroft int len; 739 1.1 deraadt 740 1.44 mycroft MGETHDR(m0, M_DONTWAIT, MT_DATA); 741 1.44 mycroft if (m0 == 0) 742 1.44 mycroft return (0); 743 1.90 ozaki m_set_rcvif(m0, ifp); 744 1.44 mycroft m0->m_pkthdr.len = totlen; 745 1.2 mycroft len = MHLEN; 746 1.44 mycroft m = m0; 747 1.2 mycroft 748 1.2 mycroft while (totlen > 0) { 749 1.2 mycroft if (totlen >= MINCLSIZE) { 750 1.2 mycroft MCLGET(m, M_DONTWAIT); 751 1.44 mycroft if ((m->m_flags & M_EXT) == 0) 752 1.44 mycroft goto bad; 753 1.34 mycroft len = MCLBYTES; 754 1.2 mycroft } 755 1.44 mycroft 756 1.95 riastrad m->m_len = len = uimin(totlen, len); 757 1.72 christos memcpy(mtod(m, void *), buf, len); 758 1.72 christos buf = (char *)buf + len; 759 1.44 mycroft 760 1.2 mycroft totlen -= len; 761 1.44 mycroft if (totlen > 0) { 762 1.44 mycroft MGET(newm, M_DONTWAIT, MT_DATA); 763 1.44 mycroft if (newm == 0) 764 1.44 mycroft goto bad; 765 1.44 mycroft len = MLEN; 766 1.44 mycroft m = m->m_next = newm; 767 1.44 mycroft } 768 1.2 mycroft } 769 1.1 deraadt 770 1.44 mycroft return (m0); 771 1.44 mycroft 772 1.44 mycroft bad: 773 1.44 mycroft m_freem(m0); 774 1.44 mycroft return (0); 775 1.1 deraadt } 776 1.1 deraadt 777 1.99 thorpej static int 778 1.77 dyoung egioctl(struct ifnet *ifp, unsigned long cmd, void *data) 779 1.1 deraadt { 780 1.25 thorpej struct eg_softc *sc = ifp->if_softc; 781 1.18 mycroft struct ifaddr *ifa = (struct ifaddr *)data; 782 1.2 mycroft int s, error = 0; 783 1.2 mycroft 784 1.21 mycroft s = splnet(); 785 1.2 mycroft 786 1.18 mycroft switch (cmd) { 787 1.1 deraadt 788 1.77 dyoung case SIOCINITIFADDR: 789 1.1 deraadt ifp->if_flags |= IFF_UP; 790 1.2 mycroft 791 1.77 dyoung eginit(sc); 792 1.1 deraadt switch (ifa->ifa_addr->sa_family) { 793 1.1 deraadt #ifdef INET 794 1.1 deraadt case AF_INET: 795 1.33 is arp_ifinit(ifp, ifa); 796 1.1 deraadt break; 797 1.1 deraadt #endif 798 1.1 deraadt default: 799 1.1 deraadt break; 800 1.1 deraadt } 801 1.1 deraadt break; 802 1.2 mycroft 803 1.1 deraadt case SIOCSIFFLAGS: 804 1.77 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 805 1.77 dyoung break; 806 1.77 dyoung /* XXX re-use ether_ioctl() */ 807 1.77 dyoung switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) { 808 1.77 dyoung case IFF_RUNNING: 809 1.2 mycroft /* 810 1.2 mycroft * If interface is marked down and it is running, then 811 1.2 mycroft * stop it. 812 1.2 mycroft */ 813 1.2 mycroft egstop(sc); 814 1.1 deraadt ifp->if_flags &= ~IFF_RUNNING; 815 1.77 dyoung break; 816 1.77 dyoung case IFF_UP: 817 1.2 mycroft /* 818 1.2 mycroft * If interface is marked up and it is stopped, then 819 1.2 mycroft * start it. 820 1.2 mycroft */ 821 1.1 deraadt eginit(sc); 822 1.77 dyoung break; 823 1.77 dyoung default: 824 1.3 deraadt sc->eg_pcb[0] = EG_CMD_GETSTATS; 825 1.3 deraadt sc->eg_pcb[1] = 0; 826 1.69 christos if (egwritePCB(sc->sc_iot, sc->sc_ioh, sc->eg_pcb) != 0) { 827 1.29 christos DPRINTF(("write error\n")); 828 1.69 christos } 829 1.1 deraadt /* 830 1.1 deraadt * XXX deal with flags changes: 831 1.1 deraadt * IFF_MULTICAST, IFF_PROMISC, 832 1.1 deraadt * IFF_LINK0, IFF_LINK1, 833 1.1 deraadt */ 834 1.77 dyoung break; 835 1.1 deraadt } 836 1.1 deraadt break; 837 1.2 mycroft 838 1.1 deraadt default: 839 1.77 dyoung error = ether_ioctl(ifp, cmd, data); 840 1.18 mycroft break; 841 1.1 deraadt } 842 1.2 mycroft 843 1.2 mycroft splx(s); 844 1.2 mycroft return error; 845 1.1 deraadt } 846 1.1 deraadt 847 1.99 thorpej static void 848 1.78 dsl egreset(struct eg_softc *sc) 849 1.1 deraadt { 850 1.2 mycroft int s; 851 1.1 deraadt 852 1.85 chs DPRINTF(("%s: egreset()\n", device_xname(sc->sc_dev))); 853 1.21 mycroft s = splnet(); 854 1.2 mycroft egstop(sc); 855 1.2 mycroft eginit(sc); 856 1.2 mycroft splx(s); 857 1.1 deraadt } 858 1.1 deraadt 859 1.99 thorpej static void 860 1.78 dsl egwatchdog(struct ifnet *ifp) 861 1.1 deraadt { 862 1.25 thorpej struct eg_softc *sc = ifp->if_softc; 863 1.1 deraadt 864 1.85 chs log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); 865 1.97 thorpej if_statinc(ifp, if_oerrors); 866 1.1 deraadt 867 1.1 deraadt egreset(sc); 868 1.1 deraadt } 869 1.1 deraadt 870 1.99 thorpej static void 871 1.78 dsl egstop(struct eg_softc *sc) 872 1.1 deraadt { 873 1.65 perry 874 1.32 thorpej bus_space_write_1(sc->sc_iot, sc->sc_ioh, EG_CONTROL, 0); 875 1.1 deraadt } 876