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