if_ed_hpp.c revision 154894
1219393Sadrian/*- 2219393Sadrian * Copyright (c) 2005, M. Warner Losh 3219393Sadrian * All rights reserved. 4219393Sadrian * Copyright (c) 1995, David Greenman 5219393Sadrian * All rights reserved. 6219393Sadrian * 7219393Sadrian * Redistribution and use in source and binary forms, with or without 8219393Sadrian * modification, are permitted provided that the following conditions 9219393Sadrian * are met: 10219393Sadrian * 1. Redistributions of source code must retain the above copyright 11219393Sadrian * notice unmodified, this list of conditions, and the following 12219393Sadrian * disclaimer. 13219393Sadrian * 2. Redistributions in binary form must reproduce the above copyright 14219393Sadrian * notice, this list of conditions and the following disclaimer in the 15219393Sadrian * documentation and/or other materials provided with the distribution. 16219393Sadrian * 17219393Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219393Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219393Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219393Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219393Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219393Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219393Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219393Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219393Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219393Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219393Sadrian * SUCH DAMAGE. 28219393Sadrian */ 29219393Sadrian 30219393Sadrian#include <sys/cdefs.h> 31219393Sadrian__FBSDID("$FreeBSD: head/sys/dev/ed/if_ed_hpp.c 154894 2006-01-27 08:10:36Z imp $"); 32219393Sadrian 33219393Sadrian#include "opt_ed.h" 34219393Sadrian 35219393Sadrian#ifdef ED_HPP 36219393Sadrian 37219393Sadrian#include <sys/param.h> 38219393Sadrian#include <sys/systm.h> 39219393Sadrian#include <sys/sockio.h> 40219393Sadrian#include <sys/mbuf.h> 41219393Sadrian#include <sys/kernel.h> 42219393Sadrian#include <sys/socket.h> 43219393Sadrian#include <sys/syslog.h> 44219393Sadrian 45220590Sadrian#include <sys/bus.h> 46220590Sadrian 47219393Sadrian#include <machine/bus.h> 48219393Sadrian#include <sys/rman.h> 49219393Sadrian#include <machine/resource.h> 50219393Sadrian 51219393Sadrian#include <net/ethernet.h> 52220590Sadrian#include <net/if.h> 53220590Sadrian#include <net/if_arp.h> 54220590Sadrian#include <net/if_dl.h> 55220590Sadrian#include <net/if_mib.h> 56220590Sadrian#include <net/if_media.h> 57219393Sadrian 58#include <net/bpf.h> 59 60#include <dev/ed/if_edreg.h> 61#include <dev/ed/if_edvar.h> 62 63static void ed_hpp_writemem(struct ed_softc *, uint8_t *, uint16_t, 64 uint16_t); 65 66/* 67 * Interrupt conversion table for the HP PC LAN+ 68 */ 69static uint16_t ed_hpp_intr_val[] = { 70 0, /* 0 */ 71 0, /* 1 */ 72 0, /* 2 */ 73 3, /* 3 */ 74 4, /* 4 */ 75 5, /* 5 */ 76 6, /* 6 */ 77 7, /* 7 */ 78 0, /* 8 */ 79 9, /* 9 */ 80 10, /* 10 */ 81 11, /* 11 */ 82 12, /* 12 */ 83 0, /* 13 */ 84 0, /* 14 */ 85 15 /* 15 */ 86}; 87 88#define ED_HPP_TEST_SIZE 16 89 90/* 91 * Probe and vendor specific initialization for the HP PC Lan+ Cards. 92 * (HP Part nos: 27247B and 27252A). 93 * 94 * The card has an asic wrapper around a DS8390 core. The asic handles 95 * host accesses and offers both standard register IO and memory mapped 96 * IO. Memory mapped I/O allows better performance at the expense of greater 97 * chance of an incompatibility with existing ISA cards. 98 * 99 * The card has a few caveats: it isn't tolerant of byte wide accesses, only 100 * short (16 bit) or word (32 bit) accesses are allowed. Some card revisions 101 * don't allow 32 bit accesses; these are indicated by a bit in the software 102 * ID register (see if_edreg.h). 103 * 104 * Other caveats are: we should read the MAC address only when the card 105 * is inactive. 106 * 107 * For more information; please consult the CRYNWR packet driver. 108 * 109 * The AUI port is turned on using the "link2" option on the ifconfig 110 * command line. 111 */ 112int 113ed_probe_HP_pclanp(device_t dev, int port_rid, int flags) 114{ 115 struct ed_softc *sc = device_get_softc(dev); 116 int error; 117 int n; /* temp var */ 118 int memsize; /* mem on board */ 119 u_char checksum; /* checksum of board address */ 120 u_char irq; /* board configured IRQ */ 121 uint8_t test_pattern[ED_HPP_TEST_SIZE]; /* read/write areas for */ 122 uint8_t test_buffer[ED_HPP_TEST_SIZE]; /* probing card */ 123 u_long conf_maddr, conf_msize, conf_irq, junk; 124 125 error = ed_alloc_port(dev, 0, ED_HPP_IO_PORTS); 126 if (error) 127 return (error); 128 129 /* Fill in basic information */ 130 sc->asic_offset = ED_HPP_ASIC_OFFSET; 131 sc->nic_offset = ED_HPP_NIC_OFFSET; 132 133 sc->chip_type = ED_CHIP_TYPE_DP8390; 134 sc->isa16bit = 0; /* the 8390 core needs to be in byte mode */ 135 136 /* 137 * Look for the HP PCLAN+ signature: "0x50,0x48,0x00,0x53" 138 */ 139 140 if ((ed_asic_inb(sc, ED_HPP_ID) != 0x50) || 141 (ed_asic_inb(sc, ED_HPP_ID + 1) != 0x48) || 142 ((ed_asic_inb(sc, ED_HPP_ID + 2) & 0xF0) != 0) || 143 (ed_asic_inb(sc, ED_HPP_ID + 3) != 0x53)) 144 return (ENXIO); 145 146 /* 147 * Read the MAC address and verify checksum on the address. 148 */ 149 150 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_MAC); 151 for (n = 0, checksum = 0; n < ETHER_ADDR_LEN; n++) 152 checksum += (sc->enaddr[n] = 153 ed_asic_inb(sc, ED_HPP_MAC_ADDR + n)); 154 155 checksum += ed_asic_inb(sc, ED_HPP_MAC_ADDR + ETHER_ADDR_LEN); 156 157 if (checksum != 0xFF) 158 return (ENXIO); 159 160 /* 161 * Verify that the software model number is 0. 162 */ 163 164 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_ID); 165 if (((sc->hpp_id = ed_asic_inw(sc, ED_HPP_PAGE_4)) & 166 ED_HPP_ID_SOFT_MODEL_MASK) != 0x0000) 167 return (ENXIO); 168 169 /* 170 * Read in and save the current options configured on card. 171 */ 172 173 sc->hpp_options = ed_asic_inw(sc, ED_HPP_OPTION); 174 175 sc->hpp_options |= (ED_HPP_OPTION_NIC_RESET | 176 ED_HPP_OPTION_CHIP_RESET | ED_HPP_OPTION_ENABLE_IRQ); 177 178 /* 179 * Reset the chip. This requires writing to the option register 180 * so take care to preserve the other bits. 181 */ 182 183 ed_asic_outw(sc, ED_HPP_OPTION, 184 (sc->hpp_options & ~(ED_HPP_OPTION_NIC_RESET | 185 ED_HPP_OPTION_CHIP_RESET))); 186 187 DELAY(5000); /* wait for chip reset to complete */ 188 189 ed_asic_outw(sc, ED_HPP_OPTION, 190 (sc->hpp_options | (ED_HPP_OPTION_NIC_RESET | 191 ED_HPP_OPTION_CHIP_RESET | 192 ED_HPP_OPTION_ENABLE_IRQ))); 193 194 DELAY(5000); 195 196 if (!(ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST)) 197 return (ENXIO); /* reset did not complete */ 198 199 /* 200 * Read out configuration information. 201 */ 202 203 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); 204 205 irq = ed_asic_inb(sc, ED_HPP_HW_IRQ); 206 207 /* 208 * Check for impossible IRQ. 209 */ 210 211 if (irq >= (sizeof(ed_hpp_intr_val) / sizeof(ed_hpp_intr_val[0]))) 212 return (ENXIO); 213 214 /* 215 * If the kernel IRQ was specified with a '?' use the cards idea 216 * of the IRQ. If the kernel IRQ was explicitly specified, it 217 * should match that of the hardware. 218 */ 219 error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk); 220 if (error) 221 bus_set_resource(dev, SYS_RES_IRQ, 0, ed_hpp_intr_val[irq], 1); 222 else { 223 if (conf_irq != ed_hpp_intr_val[irq]) 224 return (ENXIO); 225 } 226 227 /* 228 * Fill in softconfig info. 229 */ 230 231 sc->vendor = ED_VENDOR_HP; 232 sc->type = ED_TYPE_HP_PCLANPLUS; 233 sc->type_str = "HP-PCLAN+"; 234 235 sc->mem_shared = 0; /* we DON'T have dual ported RAM */ 236 sc->mem_start = 0; /* we use offsets inside the card RAM */ 237 238 sc->hpp_mem_start = NULL;/* no memory mapped I/O by default */ 239 240 /* 241 * The board has 32KB of memory. Is there a way to determine 242 * this programmatically? 243 */ 244 245 memsize = 32768; 246 247 /* 248 * Check if memory mapping of the I/O registers possible. 249 */ 250 if (sc->hpp_options & ED_HPP_OPTION_MEM_ENABLE) { 251 u_long mem_addr; 252 253 /* 254 * determine the memory address from the board. 255 */ 256 257 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); 258 mem_addr = (ed_asic_inw(sc, ED_HPP_HW_MEM_MAP) << 8); 259 260 /* 261 * Check that the kernel specified start of memory and 262 * hardware's idea of it match. 263 */ 264 error = bus_get_resource(dev, SYS_RES_MEMORY, 0, 265 &conf_maddr, &conf_msize); 266 if (error) 267 return (error); 268 269 if (mem_addr != conf_maddr) 270 return (ENXIO); 271 272 error = ed_alloc_memory(dev, 0, memsize); 273 if (error) 274 return (error); 275 276 sc->hpp_mem_start = rman_get_virtual(sc->mem_res); 277 } 278 279 /* 280 * Fill in the rest of the soft config structure. 281 */ 282 283 /* 284 * The transmit page index. 285 */ 286 287 sc->tx_page_start = ED_HPP_TX_PAGE_OFFSET; 288 289 if (device_get_flags(dev) & ED_FLAGS_NO_MULTI_BUFFERING) 290 sc->txb_cnt = 1; 291 else 292 sc->txb_cnt = 2; 293 294 /* 295 * Memory description 296 */ 297 298 sc->mem_size = memsize; 299 sc->mem_ring = sc->mem_start + 300 (sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE); 301 sc->mem_end = sc->mem_start + sc->mem_size; 302 303 /* 304 * Receive area starts after the transmit area and 305 * continues till the end of memory. 306 */ 307 308 sc->rec_page_start = sc->tx_page_start + 309 (sc->txb_cnt * ED_TXBUF_SIZE); 310 sc->rec_page_stop = (sc->mem_size / ED_PAGE_SIZE); 311 312 313 sc->cr_proto = 0; /* value works */ 314 315 /* 316 * Set the wrap registers for string I/O reads. 317 */ 318 319 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); 320 ed_asic_outw(sc, ED_HPP_HW_WRAP, 321 ((sc->rec_page_start / ED_PAGE_SIZE) | 322 (((sc->rec_page_stop / ED_PAGE_SIZE) - 1) << 8))); 323 324 /* 325 * Reset the register page to normal operation. 326 */ 327 328 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_PERF); 329 330 /* 331 * Verify that we can read/write from adapter memory. 332 * Create test pattern. 333 */ 334 335 for (n = 0; n < ED_HPP_TEST_SIZE; n++) 336 test_pattern[n] = (n*n) ^ ~n; 337 338#undef ED_HPP_TEST_SIZE 339 340 /* 341 * Check that the memory is accessible thru the I/O ports. 342 * Write out the contents of "test_pattern", read back 343 * into "test_buffer" and compare the two for any 344 * mismatch. 345 */ 346 347 for (n = 0; n < (32768 / ED_PAGE_SIZE); n ++) { 348 ed_hpp_writemem(sc, test_pattern, (n * ED_PAGE_SIZE), 349 sizeof(test_pattern)); 350 ed_hpp_readmem(sc, (n * ED_PAGE_SIZE), 351 test_buffer, sizeof(test_pattern)); 352 353 if (bcmp(test_pattern, test_buffer, 354 sizeof(test_pattern))) 355 return (ENXIO); 356 } 357 358 return (0); 359} 360 361/* 362 * HP PC Lan+ : Set the physical link to use AUI or TP/TL. 363 */ 364 365void 366ed_hpp_set_physical_link(struct ed_softc *sc) 367{ 368 struct ifnet *ifp = sc->ifp; 369 int lan_page; 370 371 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); 372 lan_page = ed_asic_inw(sc, ED_HPP_PAGE_0); 373 374 if (ifp->if_flags & IFF_LINK2) { 375 /* 376 * Use the AUI port. 377 */ 378 379 lan_page |= ED_HPP_LAN_AUI; 380 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); 381 ed_asic_outw(sc, ED_HPP_PAGE_0, lan_page); 382 } else { 383 /* 384 * Use the ThinLan interface 385 */ 386 387 lan_page &= ~ED_HPP_LAN_AUI; 388 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); 389 ed_asic_outw(sc, ED_HPP_PAGE_0, lan_page); 390 } 391 392 /* 393 * Wait for the lan card to re-initialize itself 394 */ 395 DELAY(150000); /* wait 150 ms */ 396 397 /* 398 * Restore normal pages. 399 */ 400 ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_PERF); 401} 402 403/* 404 * Support routines to handle the HP PC Lan+ card. 405 */ 406 407/* 408 * HP PC Lan+: Read from NIC memory, using either PIO or memory mapped 409 * IO. 410 */ 411 412void 413ed_hpp_readmem(struct ed_softc *sc, bus_size_t src, uint8_t *dst, 414 uint16_t amount) 415{ 416 int use_32bit_access = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS); 417 418 /* Program the source address in RAM */ 419 ed_asic_outw(sc, ED_HPP_PAGE_2, src); 420 421 /* 422 * The HP PC Lan+ card supports word reads as well as 423 * a memory mapped i/o port that is aliased to every 424 * even address on the board. 425 */ 426 if (sc->hpp_mem_start) { 427 /* Enable memory mapped access. */ 428 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & 429 ~(ED_HPP_OPTION_MEM_DISABLE | 430 ED_HPP_OPTION_BOOT_ROM_ENB)); 431 432 if (use_32bit_access && (amount > 3)) { 433 uint32_t *dl = (uint32_t *) dst; 434 volatile uint32_t *const sl = 435 (uint32_t *) sc->hpp_mem_start; 436 uint32_t *const fence = dl + (amount >> 2); 437 438 /* 439 * Copy out NIC data. We could probably write this 440 * as a `movsl'. The currently generated code is lousy. 441 */ 442 while (dl < fence) 443 *dl++ = *sl; 444 445 dst += (amount & ~3); 446 amount &= 3; 447 448 } 449 450 /* Finish off any words left, as a series of short reads */ 451 if (amount > 1) { 452 u_short *d = (u_short *) dst; 453 volatile u_short *const s = 454 (u_short *) sc->hpp_mem_start; 455 u_short *const fence = d + (amount >> 1); 456 457 /* Copy out NIC data. */ 458 while (d < fence) 459 *d++ = *s; 460 461 dst += (amount & ~1); 462 amount &= 1; 463 } 464 465 /* 466 * read in a byte; however we need to always read 16 bits 467 * at a time or the hardware gets into a funny state 468 */ 469 470 if (amount == 1) { 471 /* need to read in a short and copy LSB */ 472 volatile u_short *const s = 473 (volatile u_short *) sc->hpp_mem_start; 474 *dst = (*s) & 0xFF; 475 } 476 477 /* Restore Boot ROM access. */ 478 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); 479 } else { 480 /* Read in data using the I/O port */ 481 if (use_32bit_access && (amount > 3)) { 482 ed_asic_insl(sc, ED_HPP_PAGE_4, dst, amount >> 2); 483 dst += (amount & ~3); 484 amount &= 3; 485 } 486 if (amount > 1) { 487 ed_asic_insw(sc, ED_HPP_PAGE_4, dst, amount >> 1); 488 dst += (amount & ~1); 489 amount &= 1; 490 } 491 if (amount == 1) { /* read in a short and keep the LSB */ 492 *dst = ed_asic_inw(sc, ED_HPP_PAGE_4) & 0xFF; 493 } 494 } 495} 496 497/* 498 * HP PC Lan+: Write to NIC memory, using either PIO or memory mapped 499 * IO. 500 * Only used in the probe routine to test the memory. 'len' must 501 * be even. 502 */ 503static void 504ed_hpp_writemem(struct ed_softc *sc, uint8_t *src, uint16_t dst, uint16_t len) 505{ 506 /* reset remote DMA complete flag */ 507 ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RDC); 508 509 /* program the write address in RAM */ 510 ed_asic_outw(sc, ED_HPP_PAGE_0, dst); 511 512 if (sc->hpp_mem_start) { 513 u_short *s = (u_short *) src; 514 volatile u_short *d = (u_short *) sc->hpp_mem_start; 515 u_short *const fence = s + (len >> 1); 516 517 /* 518 * Enable memory mapped access. 519 */ 520 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & 521 ~(ED_HPP_OPTION_MEM_DISABLE | 522 ED_HPP_OPTION_BOOT_ROM_ENB)); 523 524 /* 525 * Copy to NIC memory. 526 */ 527 while (s < fence) 528 *d = *s++; 529 530 /* 531 * Restore Boot ROM access. 532 */ 533 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); 534 } else { 535 /* write data using I/O writes */ 536 ed_asic_outsw(sc, ED_HPP_PAGE_4, src, len / 2); 537 } 538} 539 540/* 541 * Write to HP PC Lan+ NIC memory. Access to the NIC can be by using 542 * outsw() or via the memory mapped interface to the same register. 543 * Writes have to be in word units; byte accesses won't work and may cause 544 * the NIC to behave weirdly. Long word accesses are permitted if the ASIC 545 * allows it. 546 */ 547 548u_short 549ed_hpp_write_mbufs(struct ed_softc *sc, struct mbuf *m, int dst) 550{ 551 int len, wantbyte; 552 unsigned short total_len; 553 unsigned char savebyte[2]; 554 volatile u_short * const d = 555 (volatile u_short *) sc->hpp_mem_start; 556 int use_32bit_accesses = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS); 557 558 /* select page 0 registers */ 559 ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_STA); 560 561 /* reset remote DMA complete flag */ 562 ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RDC); 563 564 /* program the write address in RAM */ 565 ed_asic_outw(sc, ED_HPP_PAGE_0, dst); 566 567 if (sc->hpp_mem_start) /* enable memory mapped I/O */ 568 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & 569 ~(ED_HPP_OPTION_MEM_DISABLE | 570 ED_HPP_OPTION_BOOT_ROM_ENB)); 571 572 wantbyte = 0; 573 total_len = 0; 574 575 if (sc->hpp_mem_start) { /* Memory mapped I/O port */ 576 while (m) { 577 total_len += (len = m->m_len); 578 if (len) { 579 caddr_t data = mtod(m, caddr_t); 580 /* finish the last word of the previous mbuf */ 581 if (wantbyte) { 582 savebyte[1] = *data; 583 *d = *((u_short *) savebyte); 584 data++; len--; wantbyte = 0; 585 } 586 /* output contiguous words */ 587 if ((len > 3) && (use_32bit_accesses)) { 588 volatile uint32_t *const dl = 589 (volatile uint32_t *) d; 590 uint32_t *sl = (uint32_t *) data; 591 uint32_t *fence = sl + (len >> 2); 592 593 while (sl < fence) 594 *dl = *sl++; 595 596 data += (len & ~3); 597 len &= 3; 598 } 599 /* finish off remain 16 bit writes */ 600 if (len > 1) { 601 u_short *s = (u_short *) data; 602 u_short *fence = s + (len >> 1); 603 604 while (s < fence) 605 *d = *s++; 606 607 data += (len & ~1); 608 len &= 1; 609 } 610 /* save last byte if needed */ 611 if ((wantbyte = (len == 1)) != 0) 612 savebyte[0] = *data; 613 } 614 m = m->m_next; /* to next mbuf */ 615 } 616 if (wantbyte) /* write last byte */ 617 *d = *((u_short *) savebyte); 618 } else { 619 /* use programmed I/O */ 620 while (m) { 621 total_len += (len = m->m_len); 622 if (len) { 623 caddr_t data = mtod(m, caddr_t); 624 /* finish the last word of the previous mbuf */ 625 if (wantbyte) { 626 savebyte[1] = *data; 627 ed_asic_outw(sc, ED_HPP_PAGE_4, 628 *((u_short *)savebyte)); 629 data++; 630 len--; 631 wantbyte = 0; 632 } 633 /* output contiguous words */ 634 if ((len > 3) && use_32bit_accesses) { 635 ed_asic_outsl(sc, ED_HPP_PAGE_4, 636 data, len >> 2); 637 data += (len & ~3); 638 len &= 3; 639 } 640 /* finish off remaining 16 bit accesses */ 641 if (len > 1) { 642 ed_asic_outsw(sc, ED_HPP_PAGE_4, 643 data, len >> 1); 644 data += (len & ~1); 645 len &= 1; 646 } 647 if ((wantbyte = (len == 1)) != 0) 648 savebyte[0] = *data; 649 650 } /* if len != 0 */ 651 m = m->m_next; 652 } 653 if (wantbyte) /* spit last byte */ 654 ed_asic_outw(sc, ED_HPP_PAGE_4, *(u_short *)savebyte); 655 656 } 657 658 if (sc->hpp_mem_start) /* turn off memory mapped i/o */ 659 ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); 660 661 return (total_len); 662} 663 664#endif /* ED_HPP */ 665