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