Annotation of sys/dev/pcmcia/if_sm_pcmcia.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_sm_pcmcia.c,v 1.27 2006/06/17 18:01:52 brad Exp $ */
2: /* $NetBSD: if_sm_pcmcia.c,v 1.11 1998/08/15 20:47:32 thorpej Exp $ */
3:
4: /*-
5: * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10: * NASA Ames Research Center.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the NetBSD
23: * Foundation, Inc. and its contributors.
24: * 4. Neither the name of The NetBSD Foundation nor the names of its
25: * contributors may be used to endorse or promote products derived
26: * from this software without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38: * POSSIBILITY OF SUCH DAMAGE.
39: */
40:
41: #include "bpfilter.h"
42:
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/mbuf.h>
46: #include <sys/socket.h>
47: #include <sys/ioctl.h>
48: #include <sys/errno.h>
49: #include <sys/syslog.h>
50: #include <sys/selinfo.h>
51: #include <sys/timeout.h>
52: #include <sys/device.h>
53:
54: #include <net/if.h>
55: #include <net/if_dl.h>
56: #include <net/if_media.h>
57:
58: #ifdef INET
59: #include <netinet/in.h>
60: #include <netinet/in_systm.h>
61: #include <netinet/in_var.h>
62: #include <netinet/ip.h>
63: #include <netinet/if_ether.h>
64: #endif
65:
66: #if NBPFILTER > 0
67: #include <net/bpf.h>
68: #endif
69:
70: #include <machine/intr.h>
71: #include <machine/bus.h>
72:
73: #include <net/if_media.h>
74:
75: #include <dev/mii/mii.h>
76: #include <dev/mii/miivar.h>
77:
78: #include <dev/ic/smc91cxxreg.h>
79: #include <dev/ic/smc91cxxvar.h>
80:
81: #include <dev/pcmcia/pcmciareg.h>
82: #include <dev/pcmcia/pcmciavar.h>
83: #include <dev/pcmcia/pcmciadevs.h>
84:
85: int sm_pcmcia_match(struct device *, void *, void *);
86: void sm_pcmcia_attach(struct device *, struct device *, void *);
87: int sm_pcmcia_detach(struct device *, int);
88: int sm_pcmcia_activate(struct device *, enum devact);
89:
90: struct sm_pcmcia_softc {
91: struct smc91cxx_softc sc_smc; /* real "smc" softc */
92:
93: /* PCMCIA-specific goo. */
94: struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */
95: int sc_io_window; /* our i/o window */
96: void *sc_ih; /* interrupt cookie */
97: struct pcmcia_function *sc_pf; /* our PCMCIA function */
98: };
99:
100: struct cfattach sm_pcmcia_ca = {
101: sizeof(struct sm_pcmcia_softc), sm_pcmcia_match, sm_pcmcia_attach,
102: sm_pcmcia_detach, sm_pcmcia_activate
103: };
104:
105: int sm_pcmcia_enable(struct smc91cxx_softc *);
106: void sm_pcmcia_disable(struct smc91cxx_softc *);
107:
108: int sm_pcmcia_ascii_enaddr(const char *, u_int8_t *);
109: int sm_pcmcia_funce_enaddr(struct device *, u_int8_t *);
110:
111: int sm_pcmcia_lannid_ciscallback(struct pcmcia_tuple *, void *);
112:
113: struct sm_pcmcia_product {
114: u_int16_t spp_vendor; /* vendor ID */
115: u_int16_t spp_product; /* product ID */
116: int spp_expfunc; /* expected function */
117: } sm_pcmcia_prod[] = {
118: { PCMCIA_VENDOR_MEGAHERTZ2, PCMCIA_PRODUCT_MEGAHERTZ2_XJACK,
119: 0 },
120: { PCMCIA_VENDOR_MEGAHERTZ2, PCMCIA_PRODUCT_MEGAHERTZ2_XJEM1144,
121: 0 },
122: { PCMCIA_VENDOR_NEWMEDIA, PCMCIA_PRODUCT_NEWMEDIA_BASICS,
123: 0 },
124: { PCMCIA_VENDOR_SMC, PCMCIA_PRODUCT_SMC_8020,
125: 0 },
126: { PCMCIA_VENDOR_PSION, PCMCIA_PRODUCT_PSION_GOLDCARD,
127: 0 }
128: };
129:
130: int
131: sm_pcmcia_match(parent, match, aux)
132: struct device *parent;
133: void *match, *aux;
134: {
135: struct pcmcia_attach_args *pa = aux;
136: int i;
137:
138: for (i = 0; i < sizeof(sm_pcmcia_prod)/sizeof(sm_pcmcia_prod[0]); i++)
139: if (pa->manufacturer == sm_pcmcia_prod[i].spp_vendor &&
140: pa->product == sm_pcmcia_prod[i].spp_product &&
141: pa->pf->number == sm_pcmcia_prod[i].spp_expfunc)
142: return (1);
143: return (0);
144: }
145:
146: void
147: sm_pcmcia_attach(parent, self, aux)
148: struct device *parent, *self;
149: void *aux;
150: {
151: struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)self;
152: struct smc91cxx_softc *sc = &psc->sc_smc;
153: struct pcmcia_attach_args *pa = aux;
154: struct pcmcia_config_entry *cfe;
155: u_int8_t myla[ETHER_ADDR_LEN], *enaddr = NULL;
156: const char *intrstr;
157:
158: psc->sc_pf = pa->pf;
159: cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head);
160:
161: /* Enable the card. */
162: pcmcia_function_init(pa->pf, cfe);
163: if (pcmcia_function_enable(pa->pf)) {
164: printf(": function enable failed\n");
165: return;
166: }
167:
168: /* XXX sanity check number of mem and i/o spaces */
169:
170: /* Allocate and map i/o space for the card. */
171: if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length,
172: cfe->iospace[0].length, &psc->sc_pcioh)) {
173: printf(": can't allocate i/o space\n");
174: return;
175: }
176:
177: sc->sc_bst = psc->sc_pcioh.iot;
178: sc->sc_bsh = psc->sc_pcioh.ioh;
179:
180: #ifdef notyet
181: sc->sc_enable = sm_pcmcia_enable;
182: sc->sc_disable = sm_pcmcia_disable;
183: #endif
184: sc->sc_enabled = 1;
185:
186: if (pcmcia_io_map(pa->pf, (cfe->flags & PCMCIA_CFE_IO16) ?
187: PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8, 0, cfe->iospace[0].length,
188: &psc->sc_pcioh, &psc->sc_io_window)) {
189: printf(": can't map i/o space\n");
190: return;
191: }
192:
193: printf(" port 0x%lx/%lu", psc->sc_pcioh.addr,
194: (u_long)psc->sc_pcioh.size);
195:
196: /*
197: * First try to get the Ethernet address from FUNCE/LANNID tuple.
198: */
199: if (sm_pcmcia_funce_enaddr(parent, myla))
200: enaddr = myla;
201:
202: /*
203: * If that failed, try one of the CIS info strings.
204: */
205: if (enaddr == NULL) {
206: char *cisstr = NULL;
207:
208: switch (pa->manufacturer) {
209: case PCMCIA_VENDOR_MEGAHERTZ2:
210: cisstr = pa->pf->sc->card.cis1_info[3];
211: break;
212: case PCMCIA_VENDOR_SMC:
213: cisstr = pa->pf->sc->card.cis1_info[2];
214: break;
215: }
216: if (cisstr != NULL && sm_pcmcia_ascii_enaddr(cisstr, myla))
217: enaddr = myla;
218: }
219:
220: if (enaddr == NULL)
221: printf(", unable to get Ethernet address\n");
222:
223: psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
224: smc91cxx_intr, sc, sc->sc_dev.dv_xname);
225: intrstr = pcmcia_intr_string(psc->sc_pf, psc->sc_ih);
226: if (*intrstr)
227: printf(", %s", intrstr);
228:
229: /* Perform generic initialization. */
230: smc91cxx_attach(sc, enaddr);
231:
232: #ifdef notyet
233: pcmcia_function_disable(pa->pf);
234: #endif
235: }
236:
237: int
238: sm_pcmcia_detach(dev, flags)
239: struct device *dev;
240: int flags;
241: {
242: struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)dev;
243: struct ifnet *ifp = &psc->sc_smc.sc_arpcom.ac_if;
244: int rv = 0;
245:
246: pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
247: pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
248:
249: ether_ifdetach(ifp);
250: if_detach(ifp);
251:
252: return (rv);
253: }
254:
255: int
256: sm_pcmcia_activate(dev, act)
257: struct device *dev;
258: enum devact act;
259: {
260: struct sm_pcmcia_softc *sc = (struct sm_pcmcia_softc *)dev;
261: struct ifnet *ifp = &sc->sc_smc.sc_arpcom.ac_if;
262: int s;
263:
264: s = splnet();
265: switch (act) {
266: case DVACT_ACTIVATE:
267: pcmcia_function_enable(sc->sc_pf);
268: sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
269: smc91cxx_intr, sc, sc->sc_smc.sc_dev.dv_xname);
270: smc91cxx_init(&sc->sc_smc);
271: break;
272:
273: case DVACT_DEACTIVATE:
274: ifp->if_timer = 0;
275: if (ifp->if_flags & IFF_RUNNING)
276: smc91cxx_stop(&sc->sc_smc);
277: pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
278: pcmcia_function_disable(sc->sc_pf);
279: break;
280: }
281: splx(s);
282: return (0);
283: }
284:
285: int
286: sm_pcmcia_ascii_enaddr(cisstr, myla)
287: const char *cisstr;
288: u_int8_t *myla;
289: {
290: char enaddr_str[12];
291: int i, j;
292:
293: if (strlen(cisstr) != 12) {
294: /* Bogus address! */
295: return (0);
296: }
297: bcopy(cisstr, enaddr_str, sizeof enaddr_str);
298: for (i = 0; i < 6; i++) {
299: for (j = 0; j < 2; j++) {
300: /* Convert to upper case. */
301: if (enaddr_str[(i * 2) + j] >= 'a' &&
302: enaddr_str[(i * 2) + j] <= 'z')
303: enaddr_str[(i * 2) + j] -= 'a' - 'A';
304:
305: /* Parse the digit. */
306: if (enaddr_str[(i * 2) + j] >= '0' &&
307: enaddr_str[(i * 2) + j] <= '9')
308: myla[i] |= enaddr_str[(i * 2) + j]
309: - '0';
310: else if (enaddr_str[(i * 2) + j] >= 'A' &&
311: enaddr_str[(i * 2) + j] <= 'F')
312: myla[i] |= enaddr_str[(i * 2) + j]
313: - 'A' + 10;
314: else {
315: /* Bogus digit!! */
316: return (0);
317: }
318:
319: /* Compensate for ordering of digits. */
320: if (j == 0)
321: myla[i] <<= 4;
322: }
323: }
324:
325: return (1);
326: }
327:
328: int
329: sm_pcmcia_funce_enaddr(parent, myla)
330: struct device *parent;
331: u_int8_t *myla;
332: {
333:
334: return (pcmcia_scan_cis(parent, sm_pcmcia_lannid_ciscallback, myla));
335: }
336:
337: int
338: sm_pcmcia_lannid_ciscallback(tuple, arg)
339: struct pcmcia_tuple *tuple;
340: void *arg;
341: {
342: u_int8_t *myla = arg;
343: int i;
344:
345: if (tuple->code == PCMCIA_CISTPL_FUNCE || tuple->code ==
346: PCMCIA_CISTPL_SPCL) {
347: /* subcode, length */
348: if (tuple->length < 2)
349: return (0);
350:
351: if ((pcmcia_tuple_read_1(tuple, 0) !=
352: PCMCIA_TPLFE_TYPE_LAN_NID) ||
353: (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN))
354: return (0);
355:
356: for (i = 0; i < ETHER_ADDR_LEN; i++)
357: myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
358: return (1);
359: }
360: return (0);
361: }
362:
363: int
364: sm_pcmcia_enable(sc)
365: struct smc91cxx_softc *sc;
366: {
367: struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)sc;
368:
369: /* Establish the interrupt handler. */
370: psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, smc91cxx_intr,
371: sc, sc->sc_dev.dv_xname);
372: if (psc->sc_ih == NULL) {
373: printf("%s: couldn't establish interrupt handler\n",
374: sc->sc_dev.dv_xname);
375: return (1);
376: }
377:
378: return (pcmcia_function_enable(psc->sc_pf));
379: }
380:
381: void
382: sm_pcmcia_disable(sc)
383: struct smc91cxx_softc *sc;
384: {
385: struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)sc;
386:
387: pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
388: pcmcia_function_disable(psc->sc_pf);
389: }
CVSweb