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 43 #include "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 = NELEM(pccard_cis_quirks); 200 201 static int 202 pccard_cis_quirk_match(struct pccard_softc *sc, struct pccard_cis_quirk *q) 203 { 204 if ((sc->card.manufacturer == q->manufacturer) && 205 (sc->card.product == q->product) && 206 (((sc->card.manufacturer != PCMCIA_VENDOR_INVALID) && 207 (sc->card.product != PCMCIA_PRODUCT_INVALID)) || 208 ((sc->card.manufacturer == PCMCIA_VENDOR_INVALID) && 209 (sc->card.product == PCMCIA_PRODUCT_INVALID) && 210 sc->card.cis1_info[0] && 211 (strcmp(sc->card.cis1_info[0], q->cis1_info[0]) == 0) && 212 sc->card.cis1_info[1] && 213 (strcmp(sc->card.cis1_info[1], q->cis1_info[1]) == 0)))) 214 return (1); 215 return (0); 216 } 217 218 void 219 pccard_check_cis_quirks(device_t dev) 220 { 221 struct pccard_softc *sc = PCCARD_SOFTC(dev); 222 int wiped = 0; 223 int i, j; 224 struct pccard_function *pf, *pf_next, *pf_last; 225 struct pccard_config_entry *cfe, *cfe_next; 226 struct pccard_cis_quirk *q; 227 228 pf = NULL; 229 pf_last = NULL; 230 231 for (i=0; i<n_pccard_cis_quirks; i++) { 232 q = &pccard_cis_quirks[i]; 233 if (!pccard_cis_quirk_match(sc, q)) 234 continue; 235 if (!wiped) { 236 if (bootverbose) { 237 device_printf(dev, "using CIS quirks for "); 238 for (j = 0; j < 4; j++) { 239 if (sc->card.cis1_info[j] == NULL) 240 break; 241 if (j) 242 kprintf(", "); 243 kprintf("%s", sc->card.cis1_info[j]); 244 } 245 kprintf("\n"); 246 } 247 248 for (pf = STAILQ_FIRST(&sc->card.pf_head); pf != NULL; 249 pf = pf_next) { 250 for (cfe = STAILQ_FIRST(&pf->cfe_head); cfe != NULL; 251 cfe = cfe_next) { 252 cfe_next = STAILQ_NEXT(cfe, cfe_list); 253 kfree(cfe, M_DEVBUF); 254 } 255 pf_next = STAILQ_NEXT(pf, pf_list); 256 kfree(pf, M_DEVBUF); 257 } 258 259 STAILQ_INIT(&sc->card.pf_head); 260 wiped = 1; 261 } 262 263 if (pf_last == q->pf) { 264 cfe = kmalloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 265 if (cfe == NULL) { 266 device_printf(dev, "no memory for quirk (1)\n"); 267 continue; 268 } 269 *cfe = *q->cfe; 270 STAILQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list); 271 } else { 272 pf = kmalloc(sizeof(*pf), M_DEVBUF, M_NOWAIT); 273 if (pf == NULL) { 274 device_printf(dev, 275 "no memory for pccard function\n"); 276 continue; 277 } 278 *pf = *q->pf; 279 STAILQ_INIT(&pf->cfe_head); 280 cfe = kmalloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 281 if (cfe == NULL) { 282 kfree(pf, M_DEVBUF); 283 device_printf(dev, "no memory for quirk (2)\n"); 284 continue; 285 } 286 *cfe = *q->cfe; 287 STAILQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list); 288 STAILQ_INSERT_TAIL(&sc->card.pf_head, pf, pf_list); 289 pf_last = q->pf; 290 } 291 } 292 } 293