1 /* $NetBSD: com_pcmcia.c,v 1.37 2004/07/07 06:43:22 mycroft Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 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 the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 1991 The Regents of the University of California. 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. Neither the name of the University nor the names of its contributors 52 * may be used to endorse or promote products derived from this software 53 * without specific prior written permission. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65 * SUCH DAMAGE. 66 * 67 * @(#)com.c 7.5 (Berkeley) 5/16/91 68 */ 69 70 #include <sys/cdefs.h> 71 __KERNEL_RCSID(0, "$NetBSD: com_pcmcia.c,v 1.37 2004/07/07 06:43:22 mycroft Exp $"); 72 73 #include <sys/param.h> 74 #include <sys/systm.h> 75 #include <sys/ioctl.h> 76 #include <sys/select.h> 77 #include <sys/tty.h> 78 #include <sys/proc.h> 79 #include <sys/user.h> 80 #include <sys/conf.h> 81 #include <sys/file.h> 82 #include <sys/uio.h> 83 #include <sys/kernel.h> 84 #include <sys/syslog.h> 85 #include <sys/device.h> 86 87 #include <machine/intr.h> 88 #include <machine/bus.h> 89 90 #include <dev/pcmcia/pcmciavar.h> 91 #include <dev/pcmcia/pcmciareg.h> 92 #include <dev/pcmcia/pcmciadevs.h> 93 94 #include <dev/ic/comreg.h> 95 #include <dev/ic/comvar.h> 96 97 #include <dev/isa/isareg.h> 98 99 struct com_dev { 100 char *cis1_info[4]; 101 }; 102 103 /* Devices that we need to match by CIS strings */ 104 static struct com_dev com_devs[] = { 105 { PCMCIA_CIS_MEGAHERTZ_XJ2288 }, 106 }; 107 108 109 static int com_devs_size = sizeof(com_devs) / sizeof(com_devs[0]); 110 static struct com_dev *com_dev_match __P((struct pcmcia_card *)); 111 112 int com_pcmcia_match __P((struct device *, struct cfdata *, void *)); 113 void com_pcmcia_attach __P((struct device *, struct device *, void *)); 114 int com_pcmcia_detach __P((struct device *, int)); 115 void com_pcmcia_cleanup __P((void *)); 116 117 int com_pcmcia_enable __P((struct com_softc *)); 118 void com_pcmcia_disable __P((struct com_softc *)); 119 int com_pcmcia_enable1 __P((struct com_softc *)); 120 void com_pcmcia_disable1 __P((struct com_softc *)); 121 122 struct com_pcmcia_softc { 123 struct com_softc sc_com; /* real "com" softc */ 124 125 /* PCMCIA-specific goo */ 126 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ 127 int sc_io_window; /* our i/o window */ 128 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 129 void *sc_ih; /* interrupt handler */ 130 }; 131 132 CFATTACH_DECL(com_pcmcia, sizeof(struct com_pcmcia_softc), 133 com_pcmcia_match, com_pcmcia_attach, com_pcmcia_detach, com_activate); 134 135 /* Look for pcmcia cards with particular CIS strings */ 136 static struct com_dev * 137 com_dev_match(card) 138 struct pcmcia_card *card; 139 { 140 int i, j; 141 142 for (i = 0; i < com_devs_size; i++) { 143 for (j = 0; j < 4; j++) 144 if (com_devs[i].cis1_info[j] && 145 strcmp(com_devs[i].cis1_info[j], 146 card->cis1_info[j]) != 0) 147 break; 148 if (j == 4) 149 return &com_devs[i]; 150 } 151 152 return NULL; 153 } 154 155 156 int 157 com_pcmcia_match(parent, match, aux) 158 struct device *parent; 159 struct cfdata *match; 160 void *aux; 161 { 162 int comportmask; 163 struct pcmcia_attach_args *pa = aux; 164 struct pcmcia_config_entry *cfe; 165 166 /* 1. Does it claim to be a serial device? */ 167 if (pa->pf->function == PCMCIA_FUNCTION_SERIAL) 168 return 1; 169 170 /* 2. Does it have all four 'standard' port ranges? */ 171 comportmask = 0; 172 SIMPLEQ_FOREACH(cfe, &pa->pf->cfe_head, cfe_list) { 173 switch (cfe->iospace[0].start) { 174 case IO_COM1: 175 comportmask |= 1; 176 break; 177 case IO_COM2: 178 comportmask |= 2; 179 break; 180 case IO_COM3: 181 comportmask |= 4; 182 break; 183 case IO_COM4: 184 comportmask |= 8; 185 break; 186 } 187 } 188 189 if (comportmask == 15) 190 return 1; 191 192 /* 3. Is this a card we know about? */ 193 if (com_dev_match(pa->card) != NULL) 194 return 1; 195 196 return 0; 197 } 198 199 void 200 com_pcmcia_attach(parent, self, aux) 201 struct device *parent, *self; 202 void *aux; 203 { 204 struct com_pcmcia_softc *psc = (void *) self; 205 struct com_softc *sc = &psc->sc_com; 206 struct pcmcia_attach_args *pa = aux; 207 struct pcmcia_config_entry *cfe; 208 int autoalloc = 0; 209 210 psc->sc_pf = pa->pf; 211 212 psc->sc_io_window = -1; 213 214 retry: 215 /* find a cfe we can use */ 216 217 SIMPLEQ_FOREACH(cfe, &pa->pf->cfe_head, cfe_list) { 218 #if 0 219 /* 220 * Some modem cards (e.g. Xircom CM33) also have 221 * mem space. Don't bother with this check. 222 */ 223 if (cfe->num_memspace != 0) 224 continue; 225 #endif 226 227 if (cfe->num_iospace != 1) 228 continue; 229 230 if (autoalloc == 0) { 231 /* 232 * cfe->iomask == 3 is our test for the "generic" 233 * config table entry, which we want to avoid on the 234 * first pass and use exclusively on the second pass. 235 */ 236 if ((cfe->iomask != 3) && 237 (cfe->iospace[0].start != 0)) { 238 if (!pcmcia_io_alloc(pa->pf, 239 cfe->iospace[0].start, 240 cfe->iospace[0].length, 241 cfe->iospace[0].length, &psc->sc_pcioh)) { 242 goto found; 243 } 244 } 245 } else { 246 if (cfe->iomask == 3) { 247 if (!pcmcia_io_alloc(pa->pf, 0, 248 cfe->iospace[0].length, 249 cfe->iospace[0].length, &psc->sc_pcioh)) { 250 goto found; 251 } 252 } 253 } 254 } 255 if (autoalloc == 0) { 256 autoalloc = 1; 257 goto retry; 258 } else if (!cfe) { 259 printf(": can't allocate i/o space\n"); 260 return; 261 } 262 found: 263 /* Enable the card. */ 264 pcmcia_function_init(pa->pf, cfe); 265 if (com_pcmcia_enable1(sc)) 266 printf(": function enable failed\n"); 267 268 sc->enabled = 1; 269 270 /* map in the io space */ 271 272 if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? 273 PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, psc->sc_pcioh.size, 274 &psc->sc_pcioh, &psc->sc_io_window)) { 275 printf(": can't map i/o space\n"); 276 return; 277 } 278 sc->sc_iot = psc->sc_pcioh.iot; 279 sc->sc_ioh = psc->sc_pcioh.ioh; 280 281 sc->sc_iobase = -1; 282 sc->sc_frequency = COM_FREQ; 283 284 sc->enable = com_pcmcia_enable; 285 sc->disable = com_pcmcia_disable; 286 287 aprint_normal("\n%s", sc->sc_dev.dv_xname); 288 289 com_attach_subr(sc); 290 291 sc->enabled = 0; 292 293 com_pcmcia_disable1(sc); 294 } 295 296 int 297 com_pcmcia_detach(self, flags) 298 struct device *self; 299 int flags; 300 { 301 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) self; 302 int error; 303 304 /* Unmap our i/o window. */ 305 if (psc->sc_io_window == -1) { 306 printf("%s: I/O window not allocated.\n", 307 psc->sc_com.sc_dev.dv_xname); 308 return 0; 309 } 310 311 if ((error = com_detach(self, flags)) != 0) 312 return error; 313 314 /* Unmap our i/o window. */ 315 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); 316 317 /* Free our i/o space. */ 318 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); 319 320 return 0; 321 } 322 323 int 324 com_pcmcia_enable(sc) 325 struct com_softc *sc; 326 { 327 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; 328 struct pcmcia_function *pf = psc->sc_pf; 329 int error; 330 331 if ((error = com_pcmcia_enable1(sc)) != 0) 332 return error; 333 334 /* establish the interrupt. */ 335 psc->sc_ih = pcmcia_intr_establish(pf, IPL_SERIAL, comintr, sc); 336 if (psc->sc_ih == NULL) { 337 printf("%s: couldn't establish interrupt\n", 338 sc->sc_dev.dv_xname); 339 com_pcmcia_disable1(sc); 340 return 1; 341 } 342 return 0; 343 } 344 345 int 346 com_pcmcia_enable1(sc) 347 struct com_softc *sc; 348 { 349 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; 350 struct pcmcia_function *pf = psc->sc_pf; 351 int ret; 352 353 if ((ret = pcmcia_function_enable(pf)) != 0) 354 return ret; 355 356 if ((psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) || 357 (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556) || 358 (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556INT)) { 359 int reg; 360 361 /* turn off the ethernet-disable bit */ 362 363 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION); 364 if (reg & 0x08) { 365 reg &= ~0x08; 366 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg); 367 } 368 } 369 return ret; 370 } 371 372 void 373 com_pcmcia_disable(sc) 374 struct com_softc *sc; 375 { 376 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; 377 378 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 379 com_pcmcia_disable1(sc); 380 } 381 382 void 383 com_pcmcia_disable1(sc) 384 struct com_softc *sc; 385 { 386 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc; 387 388 pcmcia_function_disable(psc->sc_pf); 389 } 390