1 1.36 chs /* $NetBSD: pcmcia_cis_quirks.c,v 1.36 2019/11/10 21:16:36 chs Exp $ */ 2 1.1 marc 3 1.1 marc /* 4 1.1 marc * Copyright (c) 1998 Marc Horowitz. All rights reserved. 5 1.1 marc * 6 1.1 marc * Redistribution and use in source and binary forms, with or without 7 1.1 marc * modification, are permitted provided that the following conditions 8 1.1 marc * are met: 9 1.1 marc * 1. Redistributions of source code must retain the above copyright 10 1.1 marc * notice, this list of conditions and the following disclaimer. 11 1.1 marc * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 marc * notice, this list of conditions and the following disclaimer in the 13 1.1 marc * documentation and/or other materials provided with the distribution. 14 1.1 marc * 3. All advertising materials mentioning features or use of this software 15 1.1 marc * must display the following acknowledgement: 16 1.1 marc * This product includes software developed by Marc Horowitz. 17 1.1 marc * 4. The name of the author may not be used to endorse or promote products 18 1.1 marc * derived from this software without specific prior written permission. 19 1.1 marc * 20 1.1 marc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 1.1 marc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 1.1 marc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 1.1 marc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 1.1 marc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 1.1 marc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 1.1 marc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 1.1 marc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 1.1 marc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 1.1 marc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 1.1 marc */ 31 1.13 lukem 32 1.13 lukem #include <sys/cdefs.h> 33 1.36 chs __KERNEL_RCSID(0, "$NetBSD: pcmcia_cis_quirks.c,v 1.36 2019/11/10 21:16:36 chs Exp $"); 34 1.1 marc 35 1.1 marc #include <sys/param.h> 36 1.1 marc #include <sys/systm.h> 37 1.1 marc #include <sys/device.h> 38 1.23 enami #include <sys/kernel.h> 39 1.1 marc #include <sys/mbuf.h> 40 1.1 marc 41 1.1 marc #include <dev/pcmcia/pcmciadevs.h> 42 1.1 marc #include <dev/pcmcia/pcmciareg.h> 43 1.1 marc #include <dev/pcmcia/pcmciachip.h> 44 1.1 marc #include <dev/pcmcia/pcmciavar.h> 45 1.1 marc 46 1.1 marc /* There are cards out there whose CIS flat-out lies. This file 47 1.1 marc contains struct pcmcia_function chains for those devices. */ 48 1.1 marc 49 1.1 marc /* these structures are just static templates which are then copied 50 1.1 marc into "live" allocated structures */ 51 1.1 marc 52 1.8 jdolecek static const struct pcmcia_function pcmcia_3cxem556_func0 = { 53 1.29 christos .number = 0, /* function number */ 54 1.29 christos .function = PCMCIA_FUNCTION_NETWORK, 55 1.29 christos .last_config_index = 0x07, /* last cfe number */ 56 1.29 christos .ccr_base = 0x800, /* ccr_base */ 57 1.29 christos .ccr_mask = 0x63, /* ccr_mask */ 58 1.1 marc }; 59 1.1 marc 60 1.8 jdolecek static const struct pcmcia_config_entry pcmcia_3cxem556_func0_cfe0 = { 61 1.29 christos .number = 0x07, /* cfe number */ 62 1.29 christos .flags = PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL, 63 1.29 christos .iftype = PCMCIA_IFTYPE_IO, 64 1.29 christos .num_iospace = 1, /* num_iospace */ 65 1.29 christos .iomask = 4, /* iomask */ 66 1.29 christos .iospace = { { .length = 0x0010, .start = 0 } }, /* iospace */ 67 1.29 christos .irqmask = 0xffff, /* irqmask */ 68 1.1 marc }; 69 1.1 marc 70 1.8 jdolecek static const struct pcmcia_function pcmcia_3cxem556_func1 = { 71 1.29 christos .number = 1, /* function number */ 72 1.29 christos .function = PCMCIA_FUNCTION_SERIAL, 73 1.29 christos .last_config_index = 0x27, /* last cfe number */ 74 1.29 christos .ccr_base = 0x900, /* ccr_base */ 75 1.29 christos .ccr_mask = 0x63, /* ccr_mask */ 76 1.1 marc }; 77 1.1 marc 78 1.8 jdolecek static const struct pcmcia_config_entry pcmcia_3cxem556_func1_cfe0 = { 79 1.29 christos .number = 0x27, /* cfe number */ 80 1.29 christos .flags = PCMCIA_CFE_IO8 | PCMCIA_CFE_IRQLEVEL, 81 1.29 christos .iftype = PCMCIA_IFTYPE_IO, 82 1.29 christos .num_iospace = 1, /* num_iospace */ 83 1.29 christos .iomask = 3, /* iomask */ 84 1.29 christos .iospace = { { .length = 0x0008, .start = 0 } }, /* iospace */ 85 1.29 christos .irqmask = 0xffff, /* irqmask */ 86 1.1 marc }; 87 1.1 marc 88 1.8 jdolecek static const struct pcmcia_function pcmcia_3ccfem556bi_func0 = { 89 1.29 christos .number = 0, /* function number */ 90 1.29 christos .function = PCMCIA_FUNCTION_NETWORK, 91 1.29 christos .last_config_index = 0x07, /* last cfe number */ 92 1.29 christos .ccr_base = 0x1000, /* ccr_base */ 93 1.29 christos .ccr_mask = 0x267, /* ccr_mask */ 94 1.5 thorpej }; 95 1.5 thorpej 96 1.8 jdolecek static const struct pcmcia_config_entry pcmcia_3ccfem556bi_func0_cfe0 = { 97 1.29 christos .number = 0x07, /* cfe number */ 98 1.29 christos .flags = PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL, 99 1.29 christos .iftype = PCMCIA_IFTYPE_IO, 100 1.29 christos .num_iospace = 1, /* num_iospace */ 101 1.29 christos .iomask = 5, /* iomask */ 102 1.29 christos .iospace = { { .length = 0x0020, .start = 0 } }, /* iospace */ 103 1.5 thorpej }; 104 1.5 thorpej 105 1.8 jdolecek static const struct pcmcia_function pcmcia_3ccfem556bi_func1 = { 106 1.29 christos .number = 1, /* function number */ 107 1.29 christos .function = PCMCIA_FUNCTION_SERIAL, 108 1.29 christos .last_config_index = 0x27, /* last cfe number */ 109 1.29 christos .ccr_base = 0x1100, /* ccr_base */ 110 1.29 christos .ccr_mask = 0x277, /* ccr_mask */ 111 1.5 thorpej }; 112 1.5 thorpej 113 1.8 jdolecek static const struct pcmcia_config_entry pcmcia_3ccfem556bi_func1_cfe0 = { 114 1.29 christos .number = 0x27, /* cfe number */ 115 1.29 christos .flags = PCMCIA_CFE_IO8 | PCMCIA_CFE_IRQLEVEL, 116 1.29 christos .iftype = PCMCIA_IFTYPE_IO, 117 1.29 christos .num_iospace = 1, /* num_iospace */ 118 1.29 christos .iomask = 3, /* iomask */ 119 1.29 christos .iospace = { { .length = 0x0008, .start = 0 } }, /* iospace */ 120 1.29 christos .irqmask = 0xffff, /* irqmask */ 121 1.5 thorpej }; 122 1.5 thorpej 123 1.8 jdolecek static const struct pcmcia_function pcmcia_sveclancard_func0 = { 124 1.29 christos .number = 0, /* function number */ 125 1.29 christos .function = PCMCIA_FUNCTION_NETWORK, 126 1.29 christos .last_config_index = 0x1, /* last cfe number */ 127 1.29 christos .ccr_base = 0x100, /* ccr_base */ 128 1.29 christos .ccr_mask = 0x1, /* ccr_mask */ 129 1.3 marc }; 130 1.3 marc 131 1.8 jdolecek static const struct pcmcia_config_entry pcmcia_sveclancard_func0_cfe0 = { 132 1.29 christos .number = 0x1, /* cfe number */ 133 1.29 christos .flags = PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_RDYBSY_ACTIVE | 134 1.29 christos PCMCIA_CFE_WP_ACTIVE | PCMCIA_CFE_BVD_ACTIVE | PCMCIA_CFE_IO16, 135 1.29 christos .iftype = PCMCIA_IFTYPE_IO, 136 1.29 christos .num_iospace = 1, /* num_iospace */ 137 1.29 christos .iomask = 5, /* iomask */ 138 1.29 christos .iospace = { { .length = 0x20, .start = 0x300 } }, /* iospace */ 139 1.29 christos .irqmask = 0xdeb8, /* irqmask */ 140 1.3 marc }; 141 1.3 marc 142 1.8 jdolecek static const struct pcmcia_function pcmcia_ndc_nd5100_func0 = { 143 1.29 christos .number = 0, /* function number */ 144 1.29 christos .function = PCMCIA_FUNCTION_NETWORK, 145 1.29 christos .last_config_index = 0x23, /* last cfe number */ 146 1.29 christos .ccr_base = 0x3f8, /* ccr_base */ 147 1.29 christos .ccr_mask = 0x3, /* ccr_mask */ 148 1.6 scw }; 149 1.6 scw 150 1.8 jdolecek static const struct pcmcia_config_entry pcmcia_ndc_nd5100_func0_cfe0 = { 151 1.29 christos .number = 0x20, /* cfe number */ 152 1.29 christos .flags = PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_IO16 | 153 1.29 christos PCMCIA_CFE_IRQLEVEL, 154 1.29 christos .iftype = PCMCIA_IFTYPE_IO, 155 1.29 christos .num_iospace = 1, /* num_iospace */ 156 1.29 christos .iomask = 5, /* iomask */ 157 1.29 christos .iospace = { { .length = 0x20, .start = 0x300 } }, /* iospace */ 158 1.29 christos .irqmask = 0xdeb8, /* irqmask */ 159 1.6 scw }; 160 1.6 scw 161 1.12 ichiro static const struct pcmcia_function pcmcia_emtac_a2424i_func0 = { 162 1.29 christos .number = 0, /* function number */ 163 1.29 christos .function = PCMCIA_FUNCTION_NETWORK, 164 1.29 christos .last_config_index = 0x21, /* last cfe number */ 165 1.29 christos .ccr_base = 0x3e0, /* ccr_base */ 166 1.29 christos .ccr_mask = 0x1, /* ccr_mask */ 167 1.12 ichiro }; 168 1.12 ichiro 169 1.12 ichiro static const struct pcmcia_config_entry pcmcia_emtac_a2424i_func0_cfe0 = { 170 1.29 christos .number = 0x21, /* cfe number */ 171 1.29 christos .flags = PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL | PCMCIA_CFE_IRQPULSE, 172 1.29 christos .iftype = PCMCIA_IFTYPE_IO, 173 1.29 christos .num_iospace = 1, /* num_iospace */ 174 1.29 christos .iomask = 6, /* iomask */ 175 1.29 christos .iospace = { { .length = 0x40, .start = 0x100 } }, /* iospace */ 176 1.29 christos .irqmask = 0xffff, /* irqmask */ 177 1.12 ichiro }; 178 1.12 ichiro 179 1.17 ichiro static const struct pcmcia_function pcmcia_fujitsu_j181_func0 = { 180 1.29 christos .number = 0, /* function number */ 181 1.29 christos .function = PCMCIA_FUNCTION_NETWORK, 182 1.29 christos .last_config_index = 0x21, /* last cfe number */ 183 1.29 christos .ccr_base = 0xfe0, /* ccr_base */ 184 1.29 christos .ccr_mask = 0xf, /* ccr_mask */ 185 1.17 ichiro }; 186 1.15 ichiro 187 1.17 ichiro static const struct pcmcia_config_entry pcmcia_fujitsu_j181_func0_cfe0 = { 188 1.29 christos .number = 0xc, /* cfe number */ 189 1.29 christos .flags = PCMCIA_CFE_MWAIT_REQUIRED | PCMCIA_CFE_WP_ACTIVE | 190 1.29 christos PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16 | PCMCIA_CFE_IRQLEVEL | 191 1.29 christos PCMCIA_CFE_IRQPULSE, 192 1.29 christos .iftype = PCMCIA_IFTYPE_IO, 193 1.29 christos .num_iospace = 1, /* num_iospace */ 194 1.29 christos .iomask = 10, /* iomask */ 195 1.29 christos .iospace = { { .length = 0x20, .start = 0x140 } }, /* iospace */ 196 1.29 christos .irqmask = 0xffff, /* irqmask */ 197 1.15 ichiro }; 198 1.15 ichiro 199 1.30 ichiro static const struct pcmcia_function pcmcia_necinfrontia_ax420n_func0 = { 200 1.30 ichiro .number = 0, /* function number */ 201 1.30 ichiro .function = PCMCIA_FUNCTION_SERIAL, 202 1.30 ichiro .last_config_index = 0x38, /* last cfe number */ 203 1.30 ichiro .ccr_base = 0x200, /* ccr_base */ 204 1.30 ichiro .ccr_mask = 0x1f, /* ccr_mask */ 205 1.30 ichiro }; 206 1.30 ichiro 207 1.30 ichiro static const struct pcmcia_config_entry pcmcia_necinfrontia_ax420n_func0_cfe0 = { 208 1.30 ichiro .number = 0x25, /* cfe number */ 209 1.30 ichiro .flags = PCMCIA_CFE_RDYBSY_ACTIVE | PCMCIA_CFE_IO8 | 210 1.30 ichiro PCMCIA_CFE_IRQLEVEL | PCMCIA_CFE_POWERDOWN | 211 1.30 ichiro PCMCIA_CFE_AUDIO, 212 1.30 ichiro .iftype = PCMCIA_IFTYPE_IO, 213 1.30 ichiro .num_iospace = 1, /* num_iospace */ 214 1.30 ichiro .iomask = 10, /* iomask */ 215 1.30 ichiro .iospace = { { .length = 0x8, .start = 0x3f8 } }, /* iospace */ 216 1.30 ichiro .irqmask = 0x86bc, /* irqmask */ 217 1.30 ichiro }; 218 1.30 ichiro 219 1.8 jdolecek static const struct pcmcia_cis_quirk pcmcia_cis_quirks[] = { 220 1.30 ichiro { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, 221 1.30 ichiro PCMCIA_CIS_INVALID, 222 1.1 marc &pcmcia_3cxem556_func0, &pcmcia_3cxem556_func0_cfe0 }, 223 1.30 ichiro { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, 224 1.30 ichiro PCMCIA_CIS_INVALID, 225 1.4 tron &pcmcia_3cxem556_func1, &pcmcia_3cxem556_func1_cfe0 }, 226 1.30 ichiro { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, 227 1.30 ichiro PCMCIA_CIS_INVALID, 228 1.4 tron &pcmcia_3cxem556_func0, &pcmcia_3cxem556_func0_cfe0 }, 229 1.30 ichiro { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, 230 1.30 ichiro PCMCIA_CIS_INVALID, 231 1.1 marc &pcmcia_3cxem556_func1, &pcmcia_3cxem556_func1_cfe0 }, 232 1.5 thorpej { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI, 233 1.5 thorpej PCMCIA_CIS_INVALID, 234 1.5 thorpej &pcmcia_3ccfem556bi_func0, &pcmcia_3ccfem556bi_func0_cfe0 }, 235 1.5 thorpej { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI, 236 1.5 thorpej PCMCIA_CIS_INVALID, 237 1.5 thorpej &pcmcia_3ccfem556bi_func1, &pcmcia_3ccfem556bi_func1_cfe0 }, 238 1.30 ichiro { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, 239 1.30 ichiro PCMCIA_CIS_SVEC_LANCARD, 240 1.3 marc &pcmcia_sveclancard_func0, &pcmcia_sveclancard_func0_cfe0 }, 241 1.30 ichiro { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, 242 1.30 ichiro PCMCIA_CIS_NDC_ND5100_E, 243 1.6 scw &pcmcia_ndc_nd5100_func0, &pcmcia_ndc_nd5100_func0_cfe0 }, 244 1.30 ichiro { PCMCIA_VENDOR_EMTAC, PCMCIA_PRODUCT_EMTAC_WLAN, 245 1.30 ichiro PCMCIA_CIS_INVALID, 246 1.12 ichiro &pcmcia_emtac_a2424i_func0, &pcmcia_emtac_a2424i_func0_cfe0 }, 247 1.17 ichiro { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, 248 1.17 ichiro PCMCIA_CIS_FUJITSU_FMV_J181, 249 1.17 ichiro &pcmcia_fujitsu_j181_func0, &pcmcia_fujitsu_j181_func0_cfe0 }, 250 1.30 ichiro { PCMCIA_VENDOR_NECINFRONTIA, PCMCIA_PRODUCT_NECINFRONTIA_AX420N, 251 1.30 ichiro PCMCIA_CIS_INVALID, 252 1.30 ichiro &pcmcia_necinfrontia_ax420n_func0, 253 1.30 ichiro &pcmcia_necinfrontia_ax420n_func0_cfe0 }, 254 1.1 marc }; 255 1.25 perry 256 1.21 mycroft static const int pcmcia_cis_nquirks = 257 1.21 mycroft sizeof(pcmcia_cis_quirks) / sizeof(pcmcia_cis_quirks[0]); 258 1.1 marc 259 1.23 enami void 260 1.34 dsl pcmcia_check_cis_quirks(struct pcmcia_softc *sc) 261 1.1 marc { 262 1.1 marc int wiped = 0; 263 1.22 christos size_t i, j; 264 1.19 lukem struct pcmcia_function *pf; 265 1.8 jdolecek const struct pcmcia_function *pf_last; 266 1.19 lukem struct pcmcia_config_entry *cfe; 267 1.22 christos struct pcmcia_card *card = &sc->card; 268 1.23 enami const struct pcmcia_cis_quirk *quirk; 269 1.1 marc 270 1.2 marc pf = NULL; 271 1.1 marc pf_last = NULL; 272 1.1 marc 273 1.22 christos for (i = 0; i < pcmcia_cis_nquirks; i++) { 274 1.23 enami quirk = &pcmcia_cis_quirks[i]; 275 1.22 christos 276 1.23 enami if (card->manufacturer == quirk->manufacturer && 277 1.23 enami card->manufacturer != PCMCIA_VENDOR_INVALID && 278 1.23 enami card->product == quirk->product && 279 1.22 christos card->product != PCMCIA_PRODUCT_INVALID) 280 1.23 enami goto match; 281 1.22 christos 282 1.22 christos for (j = 0; j < 2; j++) 283 1.24 enami if (card->cis1_info[j] == NULL || 284 1.24 enami quirk->cis1_info[j] == NULL || 285 1.24 enami strcmp(card->cis1_info[j], 286 1.24 enami quirk->cis1_info[j]) != 0) 287 1.24 enami goto nomatch; 288 1.22 christos 289 1.23 enami match: 290 1.22 christos if (!wiped) { 291 1.22 christos if (pcmcia_verbose) { 292 1.22 christos printf("%s: using CIS quirks for ", 293 1.32 drochner device_xname(sc->dev)); 294 1.22 christos for (j = 0; j < 4; j++) { 295 1.22 christos if (card->cis1_info[j] == NULL) 296 1.22 christos break; 297 1.22 christos if (j) 298 1.22 christos printf(", "); 299 1.22 christos printf("%s", card->cis1_info[j]); 300 1.1 marc } 301 1.22 christos printf("\n"); 302 1.1 marc } 303 1.22 christos pcmcia_free_pf(&card->pf_head); 304 1.22 christos wiped = 1; 305 1.22 christos } 306 1.1 marc 307 1.23 enami if (pf_last != quirk->pf) { 308 1.23 enami /* 309 1.23 enami * XXX: a driver which still calls pcmcia_card_attach 310 1.23 enami * very early attach stage should be fixed instead. 311 1.23 enami */ 312 1.36 chs pf = malloc(sizeof(*pf), M_DEVBUF, M_WAITOK); 313 1.23 enami *pf = *quirk->pf; 314 1.22 christos SIMPLEQ_INIT(&pf->cfe_head); 315 1.23 enami SIMPLEQ_INSERT_TAIL(&card->pf_head, pf, pf_list); 316 1.23 enami pf_last = quirk->pf; 317 1.23 enami } 318 1.1 marc 319 1.23 enami /* 320 1.23 enami * XXX: see above. 321 1.23 enami */ 322 1.36 chs cfe = malloc(sizeof(*cfe), M_DEVBUF, M_WAITOK); 323 1.23 enami *cfe = *quirk->cfe; 324 1.27 christos KASSERT(pf != NULL); 325 1.23 enami SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list); 326 1.1 marc 327 1.23 enami nomatch:; 328 1.1 marc } 329 1.1 marc } 330