1 /* $NetBSD: pcmcia_cis_quirks.c,v 1.6 2000/04/12 21:07:55 scw Exp $ */ 2 /* $FreeBSD: src/sys/dev/pccard/pccard_cis_quirks.c,v 1.15 2005/03/26 21:30:49 sam Exp $ */ 3 4 #define PCCARDDEBUG 5 6 /*- 7 * Copyright (c) 1998 Marc Horowitz. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Marc Horowitz. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/bus.h> 37 #include <sys/malloc.h> 38 #include <sys/systm.h> 39 40 #include <bus/pccard/pccard_cis.h> 41 #include <bus/pccard/pccardvar.h> 42 #include <bus/pccard/pccarddevs.h> 43 44 /* There are cards out there whose CIS flat-out lies. This file 45 contains struct pccard_function chains for those devices. */ 46 47 /* these structures are just static templates which are then copied 48 into "live" allocated structures */ 49 50 struct pccard_function pccard_3cxem556_func0 = { 51 0, /* function number */ 52 PCCARD_FUNCTION_NETWORK, 53 0x07, /* last cfe number */ 54 0x800, /* ccr_base */ 55 0x63, /* ccr_mask */ 56 }; 57 58 struct pccard_config_entry pccard_3cxem556_func0_cfe0 = { 59 0x07, /* cfe number */ 60 PCCARD_CFE_IO8 | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL, 61 PCCARD_IFTYPE_IO, 62 1, /* num_iospace */ 63 4, /* iomask */ 64 { { 0x0010, 0 } }, /* iospace */ 65 0xffff, /* irqmask */ 66 0, /* num_memspace */ 67 { }, /* memspace */ 68 0, /* maxtwins */ 69 }; 70 71 static struct pccard_function pccard_3cxem556_func1 = { 72 1, /* function number */ 73 PCCARD_FUNCTION_SERIAL, 74 0x27, /* last cfe number */ 75 0x900, /* ccr_base */ 76 0x63, /* ccr_mask */ 77 }; 78 79 static struct pccard_config_entry pccard_3cxem556_func1_cfe0 = { 80 0x27, /* cfe number */ 81 PCCARD_CFE_IO8 | PCCARD_CFE_IRQLEVEL, 82 PCCARD_IFTYPE_IO, 83 1, /* num_iospace */ 84 3, /* iomask */ 85 { { 0x0008, 0 } }, /* iospace */ 86 0xffff, /* irqmask */ 87 0, /* num_memspace */ 88 { }, /* memspace */ 89 0, /* maxtwins */ 90 }; 91 92 static struct pccard_function pccard_3ccfem556bi_func0 = { 93 0, /* function number */ 94 PCCARD_FUNCTION_NETWORK, 95 0x07, /* last cfe number */ 96 0x1000, /* ccr_base */ 97 0x267, /* ccr_mask */ 98 }; 99 100 static struct pccard_config_entry pccard_3ccfem556bi_func0_cfe0 = { 101 0x07, /* cfe number */ 102 PCCARD_CFE_IO8 | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL, 103 PCCARD_IFTYPE_IO, 104 1, /* num_iospace */ 105 5, /* iomask */ 106 { { 0x0020, 0 } }, /* iospace */ 107 0xffff, /* irqmask */ 108 0, /* num_memspace */ 109 { }, /* memspace */ 110 0, /* maxtwins */ 111 }; 112 113 static struct pccard_function pccard_3ccfem556bi_func1 = { 114 1, /* function number */ 115 PCCARD_FUNCTION_SERIAL, 116 0x27, /* last cfe number */ 117 0x1100, /* ccr_base */ 118 0x277, /* ccr_mask */ 119 }; 120 121 static struct pccard_config_entry pccard_3ccfem556bi_func1_cfe0 = { 122 0x27, /* cfe number */ 123 PCCARD_CFE_IO8 | PCCARD_CFE_IRQLEVEL, 124 PCCARD_IFTYPE_IO, 125 1, /* num_iospace */ 126 3, /* iomask */ 127 { { 0x0008, 0 } }, /* iospace */ 128 0xffff, /* irqmask */ 129 0, /* num_memspace */ 130 { }, /* memspace */ 131 0, /* maxtwins */ 132 }; 133 134 static struct pccard_function pccard_sveclancard_func0 = { 135 0, /* function number */ 136 PCCARD_FUNCTION_NETWORK, 137 0x1, /* last cfe number */ 138 0x100, /* ccr_base */ 139 0x1, /* ccr_mask */ 140 }; 141 142 static struct pccard_config_entry pccard_sveclancard_func0_cfe0 = { 143 0x1, /* cfe number */ 144 PCCARD_CFE_MWAIT_REQUIRED | PCCARD_CFE_RDYBSY_ACTIVE | 145 PCCARD_CFE_WP_ACTIVE | PCCARD_CFE_BVD_ACTIVE | PCCARD_CFE_IO16, 146 PCCARD_IFTYPE_IO, 147 1, /* num_iospace */ 148 5, /* iomask */ 149 { { 0x20, 0x300 } }, /* iospace */ 150 0xdeb8, /* irqmask */ 151 0, /* num_memspace */ 152 { }, /* memspace */ 153 0, /* maxtwins */ 154 }; 155 156 static struct pccard_function pccard_ndc_nd5100_func0 = { 157 0, /* function number */ 158 PCCARD_FUNCTION_NETWORK, 159 0x23, /* last cfe number */ 160 0x3f8, /* ccr_base */ 161 0x3, /* ccr_mask */ 162 }; 163 164 static struct pccard_config_entry pccard_ndc_nd5100_func0_cfe0 = { 165 0x20, /* cfe number */ 166 PCCARD_CFE_MWAIT_REQUIRED | PCCARD_CFE_IO16 | PCCARD_CFE_IRQLEVEL, 167 PCCARD_IFTYPE_IO, 168 1, /* num_iospace */ 169 5, /* iomask */ 170 { { 0x20, 0x300 } }, /* iospace */ 171 0xdeb8, /* irqmask */ 172 0, /* num_memspace */ 173 { }, /* memspace */ 174 0, /* maxtwins */ 175 }; 176 177 static struct pccard_cis_quirk pccard_cis_quirks[] = { 178 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, PCMCIA_CIS_INVALID, 179 &pccard_3cxem556_func0, &pccard_3cxem556_func0_cfe0 }, 180 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556, PCMCIA_CIS_INVALID, 181 &pccard_3cxem556_func1, &pccard_3cxem556_func1_cfe0 }, 182 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, PCMCIA_CIS_INVALID, 183 &pccard_3cxem556_func0, &pccard_3cxem556_func0_cfe0 }, 184 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CXEM556INT, PCMCIA_CIS_INVALID, 185 &pccard_3cxem556_func1, &pccard_3cxem556_func1_cfe0 }, 186 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI, 187 PCMCIA_CIS_INVALID, 188 &pccard_3ccfem556bi_func0, &pccard_3ccfem556bi_func0_cfe0 }, 189 { PCMCIA_VENDOR_3COM, PCMCIA_PRODUCT_3COM_3CCFEM556BI, 190 PCMCIA_CIS_INVALID, 191 &pccard_3ccfem556bi_func1, &pccard_3ccfem556bi_func1_cfe0 }, 192 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, PCMCIA_CIS_SVEC_LANCARD, 193 &pccard_sveclancard_func0, &pccard_sveclancard_func0_cfe0 }, 194 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, PCMCIA_CIS_NDC_ND5100_E, 195 &pccard_ndc_nd5100_func0, &pccard_ndc_nd5100_func0_cfe0 }, 196 }; 197 198 static int n_pccard_cis_quirks = NELEM(pccard_cis_quirks); 199 200 static int 201 pccard_cis_quirk_match(struct pccard_softc *sc, struct pccard_cis_quirk *q) 202 { 203 if ((sc->card.manufacturer == q->manufacturer) && 204 (sc->card.product == q->product) && 205 (((sc->card.manufacturer != PCMCIA_VENDOR_INVALID) && 206 (sc->card.product != PCMCIA_PRODUCT_INVALID)) || 207 ((sc->card.manufacturer == PCMCIA_VENDOR_INVALID) && 208 (sc->card.product == PCMCIA_PRODUCT_INVALID) && 209 sc->card.cis1_info[0] && 210 (strcmp(sc->card.cis1_info[0], q->cis1_info[0]) == 0) && 211 sc->card.cis1_info[1] && 212 (strcmp(sc->card.cis1_info[1], q->cis1_info[1]) == 0)))) 213 return (1); 214 return (0); 215 } 216 217 void 218 pccard_check_cis_quirks(device_t dev) 219 { 220 struct pccard_softc *sc = PCCARD_SOFTC(dev); 221 int wiped = 0; 222 int i, j; 223 struct pccard_function *pf, *pf_next, *pf_last; 224 struct pccard_config_entry *cfe, *cfe_next; 225 struct pccard_cis_quirk *q; 226 227 pf = NULL; 228 pf_last = NULL; 229 230 for (i=0; i<n_pccard_cis_quirks; i++) { 231 q = &pccard_cis_quirks[i]; 232 if (!pccard_cis_quirk_match(sc, q)) 233 continue; 234 if (!wiped) { 235 if (bootverbose) { 236 device_printf(dev, "using CIS quirks for "); 237 for (j = 0; j < 4; j++) { 238 if (sc->card.cis1_info[j] == NULL) 239 break; 240 if (j) 241 kprintf(", "); 242 kprintf("%s", sc->card.cis1_info[j]); 243 } 244 kprintf("\n"); 245 } 246 247 for (pf = STAILQ_FIRST(&sc->card.pf_head); pf != NULL; 248 pf = pf_next) { 249 for (cfe = STAILQ_FIRST(&pf->cfe_head); cfe != NULL; 250 cfe = cfe_next) { 251 cfe_next = STAILQ_NEXT(cfe, cfe_list); 252 kfree(cfe, M_DEVBUF); 253 } 254 pf_next = STAILQ_NEXT(pf, pf_list); 255 kfree(pf, M_DEVBUF); 256 } 257 258 STAILQ_INIT(&sc->card.pf_head); 259 wiped = 1; 260 } 261 262 if (pf_last == q->pf) { 263 cfe = kmalloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 264 if (cfe == NULL) { 265 device_printf(dev, "no memory for quirk (1)\n"); 266 continue; 267 } 268 *cfe = *q->cfe; 269 STAILQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list); 270 } else { 271 pf = kmalloc(sizeof(*pf), M_DEVBUF, M_NOWAIT); 272 if (pf == NULL) { 273 device_printf(dev, 274 "no memory for pccard function\n"); 275 continue; 276 } 277 *pf = *q->pf; 278 STAILQ_INIT(&pf->cfe_head); 279 cfe = kmalloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 280 if (cfe == NULL) { 281 kfree(pf, M_DEVBUF); 282 device_printf(dev, "no memory for quirk (2)\n"); 283 continue; 284 } 285 *cfe = *q->cfe; 286 STAILQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list); 287 STAILQ_INSERT_TAIL(&sc->card.pf_head, pf, pf_list); 288 pf_last = q->pf; 289 } 290 } 291 } 292