1 /* $NetBSD: pcmcia_cis_quirks.c,v 1.18 2002/01/13 12:28:02 aymeric 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.18 2002/01/13 12:28:02 aymeric Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 #include <sys/mbuf.h> 39 40 #include <dev/pcmcia/pcmciadevs.h> 41 #include <dev/pcmcia/pcmciareg.h> 42 #include <dev/pcmcia/pcmciachip.h> 43 #include <dev/pcmcia/pcmciavar.h> 44 45 /* There are cards out there whose CIS flat-out lies. This file 46 contains struct pcmcia_function chains for those devices. */ 47 48 /* these structures are just static templates which are then copied 49 into "live" allocated structures */ 50 51 static const struct pcmcia_function pcmcia_3cxem556_func0 = { 52 0, /* function number */ 53 PCMCIA_FUNCTION_NETWORK, 54 0x07, /* last cfe number */ 55 0x800, /* ccr_base */ 56 0x63, /* ccr_mask */ 57 }; 58 59 static const struct pcmcia_config_entry pcmcia_3cxem556_func0_cfe0 = { 60 0x07, /* cfe number */ 61 PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL, 62 PCMCIA_IFTYPE_IO, 63 1, /* num_iospace */ 64 4, /* iomask */ 65 { { 0x0010, 0 } }, /* iospace */ 66 0xffff, /* irqmask */ 67 0, /* num_memspace */ 68 { { 0 } }, /* memspace */ 69 0, /* maxtwins */ 70 }; 71 72 static const struct pcmcia_function pcmcia_3cxem556_func1 = { 73 1, /* function number */ 74 PCMCIA_FUNCTION_SERIAL, 75 0x27, /* last cfe number */ 76 0x900, /* ccr_base */ 77 0x63, /* ccr_mask */ 78 }; 79 80 static const struct pcmcia_config_entry pcmcia_3cxem556_func1_cfe0 = { 81 0x27, /* cfe number */ 82 PCMCIA_CFE_IO8 | PCMCIA_CFE_IRQLEVEL, 83 PCMCIA_IFTYPE_IO, 84 1, /* num_iospace */ 85 3, /* iomask */ 86 { { 0x0008, 0 } }, /* iospace */ 87 0xffff, /* irqmask */ 88 0, /* num_memspace */ 89 { { 0 } }, /* memspace */ 90 0, /* maxtwins */ 91 }; 92 93 static const struct pcmcia_function pcmcia_3ccfem556bi_func0 = { 94 0, /* function number */ 95 PCMCIA_FUNCTION_NETWORK, 96 0x07, /* last cfe number */ 97 0x1000, /* ccr_base */ 98 0x267, /* ccr_mask */ 99 }; 100 101 static const struct pcmcia_config_entry pcmcia_3ccfem556bi_func0_cfe0 = { 102 0x07, /* cfe number */ 103 PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL, 104 PCMCIA_IFTYPE_IO, 105 1, /* num_iospace */ 106 5, /* iomask */ 107 { { 0x0020, 0 } }, /* iospace */ 108 0xffff, /* irqmask */ 109 0, /* num_memspace */ 110 { { 0 } }, /* memspace */ 111 0, /* maxtwins */ 112 }; 113 114 static const struct pcmcia_function pcmcia_3ccfem556bi_func1 = { 115 1, /* function number */ 116 PCMCIA_FUNCTION_SERIAL, 117 0x27, /* last cfe number */ 118 0x1100, /* ccr_base */ 119 0x277, /* ccr_mask */ 120 }; 121 122 static const struct pcmcia_config_entry pcmcia_3ccfem556bi_func1_cfe0 = { 123 0x27, /* cfe number */ 124 PCMCIA_CFE_IO8 | PCMCIA_CFE_IRQLEVEL, 125 PCMCIA_IFTYPE_IO, 126 1, /* num_iospace */ 127 3, /* iomask */ 128 { { 0x0008, 0 } }, /* iospace */ 129 0xffff, /* irqmask */ 130 0, /* num_memspace */ 131 { { 0 } }, /* memspace */ 132 0, /* maxtwins */ 133 }; 134 135 static const struct pcmcia_function pcmcia_sveclancard_func0 = { 136 0, /* function number */ 137 PCMCIA_FUNCTION_NETWORK, 138 0x1, /* last cfe number */ 139 0x100, /* ccr_base */ 140 0x1, /* ccr_mask */ 141 }; 142 143 static const struct pcmcia_config_entry pcmcia_sveclancard_func0_cfe0 = { 144 0x1, /* cfe number */ 145 PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_RDYBSY_ACTIVE | 146 PCMCIA_CFE_WP_ACTIVE | PCMCIA_CFE_BVD_ACTIVE | PCMCIA_CFE_IO16, 147 PCMCIA_IFTYPE_IO, 148 1, /* num_iospace */ 149 5, /* iomask */ 150 { { 0x20, 0x300 } }, /* iospace */ 151 0xdeb8, /* irqmask */ 152 0, /* num_memspace */ 153 { { 0 } }, /* memspace */ 154 0, /* maxtwins */ 155 }; 156 157 static const struct pcmcia_function pcmcia_ndc_nd5100_func0 = { 158 0, /* function number */ 159 PCMCIA_FUNCTION_NETWORK, 160 0x23, /* last cfe number */ 161 0x3f8, /* ccr_base */ 162 0x3, /* ccr_mask */ 163 }; 164 165 static const struct pcmcia_config_entry pcmcia_ndc_nd5100_func0_cfe0 = { 166 0x20, /* cfe number */ 167 PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL, 168 PCMCIA_IFTYPE_IO, 169 1, /* num_iospace */ 170 5, /* iomask */ 171 { { 0x20, 0x300 } }, /* iospace */ 172 0xdeb8, /* irqmask */ 173 0, /* num_memspace */ 174 { { 0 } }, /* memspace */ 175 0, /* maxtwins */ 176 }; 177 178 static const struct pcmcia_function pcmcia_emtac_a2424i_func0 = { 179 0, /* function number */ 180 PCMCIA_FUNCTION_NETWORK, 181 0x21, /* last cfe number */ 182 0x3e0, /* ccr_base */ 183 0x1, /* ccr_mask */ 184 }; 185 186 static const struct pcmcia_config_entry pcmcia_emtac_a2424i_func0_cfe0 = { 187 0x21, /* cfe number */ 188 PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL | PCMCIA_CFE_IRQPULSE, 189 PCMCIA_IFTYPE_IO, 190 1, /* num_iospace */ 191 6, /* iomask */ 192 { { 0x40, 0x100 } }, /* iospace */ 193 0xffff, /* irqmask */ 194 0, /* num_memspace */ 195 { { 0 } }, /* memspace */ 196 0, /* maxtwins */ 197 }; 198 199 static const struct pcmcia_function pcmcia_fujitsu_j181_func0 = { 200 0, /* function number */ 201 PCMCIA_FUNCTION_NETWORK, 202 0x21, /* last cfe number */ 203 0xfe0, /* ccr_base */ 204 0xf, /* ccr_mask */ 205 }; 206 207 static const struct pcmcia_config_entry pcmcia_fujitsu_j181_func0_cfe0 = { 208 0xc, /* cfe number */ 209 PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_WP_ACTIVE | PCMCIA_CFE_IO8 | 210 PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL | PCMCIA_CFE_IRQPULSE, 211 PCMCIA_IFTYPE_IO, 212 1, /* num_iospace */ 213 10, /* iomask */ 214 { { 0x20, 0x140 } }, /* iospace */ 215 0xffff, /* irqmask */ 216 0, /* num_memspace */ 217 { { 0 } }, /* memspace */ 218 0, /* maxtwins */ 219 }; 220 221 static const struct pcmcia_cis_quirk pcmcia_cis_quirks[] = { 222 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, PCMCIA_CIS_INVALID, 223 &pcmcia_3cxem556_func0, &pcmcia_3cxem556_func0_cfe0 }, 224 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, PCMCIA_CIS_INVALID, 225 &pcmcia_3cxem556_func1, &pcmcia_3cxem556_func1_cfe0 }, 226 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, PCMCIA_CIS_INVALID, 227 &pcmcia_3cxem556_func0, &pcmcia_3cxem556_func0_cfe0 }, 228 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, PCMCIA_CIS_INVALID, 229 &pcmcia_3cxem556_func1, &pcmcia_3cxem556_func1_cfe0 }, 230 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI, 231 PCMCIA_CIS_INVALID, 232 &pcmcia_3ccfem556bi_func0, &pcmcia_3ccfem556bi_func0_cfe0 }, 233 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI, 234 PCMCIA_CIS_INVALID, 235 &pcmcia_3ccfem556bi_func1, &pcmcia_3ccfem556bi_func1_cfe0 }, 236 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, PCMCIA_CIS_SVEC_LANCARD, 237 &pcmcia_sveclancard_func0, &pcmcia_sveclancard_func0_cfe0 }, 238 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, PCMCIA_CIS_NDC_ND5100_E, 239 &pcmcia_ndc_nd5100_func0, &pcmcia_ndc_nd5100_func0_cfe0 }, 240 { PCMCIA_VENDOR_EMTAC, PCMCIA_PRODUCT_EMTAC_WLAN, PCMCIA_CIS_INVALID, 241 &pcmcia_emtac_a2424i_func0, &pcmcia_emtac_a2424i_func0_cfe0 }, 242 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, 243 PCMCIA_CIS_FUJITSU_FMV_J181, 244 &pcmcia_fujitsu_j181_func0, &pcmcia_fujitsu_j181_func0_cfe0 }, 245 }; 246 247 static int n_pcmcia_cis_quirks = 248 sizeof(pcmcia_cis_quirks)/sizeof(pcmcia_cis_quirks[0]); 249 250 void pcmcia_check_cis_quirks(sc) 251 struct pcmcia_softc *sc; 252 { 253 int wiped = 0; 254 int i, j; 255 struct pcmcia_function *pf, *pf_next; 256 const struct pcmcia_function *pf_last; 257 struct pcmcia_config_entry *cfe, *cfe_next; 258 259 pf = NULL; 260 pf_last = NULL; 261 262 for (i=0; i<n_pcmcia_cis_quirks; i++) { 263 if ((sc->card.manufacturer == pcmcia_cis_quirks[i].manufacturer) && 264 (sc->card.product == pcmcia_cis_quirks[i].product) && 265 (((sc->card.manufacturer != PCMCIA_VENDOR_INVALID) && 266 (sc->card.product != PCMCIA_PRODUCT_INVALID)) || 267 ((sc->card.manufacturer == PCMCIA_VENDOR_INVALID) && 268 (sc->card.product == PCMCIA_PRODUCT_INVALID) && 269 sc->card.cis1_info[0] && 270 (strcmp(sc->card.cis1_info[0], 271 pcmcia_cis_quirks[i].cis1_info[0]) == 0) && 272 sc->card.cis1_info[1] && 273 (strcmp(sc->card.cis1_info[1], 274 pcmcia_cis_quirks[i].cis1_info[1]) == 0)))) { 275 if (!wiped) { 276 if (pcmcia_verbose) { 277 printf("%s: using CIS quirks for ", sc->dev.dv_xname); 278 for (j = 0; j < 4; j++) { 279 if (sc->card.cis1_info[j] == NULL) 280 break; 281 if (j) 282 printf(", "); 283 printf("%s", sc->card.cis1_info[j]); 284 } 285 printf("\n"); 286 } 287 288 for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL; 289 pf = pf_next) { 290 for (cfe = SIMPLEQ_FIRST(&pf->cfe_head); cfe != NULL; 291 cfe = cfe_next) { 292 cfe_next = SIMPLEQ_NEXT(cfe, cfe_list); 293 free(cfe, M_DEVBUF); 294 } 295 pf_next = SIMPLEQ_NEXT(pf, pf_list); 296 free(pf, M_DEVBUF); 297 } 298 299 SIMPLEQ_INIT(&sc->card.pf_head); 300 wiped = 1; 301 } 302 303 if (pf_last == pcmcia_cis_quirks[i].pf) { 304 cfe = malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 305 *cfe = *pcmcia_cis_quirks[i].cfe; 306 307 SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list); 308 } else { 309 pf = malloc(sizeof(*pf), M_DEVBUF, M_NOWAIT); 310 *pf = *pcmcia_cis_quirks[i].pf; 311 SIMPLEQ_INIT(&pf->cfe_head); 312 313 cfe = malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 314 *cfe = *pcmcia_cis_quirks[i].cfe; 315 316 SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list); 317 SIMPLEQ_INSERT_TAIL(&sc->card.pf_head, pf, pf_list); 318 319 pf_last = pcmcia_cis_quirks[i].pf; 320 } 321 } 322 } 323 } 324