xref: /netbsd-src/sys/dev/pcmcia/if_ep_pcmcia.c (revision 8bc54e5be648e06e7c6b48f7611f8bccfda032d4)
1 /*	$NetBSD: if_ep_pcmcia.c,v 1.64 2016/07/07 06:55:42 msaitoh Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998, 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  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *	This product includes software developed by Marc Horowitz.
47  * 4. The name of the author may not be used to endorse or promote products
48  *    derived from this software without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
51  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
54  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
59  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60  */
61 
62 #include <sys/cdefs.h>
63 __KERNEL_RCSID(0, "$NetBSD: if_ep_pcmcia.c,v 1.64 2016/07/07 06:55:42 msaitoh Exp $");
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/select.h>
73 #include <sys/device.h>
74 
75 #include <net/if.h>
76 #include <net/if_dl.h>
77 #include <net/if_ether.h>
78 #include <net/if_media.h>
79 
80 #include <sys/cpu.h>
81 #include <sys/bus.h>
82 #include <sys/intr.h>
83 
84 #include <dev/mii/miivar.h>
85 
86 #include <dev/ic/elink3var.h>
87 #include <dev/ic/elink3reg.h>
88 
89 #include <dev/pcmcia/pcmciareg.h>
90 #include <dev/pcmcia/pcmciavar.h>
91 #include <dev/pcmcia/pcmciadevs.h>
92 
93 int	ep_pcmcia_match(device_t, cfdata_t, void *);
94 void	ep_pcmcia_attach(device_t, device_t, void *);
95 int	ep_pcmcia_detach(device_t, int);
96 
97 int	ep_pcmcia_get_enaddr(struct pcmcia_tuple *, void *);
98 int	ep_pcmcia_enable(struct ep_softc *);
99 void	ep_pcmcia_disable(struct ep_softc *);
100 
101 void	ep_pcmcia_disable1(struct ep_softc *);
102 
103 struct ep_pcmcia_softc {
104 	struct ep_softc sc_ep;			/* real "ep" softc */
105 
106 	/* PCMCIA-specific goo */
107 	struct pcmcia_io_handle sc_pcioh;	/* PCMCIA i/o space info */
108 	int sc_io_window;			/* our i/o window */
109 	struct pcmcia_function *sc_pf;		/* our PCMCIA function */
110 };
111 
112 CFATTACH_DECL_NEW(ep_pcmcia, sizeof(struct ep_pcmcia_softc),
113     ep_pcmcia_match, ep_pcmcia_attach, ep_pcmcia_detach, ep_activate);
114 
115 const struct ep_pcmcia_product {
116 	struct pcmcia_product epp_product;
117 	u_short		epp_chipset;	/* 3Com chipset used */
118 	int		epp_flags;	/* initial softc flags */
119 } ep_pcmcia_products[] = {
120 	{ { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3C562,
121 	    PCMCIA_CIS_INVALID },
122 	  ELINK_CHIPSET_3C509, 0 },
123 
124 	{ { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3C589,
125 	    PCMCIA_CIS_INVALID },
126 	  ELINK_CHIPSET_3C509, 0 },
127 
128 	{ { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556,
129 	    PCMCIA_CIS_INVALID },
130 	  ELINK_CHIPSET_3C509, 0 },
131 
132 	{ { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT,
133 	    PCMCIA_CIS_INVALID },
134 	  ELINK_CHIPSET_3C509, 0 },
135 
136 	{ { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3C574,
137 	    PCMCIA_CIS_INVALID },
138 	  ELINK_CHIPSET_ROADRUNNER, ELINK_FLAGS_MII },
139 
140 	{ { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI,
141 	    PCMCIA_CIS_INVALID },
142 	  ELINK_CHIPSET_ROADRUNNER, ELINK_FLAGS_MII },
143 
144 	{ { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3C1,
145 	    PCMCIA_CIS_INVALID },
146 	  ELINK_CHIPSET_3C509, 0 },
147 };
148 const size_t ep_pcmcia_nproducts =
149     sizeof(ep_pcmcia_products) / sizeof(ep_pcmcia_products[0]);
150 
151 int
ep_pcmcia_match(device_t parent,cfdata_t match,void * aux)152 ep_pcmcia_match(device_t parent, cfdata_t match, void *aux)
153 {
154 	struct pcmcia_attach_args *pa = aux;
155 
156 	/* This is to differentiate the serial function of some cards. */
157 	if (pa->pf->function != PCMCIA_FUNCTION_NETWORK)
158 		return 0;
159 
160 	if (pcmcia_product_lookup(pa, ep_pcmcia_products, ep_pcmcia_nproducts,
161 	    sizeof(ep_pcmcia_products[0]), NULL))
162 		return 1;
163 	return 0;
164 }
165 
166 int
ep_pcmcia_enable(struct ep_softc * sc)167 ep_pcmcia_enable(struct ep_softc *sc)
168 {
169 	struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
170 	struct pcmcia_function *pf = psc->sc_pf;
171 	int error;
172 
173 	/* establish the interrupt. */
174 	sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, epintr, sc);
175 	if (!sc->sc_ih)
176 		return EIO;
177 
178 	error = pcmcia_function_enable(pf);
179 	if (error) {
180 		pcmcia_intr_disestablish(pf, sc->sc_ih);
181 		sc->sc_ih = 0;
182 		return error;
183 	}
184 
185 	if ((psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) ||
186 	    (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556) ||
187 	    (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556INT)) {
188 		int reg;
189 
190 		/* turn off the serial-disable bit */
191 
192 		reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
193 		if (reg & 0x08) {
194 			reg &= ~0x08;
195 			pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
196 		}
197 
198 	}
199 
200 	return 0;
201 }
202 
203 void
ep_pcmcia_disable(struct ep_softc * sc)204 ep_pcmcia_disable(struct ep_softc *sc)
205 {
206 	struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
207 
208 	pcmcia_function_disable(psc->sc_pf);
209 	pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
210 	sc->sc_ih = 0;
211 }
212 
213 void
ep_pcmcia_attach(device_t parent,device_t self,void * aux)214 ep_pcmcia_attach(device_t parent, device_t self, void *aux)
215 {
216 	struct ep_pcmcia_softc *psc = device_private(self);
217 	struct ep_softc *sc = &psc->sc_ep;
218 	struct pcmcia_attach_args *pa = aux;
219 	struct pcmcia_config_entry *cfe;
220 	const struct ep_pcmcia_product *epp;
221 	u_int8_t myla[ETHER_ADDR_LEN];
222 	u_int8_t *enaddr = NULL;
223 	int i;
224 	int error;
225 
226 	sc->sc_dev = self;
227 	psc->sc_pf = pa->pf;
228 
229 	SIMPLEQ_FOREACH(cfe, &pa->pf->cfe_head, cfe_list) {
230 		if (cfe->num_memspace != 0)
231 			continue;
232 		if (cfe->num_iospace != 1)
233 			continue;
234 
235 		if (pa->product == PCMCIA_PRODUCT_3COM_3C562) {
236 			/*
237 			 * the 3c562 can only use 0x??00-0x??7f
238 			 * according to the Linux driver
239 			 */
240 
241 			/*
242 			 * 3c562 i/o may decodes address line not only A0-3
243 			 * but also A7.  Anyway, we must sweep at most
244 			 * [0x0000, 0x0100).  The address higher is given by a
245 			 * pcmcia bridge.  But pcmcia bus-space allocation
246 			 * function implies cards will decode 10-bit address
247 			 * line.  So we must search [0x0000, 0x0400).
248 			 *
249 			 * XXX: We must not check the bunch of I/O space range
250 			 * [0x400*n, 0x300 + 0x400*n) because they are
251 			 * reserved for legacy ISA devices and their alias
252 			 * images on PC/AT architecture.
253 			 */
254 			for (i = 0x0300; i < 0x0380; i += 0x10) {
255 				if (pcmcia_io_alloc(pa->pf, i,
256 				    cfe->iospace[0].length,
257 				    cfe->iospace[0].length,
258 				    &psc->sc_pcioh) == 0)
259 					break;
260 			}
261 			if (i != 0x0380)
262 				break;
263 		} else {
264 			if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
265 			    cfe->iospace[0].length, cfe->iospace[0].length,
266 			    &psc->sc_pcioh) == 0)
267 				break;
268 		}
269 	}
270 	if (!cfe) {
271 		aprint_error_dev(self, "failed to allocate I/O space\n");
272 		goto ioalloc_failed;
273 	}
274 
275 	sc->sc_iot = psc->sc_pcioh.iot;
276 	sc->sc_ioh = psc->sc_pcioh.ioh;
277 
278 	/* Enable the card. */
279 	pcmcia_function_init(pa->pf, cfe);
280 
281 	if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ?
282 	    PCMCIA_WIDTH_AUTO : PCMCIA_WIDTH_IO8), &psc->sc_pcioh,
283 	    &psc->sc_io_window)) {
284 		aprint_error_dev(self, "can't map i/o space\n");
285 		goto iomap_failed;
286 	}
287 
288 	error = ep_pcmcia_enable(sc);
289 	if (error)
290 		goto enable_failed;
291 	sc->enabled = 1;
292 
293 	switch (pa->product) {
294 	case PCMCIA_PRODUCT_3COM_3C562:
295 		/*
296 		 * 3c562a-c use this; 3c562d does it in the regular way.
297 		 * we might want to check the revision and produce a warning
298 		 * in the future.
299 		 */
300 		/* FALLTHROUGH */
301 	case PCMCIA_PRODUCT_3COM_3C574:
302 	case PCMCIA_PRODUCT_3COM_3CCFEM556BI:
303 		/*
304 		 * Apparently, some 3c574s do it this way, as well.
305 		 */
306 		if (pcmcia_scan_cis(parent, ep_pcmcia_get_enaddr, myla))
307 			enaddr = myla;
308 		break;
309 	}
310 
311 	epp = pcmcia_product_lookup(pa, ep_pcmcia_products,
312 	    ep_pcmcia_nproducts, sizeof(ep_pcmcia_products[0]), NULL);
313 	if (!epp)
314 		panic("ep_pcmcia_attach: impossible");
315 
316 	sc->bustype = ELINK_BUS_PCMCIA;
317 	sc->ep_flags = epp->epp_flags;
318 
319 	sc->enable = ep_pcmcia_enable;
320 	sc->disable = ep_pcmcia_disable;
321 
322 	if (epconfig(sc, epp->epp_chipset, enaddr))
323 		aprint_error_dev(self, "couldn't configure controller\n");
324 
325 	sc->enabled = 0;
326 	ep_pcmcia_disable(sc);
327 	return;
328 
329 enable_failed:
330 	pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
331 iomap_failed:
332 	pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
333 ioalloc_failed:
334 	psc->sc_io_window = -1;
335 }
336 
337 int
ep_pcmcia_detach(device_t self,int flags)338 ep_pcmcia_detach(device_t self, int flags)
339 {
340 	struct ep_pcmcia_softc *psc = device_private(self);
341 	int rv;
342 
343 	if (psc->sc_io_window == -1)
344 		/* Nothing to detach. */
345 		return 0;
346 
347 	rv = ep_detach(self, flags);
348 	if (rv != 0)
349 		return rv;
350 
351 	/* Unmap our i/o window. */
352 	pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
353 
354 	/* Free our i/o space. */
355 	pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
356 
357 	return 0;
358 }
359 
360 int
ep_pcmcia_get_enaddr(struct pcmcia_tuple * tuple,void * arg)361 ep_pcmcia_get_enaddr(struct pcmcia_tuple *tuple, void *arg)
362 {
363 	u_int8_t *myla = arg;
364 	int i;
365 
366 	/* this is 3c562a-c magic */
367 	if (tuple->code == 0x88) {
368 		if (tuple->length < ETHER_ADDR_LEN)
369 			return 0;
370 
371 		for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
372 			myla[i] = pcmcia_tuple_read_1(tuple, i + 1);
373 			myla[i + 1] = pcmcia_tuple_read_1(tuple, i);
374 		}
375 
376 		return 1;
377 	}
378 	return 0;
379 }
380