xref: /netbsd-src/sys/dev/pcmcia/pcmcia_cis_quirks.c (revision d47bcd296c8b39243dd81e9cc75ea86330d4eeaf)
1 /*	$NetBSD: pcmcia_cis_quirks.c,v 1.36 2019/11/10 21:16:36 chs 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.36 2019/11/10 21:16:36 chs 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 	.number = 0,				/* function number */
54 	.function = PCMCIA_FUNCTION_NETWORK,
55 	.last_config_index = 0x07,		/* last cfe number */
56 	.ccr_base = 0x800,			/* ccr_base */
57 	.ccr_mask = 0x63,			/* ccr_mask */
58 };
59 
60 static const struct pcmcia_config_entry pcmcia_3cxem556_func0_cfe0 = {
61 	.number = 0x07,			/* cfe number */
62 	.flags = PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL,
63 	.iftype = PCMCIA_IFTYPE_IO,
64 	.num_iospace = 1,		/* num_iospace */
65 	.iomask = 4,			/* iomask */
66 	.iospace = { { .length = 0x0010, .start = 0 } },	/* iospace */
67 	.irqmask = 0xffff,		/* irqmask */
68 };
69 
70 static const struct pcmcia_function pcmcia_3cxem556_func1 = {
71 	.number = 1,			/* function number */
72 	.function = PCMCIA_FUNCTION_SERIAL,
73 	.last_config_index = 0x27,	/* last cfe number */
74 	.ccr_base = 0x900,		/* ccr_base */
75 	.ccr_mask = 0x63,		/* ccr_mask */
76 };
77 
78 static const struct pcmcia_config_entry pcmcia_3cxem556_func1_cfe0 = {
79 	.number = 0x27,			/* cfe number */
80 	.flags = PCMCIA_CFE_IO8 | PCMCIA_CFE_IRQLEVEL,
81 	.iftype = PCMCIA_IFTYPE_IO,
82 	.num_iospace = 1,		/* num_iospace */
83 	.iomask = 3,			/* iomask */
84 	.iospace = { { .length = 0x0008, .start = 0 } },	/* iospace */
85 	.irqmask = 0xffff,		/* irqmask */
86 };
87 
88 static const struct pcmcia_function pcmcia_3ccfem556bi_func0 = {
89 	.number = 0,			/* function number */
90 	.function = PCMCIA_FUNCTION_NETWORK,
91 	.last_config_index = 0x07,	/* last cfe number */
92 	.ccr_base = 0x1000,		/* ccr_base */
93 	.ccr_mask = 0x267,		/* ccr_mask */
94 };
95 
96 static const struct pcmcia_config_entry pcmcia_3ccfem556bi_func0_cfe0 = {
97 	.number = 0x07,		/* cfe number */
98 	.flags = PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL,
99 	.iftype = PCMCIA_IFTYPE_IO,
100 	.num_iospace = 1,	/* num_iospace */
101 	.iomask = 5,			/* iomask */
102 	.iospace = { { .length = 0x0020, .start = 0 } },	/* iospace */
103 };
104 
105 static const struct pcmcia_function pcmcia_3ccfem556bi_func1 = {
106 	.number = 1,			/* function number */
107 	.function = PCMCIA_FUNCTION_SERIAL,
108 	.last_config_index = 0x27,	/* last cfe number */
109 	.ccr_base = 0x1100,		/* ccr_base */
110 	.ccr_mask = 0x277,		/* ccr_mask */
111 };
112 
113 static const struct pcmcia_config_entry pcmcia_3ccfem556bi_func1_cfe0 = {
114 	.number = 0x27,		/* cfe number */
115 	.flags = PCMCIA_CFE_IO8 | PCMCIA_CFE_IRQLEVEL,
116 	.iftype = PCMCIA_IFTYPE_IO,
117 	.num_iospace = 1,	/* num_iospace */
118 	.iomask = 3,		/* iomask */
119 	.iospace = { { .length = 0x0008, .start = 0 } },	/* iospace */
120 	.irqmask = 0xffff,	/* irqmask */
121 };
122 
123 static const struct pcmcia_function pcmcia_sveclancard_func0 = {
124 	.number = 0,			/* function number */
125 	.function = PCMCIA_FUNCTION_NETWORK,
126 	.last_config_index = 0x1,	/* last cfe number */
127 	.ccr_base = 0x100,		/* ccr_base */
128 	.ccr_mask = 0x1,		/* ccr_mask */
129 };
130 
131 static const struct pcmcia_config_entry pcmcia_sveclancard_func0_cfe0 = {
132 	.number = 0x1,		/* cfe number */
133 	.flags = PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_RDYBSY_ACTIVE |
134 	    PCMCIA_CFE_WP_ACTIVE | PCMCIA_CFE_BVD_ACTIVE | PCMCIA_CFE_IO16,
135 	.iftype = PCMCIA_IFTYPE_IO,
136 	.num_iospace = 1,	/* num_iospace */
137 	.iomask = 5,		/* iomask */
138 	.iospace = { { .length = 0x20, .start = 0x300 } },	/* iospace */
139 	.irqmask = 0xdeb8,	/* irqmask */
140 };
141 
142 static const struct pcmcia_function pcmcia_ndc_nd5100_func0 = {
143 	.number = 0,			/* function number */
144 	.function = PCMCIA_FUNCTION_NETWORK,
145 	.last_config_index = 0x23,	/* last cfe number */
146 	.ccr_base = 0x3f8,		/* ccr_base */
147 	.ccr_mask = 0x3,		/* ccr_mask */
148 };
149 
150 static const struct pcmcia_config_entry pcmcia_ndc_nd5100_func0_cfe0 = {
151 	.number = 0x20,			/* cfe number */
152 	.flags = PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_IO16 |
153 	    PCMCIA_CFE_IRQLEVEL,
154 	.iftype = PCMCIA_IFTYPE_IO,
155 	.num_iospace = 1,		/* num_iospace */
156 	.iomask = 5,			/* iomask */
157 	.iospace = { { .length = 0x20, .start = 0x300 } },	/* iospace */
158 	.irqmask = 0xdeb8,		/* irqmask */
159 };
160 
161 static const struct pcmcia_function pcmcia_emtac_a2424i_func0 = {
162 	.number = 0,			/* function number */
163 	.function = PCMCIA_FUNCTION_NETWORK,
164 	.last_config_index = 0x21,	/* last cfe number */
165 	.ccr_base = 0x3e0,		/* ccr_base */
166 	.ccr_mask = 0x1,		/* ccr_mask */
167 };
168 
169 static const struct pcmcia_config_entry pcmcia_emtac_a2424i_func0_cfe0 = {
170 	.number = 0x21,		/* cfe number */
171 	.flags = PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL | PCMCIA_CFE_IRQPULSE,
172 	.iftype = PCMCIA_IFTYPE_IO,
173 	.num_iospace = 1,	/* num_iospace */
174 	.iomask = 6,		/* iomask */
175 	.iospace = { { .length = 0x40, .start = 0x100 } },	/* iospace */
176 	.irqmask = 0xffff,	/* irqmask */
177 };
178 
179 static const struct pcmcia_function pcmcia_fujitsu_j181_func0 = {
180 	.number = 0,			/* function number */
181 	.function = PCMCIA_FUNCTION_NETWORK,
182 	.last_config_index = 0x21,	/* last cfe number */
183 	.ccr_base = 0xfe0,		/* ccr_base */
184 	.ccr_mask = 0xf,		/* ccr_mask */
185 };
186 
187 static const struct pcmcia_config_entry pcmcia_fujitsu_j181_func0_cfe0 = {
188 	.number = 0xc,			/* cfe number */
189 	.flags = PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_WP_ACTIVE |
190 	    PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL |
191 	    PCMCIA_CFE_IRQPULSE,
192 	.iftype = PCMCIA_IFTYPE_IO,
193 	.num_iospace = 1,		/* num_iospace */
194 	.iomask = 10,			/* iomask */
195 	.iospace = { { .length = 0x20, .start = 0x140 } },	/* iospace */
196 	.irqmask = 0xffff,		/* irqmask */
197 };
198 
199 static const struct pcmcia_function pcmcia_necinfrontia_ax420n_func0 = {
200 	.number = 0,			/* function number */
201 	.function = PCMCIA_FUNCTION_SERIAL,
202 	.last_config_index = 0x38,	/* last cfe number */
203 	.ccr_base = 0x200,		/* ccr_base */
204 	.ccr_mask = 0x1f,		/* ccr_mask */
205 };
206 
207 static const struct pcmcia_config_entry pcmcia_necinfrontia_ax420n_func0_cfe0 = {
208 	.number = 0x25,			/* cfe number */
209 	.flags = PCMCIA_CFE_RDYBSY_ACTIVE | PCMCIA_CFE_IO8 |
210 		 PCMCIA_CFE_IRQLEVEL | PCMCIA_CFE_POWERDOWN |
211 		 PCMCIA_CFE_AUDIO,
212 	.iftype = PCMCIA_IFTYPE_IO,
213 	.num_iospace = 1,		/* num_iospace */
214 	.iomask = 10,			/* iomask */
215 	.iospace = { { .length = 0x8, .start = 0x3f8 } },	/* iospace */
216 	.irqmask = 0x86bc,		/* irqmask */
217 };
218 
219 static const struct pcmcia_cis_quirk pcmcia_cis_quirks[] = {
220 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556,
221 	  PCMCIA_CIS_INVALID,
222 	  &pcmcia_3cxem556_func0, &pcmcia_3cxem556_func0_cfe0 },
223 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556,
224 	  PCMCIA_CIS_INVALID,
225 	  &pcmcia_3cxem556_func1, &pcmcia_3cxem556_func1_cfe0 },
226 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT,
227 	  PCMCIA_CIS_INVALID,
228 	  &pcmcia_3cxem556_func0, &pcmcia_3cxem556_func0_cfe0 },
229 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT,
230 	  PCMCIA_CIS_INVALID,
231 	  &pcmcia_3cxem556_func1, &pcmcia_3cxem556_func1_cfe0 },
232 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI,
233 	  PCMCIA_CIS_INVALID,
234 	  &pcmcia_3ccfem556bi_func0, &pcmcia_3ccfem556bi_func0_cfe0 },
235 	{ PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI,
236 	  PCMCIA_CIS_INVALID,
237 	  &pcmcia_3ccfem556bi_func1, &pcmcia_3ccfem556bi_func1_cfe0 },
238 	{ PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
239 	  PCMCIA_CIS_SVEC_LANCARD,
240 	  &pcmcia_sveclancard_func0, &pcmcia_sveclancard_func0_cfe0 },
241 	{ PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
242 	  PCMCIA_CIS_NDC_ND5100_E,
243 	  &pcmcia_ndc_nd5100_func0, &pcmcia_ndc_nd5100_func0_cfe0 },
244 	{ PCMCIA_VENDOR_EMTAC, PCMCIA_PRODUCT_EMTAC_WLAN,
245 	  PCMCIA_CIS_INVALID,
246 	  &pcmcia_emtac_a2424i_func0, &pcmcia_emtac_a2424i_func0_cfe0 },
247 	{ PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
248 	  PCMCIA_CIS_FUJITSU_FMV_J181,
249 	  &pcmcia_fujitsu_j181_func0, &pcmcia_fujitsu_j181_func0_cfe0 },
250 	{ PCMCIA_VENDOR_NECINFRONTIA, PCMCIA_PRODUCT_NECINFRONTIA_AX420N,
251 	  PCMCIA_CIS_INVALID,
252 	  &pcmcia_necinfrontia_ax420n_func0,
253 	  &pcmcia_necinfrontia_ax420n_func0_cfe0 },
254 };
255 
256 static const int pcmcia_cis_nquirks =
257    sizeof(pcmcia_cis_quirks) / sizeof(pcmcia_cis_quirks[0]);
258 
259 void
pcmcia_check_cis_quirks(struct pcmcia_softc * sc)260 pcmcia_check_cis_quirks(struct pcmcia_softc *sc)
261 {
262 	int wiped = 0;
263 	size_t i, j;
264 	struct pcmcia_function *pf;
265 	const struct pcmcia_function *pf_last;
266 	struct pcmcia_config_entry *cfe;
267 	struct pcmcia_card *card = &sc->card;
268 	const struct pcmcia_cis_quirk *quirk;
269 
270 	pf = NULL;
271 	pf_last = NULL;
272 
273 	for (i = 0; i < pcmcia_cis_nquirks; i++) {
274 		quirk = &pcmcia_cis_quirks[i];
275 
276 		if (card->manufacturer == quirk->manufacturer &&
277 		    card->manufacturer != PCMCIA_VENDOR_INVALID &&
278 		    card->product == quirk->product &&
279 		    card->product != PCMCIA_PRODUCT_INVALID)
280 			goto match;
281 
282 		for (j = 0; j < 2; j++)
283 			if (card->cis1_info[j] == NULL ||
284 			    quirk->cis1_info[j] == NULL ||
285 			    strcmp(card->cis1_info[j],
286 			    quirk->cis1_info[j]) != 0)
287 				goto nomatch;
288 
289 match:
290 		if (!wiped) {
291 			if (pcmcia_verbose) {
292 				printf("%s: using CIS quirks for ",
293 				    device_xname(sc->dev));
294 				for (j = 0; j < 4; j++) {
295 					if (card->cis1_info[j] == NULL)
296 						break;
297 					if (j)
298 						printf(", ");
299 					printf("%s", card->cis1_info[j]);
300 				}
301 				printf("\n");
302 			}
303 			pcmcia_free_pf(&card->pf_head);
304 			wiped = 1;
305 		}
306 
307 		if (pf_last != quirk->pf) {
308 			/*
309 			 * XXX: a driver which still calls pcmcia_card_attach
310 			 * very early attach stage should be fixed instead.
311 			 */
312 			pf = malloc(sizeof(*pf), M_DEVBUF, M_WAITOK);
313 			*pf = *quirk->pf;
314 			SIMPLEQ_INIT(&pf->cfe_head);
315 			SIMPLEQ_INSERT_TAIL(&card->pf_head, pf, pf_list);
316 			pf_last = quirk->pf;
317 		}
318 
319 		/*
320 		 * XXX: see above.
321 		 */
322 		cfe = malloc(sizeof(*cfe), M_DEVBUF, M_WAITOK);
323 		*cfe = *quirk->cfe;
324 		KASSERT(pf != NULL);
325 		SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list);
326 
327 nomatch:;
328 	}
329 }
330