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