1 /* $NetBSD: mhzc.c,v 1.13 2002/10/02 16:52:19 thorpej 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.13 2002/10/02 16:52:19 thorpej 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 CFATTACH_DECL(mhzc, sizeof(struct mhzc_softc), 145 mhzc_match, mhzc_attach, mhzc_detach, mhzc_activate); 146 147 int mhzc_em3336_enaddr __P((struct mhzc_softc *, u_int8_t *)); 148 int mhzc_em3336_enable __P((struct mhzc_softc *)); 149 150 const struct mhzc_product { 151 struct pcmcia_product mp_product; 152 153 /* Get the Ethernet address for this card. */ 154 int (*mp_enaddr) __P((struct mhzc_softc *, u_int8_t *)); 155 156 /* Perform any special `enable' magic. */ 157 int (*mp_enable) __P((struct mhzc_softc *)); 158 } mhzc_products[] = { 159 { { PCMCIA_STR_MEGAHERTZ_XJEM3336, PCMCIA_VENDOR_MEGAHERTZ, 160 PCMCIA_PRODUCT_MEGAHERTZ_XJEM3336, 0 }, 161 mhzc_em3336_enaddr, mhzc_em3336_enable }, 162 163 /* 164 * Eventually we could add support for other Ethernet/Modem 165 * combo cards, even if they're aren't Megahertz, because 166 * most of them work more or less the same way. 167 */ 168 169 { { NULL } } 170 }; 171 172 int mhzc_print __P((void *, const char *)); 173 174 int mhzc_check_cfe __P((struct mhzc_softc *, struct pcmcia_config_entry *)); 175 int mhzc_alloc_ethernet __P((struct mhzc_softc *, struct pcmcia_config_entry *)); 176 177 int mhzc_enable __P((struct mhzc_softc *, int)); 178 void mhzc_disable __P((struct mhzc_softc *, int)); 179 180 int mhzc_intr __P((void *)); 181 182 int 183 mhzc_match(parent, match, aux) 184 struct device *parent; 185 struct cfdata *match; 186 void *aux; 187 { 188 struct pcmcia_attach_args *pa = aux; 189 190 if (pcmcia_product_lookup(pa, 191 (const struct pcmcia_product *)mhzc_products, 192 sizeof mhzc_products[0], NULL) != NULL) 193 return (10); /* beat `com' */ 194 195 return (0); 196 } 197 198 void 199 mhzc_attach(parent, self, aux) 200 struct device *parent, *self; 201 void *aux; 202 { 203 struct mhzc_softc *sc = (void *)self; 204 struct pcmcia_attach_args *pa = aux; 205 struct pcmcia_config_entry *cfe; 206 207 sc->sc_pf = pa->pf; 208 209 sc->sc_product = (const struct mhzc_product *)pcmcia_product_lookup(pa, 210 (const struct pcmcia_product *)mhzc_products, 211 sizeof mhzc_products[0], NULL); 212 if (sc->sc_product == NULL) { 213 printf("\n"); 214 panic("mhzc_attach: impossible"); 215 } 216 217 printf(": %s\n", sc->sc_product->mp_product.pp_name); 218 219 /* 220 * The address decoders on these cards are wacky. The configuration 221 * entries are set up to look like serial ports, and have no 222 * information about the Ethernet portion. In order to talk to 223 * the Modem portion, the I/O address must have bit 0x80 set. 224 * In order to talk to the Ethernet portion, the I/O address must 225 * have the 0x80 bit clear. 226 * 227 * The standard configuration entries conveniently have 0x80 set 228 * in them, and have a length of 8 (a 16550's size, convenient!), 229 * so we use those to set up the Modem portion. 230 * 231 * Once we have the Modem's address established, we search for 232 * an address suitable for the Ethernet portion. We do this by 233 * rounding up to the next 16-byte aligned address where 0x80 234 * isn't set (the SMC Ethernet chip has a 16-byte address size) 235 * and attemping to allocate a 16-byte region until we succeed. 236 * 237 * Sure would have been nice if Megahertz had made the card a 238 * proper multi-function device. 239 */ 240 SIMPLEQ_FOREACH(cfe, &pa->pf->cfe_head, 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 CFATTACH_DECL(com_mhzc, sizeof(struct com_softc), 667 com_mhzc_match, com_mhzc_attach, com_detach, com_activate); 668 669 int com_mhzc_enable __P((struct com_softc *)); 670 void com_mhzc_disable __P((struct com_softc *)); 671 672 int 673 com_mhzc_match(parent, match, aux) 674 struct device *parent; 675 struct cfdata *match; 676 void *aux; 677 { 678 extern struct cfdriver com_cd; 679 const char *name = aux; 680 681 /* Device is always present. */ 682 if (strcmp(name, com_cd.cd_name) == 0) 683 return (1); 684 685 return (0); 686 } 687 688 void 689 com_mhzc_attach(parent, self, aux) 690 struct device *parent, *self; 691 void *aux; 692 { 693 struct com_softc *sc = (void *)self; 694 struct mhzc_softc *msc = (void *)parent; 695 696 printf(":"); 697 if (pcmcia_io_map(msc->sc_pf, PCMCIA_WIDTH_IO8, 0, 698 msc->sc_modem_pcioh.size, &msc->sc_modem_pcioh, 699 &msc->sc_modem_io_window)) { 700 printf("unable to map I/O space\n"); 701 return; 702 } 703 printf(" io 0x%x-0x%x", 704 (int)msc->sc_modem_pcioh.addr, 705 (int)(msc->sc_modem_pcioh.addr + msc->sc_modem_pcioh.size - 1)); 706 707 msc->sc_flags |= MHZC_MODEM_MAPPED; 708 709 sc->sc_iot = msc->sc_modem_pcioh.iot; 710 sc->sc_ioh = msc->sc_modem_pcioh.ioh; 711 712 sc->enabled = 1; 713 714 sc->sc_iobase = -1; 715 sc->sc_frequency = COM_FREQ; 716 717 sc->enable = com_mhzc_enable; 718 sc->disable = com_mhzc_disable; 719 720 com_attach_subr(sc); 721 722 sc->enabled = 0; 723 } 724 725 int 726 com_mhzc_enable(sc) 727 struct com_softc *sc; 728 { 729 730 return (mhzc_enable((struct mhzc_softc *)sc->sc_dev.dv_parent, 731 MHZC_MODEM_ENABLED)); 732 } 733 734 void 735 com_mhzc_disable(sc) 736 struct com_softc *sc; 737 { 738 739 mhzc_disable((struct mhzc_softc *)sc->sc_dev.dv_parent, 740 MHZC_MODEM_ENABLED); 741 } 742 743 #endif /* NCOM_MHZC > 0 */ 744 745 /****** Here begins the sm attachment code. ******/ 746 747 #if NSM_MHZC > 0 748 int sm_mhzc_match __P((struct device *, struct cfdata *, void *)); 749 void sm_mhzc_attach __P((struct device *, struct device *, void *)); 750 751 /* No mhzc-specific goo in the softc; it's all in the parent. */ 752 CFATTACH_DECL(sm_mhzc, sizeof(struct smc91cxx_softc), 753 sm_mhzc_match, sm_mhzc_attach, smc91cxx_detach, smc91cxx_activate); 754 755 int sm_mhzc_enable __P((struct smc91cxx_softc *)); 756 void sm_mhzc_disable __P((struct smc91cxx_softc *)); 757 758 int 759 sm_mhzc_match(parent, match, aux) 760 struct device *parent; 761 struct cfdata *match; 762 void *aux; 763 { 764 extern struct cfdriver sm_cd; 765 const char *name = aux; 766 767 /* Device is always present. */ 768 if (strcmp(name, sm_cd.cd_name) == 0) 769 return (1); 770 771 return (0); 772 } 773 774 void 775 sm_mhzc_attach(parent, self, aux) 776 struct device *parent, *self; 777 void *aux; 778 { 779 struct smc91cxx_softc *sc = (void *)self; 780 struct mhzc_softc *msc = (void *)parent; 781 u_int8_t myla[ETHER_ADDR_LEN]; 782 783 printf(":"); 784 if (pcmcia_io_map(msc->sc_pf, PCMCIA_WIDTH_IO16, 0, 785 msc->sc_ethernet_pcioh.size, &msc->sc_ethernet_pcioh, 786 &msc->sc_ethernet_io_window)) { 787 printf("unable to map I/O space\n"); 788 return; 789 } 790 printf(" io 0x%x-0x%x\n", 791 (int)msc->sc_ethernet_pcioh.addr, 792 (int)(msc->sc_ethernet_pcioh.addr + msc->sc_ethernet_pcioh.size - 1)); 793 794 msc->sc_flags |= MHZC_ETHERNET_MAPPED; 795 796 sc->sc_bst = msc->sc_ethernet_pcioh.iot; 797 sc->sc_bsh = msc->sc_ethernet_pcioh.ioh; 798 799 sc->sc_enable = sm_mhzc_enable; 800 sc->sc_disable = sm_mhzc_disable; 801 802 if ((*msc->sc_product->mp_enaddr)(msc, myla) != 1) 803 return; 804 805 /* Perform generic initialization. */ 806 smc91cxx_attach(sc, myla); 807 } 808 809 int 810 sm_mhzc_enable(sc) 811 struct smc91cxx_softc *sc; 812 { 813 814 return (mhzc_enable((struct mhzc_softc *)sc->sc_dev.dv_parent, 815 MHZC_ETHERNET_ENABLED)); 816 } 817 818 void 819 sm_mhzc_disable(sc) 820 struct smc91cxx_softc *sc; 821 { 822 823 mhzc_disable((struct mhzc_softc *)sc->sc_dev.dv_parent, 824 MHZC_ETHERNET_ENABLED); 825 } 826 827 #endif /* NSM_MHZC > 0 */ 828