Home | History | Annotate | Line # | Download | only in pcmcia
pcmcia_cis_quirks.c revision 1.25
      1 /*	$NetBSD: pcmcia_cis_quirks.c,v 1.25 2005/02/27 00:27:43 perry 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.25 2005/02/27 00:27:43 perry 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