mhzc.c revision 1.43.8.1 1 /* $NetBSD: mhzc.c,v 1.43.8.1 2009/04/28 07:36:21 skrll 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.43.8.1 2009/04/28 07:36:21 skrll 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