1/* $NetBSD: pcmcia_cis_quirks.c,v 1.33 2008/09/06 22:07:11 rmind 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.33 2008/09/06 22:07:11 rmind 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 52static 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 60static 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 70static 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 78static 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 88static 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 96static 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 105static 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 113static 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 123static 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 131static 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 142static 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 150static 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 161static 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 169static 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 179static 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 187static 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 199static 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 207static 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 219static const struct pcmcia_function pcmcia_sierra_ac850_func0 = { 220 .number = 0, /* function number */ 221 .function = PCMCIA_FUNCTION_SERIAL, 222 .last_config_index = 0x24, /* last cfe number */ 223 .ccr_base = 0x700, /* ccr_base */ 224 .ccr_mask = 0x73, /* ccr_mask */ 225}; 226 227static const struct pcmcia_config_entry pcmcia_sierra_ac850_cfe0 = { 228 .number = 0x22, /* cfe number */ 229 .flags = PCMCIA_CFE_IO8 | PCMCIA_CFE_IRQLEVEL, 230 .iftype = PCMCIA_IFTYPE_IO, 231 .num_iospace = 1, /* num_iospace */ 232 .iomask = 0, /* iomask */ 233 .iospace = { { .length = 0x0008, .start = 0x3e8 } }, /* iospace */ 234 .irqmask = 0x3fbc, /* irqmask */ 235}; 236 237static const struct pcmcia_cis_quirk pcmcia_cis_quirks[] = { 238 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, 239 PCMCIA_CIS_INVALID, 240 &pcmcia_3cxem556_func0, &pcmcia_3cxem556_func0_cfe0 }, 241 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, 242 PCMCIA_CIS_INVALID, 243 &pcmcia_3cxem556_func1, &pcmcia_3cxem556_func1_cfe0 }, 244 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, 245 PCMCIA_CIS_INVALID, 246 &pcmcia_3cxem556_func0, &pcmcia_3cxem556_func0_cfe0 }, 247 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, 248 PCMCIA_CIS_INVALID, 249 &pcmcia_3cxem556_func1, &pcmcia_3cxem556_func1_cfe0 }, 250 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI, 251 PCMCIA_CIS_INVALID, 252 &pcmcia_3ccfem556bi_func0, &pcmcia_3ccfem556bi_func0_cfe0 }, 253 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI, 254 PCMCIA_CIS_INVALID, 255 &pcmcia_3ccfem556bi_func1, &pcmcia_3ccfem556bi_func1_cfe0 }, 256 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, 257 PCMCIA_CIS_SVEC_LANCARD, 258 &pcmcia_sveclancard_func0, &pcmcia_sveclancard_func0_cfe0 }, 259 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, 260 PCMCIA_CIS_NDC_ND5100_E, 261 &pcmcia_ndc_nd5100_func0, &pcmcia_ndc_nd5100_func0_cfe0 }, 262 { PCMCIA_VENDOR_EMTAC, PCMCIA_PRODUCT_EMTAC_WLAN, 263 PCMCIA_CIS_INVALID, 264 &pcmcia_emtac_a2424i_func0, &pcmcia_emtac_a2424i_func0_cfe0 }, 265 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, 266 PCMCIA_CIS_FUJITSU_FMV_J181, 267 &pcmcia_fujitsu_j181_func0, &pcmcia_fujitsu_j181_func0_cfe0 }, 268 { PCMCIA_VENDOR_NECINFRONTIA, PCMCIA_PRODUCT_NECINFRONTIA_AX420N, 269 PCMCIA_CIS_INVALID, 270 &pcmcia_necinfrontia_ax420n_func0, 271 &pcmcia_necinfrontia_ax420n_func0_cfe0 }, 272}; 273 274static const int pcmcia_cis_nquirks = 275 sizeof(pcmcia_cis_quirks) / sizeof(pcmcia_cis_quirks[0]); 276 277void 278pcmcia_check_cis_quirks(struct pcmcia_softc *sc) 279{ 280 int wiped = 0; 281 size_t i, j; 282 struct pcmcia_function *pf; 283 const struct pcmcia_function *pf_last; 284 struct pcmcia_config_entry *cfe; 285 struct pcmcia_card *card = &sc->card; 286 const struct pcmcia_cis_quirk *quirk; 287 288 pf = NULL; 289 pf_last = NULL; 290 291 for (i = 0; i < pcmcia_cis_nquirks; i++) { 292 quirk = &pcmcia_cis_quirks[i]; 293 294 if (card->manufacturer == quirk->manufacturer && 295 card->manufacturer != PCMCIA_VENDOR_INVALID && 296 card->product == quirk->product && 297 card->product != PCMCIA_PRODUCT_INVALID) 298 goto match; 299 300 for (j = 0; j < 2; j++) 301 if (card->cis1_info[j] == NULL || 302 quirk->cis1_info[j] == NULL || 303 strcmp(card->cis1_info[j], 304 quirk->cis1_info[j]) != 0) 305 goto nomatch; 306 307match: 308 if (!wiped) { 309 if (pcmcia_verbose) { 310 printf("%s: using CIS quirks for ", 311 device_xname(sc->dev)); 312 for (j = 0; j < 4; j++) { 313 if (card->cis1_info[j] == NULL) 314 break; 315 if (j) 316 printf(", "); 317 printf("%s", card->cis1_info[j]); 318 } 319 printf("\n"); 320 } 321 pcmcia_free_pf(&card->pf_head); 322 wiped = 1; 323 } 324 325 if (pf_last != quirk->pf) { 326 /* 327 * XXX: a driver which still calls pcmcia_card_attach 328 * very early attach stage should be fixed instead. 329 */ 330 pf = malloc(sizeof(*pf), M_DEVBUF, 331 cold ? M_NOWAIT : M_WAITOK); 332 if (pf == NULL) 333 panic("pcmcia_check_cis_quirks: malloc pf"); 334 *pf = *quirk->pf; 335 SIMPLEQ_INIT(&pf->cfe_head); 336 SIMPLEQ_INSERT_TAIL(&card->pf_head, pf, pf_list); 337 pf_last = quirk->pf; 338 } 339 340 /* 341 * XXX: see above. 342 */ 343 cfe = malloc(sizeof(*cfe), M_DEVBUF, 344 cold ? M_NOWAIT : M_WAITOK); 345 if (cfe == NULL) 346 panic("pcmcia_check_cis_quirks: malloc cfe"); 347 *cfe = *quirk->cfe; 348 KASSERT(pf != NULL); 349 SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list); 350 351nomatch:; 352 } 353} 354