xref: /netbsd-src/sys/dev/pcmcia/pcmcia_cis_quirks.c (revision e5548b402ae4c44fb816de42c7bba9581ce23ef5)
1 /*	$NetBSD: pcmcia_cis_quirks.c,v 1.26 2005/12/11 12:23:23 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1998 Marc Horowitz.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by Marc Horowitz.
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: pcmcia_cis_quirks.c,v 1.26 2005/12/11 12:23:23 christos Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/kernel.h>
39 #include <sys/mbuf.h>
40 
41 #include <dev/pcmcia/pcmciadevs.h>
42 #include <dev/pcmcia/pcmciareg.h>
43 #include <dev/pcmcia/pcmciachip.h>
44 #include <dev/pcmcia/pcmciavar.h>
45 
46 /* There are cards out there whose CIS flat-out lies.  This file
47    contains struct pcmcia_function chains for those devices. */
48 
49 /* these structures are just static templates which are then copied
50    into "live" allocated structures */
51 
52 static const struct pcmcia_function pcmcia_3cxem556_func0 = {
53 	0,			/* function number */
54 	PCMCIA_FUNCTION_NETWORK,
55 	0x07,			/* last cfe number */
56 	0x800,			/* ccr_base */
57 	0x63,			/* ccr_mask */
58 };
59 
60 static const struct pcmcia_config_entry pcmcia_3cxem556_func0_cfe0 = {
61 	0x07,			/* cfe number */
62 	PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL,
63 	PCMCIA_IFTYPE_IO,
64 	1,			/* num_iospace */
65 	4,			/* iomask */
66 	{ { 0x0010, 0 } },	/* iospace */
67 	0xffff,			/* irqmask */
68 	0,			/* num_memspace */
69 	{ { 0 } },		/* memspace */
70 	0,			/* maxtwins */
71 };
72 
73 static const struct pcmcia_function pcmcia_3cxem556_func1 = {
74 	1,			/* function number */
75 	PCMCIA_FUNCTION_SERIAL,
76 	0x27,			/* last cfe number */
77 	0x900,			/* ccr_base */
78 	0x63,			/* ccr_mask */
79 };
80 
81 static const struct pcmcia_config_entry pcmcia_3cxem556_func1_cfe0 = {
82 	0x27,			/* cfe number */
83 	PCMCIA_CFE_IO8 | PCMCIA_CFE_IRQLEVEL,
84 	PCMCIA_IFTYPE_IO,
85 	1,			/* num_iospace */
86 	3,			/* iomask */
87 	{ { 0x0008, 0 } },	/* iospace */
88 	0xffff,			/* irqmask */
89 	0,			/* num_memspace */
90 	{ { 0 } },		/* memspace */
91 	0,			/* maxtwins */
92 };
93 
94 static const struct pcmcia_function pcmcia_3ccfem556bi_func0 = {
95 	0,			/* function number */
96 	PCMCIA_FUNCTION_NETWORK,
97 	0x07,			/* last cfe number */
98 	0x1000,			/* ccr_base */
99 	0x267,			/* ccr_mask */
100 };
101 
102 static const struct pcmcia_config_entry pcmcia_3ccfem556bi_func0_cfe0 = {
103 	0x07,			/* cfe number */
104 	PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL,
105 	PCMCIA_IFTYPE_IO,
106 	1,			/* num_iospace */
107 	5,			/* iomask */
108 	{ { 0x0020, 0 } },	/* iospace */
109 	0xffff,			/* irqmask */
110 	0,			/* num_memspace */
111 	{ { 0 } },		/* memspace */
112 	0,			/* maxtwins */
113 };
114 
115 static const struct pcmcia_function pcmcia_3ccfem556bi_func1 = {
116 	1,			/* function number */
117 	PCMCIA_FUNCTION_SERIAL,
118 	0x27,			/* last cfe number */
119 	0x1100,			/* ccr_base */
120 	0x277,			/* ccr_mask */
121 };
122 
123 static const struct pcmcia_config_entry pcmcia_3ccfem556bi_func1_cfe0 = {
124 	0x27,			/* cfe number */
125 	PCMCIA_CFE_IO8 | PCMCIA_CFE_IRQLEVEL,
126 	PCMCIA_IFTYPE_IO,
127 	1,			/* num_iospace */
128 	3,			/* iomask */
129 	{ { 0x0008, 0 } },	/* iospace */
130 	0xffff,			/* irqmask */
131 	0,			/* num_memspace */
132 	{ { 0 } },		/* memspace */
133 	0,			/* maxtwins */
134 };
135 
136 static const struct pcmcia_function pcmcia_sveclancard_func0 = {
137 	0,			/* function number */
138 	PCMCIA_FUNCTION_NETWORK,
139 	0x1,			/* last cfe number */
140 	0x100,			/* ccr_base */
141 	0x1,			/* ccr_mask */
142 };
143 
144 static const struct pcmcia_config_entry pcmcia_sveclancard_func0_cfe0 = {
145 	0x1,			/* cfe number */
146 	PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_RDYBSY_ACTIVE |
147 	PCMCIA_CFE_WP_ACTIVE | PCMCIA_CFE_BVD_ACTIVE | PCMCIA_CFE_IO16,
148 	PCMCIA_IFTYPE_IO,
149 	1,			/* num_iospace */
150 	5,			/* iomask */
151 	{ { 0x20, 0x300 } },	/* iospace */
152 	0xdeb8,			/* irqmask */
153 	0,			/* num_memspace */
154 	{ { 0 } },		/* memspace */
155 	0,			/* maxtwins */
156 };
157 
158 static const struct pcmcia_function pcmcia_ndc_nd5100_func0 = {
159 	0,			/* function number */
160 	PCMCIA_FUNCTION_NETWORK,
161 	0x23,			/* last cfe number */
162 	0x3f8,			/* ccr_base */
163 	0x3,			/* ccr_mask */
164 };
165 
166 static const struct pcmcia_config_entry pcmcia_ndc_nd5100_func0_cfe0 = {
167 	0x20,			/* cfe number */
168 	PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL,
169 	PCMCIA_IFTYPE_IO,
170 	1,			/* num_iospace */
171 	5,			/* iomask */
172 	{ { 0x20, 0x300 } },	/* iospace */
173 	0xdeb8,			/* irqmask */
174 	0,			/* num_memspace */
175 	{ { 0 } },		/* memspace */
176 	0,			/* maxtwins */
177 };
178 
179 static const struct pcmcia_function pcmcia_emtac_a2424i_func0 = {
180 	0,			/* function number */
181 	PCMCIA_FUNCTION_NETWORK,
182 	0x21,			/* last cfe number */
183 	0x3e0,			/* ccr_base */
184 	0x1,			/* ccr_mask */
185 };
186 
187 static const struct pcmcia_config_entry pcmcia_emtac_a2424i_func0_cfe0 = {
188 	0x21,			/* cfe number */
189 	PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL | PCMCIA_CFE_IRQPULSE,
190 	PCMCIA_IFTYPE_IO,
191 	1,			/* num_iospace */
192 	6,			/* iomask */
193 	{ { 0x40, 0x100 } },	/* iospace */
194 	0xffff,			/* irqmask */
195 	0,			/* num_memspace */
196 	{ { 0 } },		/* memspace */
197 	0,			/* maxtwins */
198 };
199 
200 static const struct pcmcia_function pcmcia_fujitsu_j181_func0 = {
201 	0,			/* function number */
202 	PCMCIA_FUNCTION_NETWORK,
203 	0x21,			/* last cfe number */
204 	0xfe0,			/* ccr_base */
205 	0xf,			/* ccr_mask */
206 };
207 
208 static const struct pcmcia_config_entry pcmcia_fujitsu_j181_func0_cfe0 = {
209 	0xc,			/* cfe number */
210 	PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_WP_ACTIVE | PCMCIA_CFE_IO8 |
211 	PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL | PCMCIA_CFE_IRQPULSE,
212 	PCMCIA_IFTYPE_IO,
213 	1,			/* num_iospace */
214 	10,			/* iomask */
215 	{ { 0x20, 0x140 } },	/* iospace */
216 	0xffff,			/* irqmask */
217 	0,			/* num_memspace */
218 	{ { 0 } },		/* memspace */
219 	0,			/* maxtwins */
220 };
221 
222 static const struct pcmcia_cis_quirk pcmcia_cis_quirks[] = {
223 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, PCMCIA_CIS_INVALID,
224 	  &pcmcia_3cxem556_func0, &pcmcia_3cxem556_func0_cfe0 },
225 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, PCMCIA_CIS_INVALID,
226 	  &pcmcia_3cxem556_func1, &pcmcia_3cxem556_func1_cfe0 },
227 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, PCMCIA_CIS_INVALID,
228 	  &pcmcia_3cxem556_func0, &pcmcia_3cxem556_func0_cfe0 },
229 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, PCMCIA_CIS_INVALID,
230 	  &pcmcia_3cxem556_func1, &pcmcia_3cxem556_func1_cfe0 },
231 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI,
232 	  PCMCIA_CIS_INVALID,
233 	  &pcmcia_3ccfem556bi_func0, &pcmcia_3ccfem556bi_func0_cfe0 },
234 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI,
235 	  PCMCIA_CIS_INVALID,
236 	  &pcmcia_3ccfem556bi_func1, &pcmcia_3ccfem556bi_func1_cfe0 },
237 	{ PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, PCMCIA_CIS_SVEC_LANCARD,
238 	  &pcmcia_sveclancard_func0, &pcmcia_sveclancard_func0_cfe0 },
239 	{ PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, PCMCIA_CIS_NDC_ND5100_E,
240 	  &pcmcia_ndc_nd5100_func0, &pcmcia_ndc_nd5100_func0_cfe0 },
241 	{ PCMCIA_VENDOR_EMTAC, PCMCIA_PRODUCT_EMTAC_WLAN, PCMCIA_CIS_INVALID,
242 	  &pcmcia_emtac_a2424i_func0, &pcmcia_emtac_a2424i_func0_cfe0 },
243 	{ PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
244 	  PCMCIA_CIS_FUJITSU_FMV_J181,
245 	  &pcmcia_fujitsu_j181_func0, &pcmcia_fujitsu_j181_func0_cfe0 },
246 };
247 
248 static const int pcmcia_cis_nquirks =
249    sizeof(pcmcia_cis_quirks) / sizeof(pcmcia_cis_quirks[0]);
250 
251 void
252 pcmcia_check_cis_quirks(sc)
253 	struct pcmcia_softc *sc;
254 {
255 	int wiped = 0;
256 	size_t i, j;
257 	struct pcmcia_function *pf;
258 	const struct pcmcia_function *pf_last;
259 	struct pcmcia_config_entry *cfe;
260 	struct pcmcia_card *card = &sc->card;
261 	const struct pcmcia_cis_quirk *quirk;
262 
263 	pf = NULL;
264 	pf_last = NULL;
265 
266 	for (i = 0; i < pcmcia_cis_nquirks; i++) {
267 		quirk = &pcmcia_cis_quirks[i];
268 
269 		if (card->manufacturer == quirk->manufacturer &&
270 		    card->manufacturer != PCMCIA_VENDOR_INVALID &&
271 		    card->product == quirk->product &&
272 		    card->product != PCMCIA_PRODUCT_INVALID)
273 			goto match;
274 
275 		for (j = 0; j < 2; j++)
276 			if (card->cis1_info[j] == NULL ||
277 			    quirk->cis1_info[j] == NULL ||
278 			    strcmp(card->cis1_info[j],
279 			    quirk->cis1_info[j]) != 0)
280 				goto nomatch;
281 
282 match:
283 		if (!wiped) {
284 			if (pcmcia_verbose) {
285 				printf("%s: using CIS quirks for ",
286 				    sc->dev.dv_xname);
287 				for (j = 0; j < 4; j++) {
288 					if (card->cis1_info[j] == NULL)
289 						break;
290 					if (j)
291 						printf(", ");
292 					printf("%s", card->cis1_info[j]);
293 				}
294 				printf("\n");
295 			}
296 			pcmcia_free_pf(&card->pf_head);
297 			wiped = 1;
298 		}
299 
300 		if (pf_last != quirk->pf) {
301 			/*
302 			 * XXX: a driver which still calls pcmcia_card_attach
303 			 * very early attach stage should be fixed instead.
304 			 */
305 			pf = malloc(sizeof(*pf), M_DEVBUF,
306 			    cold ? M_NOWAIT : M_WAITOK);
307 			if (pf == NULL)
308 				panic("pcmcia_check_cis_quirks: malloc pf");
309 			*pf = *quirk->pf;
310 			SIMPLEQ_INIT(&pf->cfe_head);
311 			SIMPLEQ_INSERT_TAIL(&card->pf_head, pf, pf_list);
312 			pf_last = quirk->pf;
313 		}
314 
315 		/*
316 		 * XXX: see above.
317 		 */
318 		cfe = malloc(sizeof(*cfe), M_DEVBUF,
319 		    cold ? M_NOWAIT : M_WAITOK);
320 		if (cfe == NULL)
321 			panic("pcmcia_check_cis_quirks: malloc cfe");
322 		*cfe = *quirk->cfe;
323 		SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list);
324 
325 nomatch:;
326 	}
327 }
328