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