1 /* $OpenBSD: com_pcmcia.c,v 1.62 2024/05/26 08:46:28 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/tty.h>
94 #include <sys/device.h>
95
96 #include <machine/intr.h>
97
98 #include <dev/pcmcia/pcmciavar.h>
99 #include <dev/pcmcia/pcmciareg.h>
100 #include <dev/pcmcia/pcmciadevs.h>
101
102 #include <dev/ic/comreg.h>
103 #include <dev/ic/comvar.h>
104 #include <dev/ic/ns16550reg.h>
105
106 #include <dev/isa/isareg.h>
107
108 #define com_lcr com_cfcr
109
110 /* Devices that we need to match by CIS strings */
111 struct com_pcmcia_product {
112 char *cis1_info[4];
113 } com_pcmcia_prod[] = {
114 { PCMCIA_CIS_MEGAHERTZ_XJ2288 },
115 { PCMCIA_CIS_NOVATEL_NRM6831 },
116 };
117
118 int com_pcmcia_match(struct device *, void *, void *);
119 void com_pcmcia_attach(struct device *, struct device *, void *);
120 int com_pcmcia_detach(struct device *, int);
121 int com_pcmcia_activate(struct device *, int);
122
123 int com_pcmcia_enable(struct com_softc *);
124 void com_pcmcia_disable(struct com_softc *);
125 int com_pcmcia_enable1(struct com_softc *);
126 void com_pcmcia_disable1(struct com_softc *);
127
128 struct com_pcmcia_softc {
129 struct com_softc sc_com; /* real "com" softc */
130
131 /* PCMCIA-specific goo */
132 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */
133 int sc_io_window; /* our i/o window */
134 struct pcmcia_function *sc_pf; /* our PCMCIA function */
135 void *sc_ih; /* interrupt handler */
136 };
137
138 const struct cfattach com_pcmcia_ca = {
139 sizeof(struct com_pcmcia_softc), com_pcmcia_match, com_pcmcia_attach,
140 com_pcmcia_detach, com_pcmcia_activate
141 };
142
143 int
com_pcmcia_match(struct device * parent,void * match,void * aux)144 com_pcmcia_match(struct device *parent, void *match, void *aux)
145 {
146 struct pcmcia_attach_args *pa = aux;
147 struct pcmcia_config_entry *cfe;
148 int i, j, comportmask;
149
150 /* 1. Does it claim to be a serial device? */
151 if (pa->pf->function == PCMCIA_FUNCTION_SERIAL)
152 return 1;
153
154 /* 2. Does it have all four 'standard' port ranges? */
155 comportmask = 0;
156 SIMPLEQ_FOREACH(cfe, &pa->pf->cfe_head, cfe_list) {
157 switch (cfe->iospace[0].start) {
158 case IO_COM1:
159 comportmask |= 1;
160 break;
161 case IO_COM2:
162 comportmask |= 2;
163 break;
164 case IO_COM3:
165 comportmask |= 4;
166 break;
167 case IO_COM4:
168 comportmask |= 8;
169 break;
170 }
171 }
172
173 if (comportmask == 15)
174 return 1;
175
176 /* 3. Is this a card we know about? */
177 for (i = 0; i < nitems(com_pcmcia_prod); i++) {
178 for (j = 0; j < 4; j++)
179 if (com_pcmcia_prod[i].cis1_info[j] &&
180 pa->card->cis1_info[j] &&
181 strcmp(pa->card->cis1_info[j],
182 com_pcmcia_prod[i].cis1_info[j]))
183 break;
184 if (j == 4)
185 return 1;
186 }
187
188 return 0;
189 }
190
191 int
com_pcmcia_activate(struct device * dev,int act)192 com_pcmcia_activate(struct device *dev, int act)
193 {
194 struct com_pcmcia_softc *sc = (void *) dev;
195
196 switch (act) {
197 case DVACT_SUSPEND:
198 if (sc->sc_ih)
199 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
200 sc->sc_ih = NULL;
201 pcmcia_function_disable(sc->sc_pf);
202 break;
203 case DVACT_RESUME:
204 pcmcia_function_enable(sc->sc_pf);
205 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_TTY,
206 comintr, sc, sc->sc_com.sc_dev.dv_xname);
207 com_resume(&sc->sc_com);
208 break;
209 case DVACT_DEACTIVATE:
210 if (sc->sc_ih)
211 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
212 sc->sc_ih = NULL;
213 pcmcia_function_disable(sc->sc_pf);
214 break;
215 }
216 return (0);
217 }
218
219 void
com_pcmcia_attach(struct device * parent,struct device * self,void * aux)220 com_pcmcia_attach(struct device *parent, struct device *self, void *aux)
221 {
222 struct com_pcmcia_softc *psc = (void *) self;
223 struct com_softc *sc = &psc->sc_com;
224 struct pcmcia_attach_args *pa = aux;
225 struct pcmcia_config_entry *cfe;
226 const char *intrstr;
227 int autoalloc = 0;
228
229 psc->sc_pf = pa->pf;
230
231 retry:
232 /* find a cfe we can use */
233
234 for (cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); cfe;
235 cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
236 #if 0
237 /*
238 * Some modem cards (e.g. Xircom CM33) also have
239 * mem space. Don't bother with this check.
240 */
241 if (cfe->num_memspace != 0)
242 continue;
243 #endif
244
245 if (cfe->num_iospace != 1)
246 continue;
247
248 if (!pcmcia_io_alloc(pa->pf,
249 autoalloc ? 0 : cfe->iospace[0].start,
250 cfe->iospace[0].length, COM_NPORTS, &psc->sc_pcioh)) {
251 goto found;
252 }
253 }
254 if (autoalloc == 0) {
255 autoalloc = 1;
256 goto retry;
257 } else if (!cfe) {
258 printf(": can't allocate i/o space\n");
259 return;
260 }
261
262 found:
263 sc->sc_iot = psc->sc_pcioh.iot;
264 sc->sc_ioh = psc->sc_pcioh.ioh;
265
266 /* Enable the card. */
267 pcmcia_function_init(pa->pf, cfe);
268 if (com_pcmcia_enable1(sc))
269 printf(": function enable failed\n");
270
271 sc->enabled = 1;
272
273 /* map in the io space */
274
275 if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ?
276 PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, psc->sc_pcioh.size,
277 &psc->sc_pcioh, &psc->sc_io_window)) {
278 printf(": can't map i/o space\n");
279 return;
280 }
281
282 printf(" port 0x%lx/%lu", psc->sc_pcioh.addr,
283 (u_long)psc->sc_pcioh.size);
284
285 sc->sc_iobase = -1;
286 sc->enable = com_pcmcia_enable;
287 sc->disable = com_pcmcia_disable;
288 sc->sc_frequency = COM_FREQ;
289
290 sc->sc_hwflags = 0;
291 sc->sc_swflags = 0;
292
293 if (psc->sc_pf->sc->card.manufacturer == PCMCIA_VENDOR_AUDIOVOX &&
294 psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_AUDIOVOX_RTM8000)
295 sc->sc_fifolen = 16;
296
297 com_attach_subr(sc);
298
299 /* establish the interrupt. */
300 psc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_TTY, comintr, sc,
301 sc->sc_dev.dv_xname);
302 intrstr = pcmcia_intr_string(psc->sc_pf, psc->sc_ih);
303 if (*intrstr)
304 printf(", %s", intrstr);
305
306 #ifdef notyet
307 sc->enabled = 0;
308
309 com_pcmcia_disable1(sc);
310 #endif
311 }
312
313 int
com_pcmcia_detach(struct device * dev,int flags)314 com_pcmcia_detach(struct device *dev, int flags)
315 {
316 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *)dev;
317 int error;
318
319 /* Release all resources. */
320 error = com_detach(dev, flags);
321 if (error)
322 return (error);
323
324 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
325 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
326
327 return (0);
328 }
329
330 int
com_pcmcia_enable(struct com_softc * sc)331 com_pcmcia_enable(struct com_softc *sc)
332 {
333 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc;
334 struct pcmcia_function *pf = psc->sc_pf;
335
336 /* establish the interrupt. */
337 psc->sc_ih = pcmcia_intr_establish(pf, IPL_TTY, comintr, sc,
338 sc->sc_dev.dv_xname);
339 if (psc->sc_ih == NULL) {
340 printf("%s: couldn't establish interrupt\n",
341 sc->sc_dev.dv_xname);
342 return (1);
343 }
344 return com_pcmcia_enable1(sc);
345 }
346
347 int
com_pcmcia_enable1(struct com_softc * sc)348 com_pcmcia_enable1(struct com_softc *sc)
349 {
350 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc;
351 struct pcmcia_function *pf = psc->sc_pf;
352 int ret;
353
354 if ((ret = pcmcia_function_enable(pf)))
355 return(ret);
356
357 if ((psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) ||
358 (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556) ||
359 (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556B)) {
360 int reg;
361
362 /* turn off the ethernet-disable bit */
363
364 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
365 if (reg & 0x08) {
366 reg &= ~0x08;
367 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
368 }
369 }
370
371 return(ret);
372 }
373
374 void
com_pcmcia_disable(struct com_softc * sc)375 com_pcmcia_disable(struct com_softc *sc)
376 {
377 struct com_pcmcia_softc *psc = (struct com_pcmcia_softc *) sc;
378
379 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
380 com_pcmcia_disable1(sc);
381 }
382
383 void
com_pcmcia_disable1(struct com_softc * sc)384 com_pcmcia_disable1(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