Line data Source code
1 : /* $OpenBSD: if_ep_pcmcia.c,v 1.48 2015/11/25 11:20:38 mpi Exp $ */
2 : /* $NetBSD: if_ep_pcmcia.c,v 1.16 1998/08/17 23:20:40 thorpej Exp $ */
3 :
4 : /*-
5 : * Copyright (c) 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 : /*
35 : * Copyright (c) 1997 Marc Horowitz. All rights reserved.
36 : *
37 : * Redistribution and use in source and binary forms, with or without
38 : * modification, are permitted provided that the following conditions
39 : * are met:
40 : * 1. Redistributions of source code must retain the above copyright
41 : * notice, this list of conditions and the following disclaimer.
42 : * 2. Redistributions in binary form must reproduce the above copyright
43 : * notice, this list of conditions and the following disclaimer in the
44 : * documentation and/or other materials provided with the distribution.
45 : * 3. All advertising materials mentioning features or use of this software
46 : * must display the following acknowledgement:
47 : * This product includes software developed by Marc Horowitz.
48 : * 4. The name of the author may not be used to endorse or promote products
49 : * derived from this software without specific prior written permission.
50 : *
51 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
52 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
53 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
54 : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
55 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
56 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
57 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
58 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
60 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 : */
62 :
63 : #include "bpfilter.h"
64 :
65 : #include <sys/param.h>
66 : #include <sys/systm.h>
67 : #include <sys/mbuf.h>
68 : #include <sys/socket.h>
69 : #include <sys/ioctl.h>
70 : #include <sys/errno.h>
71 : #include <sys/syslog.h>
72 : #include <sys/selinfo.h>
73 : #include <sys/timeout.h>
74 : #include <sys/device.h>
75 :
76 : #include <net/if.h>
77 : #include <net/if_media.h>
78 :
79 : #include <netinet/in.h>
80 : #include <netinet/if_ether.h>
81 :
82 : #if NBPFILTER > 0
83 : #include <net/bpf.h>
84 : #endif
85 :
86 : #include <machine/cpu.h>
87 : #include <machine/bus.h>
88 :
89 : #include <dev/mii/mii.h>
90 : #include <dev/mii/miivar.h>
91 :
92 : #include <dev/ic/elink3var.h>
93 :
94 : #include <dev/pcmcia/pcmciareg.h>
95 : #include <dev/pcmcia/pcmciavar.h>
96 : #include <dev/pcmcia/pcmciadevs.h>
97 :
98 : int ep_pcmcia_match(struct device *, void *, void *);
99 : void ep_pcmcia_attach(struct device *, struct device *, void *);
100 : int ep_pcmcia_detach(struct device *, int);
101 : int ep_pcmcia_activate(struct device *, int);
102 :
103 : int ep_pcmcia_get_enaddr(struct pcmcia_tuple *, void *);
104 : #ifdef notyet
105 : int ep_pcmcia_enable(struct ep_softc *);
106 : void ep_pcmcia_disable(struct ep_softc *);
107 : void ep_pcmcia_disable1(struct ep_softc *);
108 : #endif
109 :
110 : int ep_pcmcia_enable1(struct ep_softc *);
111 :
112 : struct ep_pcmcia_softc {
113 : struct ep_softc sc_ep; /* real "ep" softc */
114 :
115 : /* PCMCIA-specific goo */
116 : struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */
117 : int sc_io_window; /* our i/o window */
118 : struct pcmcia_function *sc_pf; /* our PCMCIA function */
119 : };
120 :
121 : struct cfattach ep_pcmcia_ca = {
122 : sizeof(struct ep_pcmcia_softc), ep_pcmcia_match, ep_pcmcia_attach,
123 : ep_pcmcia_detach, ep_pcmcia_activate
124 : };
125 :
126 : struct ep_pcmcia_product {
127 : u_int16_t epp_product; /* PCMCIA product ID */
128 : u_short epp_chipset; /* 3Com chipset used */
129 : int epp_flags; /* initial softc flags */
130 : int epp_expfunc; /* expected function */
131 : } ep_pcmcia_prod[] = {
132 : { PCMCIA_PRODUCT_3COM_3C562, EP_CHIPSET_3C509,
133 : 0, 0 },
134 :
135 : { PCMCIA_PRODUCT_3COM_3C589, EP_CHIPSET_3C509,
136 : 0, 0 },
137 :
138 : { PCMCIA_PRODUCT_3COM_3CXEM556, EP_CHIPSET_3C509,
139 : 0, 0 },
140 :
141 : { PCMCIA_PRODUCT_3COM_3CXEM556B,EP_CHIPSET_3C509,
142 : 0, 0 },
143 :
144 : { PCMCIA_PRODUCT_3COM_3C1, EP_CHIPSET_3C509,
145 : 0, 0 },
146 :
147 : { PCMCIA_PRODUCT_3COM_3CCFEM556BI, EP_CHIPSET_ROADRUNNER,
148 : EP_FLAGS_MII, 0 },
149 :
150 : { PCMCIA_PRODUCT_3COM_3C574, EP_CHIPSET_ROADRUNNER,
151 : EP_FLAGS_MII, 0 }
152 : };
153 :
154 : struct ep_pcmcia_product *ep_pcmcia_lookup(struct pcmcia_attach_args *);
155 :
156 : struct ep_pcmcia_product *
157 0 : ep_pcmcia_lookup(pa)
158 : struct pcmcia_attach_args *pa;
159 : {
160 : int i;
161 :
162 0 : for (i = 0; i < nitems(ep_pcmcia_prod); i++)
163 0 : if (pa->product == ep_pcmcia_prod[i].epp_product &&
164 0 : pa->pf->number == ep_pcmcia_prod[i].epp_expfunc)
165 0 : return &ep_pcmcia_prod[i];
166 :
167 0 : return (NULL);
168 0 : }
169 :
170 : int
171 0 : ep_pcmcia_match(parent, match, aux)
172 : struct device *parent;
173 : void *match, *aux;
174 : {
175 0 : struct pcmcia_attach_args *pa = aux;
176 :
177 0 : if (pa->manufacturer != PCMCIA_VENDOR_3COM)
178 0 : return (0);
179 :
180 0 : if (ep_pcmcia_lookup(pa) != NULL)
181 0 : return (1);
182 :
183 0 : return (0);
184 0 : }
185 :
186 : #ifdef notdef
187 : int
188 : ep_pcmcia_enable(sc)
189 : struct ep_softc *sc;
190 : {
191 : struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
192 : struct pcmcia_function *pf = psc->sc_pf;
193 :
194 : /* establish the interrupt. */
195 : sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, epintr,
196 : sc, sc->sc_dev.dv_xname);
197 : if (sc->sc_ih == NULL) {
198 : printf("%s: couldn't establish interrupt\n",
199 : sc->sc_dev.dv_xname);
200 : return (1);
201 : }
202 :
203 : return (ep_pcmcia_enable1(sc));
204 : }
205 : #endif
206 :
207 : int
208 0 : ep_pcmcia_enable1(sc)
209 : struct ep_softc *sc;
210 : {
211 0 : struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
212 0 : struct pcmcia_function *pf = psc->sc_pf;
213 : int ret;
214 :
215 0 : if ((ret = pcmcia_function_enable(pf)))
216 0 : return (ret);
217 :
218 0 : if ((psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) ||
219 0 : (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556) ||
220 0 : (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556B)) {
221 : int reg;
222 :
223 : /* turn off the serial-disable bit */
224 :
225 0 : reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
226 0 : if (reg & 0x08) {
227 0 : reg &= ~0x08;
228 0 : pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
229 0 : }
230 :
231 0 : }
232 :
233 0 : return (ret);
234 0 : }
235 :
236 : #ifdef notyet
237 : void
238 : ep_pcmcia_disable(sc)
239 : struct ep_softc *sc;
240 : {
241 : struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
242 :
243 : pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
244 : ep_pcmcia_disable1(sc);
245 : }
246 :
247 : void
248 : ep_pcmcia_disable1(sc)
249 : struct ep_softc *sc;
250 : {
251 : struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
252 :
253 : pcmcia_function_disable(psc->sc_pf);
254 : }
255 : #endif
256 :
257 : void
258 0 : ep_pcmcia_attach(parent, self, aux)
259 : struct device *parent, *self;
260 : void *aux;
261 : {
262 0 : struct ep_pcmcia_softc *psc = (void *) self;
263 0 : struct ep_softc *sc = &psc->sc_ep;
264 0 : struct pcmcia_attach_args *pa = aux;
265 : struct pcmcia_config_entry *cfe;
266 : struct ep_pcmcia_product *epp;
267 0 : u_int8_t myla[ETHER_ADDR_LEN];
268 : u_int8_t *enaddr = NULL;
269 : const char *intrstr;
270 : int i;
271 :
272 0 : psc->sc_pf = pa->pf;
273 0 : cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head);
274 :
275 : /* Enable the card. */
276 0 : pcmcia_function_init(pa->pf, cfe);
277 0 : if (ep_pcmcia_enable1(sc))
278 0 : printf(": function enable failed\n");
279 :
280 : #ifdef notyet
281 : sc->enabled = 1;
282 : #endif
283 :
284 0 : if (cfe->num_memspace != 0)
285 0 : printf(": unexpected number of memory spaces %d should be 0\n",
286 : cfe->num_memspace);
287 :
288 0 : if (cfe->num_iospace != 1)
289 0 : printf(": unexpected number of I/O spaces %d should be 1\n",
290 : cfe->num_iospace);
291 :
292 0 : if (pa->product == PCMCIA_PRODUCT_3COM_3C562) {
293 0 : bus_addr_t maxaddr = (pa->pf->sc->iobase + pa->pf->sc->iosize);
294 :
295 0 : for (i = pa->pf->sc->iobase; i < maxaddr; i += 0x10) {
296 : /*
297 : * the 3c562 can only use 0x??00-0x??7f
298 : * according to the Linux driver
299 : */
300 0 : if (i & 0x80)
301 : continue;
302 0 : if (pcmcia_io_alloc(pa->pf, i, cfe->iospace[0].length,
303 0 : cfe->iospace[0].length, &psc->sc_pcioh) == 0)
304 : break;
305 : }
306 0 : if (i >= maxaddr) {
307 0 : printf(": can't allocate i/o space\n");
308 0 : return;
309 : }
310 0 : } else {
311 0 : if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length,
312 : cfe->iospace[0].length, &psc->sc_pcioh))
313 0 : printf(": can't allocate i/o space\n");
314 : }
315 :
316 0 : sc->sc_iot = psc->sc_pcioh.iot;
317 0 : sc->sc_ioh = psc->sc_pcioh.ioh;
318 :
319 0 : if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ?
320 0 : PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, cfe->iospace[0].length,
321 0 : &psc->sc_pcioh, &psc->sc_io_window)) {
322 0 : printf(": can't map i/o space\n");
323 0 : return;
324 : }
325 :
326 0 : printf(" port 0x%lx/%ld", psc->sc_pcioh.addr, psc->sc_pcioh.size);
327 :
328 0 : switch (pa->product) {
329 : case PCMCIA_PRODUCT_3COM_3C562:
330 : /*
331 : * 3c562a-c use this; 3c562d does it in the regular way.
332 : * we might want to check the revision and produce a warning
333 : * in the future.
334 : */
335 : /* FALLTHROUGH */
336 : case PCMCIA_PRODUCT_3COM_3C574:
337 : case PCMCIA_PRODUCT_3COM_3CCFEM556BI:
338 : /*
339 : * Apparently, some 3c574s do it this way, as well.
340 : */
341 0 : if (pcmcia_scan_cis(parent, ep_pcmcia_get_enaddr, myla))
342 0 : enaddr = myla;
343 : break;
344 : }
345 :
346 0 : sc->bustype = EP_BUS_PCMCIA;
347 :
348 0 : epp = ep_pcmcia_lookup(pa);
349 0 : if (epp == NULL)
350 0 : panic("ep_pcmcia_attach: impossible");
351 :
352 0 : sc->ep_flags = epp->epp_flags;
353 :
354 : #ifdef notyet
355 : sc->enable = ep_pcmcia_enable;
356 : sc->disable = ep_pcmcia_disable;
357 : #endif
358 :
359 : /* establish the interrupt. */
360 0 : sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, epintr, sc,
361 0 : sc->sc_dev.dv_xname);
362 0 : intrstr = pcmcia_intr_string(psc->sc_pf, sc->sc_ih);
363 0 : if (*intrstr)
364 0 : printf(", %s", intrstr);
365 :
366 0 : printf(":");
367 :
368 0 : epconfig(sc, epp->epp_chipset, enaddr);
369 :
370 : #ifdef notyet
371 : sc->enabled = 0;
372 :
373 : ep_pcmcia_disable1(sc);
374 : #endif
375 0 : }
376 :
377 : int
378 0 : ep_pcmcia_detach(dev, flags)
379 : struct device *dev;
380 : int flags;
381 : {
382 : int rv;
383 0 : struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *)dev;
384 :
385 0 : if ((rv = ep_detach(dev)) != 0)
386 0 : return (rv);
387 :
388 0 : pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
389 0 : pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
390 :
391 0 : return (0);
392 0 : }
393 :
394 : int
395 0 : ep_pcmcia_activate(dev, act)
396 : struct device *dev;
397 : int act;
398 : {
399 0 : struct ep_pcmcia_softc *sc = (struct ep_pcmcia_softc *)dev;
400 0 : struct ep_softc *esc = &sc->sc_ep;
401 0 : struct ifnet *ifp = &esc->sc_arpcom.ac_if;
402 :
403 0 : switch (act) {
404 : case DVACT_SUSPEND:
405 0 : ifp->if_timer = 0;
406 0 : if (ifp->if_flags & IFF_RUNNING)
407 0 : epstop(esc);
408 0 : if (sc->sc_ep.sc_ih)
409 0 : pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ep.sc_ih);
410 0 : sc->sc_ep.sc_ih = NULL;
411 0 : pcmcia_function_disable(sc->sc_pf);
412 0 : break;
413 : case DVACT_RESUME:
414 0 : pcmcia_function_enable(sc->sc_pf);
415 0 : sc->sc_ep.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
416 0 : epintr, sc, esc->sc_dev.dv_xname);
417 0 : if (ifp->if_flags & IFF_UP)
418 0 : epinit(esc);
419 : break;
420 : case DVACT_DEACTIVATE:
421 0 : if (sc->sc_ep.sc_ih)
422 0 : pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ep.sc_ih);
423 0 : sc->sc_ep.sc_ih = NULL;
424 0 : pcmcia_function_disable(sc->sc_pf);
425 0 : break;
426 : }
427 0 : return (0);
428 : }
429 :
430 : int
431 0 : ep_pcmcia_get_enaddr(tuple, arg)
432 : struct pcmcia_tuple *tuple;
433 : void *arg;
434 : {
435 : u_int8_t *myla = arg;
436 : int i;
437 :
438 : /* this is 3c562a-c magic */
439 0 : if (tuple->code == 0x88) {
440 0 : if (tuple->length < ETHER_ADDR_LEN)
441 0 : return (0);
442 :
443 0 : for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
444 0 : myla[i] = pcmcia_tuple_read_1(tuple, i + 1);
445 0 : myla[i + 1] = pcmcia_tuple_read_1(tuple, i);
446 : }
447 :
448 0 : return (1);
449 : }
450 0 : return (0);
451 0 : }
|