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