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