1 /* $NetBSD: mhzc.c,v 1.7 2001/07/01 02:16:25 uwe Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Device driver for the Megaherz X-JACK Ethernet/Modem combo cards. 42 * 43 * Many thanks to Chuck Cranor for having the patience to sift through 44 * the Linux smc91c92_cs.c driver to find the magic details to get this 45 * working! 46 */ 47 48 #include "opt_inet.h" 49 #include "opt_ns.h" 50 #include "bpfilter.h" 51 52 #include <sys/param.h> 53 #include <sys/systm.h> 54 #include <sys/mbuf.h> 55 #include <sys/socket.h> 56 #include <sys/ioctl.h> 57 #include <sys/errno.h> 58 #include <sys/syslog.h> 59 #include <sys/select.h> 60 #include <sys/tty.h> 61 #include <sys/device.h> 62 63 #include <net/if.h> 64 #include <net/if_dl.h> 65 #include <net/if_ether.h> 66 #include <net/if_media.h> 67 68 #ifdef INET 69 #include <netinet/in.h> 70 #include <netinet/in_systm.h> 71 #include <netinet/in_var.h> 72 #include <netinet/ip.h> 73 #include <netinet/if_inarp.h> 74 #endif 75 76 #ifdef NS 77 #include <netns/ns.h> 78 #include <netns/ns_if.h> 79 #endif 80 81 #if NBPFILTER > 0 82 #include <net/bpf.h> 83 #include <net/bpfdesc.h> 84 #endif 85 86 #include <machine/intr.h> 87 #include <machine/bus.h> 88 89 #include <dev/ic/comreg.h> 90 #include <dev/ic/comvar.h> 91 92 #include <dev/mii/mii.h> 93 #include <dev/mii/miivar.h> 94 95 #include <dev/ic/smc91cxxreg.h> 96 #include <dev/ic/smc91cxxvar.h> 97 98 #include <dev/pcmcia/pcmciareg.h> 99 #include <dev/pcmcia/pcmciavar.h> 100 #include <dev/pcmcia/pcmciadevs.h> 101 102 #include "mhzc.h" 103 104 struct mhzc_softc { 105 struct device sc_dev; /* generic device glue */ 106 107 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 108 void *sc_ih; /* interrupt handle */ 109 110 const struct mhzc_product *sc_product; 111 112 /* 113 * Data for the Modem portion. 114 */ 115 struct device *sc_modem; 116 struct pcmcia_io_handle sc_modem_pcioh; 117 int sc_modem_io_window; 118 119 /* 120 * Data for the Ethernet portion. 121 */ 122 struct device *sc_ethernet; 123 struct pcmcia_io_handle sc_ethernet_pcioh; 124 int sc_ethernet_io_window; 125 126 int sc_flags; 127 }; 128 129 /* sc_flags */ 130 #define MHZC_MODEM_MAPPED 0x01 131 #define MHZC_ETHERNET_MAPPED 0x02 132 #define MHZC_MODEM_ENABLED 0x04 133 #define MHZC_ETHERNET_ENABLED 0x08 134 #define MHZC_IOSPACE_ALLOCED 0x10 135 136 int mhzc_match __P((struct device *, struct cfdata *, void *)); 137 void mhzc_attach __P((struct device *, struct device *, void *)); 138 int mhzc_detach __P((struct device *, int)); 139 int mhzc_activate __P((struct device *, enum devact)); 140 141 struct cfattach mhzc_ca = { 142 sizeof(struct mhzc_softc), mhzc_match, mhzc_attach, 143 mhzc_detach, mhzc_activate 144 }; 145 146 int mhzc_em3336_enaddr __P((struct mhzc_softc *, u_int8_t *)); 147 int mhzc_em3336_enable __P((struct mhzc_softc *)); 148 149 const struct mhzc_product { 150 struct pcmcia_product mp_product; 151 152 /* Get the Ethernet address for this card. */ 153 int (*mp_enaddr) __P((struct mhzc_softc *, u_int8_t *)); 154 155 /* Perform any special `enable' magic. */ 156 int (*mp_enable) __P((struct mhzc_softc *)); 157 } mhzc_products[] = { 158 { { PCMCIA_STR_MEGAHERTZ_XJEM3336, PCMCIA_VENDOR_MEGAHERTZ, 159 PCMCIA_PRODUCT_MEGAHERTZ_XJEM3336, 0 }, 160 mhzc_em3336_enaddr, mhzc_em3336_enable }, 161 162 /* 163 * Eventually we could add support for other Ethernet/Modem 164 * combo cards, even if they're aren't Megahertz, because 165 * most of them work more or less the same way. 166 */ 167 168 { { NULL } } 169 }; 170 171 int mhzc_print __P((void *, const char *)); 172 173 int mhzc_check_cfe __P((struct mhzc_softc *, struct pcmcia_config_entry *)); 174 int mhzc_alloc_ethernet __P((struct mhzc_softc *, struct pcmcia_config_entry *)); 175 176 int mhzc_enable __P((struct mhzc_softc *, int)); 177 void mhzc_disable __P((struct mhzc_softc *, int)); 178 179 int mhzc_intr __P((void *)); 180 181 int 182 mhzc_match(parent, match, aux) 183 struct device *parent; 184 struct cfdata *match; 185 void *aux; 186 { 187 struct pcmcia_attach_args *pa = aux; 188 189 if (pcmcia_product_lookup(pa, 190 (const struct pcmcia_product *)mhzc_products, 191 sizeof mhzc_products[0], NULL) != NULL) 192 return (10); /* beat `com' */ 193 194 return (0); 195 } 196 197 void 198 mhzc_attach(parent, self, aux) 199 struct device *parent, *self; 200 void *aux; 201 { 202 struct mhzc_softc *sc = (void *)self; 203 struct pcmcia_attach_args *pa = aux; 204 struct pcmcia_config_entry *cfe; 205 206 sc->sc_pf = pa->pf; 207 208 sc->sc_product = (const struct mhzc_product *)pcmcia_product_lookup(pa, 209 (const struct pcmcia_product *)mhzc_products, 210 sizeof mhzc_products[0], NULL); 211 if (sc->sc_product == NULL) { 212 printf("\n"); 213 panic("mhzc_attach: impossible"); 214 } 215 216 printf(": %s\n", sc->sc_product->mp_product.pp_name); 217 218 /* 219 * The address decoders on these cards are wacky. The configuration 220 * entries are set up to look like serial ports, and have no 221 * information about the Ethernet portion. In order to talk to 222 * the Modem portion, the I/O address must have bit 0x80 set. 223 * In order to talk to the Ethernet portion, the I/O address must 224 * have the 0x80 bit clear. 225 * 226 * The standard configuration entries conveniently have 0x80 set 227 * in them, and have a length of 8 (a 16550's size, convenient!), 228 * so we use those to set up the Modem portion. 229 * 230 * Once we have the Modem's address established, we search for 231 * an address suitable for the Ethernet portion. We do this by 232 * rounding up to the next 16-byte aligned address where 0x80 233 * isn't set (the SMC Ethernet chip has a 16-byte address size) 234 * and attemping to allocate a 16-byte region until we succeed. 235 * 236 * Sure would have been nice if Megahertz had made the card a 237 * proper multi-function device. 238 */ 239 for (cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); cfe != NULL; 240 cfe = SIMPLEQ_NEXT(cfe, cfe_list)) { 241 if (mhzc_check_cfe(sc, cfe)) { 242 /* Found one! */ 243 break; 244 } 245 } 246 if (cfe == NULL) { 247 printf("%s: unable to find suitable config table entry\n", 248 sc->sc_dev.dv_xname); 249 return; 250 } 251 252 if (mhzc_alloc_ethernet(sc, cfe) == 0) { 253 printf("%s: unable to allocate space for Ethernet portion\n", 254 sc->sc_dev.dv_xname); 255 goto alloc_ethernet_failed; 256 } 257 258 /* Enable the card. */ 259 pcmcia_function_init(pa->pf, cfe); 260 if (pcmcia_function_enable(pa->pf)) { 261 printf(": function enable failed\n"); 262 goto enable_failed; 263 } 264 sc->sc_flags |= MHZC_IOSPACE_ALLOCED; 265 266 if (sc->sc_product->mp_enable != NULL) 267 (*sc->sc_product->mp_enable)(sc); 268 269 sc->sc_modem = config_found(&sc->sc_dev, "com", mhzc_print); 270 sc->sc_ethernet = config_found(&sc->sc_dev, "sm", mhzc_print); 271 272 pcmcia_function_disable(pa->pf); 273 return; 274 275 enable_failed: 276 /* Free the Ethernet's I/O space. */ 277 pcmcia_io_free(sc->sc_pf, &sc->sc_ethernet_pcioh); 278 279 alloc_ethernet_failed: 280 /* Free the Modem's I/O space. */ 281 pcmcia_io_free(sc->sc_pf, &sc->sc_modem_pcioh); 282 } 283 284 int 285 mhzc_check_cfe(sc, cfe) 286 struct mhzc_softc *sc; 287 struct pcmcia_config_entry *cfe; 288 { 289 290 if (cfe->num_memspace != 0) 291 return (0); 292 293 if (cfe->num_iospace != 1) 294 return (0); 295 296 if (pcmcia_io_alloc(sc->sc_pf, 297 cfe->iospace[0].start, 298 cfe->iospace[0].length, 299 cfe->iospace[0].length, 300 &sc->sc_modem_pcioh) == 0) { 301 /* Found one for the modem! */ 302 return (1); 303 } 304 305 return (0); 306 } 307 308 int 309 mhzc_alloc_ethernet(sc, cfe) 310 struct mhzc_softc *sc; 311 struct pcmcia_config_entry *cfe; 312 { 313 bus_addr_t addr, maxaddr; 314 315 addr = cfe->iospace[0].start + cfe->iospace[0].length; 316 maxaddr = 0x1000; 317 318 /* 319 * Now round it up so that it starts on a 16-byte boundary. 320 */ 321 addr = roundup(addr, 0x10); 322 323 for (; (addr + 0x10) < maxaddr; addr += 0x10) { 324 if (addr & 0x80) 325 continue; 326 if (pcmcia_io_alloc(sc->sc_pf, addr, 0x10, 0x10, 327 &sc->sc_ethernet_pcioh) == 0) { 328 /* Found one for the ethernet! */ 329 return (1); 330 } 331 } 332 333 return (0); 334 } 335 336 int 337 mhzc_print(aux, pnp) 338 void *aux; 339 const char *pnp; 340 { 341 const char *name = aux; 342 343 if (pnp) 344 printf("%s at %s(*)", name, pnp); 345 346 return (UNCONF); 347 } 348 349 int 350 mhzc_detach(self, flags) 351 struct device *self; 352 int flags; 353 { 354 struct mhzc_softc *sc = (void *)self; 355 int rv; 356 357 if (sc->sc_ethernet != NULL) { 358 rv = config_detach(sc->sc_ethernet, flags); 359 if (rv != 0) 360 return (rv); 361 sc->sc_ethernet = NULL; 362 } 363 364 if (sc->sc_modem != NULL) { 365 rv = config_detach(sc->sc_modem, flags); 366 if (rv != 0) 367 return (rv); 368 #ifdef not_necessary 369 sc->sc_modem = NULL; 370 #endif 371 } 372 373 /* Unmap our i/o windows. */ 374 if (sc->sc_flags & MHZC_MODEM_MAPPED) 375 pcmcia_io_unmap(sc->sc_pf, sc->sc_modem_io_window); 376 if (sc->sc_flags & MHZC_ETHERNET_MAPPED) 377 pcmcia_io_unmap(sc->sc_pf, sc->sc_ethernet_io_window); 378 379 /* Free our i/o spaces. */ 380 if (sc->sc_flags & MHZC_IOSPACE_ALLOCED) { 381 pcmcia_io_free(sc->sc_pf, &sc->sc_modem_pcioh); 382 pcmcia_io_free(sc->sc_pf, &sc->sc_ethernet_pcioh); 383 } 384 385 return (0); 386 } 387 388 int 389 mhzc_activate(self, act) 390 struct device *self; 391 enum devact act; 392 { 393 struct mhzc_softc *sc = (void *)self; 394 int s, rv = 0; 395 396 s = splhigh(); 397 switch (act) { 398 case DVACT_ACTIVATE: 399 rv = EOPNOTSUPP; 400 break; 401 402 case DVACT_DEACTIVATE: 403 if (sc->sc_ethernet != NULL) { 404 rv = config_deactivate(sc->sc_ethernet); 405 if (rv != 0) 406 goto out; 407 } 408 409 if (sc->sc_modem != NULL) { 410 rv = config_deactivate(sc->sc_modem); 411 if (rv != 0) 412 goto out; 413 } 414 break; 415 } 416 out: 417 splx(s); 418 return (rv); 419 } 420 421 int 422 mhzc_intr(arg) 423 void *arg; 424 { 425 struct mhzc_softc *sc = arg; 426 int rval = 0; 427 428 #if NCOM_MHZC > 0 429 if (sc->sc_modem != NULL && 430 (sc->sc_flags & MHZC_MODEM_ENABLED) != 0) 431 rval |= comintr(sc->sc_modem); 432 #endif 433 434 #if NSM_MHZC > 0 435 if (sc->sc_ethernet != NULL && 436 (sc->sc_flags & MHZC_ETHERNET_ENABLED) != 0) 437 rval |= smc91cxx_intr(sc->sc_ethernet); 438 #endif 439 440 return (rval); 441 } 442 443 int 444 mhzc_enable(sc, flag) 445 struct mhzc_softc *sc; 446 int flag; 447 { 448 449 if (sc->sc_flags & flag) { 450 printf("%s: %s already enabled\n", sc->sc_dev.dv_xname, 451 (flag & MHZC_MODEM_ENABLED) ? "modem" : "ethernet"); 452 panic("mhzc_enable"); 453 } 454 455 if ((sc->sc_flags & (MHZC_MODEM_ENABLED|MHZC_ETHERNET_ENABLED)) != 0) { 456 sc->sc_flags |= flag; 457 return (0); 458 } 459 460 /* 461 * Establish our interrupt handler. 462 * 463 * XXX Note, we establish this at IPL_NET. This is suboptimal 464 * XXX the Modem portion, but is necessary to make the Ethernet 465 * XXX portion have the correct interrupt level semantics. 466 * 467 * XXX Eventually we should use the `enabled' bits in the 468 * XXX flags word to determine which level we should be at. 469 */ 470 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, 471 mhzc_intr, sc); 472 if (sc->sc_ih == NULL) { 473 printf("%s: unable to establish interrupt\n", 474 sc->sc_dev.dv_xname); 475 return (1); 476 } 477 478 if (pcmcia_function_enable(sc->sc_pf)) { 479 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 480 return (1); 481 } 482 483 /* 484 * Perform any special enable magic necessary. 485 */ 486 if (sc->sc_product->mp_enable != NULL && 487 (*sc->sc_product->mp_enable)(sc) != 0) { 488 pcmcia_function_disable(sc->sc_pf); 489 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 490 return (1); 491 } 492 493 sc->sc_flags |= flag; 494 return (0); 495 } 496 497 void 498 mhzc_disable(sc, flag) 499 struct mhzc_softc *sc; 500 int flag; 501 { 502 503 if ((sc->sc_flags & flag) == 0) { 504 printf("%s: %s already disabled\n", sc->sc_dev.dv_xname, 505 (flag & MHZC_MODEM_ENABLED) ? "modem" : "ethernet"); 506 panic("mhzc_disable"); 507 } 508 509 sc->sc_flags &= ~flag; 510 if ((sc->sc_flags & (MHZC_MODEM_ENABLED|MHZC_ETHERNET_ENABLED)) != 0) 511 return; 512 513 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 514 pcmcia_function_disable(sc->sc_pf); 515 } 516 517 /***************************************************************************** 518 * Megahertz EM3336 (and compatibles) support 519 *****************************************************************************/ 520 521 int mhzc_em3336_lannid_ciscallback __P((struct pcmcia_tuple *, void *)); 522 int mhzc_em3336_ascii_enaddr __P((const char *cisstr, u_int8_t *)); 523 524 int 525 mhzc_em3336_enaddr(sc, myla) 526 struct mhzc_softc *sc; 527 u_int8_t *myla; 528 { 529 530 /* Get the station address from CIS tuple 0x81. */ 531 if (pcmcia_scan_cis(sc->sc_dev.dv_parent, 532 mhzc_em3336_lannid_ciscallback, myla) != 1) { 533 printf("%s: unable to get Ethernet address from CIS\n", 534 sc->sc_dev.dv_xname); 535 return (0); 536 } 537 538 return (1); 539 } 540 541 int 542 mhzc_em3336_enable(sc) 543 struct mhzc_softc *sc; 544 { 545 struct pcmcia_mem_handle memh; 546 bus_addr_t memoff; 547 int memwin, reg; 548 549 /* 550 * Bring the chip to live by touching its registers in the correct 551 * way (as per my reference... the Linux smc91c92_cs.c driver by 552 * David A. Hinds). 553 */ 554 555 /* Map the ISRPOWEREG. */ 556 if (pcmcia_mem_alloc(sc->sc_pf, 0x1000, &memh) != 0) { 557 printf("%s: unable to allocate memory space\n", 558 sc->sc_dev.dv_xname); 559 return (1); 560 } 561 562 if (pcmcia_mem_map(sc->sc_pf, PCMCIA_MEM_ATTR, 0, 0x1000, 563 &memh, &memoff, &memwin)) { 564 printf("%s: unable to map memory space\n", 565 sc->sc_dev.dv_xname); 566 pcmcia_mem_free(sc->sc_pf, &memh); 567 return (1); 568 } 569 570 /* 571 * The magic sequence: 572 * 573 * - read/write the CCR option register. 574 * - read the ISRPOWEREG 2 times. 575 * - read/write the CCR option register again. 576 */ 577 578 reg = pcmcia_ccr_read(sc->sc_pf, PCMCIA_CCR_OPTION); 579 pcmcia_ccr_write(sc->sc_pf, PCMCIA_CCR_OPTION, reg); 580 581 reg = bus_space_read_1(memh.memt, memh.memh, 0x380); 582 delay(5); 583 reg = bus_space_read_1(memh.memt, memh.memh, 0x380); 584 585 delay(200000); 586 587 reg = pcmcia_ccr_read(sc->sc_pf, PCMCIA_CCR_OPTION); 588 delay(5); 589 pcmcia_ccr_write(sc->sc_pf, PCMCIA_CCR_OPTION, reg); 590 591 pcmcia_mem_unmap(sc->sc_pf, memwin); 592 pcmcia_mem_free(sc->sc_pf, &memh); 593 594 return (0); 595 } 596 597 int 598 mhzc_em3336_lannid_ciscallback(tuple, arg) 599 struct pcmcia_tuple *tuple; 600 void *arg; 601 { 602 u_int8_t *myla = arg, addr_str[ETHER_ADDR_LEN * 2]; 603 int i; 604 605 if (tuple->code == 0x81) { 606 /* 607 * We have a string-encoded address. Length includes 608 * terminating 0xff. 609 */ 610 if (tuple->length != (ETHER_ADDR_LEN * 2) + 1) 611 return (0); 612 613 for (i = 0; i < tuple->length - 1; i++) 614 addr_str[i] = pcmcia_tuple_read_1(tuple, i); 615 616 /* 617 * Decode the string into `myla'. 618 */ 619 return (mhzc_em3336_ascii_enaddr(addr_str, myla)); 620 } 621 return (0); 622 } 623 624 /* XXX This should be shared w/ if_sm_pcmcia.c */ 625 int 626 mhzc_em3336_ascii_enaddr(cisstr, myla) 627 const char *cisstr; 628 u_int8_t *myla; 629 { 630 u_int8_t digit; 631 int i; 632 633 memset(myla, 0, ETHER_ADDR_LEN); 634 635 for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) { 636 if (cisstr[i] >= '0' && cisstr[i] <= '9') 637 digit |= cisstr[i] - '0'; 638 else if (cisstr[i] >= 'a' && cisstr[i] <= 'f') 639 digit |= (cisstr[i] - 'a') + 10; 640 else if (cisstr[i] >= 'A' && cisstr[i] <= 'F') 641 digit |= (cisstr[i] - 'A') + 10; 642 else { 643 /* Bogus digit!! */ 644 return (0); 645 } 646 647 /* Compensate for ordering of digits. */ 648 if (i & 1) { 649 myla[i >> 1] = digit; 650 digit = 0; 651 } else 652 digit <<= 4; 653 } 654 655 return (1); 656 } 657 658 /****** Here begins the com attachment code. ******/ 659 660 #if NCOM_MHZC > 0 661 int com_mhzc_match __P((struct device *, struct cfdata *, void *)); 662 void com_mhzc_attach __P((struct device *, struct device *, void *)); 663 int com_mhzc_detach __P((struct device *, int)); 664 665 /* No mhzc-specific goo in the softc; it's all in the parent. */ 666 struct cfattach com_mhzc_ca = { 667 sizeof(struct com_softc), com_mhzc_match, com_mhzc_attach, 668 com_detach, com_activate 669 }; 670 671 int com_mhzc_enable __P((struct com_softc *)); 672 void com_mhzc_disable __P((struct com_softc *)); 673 674 int 675 com_mhzc_match(parent, match, aux) 676 struct device *parent; 677 struct cfdata *match; 678 void *aux; 679 { 680 extern struct cfdriver com_cd; 681 const char *name = aux; 682 683 /* Device is always present. */ 684 if (strcmp(name, com_cd.cd_name) == 0) 685 return (1); 686 687 return (0); 688 } 689 690 void 691 com_mhzc_attach(parent, self, aux) 692 struct device *parent, *self; 693 void *aux; 694 { 695 struct com_softc *sc = (void *)self; 696 struct mhzc_softc *msc = (void *)parent; 697 698 printf(":"); 699 if (pcmcia_io_map(msc->sc_pf, PCMCIA_WIDTH_IO8, 0, 700 msc->sc_modem_pcioh.size, &msc->sc_modem_pcioh, 701 &msc->sc_modem_io_window)) { 702 printf("unable to map I/O space\n"); 703 return; 704 } 705 printf(" io 0x%x-0x%x", 706 (int)msc->sc_modem_pcioh.addr, 707 (int)(msc->sc_modem_pcioh.addr + msc->sc_modem_pcioh.size - 1)); 708 709 msc->sc_flags |= MHZC_MODEM_MAPPED; 710 711 sc->sc_iot = msc->sc_modem_pcioh.iot; 712 sc->sc_ioh = msc->sc_modem_pcioh.ioh; 713 714 sc->enabled = 1; 715 716 sc->sc_iobase = -1; 717 sc->sc_frequency = COM_FREQ; 718 719 sc->enable = com_mhzc_enable; 720 sc->disable = com_mhzc_disable; 721 722 com_attach_subr(sc); 723 724 sc->enabled = 0; 725 } 726 727 int 728 com_mhzc_enable(sc) 729 struct com_softc *sc; 730 { 731 732 return (mhzc_enable((struct mhzc_softc *)sc->sc_dev.dv_parent, 733 MHZC_MODEM_ENABLED)); 734 } 735 736 void 737 com_mhzc_disable(sc) 738 struct com_softc *sc; 739 { 740 741 mhzc_disable((struct mhzc_softc *)sc->sc_dev.dv_parent, 742 MHZC_MODEM_ENABLED); 743 } 744 745 #endif /* NCOM_MHZC > 0 */ 746 747 /****** Here begins the sm attachment code. ******/ 748 749 #if NSM_MHZC > 0 750 int sm_mhzc_match __P((struct device *, struct cfdata *, void *)); 751 void sm_mhzc_attach __P((struct device *, struct device *, void *)); 752 753 /* No mhzc-specific goo in the softc; it's all in the parent. */ 754 struct cfattach sm_mhzc_ca = { 755 sizeof(struct smc91cxx_softc), sm_mhzc_match, sm_mhzc_attach, 756 smc91cxx_detach, smc91cxx_activate 757 }; 758 759 int sm_mhzc_enable __P((struct smc91cxx_softc *)); 760 void sm_mhzc_disable __P((struct smc91cxx_softc *)); 761 762 int 763 sm_mhzc_match(parent, match, aux) 764 struct device *parent; 765 struct cfdata *match; 766 void *aux; 767 { 768 extern struct cfdriver sm_cd; 769 const char *name = aux; 770 771 /* Device is always present. */ 772 if (strcmp(name, sm_cd.cd_name) == 0) 773 return (1); 774 775 return (0); 776 } 777 778 void 779 sm_mhzc_attach(parent, self, aux) 780 struct device *parent, *self; 781 void *aux; 782 { 783 struct smc91cxx_softc *sc = (void *)self; 784 struct mhzc_softc *msc = (void *)parent; 785 u_int8_t myla[ETHER_ADDR_LEN]; 786 787 printf(":"); 788 if (pcmcia_io_map(msc->sc_pf, PCMCIA_WIDTH_IO16, 0, 789 msc->sc_ethernet_pcioh.size, &msc->sc_ethernet_pcioh, 790 &msc->sc_ethernet_io_window)) { 791 printf("unable to map I/O space\n"); 792 return; 793 } 794 printf(" io 0x%x-0x%x\n", 795 (int)msc->sc_ethernet_pcioh.addr, 796 (int)(msc->sc_ethernet_pcioh.addr + msc->sc_modem_pcioh.size - 1)); 797 798 msc->sc_flags |= MHZC_ETHERNET_MAPPED; 799 800 sc->sc_bst = msc->sc_ethernet_pcioh.iot; 801 sc->sc_bsh = msc->sc_ethernet_pcioh.ioh; 802 803 sc->sc_enable = sm_mhzc_enable; 804 sc->sc_disable = sm_mhzc_disable; 805 806 if ((*msc->sc_product->mp_enaddr)(msc, myla) != 1) 807 return; 808 809 /* Perform generic initialization. */ 810 smc91cxx_attach(sc, myla); 811 } 812 813 int 814 sm_mhzc_enable(sc) 815 struct smc91cxx_softc *sc; 816 { 817 818 return (mhzc_enable((struct mhzc_softc *)sc->sc_dev.dv_parent, 819 MHZC_ETHERNET_ENABLED)); 820 } 821 822 void 823 sm_mhzc_disable(sc) 824 struct smc91cxx_softc *sc; 825 { 826 827 mhzc_disable((struct mhzc_softc *)sc->sc_dev.dv_parent, 828 MHZC_ETHERNET_ENABLED); 829 } 830 831 #endif /* NSM_MHZC > 0 */ 832