1 /* $NetBSD: pcmcia_cis_quirks.c,v 1.35 2013/09/14 13:13:33 joerg 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.35 2013/09/14 13:13:33 joerg 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 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, 313 cold ? M_NOWAIT : M_WAITOK); 314 if (pf == NULL) 315 panic("pcmcia_check_cis_quirks: malloc pf"); 316 *pf = *quirk->pf; 317 SIMPLEQ_INIT(&pf->cfe_head); 318 SIMPLEQ_INSERT_TAIL(&card->pf_head, pf, pf_list); 319 pf_last = quirk->pf; 320 } 321 322 /* 323 * XXX: see above. 324 */ 325 cfe = malloc(sizeof(*cfe), M_DEVBUF, 326 cold ? M_NOWAIT : M_WAITOK); 327 if (cfe == NULL) 328 panic("pcmcia_check_cis_quirks: malloc cfe"); 329 *cfe = *quirk->cfe; 330 KASSERT(pf != NULL); 331 SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list); 332 333 nomatch:; 334 } 335 } 336