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