1 /* $NetBSD: if_le_vme.c,v 1.13 2001/07/26 15:05:09 wiz Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 maximum entropy. All rights reserved. 5 * Copyright (c) 1997 Leo Weppelman. All rights reserved. 6 * Copyright (c) 1995 Charles M. Hannum. All rights reserved. 7 * Copyright (c) 1992, 1993 8 * The Regents of the University of California. All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Ralph Campbell and Rick Macklem. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * @(#)if_le.c 8.2 (Berkeley) 11/16/93 42 */ 43 44 #include "opt_inet.h" 45 #include "bpfilter.h" 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/mbuf.h> 50 #include <sys/syslog.h> 51 #include <sys/socket.h> 52 #include <sys/device.h> 53 54 #include <net/if.h> 55 #include <net/if_media.h> 56 #include <net/if_ether.h> 57 58 #ifdef INET 59 #include <netinet/in.h> 60 #include <netinet/if_inarp.h> 61 #endif 62 63 #include <machine/cpu.h> 64 #include <machine/bus.h> 65 #include <machine/iomap.h> 66 #include <machine/scu.h> 67 68 #include <atari/atari/device.h> 69 #include <atari/atari/intr.h> 70 71 #include <dev/ic/lancereg.h> 72 #include <dev/ic/lancevar.h> 73 #include <dev/ic/am7990reg.h> 74 #include <dev/ic/am7990var.h> 75 76 #include <atari/vme/vmevar.h> 77 #include <atari/vme/if_levar.h> 78 79 /* 80 * All cards except BVME410 have 64KB RAM. However.... On the Riebl cards the 81 * area between the offsets 0xee70-0xeec0 is used to store config data. 82 */ 83 struct le_addresses { 84 u_long reg_addr; 85 u_long mem_addr; 86 int irq; 87 int reg_size; 88 int mem_size; 89 int type_hint; 90 } lestd[] = { 91 { 0xfe00fff0, 0xfe010000, IRQUNK, 16, 64*1024, 92 LE_OLD_RIEBL|LE_NEW_RIEBL }, /* Riebl */ 93 { 0xffcffff0, 0xffcf0000, 5, 16, 64*1024, 94 LE_PAM }, /* PAM */ 95 { 0xfecffff0, 0xfecf0000, 5, 16, 64*1024, 96 LE_ROTHRON }, /* Rhotron */ 97 { 0xfeff4100, 0xfe000000, 4, 8, VMECF_MEMSIZ_DEFAULT, 98 LE_BVME410 } /* BVME410 */ 99 }; 100 101 #define NLESTD (sizeof(lestd) / sizeof(lestd[0])) 102 103 /* 104 * Default mac for RIEBL cards without a (working) battery. The first 4 bytes 105 * are the manufacturer id. 106 */ 107 static u_char riebl_def_mac[] = { 108 0x00, 0x00, 0x36, 0x04, 0x00, 0x00 109 }; 110 111 static int le_intr __P((struct le_softc *, int)); 112 static void lepseudointr __P((struct le_softc *, void *)); 113 static int le_vme_match __P((struct device *, struct cfdata *, void *)); 114 static void le_vme_attach __P((struct device *, struct device *, void *)); 115 static int probe_addresses __P((bus_space_tag_t *, bus_space_tag_t *, 116 bus_space_handle_t *, bus_space_handle_t *)); 117 static void riebl_skip_reserved_area __P((struct lance_softc *)); 118 static int nm93c06_read __P((bus_space_tag_t, bus_space_handle_t, int)); 119 static int bvme410_probe __P((bus_space_tag_t, bus_space_handle_t)); 120 static int bvme410_mem_size __P((bus_space_tag_t, u_long)); 121 static void bvme410_copytobuf __P((struct lance_softc *, void *, int, int)); 122 static void bvme410_zerobuf __P((struct lance_softc *, int, int)); 123 124 struct cfattach le_vme_ca = { 125 sizeof(struct le_softc), le_vme_match, le_vme_attach 126 }; 127 128 #if defined(_KERNEL_OPT) 129 #include "opt_ddb.h" 130 #endif 131 132 #ifdef DDB 133 #define integrate 134 #define hide 135 #else 136 #define integrate static __inline 137 #define hide static 138 #endif 139 140 hide void lewrcsr __P((struct lance_softc *, u_int16_t, u_int16_t)); 141 hide u_int16_t lerdcsr __P((struct lance_softc *, u_int16_t)); 142 143 hide void 144 lewrcsr(sc, port, val) 145 struct lance_softc *sc; 146 u_int16_t port, val; 147 { 148 struct le_softc *lesc = (struct le_softc *)sc; 149 int s; 150 151 s = splhigh(); 152 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port); 153 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP, val); 154 splx(s); 155 } 156 157 hide u_int16_t 158 lerdcsr(sc, port) 159 struct lance_softc *sc; 160 u_int16_t port; 161 { 162 struct le_softc *lesc = (struct le_softc *)sc; 163 u_int16_t val; 164 int s; 165 166 s = splhigh(); 167 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port); 168 val = bus_space_read_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP); 169 splx(s); 170 171 return (val); 172 } 173 174 static int 175 le_vme_match(parent, cfp, aux) 176 struct device *parent; 177 struct cfdata *cfp; 178 void *aux; 179 { 180 struct vme_attach_args *va = aux; 181 int i; 182 bus_space_tag_t iot; 183 bus_space_tag_t memt; 184 bus_space_handle_t ioh; 185 bus_space_handle_t memh; 186 187 iot = va->va_iot; 188 memt = va->va_memt; 189 190 for (i = 0; i < NLESTD; i++) { 191 struct le_addresses *le_ap = &lestd[i]; 192 int found = 0; 193 194 if ((va->va_iobase != IOBASEUNK) 195 && (va->va_iobase != le_ap->reg_addr)) 196 continue; 197 198 if ((va->va_maddr != MADDRUNK) 199 && (va->va_maddr != le_ap->mem_addr)) 200 continue; 201 202 if ((le_ap->irq != IRQUNK) && (va->va_irq != le_ap->irq)) 203 continue; 204 205 if (bus_space_map(iot, le_ap->reg_addr, le_ap->reg_size, 0, &ioh)) { 206 printf("leprobe: cannot map io-area\n"); 207 return (0); 208 } 209 if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) { 210 if (bvme410_probe(iot, ioh)) { 211 bus_space_write_2(iot, ioh, BVME410_BAR, 0x1); /* XXX */ 212 le_ap->mem_size = bvme410_mem_size(memt, le_ap->mem_addr); 213 } 214 } 215 if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) { 216 bus_space_unmap(iot, ioh, le_ap->reg_size); 217 continue; 218 } 219 220 if (bus_space_map(memt, le_ap->mem_addr, le_ap->mem_size, 0, &memh)) { 221 bus_space_unmap(iot, ioh, le_ap->reg_size); 222 printf("leprobe: cannot map memory-area\n"); 223 return (0); 224 } 225 found = probe_addresses(&iot, &memt, &ioh, &memh); 226 bus_space_unmap(iot, ioh, le_ap->reg_size); 227 bus_space_unmap(memt, memh, le_ap->mem_size); 228 229 if (found) { 230 va->va_iobase = le_ap->reg_addr; 231 va->va_iosize = le_ap->reg_size; 232 va->va_maddr = le_ap->mem_addr; 233 va->va_msize = le_ap->mem_size; 234 va->va_aux = le_ap; 235 if (va->va_irq == IRQUNK) 236 va->va_irq = le_ap->irq; 237 return 1; 238 } 239 } 240 return (0); 241 } 242 243 static int 244 probe_addresses(iot, memt, ioh, memh) 245 bus_space_tag_t *iot; 246 bus_space_tag_t *memt; 247 bus_space_handle_t *ioh; 248 bus_space_handle_t *memh; 249 { 250 /* 251 * Test accesibility of register and memory area 252 */ 253 if(!bus_space_peek_2(*iot, *ioh, LER_RDP)) 254 return 0; 255 if(!bus_space_peek_1(*memt, *memh, 0)) 256 return 0; 257 258 /* 259 * Test for writable memory 260 */ 261 bus_space_write_2(*memt, *memh, 0, 0xa5a5); 262 if (bus_space_read_2(*memt, *memh, 0) != 0xa5a5) 263 return 0; 264 265 /* 266 * Test writability of selector port. 267 */ 268 bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR1); 269 if (bus_space_read_2(*iot, *ioh, LER_RAP) != LE_CSR1) 270 return 0; 271 272 /* 273 * Do a small register test 274 */ 275 bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR0); 276 bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_INIT | LE_C0_STOP); 277 if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP) 278 return 0; 279 280 bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_STOP); 281 if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP) 282 return 0; 283 284 return 1; 285 } 286 287 /* 288 * Interrupt mess. Because the card's interrupt is hardwired to either 289 * ipl5 or ipl3 (mostly on ipl5) and raising splnet to spl5() just won't do 290 * (it kills the serial at the least), we use a 2-level interrupt scheme. The 291 * card interrupt is routed to 'le_intr'. If the previous ipl was below 292 * splnet, just call the mi-function. If not, save the interrupt status, 293 * turn off card interrupts (the card is *very* persistent) and arrange 294 * for a softint 'callback' through 'lepseudointr'. 295 */ 296 static int 297 le_intr(lesc, sr) 298 struct le_softc *lesc; 299 int sr; 300 { 301 struct lance_softc *sc = &lesc->sc_am7990.lsc; 302 u_int16_t csr0; 303 304 if ((sr & PSL_IPL) < (IPL_NET & PSL_IPL)) 305 am7990_intr(sc); 306 else { 307 sc->sc_saved_csr0 = csr0 = lerdcsr(sc, LE_CSR0); 308 lewrcsr(sc, LE_CSR0, csr0 & ~LE_C0_INEA); 309 add_sicallback((si_farg)lepseudointr, lesc, sc); 310 } 311 return 1; 312 } 313 314 315 static void 316 lepseudointr(lesc, sc) 317 struct le_softc *lesc; 318 void *sc; 319 { 320 int s; 321 322 s = splx(lesc->sc_splval); 323 am7990_intr(sc); 324 splx(s); 325 } 326 327 static void 328 le_vme_attach(parent, self, aux) 329 struct device *parent, *self; 330 void *aux; 331 { 332 struct le_softc *lesc = (struct le_softc *)self; 333 struct lance_softc *sc = &lesc->sc_am7990.lsc; 334 struct vme_attach_args *va = aux; 335 bus_space_handle_t ioh; 336 bus_space_handle_t memh; 337 struct le_addresses *le_ap; 338 int i; 339 340 printf("\n%s: ", sc->sc_dev.dv_xname); 341 342 if (bus_space_map(va->va_iot, va->va_iobase, va->va_iosize, 0, &ioh)) 343 panic("leattach: cannot map io-area\n"); 344 if (bus_space_map(va->va_memt, va->va_maddr, va->va_msize, 0, &memh)) 345 panic("leattach: cannot map mem-area\n"); 346 347 lesc->sc_iot = va->va_iot; 348 lesc->sc_ioh = ioh; 349 lesc->sc_memt = va->va_memt; 350 lesc->sc_memh = memh; 351 lesc->sc_splval = (va->va_irq << 8) | PSL_S; /* XXX */ 352 le_ap = (struct le_addresses *)va->va_aux; 353 354 /* 355 * Go on to find board type 356 */ 357 if ((le_ap->type_hint & LE_PAM) 358 && bus_space_peek_1(va->va_iot, ioh, LER_EEPROM)) { 359 printf("PAM card"); 360 lesc->sc_type = LE_PAM; 361 bus_space_read_1(va->va_iot, ioh, LER_MEME); 362 } 363 else if((le_ap->type_hint & LE_BVME410) 364 && bvme410_probe(va->va_iot, ioh)) { 365 printf("BVME410"); 366 lesc->sc_type = LE_BVME410; 367 } 368 else if (le_ap->type_hint & (LE_NEW_RIEBL|LE_OLD_RIEBL)) { 369 printf("Riebl card"); 370 if(bus_space_read_4(va->va_memt, memh, RIEBL_MAGIC_ADDR) 371 == RIEBL_MAGIC) 372 lesc->sc_type = LE_NEW_RIEBL; 373 else { 374 printf("(without battery) "); 375 lesc->sc_type = LE_OLD_RIEBL; 376 } 377 } 378 else printf("le_vme_attach: Unsupported card!"); 379 380 switch (lesc->sc_type) { 381 case LE_BVME410: 382 sc->sc_copytodesc = bvme410_copytobuf; 383 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 384 sc->sc_copytobuf = bvme410_copytobuf; 385 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 386 sc->sc_zerobuf = bvme410_zerobuf; 387 break; 388 default: 389 sc->sc_copytodesc = lance_copytobuf_contig; 390 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 391 sc->sc_copytobuf = lance_copytobuf_contig; 392 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 393 sc->sc_zerobuf = lance_zerobuf_contig; 394 break; 395 } 396 397 sc->sc_rdcsr = lerdcsr; 398 sc->sc_wrcsr = lewrcsr; 399 sc->sc_hwinit = NULL; 400 sc->sc_conf3 = LE_C3_BSWP; 401 sc->sc_addr = 0; 402 sc->sc_memsize = va->va_msize; 403 sc->sc_mem = (void *)memh; /* XXX */ 404 405 /* 406 * Get MAC address 407 */ 408 switch (lesc->sc_type) { 409 case LE_OLD_RIEBL: 410 bcopy(riebl_def_mac, sc->sc_enaddr, 411 sizeof(sc->sc_enaddr)); 412 break; 413 case LE_NEW_RIEBL: 414 for (i = 0; i < sizeof(sc->sc_enaddr); i++) 415 sc->sc_enaddr[i] = 416 bus_space_read_1(va->va_memt, memh, i + RIEBL_MAC_ADDR); 417 break; 418 case LE_PAM: 419 i = bus_space_read_1(va->va_iot, ioh, LER_EEPROM); 420 for (i = 0; i < sizeof(sc->sc_enaddr); i++) { 421 sc->sc_enaddr[i] = 422 (bus_space_read_2(va->va_memt, memh, 2 * i) << 4) | 423 (bus_space_read_2(va->va_memt, memh, 2 * i + 1) & 0xf); 424 } 425 i = bus_space_read_1(va->va_iot, ioh, LER_MEME); 426 break; 427 case LE_BVME410: 428 for (i = 0; i < (sizeof(sc->sc_enaddr) >> 1); i++) { 429 u_int16_t tmp; 430 431 tmp = nm93c06_read(va->va_iot, ioh, i); 432 sc->sc_enaddr[2 * i] = (tmp >> 8) & 0xff; 433 sc->sc_enaddr[2 * i + 1] = tmp & 0xff; 434 } 435 bus_space_write_2(va->va_iot, ioh, BVME410_BAR, 0x1); /* XXX */ 436 } 437 438 am7990_config(&lesc->sc_am7990); 439 440 if ((lesc->sc_type == LE_OLD_RIEBL) || (lesc->sc_type == LE_NEW_RIEBL)) 441 riebl_skip_reserved_area(sc); 442 443 /* 444 * XXX: We always use uservector 64.... 445 */ 446 if ((lesc->sc_intr = intr_establish(64, USER_VEC, 0, 447 (hw_ifun_t)le_intr, lesc)) == NULL) { 448 printf("le_vme_attach: Can't establish interrupt\n"); 449 return; 450 } 451 452 /* 453 * Notify the card of the vector 454 */ 455 switch (lesc->sc_type) { 456 case LE_OLD_RIEBL: 457 case LE_NEW_RIEBL: 458 bus_space_write_2(va->va_memt, memh, RIEBL_IVEC_ADDR, 459 64 + 64); 460 break; 461 case LE_PAM: 462 bus_space_write_1(va->va_iot, ioh, LER_IVEC, 64 + 64); 463 break; 464 case LE_BVME410: 465 bus_space_write_2(va->va_iot, ioh, BVME410_IVEC, 64 + 64); 466 break; 467 } 468 469 /* 470 * Unmask the VME-interrupt we're on 471 */ 472 if (machineid & ATARI_TT) 473 SCU->vme_mask |= 1 << va->va_irq; 474 } 475 476 /* 477 * True if 'addr' containe within [start,len] 478 */ 479 #define WITHIN(start, len, addr) \ 480 ((addr >= start) && ((addr) <= ((start) + (len)))) 481 static void 482 riebl_skip_reserved_area(sc) 483 struct lance_softc *sc; 484 { 485 int offset = 0; 486 int i; 487 488 for(i = 0; i < sc->sc_nrbuf; i++) { 489 if (WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_START) 490 || WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_END)) { 491 offset = RIEBL_RES_END - sc->sc_rbufaddr[i]; 492 } 493 sc->sc_rbufaddr[i] += offset; 494 } 495 496 for(i = 0; i < sc->sc_ntbuf; i++) { 497 if (WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_START) 498 || WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_END)) { 499 offset = RIEBL_RES_END - sc->sc_tbufaddr[i]; 500 } 501 sc->sc_tbufaddr[i] += offset; 502 } 503 } 504 505 static int 506 nm93c06_read(iot, ioh, nm93c06reg) 507 bus_space_tag_t iot; 508 bus_space_handle_t ioh; 509 int nm93c06reg; 510 { 511 int bar; 512 int shift; 513 int bits = 0x180 | (nm93c06reg & 0xf); 514 int data = 0; 515 516 bar = 1<<BVME410_CS_SHIFT; 517 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 518 delay(1); /* tCSS = 1 us */ 519 for (shift = 9; shift >= 0; shift--) { 520 if (((bits >> shift) & 1) == 1) 521 bar |= 1<<BVME410_DIN_SHIFT; 522 else 523 bar &= ~(1<<BVME410_DIN_SHIFT); 524 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 525 delay(1); /* tDIS = 0.4 us */ 526 bar |= 1<<BVME410_CLK_SHIFT; 527 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 528 delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */ 529 bar &= ~(1<<BVME410_CLK_SHIFT); 530 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 531 delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */ 532 } 533 bar &= ~(1<<BVME410_DIN_SHIFT); 534 for (shift = 15; shift >= 0; shift--) { 535 delay(1); /* tDIS = 100 ns, BVM manual says 0.4 us */ 536 bar |= 1<<BVME410_CLK_SHIFT; 537 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 538 delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */ 539 data |= (bus_space_read_2(iot, ioh, BVME410_BAR) & 1) << shift; 540 bar &= ~(1<<BVME410_CLK_SHIFT); 541 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 542 delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */ 543 } 544 bar &= ~(1<<BVME410_CS_SHIFT); 545 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 546 delay(1); /* tCS = 1 us */ 547 return data; 548 } 549 550 static int 551 bvme410_probe(iot, ioh) 552 bus_space_tag_t iot; 553 bus_space_handle_t ioh; 554 { 555 if (!bus_space_peek_2(iot, ioh, BVME410_IVEC)) 556 return 0; 557 558 bus_space_write_2(iot, ioh, BVME410_IVEC, 0x0000); 559 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xff00) 560 return 0; 561 562 bus_space_write_2(iot, ioh, BVME410_IVEC, 0xffff); 563 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffff) 564 return 0; 565 566 bus_space_write_2(iot, ioh, BVME410_IVEC, 0xa5a5); 567 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffa5) 568 return 0; 569 570 return 1; 571 } 572 573 static int 574 bvme410_mem_size(memt, mem_addr) 575 bus_space_tag_t memt; 576 u_long mem_addr; 577 { 578 bus_space_handle_t memh; 579 int r; 580 581 if (bus_space_map(memt, mem_addr, 256*1024, 0, &memh)) 582 return VMECF_MEMSIZ_DEFAULT; 583 if (!bus_space_peek_1(memt, memh, 0)) { 584 bus_space_unmap(memt, memh, 256*1024); 585 return VMECF_MEMSIZ_DEFAULT; 586 } 587 bus_space_write_1(memt, memh, 0, 128); 588 bus_space_write_1(memt, memh, 64*1024, 32); 589 bus_space_write_1(memt, memh, 32*1024, 8); 590 r = (int)(bus_space_read_1(memt, memh, 0) * 2048); 591 bus_space_unmap(memt, memh, 256*1024); 592 return r; 593 } 594 595 /* 596 * Need to be careful when writing to the bvme410 dual port memory. 597 * Continue writing each byte until it reads back the same. 598 */ 599 600 static void 601 bvme410_copytobuf(sc, from, boff, len) 602 struct lance_softc *sc; 603 void *from; 604 int boff, len; 605 { 606 volatile char *buf = (volatile char *) sc->sc_mem; 607 char *f = (char *) from; 608 609 for (buf += boff; len; buf++,f++,len--) 610 do { 611 *buf = *f; 612 } while (*buf != *f); 613 } 614 615 static void 616 bvme410_zerobuf(sc, boff, len) 617 struct lance_softc *sc; 618 int boff, len; 619 { 620 volatile char *buf = (volatile char *)sc->sc_mem; 621 622 for (buf += boff; len; buf++,len--) 623 do { 624 *buf = '\0'; 625 } while (*buf != '\0'); 626 } 627 628