1 /* $NetBSD: mhzc.c,v 1.9 2002/06/01 23:51:01 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.9 2002/06/01 23:51:01 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 SIMPLEQ_FOREACH(cfe, &pa->pf->cfe_head, cfe_list) { 243 if (mhzc_check_cfe(sc, cfe)) { 244 /* Found one! */ 245 break; 246 } 247 } 248 if (cfe == NULL) { 249 printf("%s: unable to find suitable config table entry\n", 250 sc->sc_dev.dv_xname); 251 return; 252 } 253 254 if (mhzc_alloc_ethernet(sc, cfe) == 0) { 255 printf("%s: unable to allocate space for Ethernet portion\n", 256 sc->sc_dev.dv_xname); 257 goto alloc_ethernet_failed; 258 } 259 260 /* Enable the card. */ 261 pcmcia_function_init(pa->pf, cfe); 262 if (pcmcia_function_enable(pa->pf)) { 263 printf(": function enable failed\n"); 264 goto enable_failed; 265 } 266 sc->sc_flags |= MHZC_IOSPACE_ALLOCED; 267 268 if (sc->sc_product->mp_enable != NULL) 269 (*sc->sc_product->mp_enable)(sc); 270 271 sc->sc_modem = config_found(&sc->sc_dev, "com", mhzc_print); 272 sc->sc_ethernet = config_found(&sc->sc_dev, "sm", mhzc_print); 273 274 pcmcia_function_disable(pa->pf); 275 return; 276 277 enable_failed: 278 /* Free the Ethernet's I/O space. */ 279 pcmcia_io_free(sc->sc_pf, &sc->sc_ethernet_pcioh); 280 281 alloc_ethernet_failed: 282 /* Free the Modem's I/O space. */ 283 pcmcia_io_free(sc->sc_pf, &sc->sc_modem_pcioh); 284 } 285 286 int 287 mhzc_check_cfe(sc, cfe) 288 struct mhzc_softc *sc; 289 struct pcmcia_config_entry *cfe; 290 { 291 292 if (cfe->num_memspace != 0) 293 return (0); 294 295 if (cfe->num_iospace != 1) 296 return (0); 297 298 if (pcmcia_io_alloc(sc->sc_pf, 299 cfe->iospace[0].start, 300 cfe->iospace[0].length, 301 cfe->iospace[0].length, 302 &sc->sc_modem_pcioh) == 0) { 303 /* Found one for the modem! */ 304 return (1); 305 } 306 307 return (0); 308 } 309 310 int 311 mhzc_alloc_ethernet(sc, cfe) 312 struct mhzc_softc *sc; 313 struct pcmcia_config_entry *cfe; 314 { 315 bus_addr_t addr, maxaddr; 316 317 addr = cfe->iospace[0].start + cfe->iospace[0].length; 318 maxaddr = 0x1000; 319 320 /* 321 * Now round it up so that it starts on a 16-byte boundary. 322 */ 323 addr = roundup(addr, 0x10); 324 325 for (; (addr + 0x10) < maxaddr; addr += 0x10) { 326 if (addr & 0x80) 327 continue; 328 if (pcmcia_io_alloc(sc->sc_pf, addr, 0x10, 0x10, 329 &sc->sc_ethernet_pcioh) == 0) { 330 /* Found one for the ethernet! */ 331 return (1); 332 } 333 } 334 335 return (0); 336 } 337 338 int 339 mhzc_print(aux, pnp) 340 void *aux; 341 const char *pnp; 342 { 343 const char *name = aux; 344 345 if (pnp) 346 printf("%s at %s(*)", name, pnp); 347 348 return (UNCONF); 349 } 350 351 int 352 mhzc_detach(self, flags) 353 struct device *self; 354 int flags; 355 { 356 struct mhzc_softc *sc = (void *)self; 357 int rv; 358 359 if (sc->sc_ethernet != NULL) { 360 rv = config_detach(sc->sc_ethernet, flags); 361 if (rv != 0) 362 return (rv); 363 sc->sc_ethernet = NULL; 364 } 365 366 if (sc->sc_modem != NULL) { 367 rv = config_detach(sc->sc_modem, flags); 368 if (rv != 0) 369 return (rv); 370 #ifdef not_necessary 371 sc->sc_modem = NULL; 372 #endif 373 } 374 375 /* Unmap our i/o windows. */ 376 if (sc->sc_flags & MHZC_MODEM_MAPPED) 377 pcmcia_io_unmap(sc->sc_pf, sc->sc_modem_io_window); 378 if (sc->sc_flags & MHZC_ETHERNET_MAPPED) 379 pcmcia_io_unmap(sc->sc_pf, sc->sc_ethernet_io_window); 380 381 /* Free our i/o spaces. */ 382 if (sc->sc_flags & MHZC_IOSPACE_ALLOCED) { 383 pcmcia_io_free(sc->sc_pf, &sc->sc_modem_pcioh); 384 pcmcia_io_free(sc->sc_pf, &sc->sc_ethernet_pcioh); 385 } 386 387 return (0); 388 } 389 390 int 391 mhzc_activate(self, act) 392 struct device *self; 393 enum devact act; 394 { 395 struct mhzc_softc *sc = (void *)self; 396 int s, rv = 0; 397 398 s = splhigh(); 399 switch (act) { 400 case DVACT_ACTIVATE: 401 rv = EOPNOTSUPP; 402 break; 403 404 case DVACT_DEACTIVATE: 405 if (sc->sc_ethernet != NULL) { 406 rv = config_deactivate(sc->sc_ethernet); 407 if (rv != 0) 408 goto out; 409 } 410 411 if (sc->sc_modem != NULL) { 412 rv = config_deactivate(sc->sc_modem); 413 if (rv != 0) 414 goto out; 415 } 416 break; 417 } 418 out: 419 splx(s); 420 return (rv); 421 } 422 423 int 424 mhzc_intr(arg) 425 void *arg; 426 { 427 struct mhzc_softc *sc = arg; 428 int rval = 0; 429 430 #if NCOM_MHZC > 0 431 if (sc->sc_modem != NULL && 432 (sc->sc_flags & MHZC_MODEM_ENABLED) != 0) 433 rval |= comintr(sc->sc_modem); 434 #endif 435 436 #if NSM_MHZC > 0 437 if (sc->sc_ethernet != NULL && 438 (sc->sc_flags & MHZC_ETHERNET_ENABLED) != 0) 439 rval |= smc91cxx_intr(sc->sc_ethernet); 440 #endif 441 442 return (rval); 443 } 444 445 int 446 mhzc_enable(sc, flag) 447 struct mhzc_softc *sc; 448 int flag; 449 { 450 451 if (sc->sc_flags & flag) { 452 printf("%s: %s already enabled\n", sc->sc_dev.dv_xname, 453 (flag & MHZC_MODEM_ENABLED) ? "modem" : "ethernet"); 454 panic("mhzc_enable"); 455 } 456 457 if ((sc->sc_flags & (MHZC_MODEM_ENABLED|MHZC_ETHERNET_ENABLED)) != 0) { 458 sc->sc_flags |= flag; 459 return (0); 460 } 461 462 /* 463 * Establish our interrupt handler. 464 * 465 * XXX Note, we establish this at IPL_NET. This is suboptimal 466 * XXX the Modem portion, but is necessary to make the Ethernet 467 * XXX portion have the correct interrupt level semantics. 468 * 469 * XXX Eventually we should use the `enabled' bits in the 470 * XXX flags word to determine which level we should be at. 471 */ 472 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, 473 mhzc_intr, sc); 474 if (sc->sc_ih == NULL) { 475 printf("%s: unable to establish interrupt\n", 476 sc->sc_dev.dv_xname); 477 return (1); 478 } 479 480 if (pcmcia_function_enable(sc->sc_pf)) { 481 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 482 return (1); 483 } 484 485 /* 486 * Perform any special enable magic necessary. 487 */ 488 if (sc->sc_product->mp_enable != NULL && 489 (*sc->sc_product->mp_enable)(sc) != 0) { 490 pcmcia_function_disable(sc->sc_pf); 491 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 492 return (1); 493 } 494 495 sc->sc_flags |= flag; 496 return (0); 497 } 498 499 void 500 mhzc_disable(sc, flag) 501 struct mhzc_softc *sc; 502 int flag; 503 { 504 505 if ((sc->sc_flags & flag) == 0) { 506 printf("%s: %s already disabled\n", sc->sc_dev.dv_xname, 507 (flag & MHZC_MODEM_ENABLED) ? "modem" : "ethernet"); 508 panic("mhzc_disable"); 509 } 510 511 sc->sc_flags &= ~flag; 512 if ((sc->sc_flags & (MHZC_MODEM_ENABLED|MHZC_ETHERNET_ENABLED)) != 0) 513 return; 514 515 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 516 pcmcia_function_disable(sc->sc_pf); 517 } 518 519 /***************************************************************************** 520 * Megahertz EM3336 (and compatibles) support 521 *****************************************************************************/ 522 523 int mhzc_em3336_lannid_ciscallback __P((struct pcmcia_tuple *, void *)); 524 int mhzc_em3336_ascii_enaddr __P((const char *cisstr, u_int8_t *)); 525 526 int 527 mhzc_em3336_enaddr(sc, myla) 528 struct mhzc_softc *sc; 529 u_int8_t *myla; 530 { 531 532 /* Get the station address from CIS tuple 0x81. */ 533 if (pcmcia_scan_cis(sc->sc_dev.dv_parent, 534 mhzc_em3336_lannid_ciscallback, myla) != 1) { 535 printf("%s: unable to get Ethernet address from CIS\n", 536 sc->sc_dev.dv_xname); 537 return (0); 538 } 539 540 return (1); 541 } 542 543 int 544 mhzc_em3336_enable(sc) 545 struct mhzc_softc *sc; 546 { 547 struct pcmcia_mem_handle memh; 548 bus_addr_t memoff; 549 int memwin, reg; 550 551 /* 552 * Bring the chip to live by touching its registers in the correct 553 * way (as per my reference... the Linux smc91c92_cs.c driver by 554 * David A. Hinds). 555 */ 556 557 /* Map the ISRPOWEREG. */ 558 if (pcmcia_mem_alloc(sc->sc_pf, 0x1000, &memh) != 0) { 559 printf("%s: unable to allocate memory space\n", 560 sc->sc_dev.dv_xname); 561 return (1); 562 } 563 564 if (pcmcia_mem_map(sc->sc_pf, PCMCIA_MEM_ATTR, 0, 0x1000, 565 &memh, &memoff, &memwin)) { 566 printf("%s: unable to map memory space\n", 567 sc->sc_dev.dv_xname); 568 pcmcia_mem_free(sc->sc_pf, &memh); 569 return (1); 570 } 571 572 /* 573 * The magic sequence: 574 * 575 * - read/write the CCR option register. 576 * - read the ISRPOWEREG 2 times. 577 * - read/write the CCR option register again. 578 */ 579 580 reg = pcmcia_ccr_read(sc->sc_pf, PCMCIA_CCR_OPTION); 581 pcmcia_ccr_write(sc->sc_pf, PCMCIA_CCR_OPTION, reg); 582 583 reg = bus_space_read_1(memh.memt, memh.memh, 0x380); 584 delay(5); 585 reg = bus_space_read_1(memh.memt, memh.memh, 0x380); 586 587 delay(200000); 588 589 reg = pcmcia_ccr_read(sc->sc_pf, PCMCIA_CCR_OPTION); 590 delay(5); 591 pcmcia_ccr_write(sc->sc_pf, PCMCIA_CCR_OPTION, reg); 592 593 pcmcia_mem_unmap(sc->sc_pf, memwin); 594 pcmcia_mem_free(sc->sc_pf, &memh); 595 596 return (0); 597 } 598 599 int 600 mhzc_em3336_lannid_ciscallback(tuple, arg) 601 struct pcmcia_tuple *tuple; 602 void *arg; 603 { 604 u_int8_t *myla = arg, addr_str[ETHER_ADDR_LEN * 2]; 605 int i; 606 607 if (tuple->code == 0x81) { 608 /* 609 * We have a string-encoded address. Length includes 610 * terminating 0xff. 611 */ 612 if (tuple->length != (ETHER_ADDR_LEN * 2) + 1) 613 return (0); 614 615 for (i = 0; i < tuple->length - 1; i++) 616 addr_str[i] = pcmcia_tuple_read_1(tuple, i); 617 618 /* 619 * Decode the string into `myla'. 620 */ 621 return (mhzc_em3336_ascii_enaddr(addr_str, myla)); 622 } 623 return (0); 624 } 625 626 /* XXX This should be shared w/ if_sm_pcmcia.c */ 627 int 628 mhzc_em3336_ascii_enaddr(cisstr, myla) 629 const char *cisstr; 630 u_int8_t *myla; 631 { 632 u_int8_t digit; 633 int i; 634 635 memset(myla, 0, ETHER_ADDR_LEN); 636 637 for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) { 638 if (cisstr[i] >= '0' && cisstr[i] <= '9') 639 digit |= cisstr[i] - '0'; 640 else if (cisstr[i] >= 'a' && cisstr[i] <= 'f') 641 digit |= (cisstr[i] - 'a') + 10; 642 else if (cisstr[i] >= 'A' && cisstr[i] <= 'F') 643 digit |= (cisstr[i] - 'A') + 10; 644 else { 645 /* Bogus digit!! */ 646 return (0); 647 } 648 649 /* Compensate for ordering of digits. */ 650 if (i & 1) { 651 myla[i >> 1] = digit; 652 digit = 0; 653 } else 654 digit <<= 4; 655 } 656 657 return (1); 658 } 659 660 /****** Here begins the com attachment code. ******/ 661 662 #if NCOM_MHZC > 0 663 int com_mhzc_match __P((struct device *, struct cfdata *, void *)); 664 void com_mhzc_attach __P((struct device *, struct device *, void *)); 665 int com_mhzc_detach __P((struct device *, int)); 666 667 /* No mhzc-specific goo in the softc; it's all in the parent. */ 668 struct cfattach com_mhzc_ca = { 669 sizeof(struct com_softc), com_mhzc_match, com_mhzc_attach, 670 com_detach, com_activate 671 }; 672 673 int com_mhzc_enable __P((struct com_softc *)); 674 void com_mhzc_disable __P((struct com_softc *)); 675 676 int 677 com_mhzc_match(parent, match, aux) 678 struct device *parent; 679 struct cfdata *match; 680 void *aux; 681 { 682 extern struct cfdriver com_cd; 683 const char *name = aux; 684 685 /* Device is always present. */ 686 if (strcmp(name, com_cd.cd_name) == 0) 687 return (1); 688 689 return (0); 690 } 691 692 void 693 com_mhzc_attach(parent, self, aux) 694 struct device *parent, *self; 695 void *aux; 696 { 697 struct com_softc *sc = (void *)self; 698 struct mhzc_softc *msc = (void *)parent; 699 700 printf(":"); 701 if (pcmcia_io_map(msc->sc_pf, PCMCIA_WIDTH_IO8, 0, 702 msc->sc_modem_pcioh.size, &msc->sc_modem_pcioh, 703 &msc->sc_modem_io_window)) { 704 printf("unable to map I/O space\n"); 705 return; 706 } 707 printf(" io 0x%x-0x%x", 708 (int)msc->sc_modem_pcioh.addr, 709 (int)(msc->sc_modem_pcioh.addr + msc->sc_modem_pcioh.size - 1)); 710 711 msc->sc_flags |= MHZC_MODEM_MAPPED; 712 713 sc->sc_iot = msc->sc_modem_pcioh.iot; 714 sc->sc_ioh = msc->sc_modem_pcioh.ioh; 715 716 sc->enabled = 1; 717 718 sc->sc_iobase = -1; 719 sc->sc_frequency = COM_FREQ; 720 721 sc->enable = com_mhzc_enable; 722 sc->disable = com_mhzc_disable; 723 724 com_attach_subr(sc); 725 726 sc->enabled = 0; 727 } 728 729 int 730 com_mhzc_enable(sc) 731 struct com_softc *sc; 732 { 733 734 return (mhzc_enable((struct mhzc_softc *)sc->sc_dev.dv_parent, 735 MHZC_MODEM_ENABLED)); 736 } 737 738 void 739 com_mhzc_disable(sc) 740 struct com_softc *sc; 741 { 742 743 mhzc_disable((struct mhzc_softc *)sc->sc_dev.dv_parent, 744 MHZC_MODEM_ENABLED); 745 } 746 747 #endif /* NCOM_MHZC > 0 */ 748 749 /****** Here begins the sm attachment code. ******/ 750 751 #if NSM_MHZC > 0 752 int sm_mhzc_match __P((struct device *, struct cfdata *, void *)); 753 void sm_mhzc_attach __P((struct device *, struct device *, void *)); 754 755 /* No mhzc-specific goo in the softc; it's all in the parent. */ 756 struct cfattach sm_mhzc_ca = { 757 sizeof(struct smc91cxx_softc), sm_mhzc_match, sm_mhzc_attach, 758 smc91cxx_detach, smc91cxx_activate 759 }; 760 761 int sm_mhzc_enable __P((struct smc91cxx_softc *)); 762 void sm_mhzc_disable __P((struct smc91cxx_softc *)); 763 764 int 765 sm_mhzc_match(parent, match, aux) 766 struct device *parent; 767 struct cfdata *match; 768 void *aux; 769 { 770 extern struct cfdriver sm_cd; 771 const char *name = aux; 772 773 /* Device is always present. */ 774 if (strcmp(name, sm_cd.cd_name) == 0) 775 return (1); 776 777 return (0); 778 } 779 780 void 781 sm_mhzc_attach(parent, self, aux) 782 struct device *parent, *self; 783 void *aux; 784 { 785 struct smc91cxx_softc *sc = (void *)self; 786 struct mhzc_softc *msc = (void *)parent; 787 u_int8_t myla[ETHER_ADDR_LEN]; 788 789 printf(":"); 790 if (pcmcia_io_map(msc->sc_pf, PCMCIA_WIDTH_IO16, 0, 791 msc->sc_ethernet_pcioh.size, &msc->sc_ethernet_pcioh, 792 &msc->sc_ethernet_io_window)) { 793 printf("unable to map I/O space\n"); 794 return; 795 } 796 printf(" io 0x%x-0x%x\n", 797 (int)msc->sc_ethernet_pcioh.addr, 798 (int)(msc->sc_ethernet_pcioh.addr + msc->sc_modem_pcioh.size - 1)); 799 800 msc->sc_flags |= MHZC_ETHERNET_MAPPED; 801 802 sc->sc_bst = msc->sc_ethernet_pcioh.iot; 803 sc->sc_bsh = msc->sc_ethernet_pcioh.ioh; 804 805 sc->sc_enable = sm_mhzc_enable; 806 sc->sc_disable = sm_mhzc_disable; 807 808 if ((*msc->sc_product->mp_enaddr)(msc, myla) != 1) 809 return; 810 811 /* Perform generic initialization. */ 812 smc91cxx_attach(sc, myla); 813 } 814 815 int 816 sm_mhzc_enable(sc) 817 struct smc91cxx_softc *sc; 818 { 819 820 return (mhzc_enable((struct mhzc_softc *)sc->sc_dev.dv_parent, 821 MHZC_ETHERNET_ENABLED)); 822 } 823 824 void 825 sm_mhzc_disable(sc) 826 struct smc91cxx_softc *sc; 827 { 828 829 mhzc_disable((struct mhzc_softc *)sc->sc_dev.dv_parent, 830 MHZC_ETHERNET_ENABLED); 831 } 832 833 #endif /* NSM_MHZC > 0 */ 834