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