Annotation of sys/dev/ic/com_subr.c, Revision 1.2
1.1 nbrk 1: /* $OpenBSD: com_subr.c,v 1.10 2007/03/20 17:37:34 deraadt Exp $ */
2:
3: /*
4: * Copyright (c) 1997 - 1999, Jason Downs. All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
19: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: */
27: /*-
28: * Copyright (c) 1993, 1994, 1995, 1996
29: * Charles M. Hannum. All rights reserved.
30: * Copyright (c) 1991 The Regents of the University of California.
31: * All rights reserved.
32: *
33: * Redistribution and use in source and binary forms, with or without
34: * modification, are permitted provided that the following conditions
35: * are met:
36: * 1. Redistributions of source code must retain the above copyright
37: * notice, this list of conditions and the following disclaimer.
38: * 2. Redistributions in binary form must reproduce the above copyright
39: * notice, this list of conditions and the following disclaimer in the
40: * documentation and/or other materials provided with the distribution.
41: * 3. Neither the name of the University nor the names of its contributors
42: * may be used to endorse or promote products derived from this software
43: * without specific prior written permission.
44: *
45: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55: * SUCH DAMAGE.
56: *
57: * @(#)com.c 7.5 (Berkeley) 5/16/91
58: */
59:
60: /*
61: * COM driver, based on HP dca driver
62: * uses National Semiconductor NS16450/NS16550AF UART
63: */
64: #include <sys/param.h>
65: #include <sys/systm.h>
66: #include <sys/kernel.h>
67: #include <sys/device.h>
68: #include <sys/tty.h>
69:
70: #include "com.h"
71: #ifdef i386
72: #include "pccom.h"
73: #else
74: #define NPCCOM 0
75: #endif
76:
77: #include <machine/bus.h>
78: #if defined(__sparc64__) || !defined(__sparc__)
79: #include <machine/intr.h>
80: #endif
81:
82: #if !defined(__sparc__) || defined(__sparc64__)
83: #define COM_CONSOLE
84: #include <dev/cons.h>
85: #endif
86:
87: #include <dev/ic/comreg.h>
88: #include <dev/ic/ns16550reg.h>
89: #define com_lcr com_cfcr
90:
91: #if NCOM > 0
92: #include <dev/ic/comvar.h>
93: #endif
94: #if NPCCOM > 0
95: #include <i386/isa/pccomvar.h>
96: #endif
97:
98: #ifdef COM_PXA2X0
99: #define com_isr 8
100: #define ISR_SEND (ISR_RXPL | ISR_XMODE | ISR_XMITIR)
101: #define ISR_RECV (ISR_RXPL | ISR_XMODE | ISR_RCVEIR)
102: #endif
103:
104: #ifdef COM_CONSOLE
105: #include <sys/conf.h>
106: cdev_decl(com);
107: #endif
108:
109: void com_enable_debugport(struct com_softc *);
110: void com_fifo_probe(struct com_softc *);
111:
112: #if defined(COM_CONSOLE) || defined(KGDB)
113: void
114: com_enable_debugport(sc)
115: struct com_softc *sc;
116: {
117: int s;
118:
119: /* Turn on line break interrupt, set carrier. */
120: s = splhigh();
121: #ifdef KGDB
122: SET(sc->sc_ier, IER_ERXRDY);
123: #ifdef COM_PXA2X0
124: if (sc->sc_uarttype == COM_UART_PXA2X0)
125: sc->sc_ier |= IER_EUART | IER_ERXTOUT;
126: #endif
127: bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_ier, sc->sc_ier);
128: #endif
129: SET(sc->sc_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
130: bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_mcr, sc->sc_mcr);
131:
132: splx(s);
133: }
134: #endif /* COM_CONSOLED || KGDB */
135:
136: void
137: com_attach_subr(sc)
138: struct com_softc *sc;
139: {
140: bus_space_tag_t iot = sc->sc_iot;
141: bus_space_handle_t ioh = sc->sc_ioh;
142: u_int8_t lcr;
143:
144: sc->sc_ier = 0;
145: #ifdef COM_PXA2X0
146: if (sc->sc_uarttype == COM_UART_PXA2X0)
147: sc->sc_ier |= IER_EUART;
148: #endif
149:
150: /* disable interrupts */
151: bus_space_write_1(iot, ioh, com_ier, sc->sc_ier);
152:
153: #ifdef COM_CONSOLE
154: if (sc->sc_iobase == comconsaddr) {
155: comconsattached = 1;
156: delay(10000); /* wait for output to finish */
157: SET(sc->sc_hwflags, COM_HW_CONSOLE);
158: SET(sc->sc_swflags, COM_SW_SOFTCAR);
159: }
160: #endif
161:
162: /*
163: * Probe for all known forms of UART.
164: */
165: lcr = bus_space_read_1(iot, ioh, com_lcr);
166: bus_space_write_1(iot, ioh, com_lcr, LCR_EFR);
167: bus_space_write_1(iot, ioh, com_efr, 0);
168: bus_space_write_1(iot, ioh, com_lcr, 0);
169:
170: bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE);
171: delay(100);
172:
173: /*
174: * Skip specific probes if attachment code knows it already.
175: */
176: if (sc->sc_uarttype == COM_UART_UNKNOWN)
177: switch (bus_space_read_1(iot, ioh, com_iir) >> 6) {
178: case 0:
179: sc->sc_uarttype = COM_UART_16450;
180: break;
181: case 2:
182: sc->sc_uarttype = COM_UART_16550;
183: break;
184: case 3:
185: sc->sc_uarttype = COM_UART_16550A;
186: break;
187: default:
188: sc->sc_uarttype = COM_UART_UNKNOWN;
189: break;
190: }
191:
192: if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for ST16650s */
193: bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
194: if (bus_space_read_1(iot, ioh, com_efr) == 0) {
195: sc->sc_uarttype = COM_UART_ST16650;
196: } else {
197: bus_space_write_1(iot, ioh, com_lcr, LCR_EFR);
198: if (bus_space_read_1(iot, ioh, com_efr) == 0)
199: sc->sc_uarttype = COM_UART_ST16650V2;
200: }
201: }
202:
203: #if NPCCOM > 0 /* until com works with large FIFOs */
204: if (sc->sc_uarttype == COM_UART_ST16650V2) { /* Probe for XR16850s */
205: u_int8_t dlbl, dlbh;
206:
207: /* Enable latch access and get the current values. */
208: bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
209: dlbl = bus_space_read_1(iot, ioh, com_dlbl);
210: dlbh = bus_space_read_1(iot, ioh, com_dlbh);
211:
212: /* Zero out the latch divisors */
213: bus_space_write_1(iot, ioh, com_dlbl, 0);
214: bus_space_write_1(iot, ioh, com_dlbh, 0);
215:
216: if (bus_space_read_1(iot, ioh, com_dlbh) == 0x10) {
217: sc->sc_uarttype = COM_UART_XR16850;
218: sc->sc_uartrev = bus_space_read_1(iot, ioh, com_dlbl);
219: }
220:
221: /* Reset to original. */
222: bus_space_write_1(iot, ioh, com_dlbl, dlbl);
223: bus_space_write_1(iot, ioh, com_dlbh, dlbh);
224: }
225: #endif
226:
227: if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for TI16750s */
228: bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
229: bus_space_write_1(iot, ioh, com_fifo,
230: FIFO_ENABLE | FIFO_ENABLE_64BYTE);
231: if ((bus_space_read_1(iot, ioh, com_iir) >> 5) == 7) {
232: #if 0
233: bus_space_write_1(iot, ioh, com_lcr, 0);
234: if ((bus_space_read_1(iot, ioh, com_iir) >> 5) == 6)
235: #endif
236: sc->sc_uarttype = COM_UART_TI16750;
237: }
238: bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE);
239: }
240:
241: /* Reset the LCR (latch access is probably enabled). */
242: bus_space_write_1(iot, ioh, com_lcr, lcr);
243: if (sc->sc_uarttype == COM_UART_16450) { /* Probe for 8250 */
244: u_int8_t scr0, scr1, scr2;
245:
246: scr0 = bus_space_read_1(iot, ioh, com_scratch);
247: bus_space_write_1(iot, ioh, com_scratch, 0xa5);
248: scr1 = bus_space_read_1(iot, ioh, com_scratch);
249: bus_space_write_1(iot, ioh, com_scratch, 0x5a);
250: scr2 = bus_space_read_1(iot, ioh, com_scratch);
251: bus_space_write_1(iot, ioh, com_scratch, scr0);
252:
253: if ((scr1 != 0xa5) || (scr2 != 0x5a))
254: sc->sc_uarttype = COM_UART_8250;
255: }
256:
257: /*
258: * Print UART type and initialize ourself.
259: */
260: switch (sc->sc_uarttype) {
261: case COM_UART_UNKNOWN:
262: printf(": unknown uart\n");
263: break;
264: case COM_UART_8250:
265: printf(": ns8250, no fifo\n");
266: break;
267: case COM_UART_16450:
268: printf(": ns16450, no fifo\n");
269: break;
270: case COM_UART_16550:
271: printf(": ns16550, no working fifo\n");
272: break;
273: case COM_UART_16550A:
274: if (sc->sc_fifolen == 0)
275: sc->sc_fifolen = 16;
276: printf(": ns16550a, %d byte fifo\n", sc->sc_fifolen);
277: SET(sc->sc_hwflags, COM_HW_FIFO);
278: break;
279: #ifdef COM_PXA2X0
280: case COM_UART_PXA2X0:
281: printf(": pxa2x0, 32 byte fifo");
282: SET(sc->sc_hwflags, COM_HW_FIFO);
283: sc->sc_fifolen = 32;
284: if (sc->sc_iobase == comsiraddr) {
285: SET(sc->sc_hwflags, COM_HW_SIR);
286: printf(" (SIR)");
287: }
288: printf("\n");
289: break;
290: #endif
291: case COM_UART_ST16650:
292: printf(": st16650, no working fifo\n");
293: break;
294: case COM_UART_ST16650V2:
295: if (sc->sc_fifolen == 0)
296: sc->sc_fifolen = 32;
297: printf(": st16650, %d byte fifo\n", sc->sc_fifolen);
298: SET(sc->sc_hwflags, COM_HW_FIFO);
299: break;
300: case COM_UART_ST16C654:
301: printf(": st16c654, 64 byte fifo\n");
302: SET(sc->sc_hwflags, COM_HW_FIFO);
303: sc->sc_fifolen = 64;
304: break;
305: case COM_UART_TI16750:
306: printf(": ti16750, 64 byte fifo\n");
307: SET(sc->sc_hwflags, COM_HW_FIFO);
308: sc->sc_fifolen = 64;
309: break;
310: #if NPCCOM > 0
311: case COM_UART_XR16850:
312: printf(": xr16850 (rev %d), 128 byte fifo\n", sc->sc_uartrev);
313: SET(sc->sc_hwflags, COM_HW_FIFO);
314: sc->sc_fifolen = 128;
315: break;
316: #ifdef COM_UART_OX16C950
317: case COM_UART_OX16C950:
318: printf(": ox16c950 (rev %d), 128 byte fifo\n", sc->sc_uartrev);
319: SET(sc->sc_hwflags, COM_HW_FIFO);
320: sc->sc_fifolen = 128;
321: break;
322: #endif
323: #endif
324: default:
325: panic("comattach: bad fifo type");
326: }
327:
328: com_fifo_probe(sc);
329:
330: if (sc->sc_fifolen == 0) {
331: CLR(sc->sc_hwflags, COM_HW_FIFO);
332: sc->sc_fifolen = 1;
333: }
334:
335: /* clear and disable fifo */
336: bus_space_write_1(iot, ioh, com_fifo, FIFO_RCV_RST | FIFO_XMT_RST);
337: (void)bus_space_read_1(iot, ioh, com_data);
338: bus_space_write_1(iot, ioh, com_fifo, 0);
339:
340: sc->sc_mcr = 0;
341: bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
342:
343: #ifdef KGDB
344: /*
345: * Allow kgdb to "take over" this port. If this is
346: * the kgdb device, it has exclusive use.
347: */
348:
349: if (iot == com_kgdb_iot && sc->sc_iobase == com_kgdb_addr &&
350: !ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
351: printf("%s: kgdb\n", sc->sc_dev.dv_xname);
352: SET(sc->sc_hwflags, COM_HW_KGDB);
353: }
354: #endif /* KGDB */
355:
356: #ifdef COM_CONSOLE
357: if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
358: int maj;
359:
360: /* locate the major number */
361: for (maj = 0; maj < nchrdev; maj++)
362: if (cdevsw[maj].d_open == comopen)
363: break;
364:
365: if (maj < nchrdev && cn_tab->cn_dev == NODEV)
366: cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
367:
368: printf("%s: console\n", sc->sc_dev.dv_xname);
369: }
370: #endif
371:
372: timeout_set(&sc->sc_diag_tmo, comdiag, sc);
373: timeout_set(&sc->sc_dtr_tmo, com_raisedtr, sc);
374: #if NCOM > 0
375: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
376: sc->sc_si = softintr_establish(IPL_TTY, comsoft, sc);
377: if (sc->sc_si == NULL)
378: panic("%s: can't establish soft interrupt",
379: sc->sc_dev.dv_xname);
380: #else
381: timeout_set(&sc->sc_comsoft_tmo, comsoft, sc);
382: #endif
383: #endif /* NCOM */
384:
385: /*
386: * If there are no enable/disable functions, assume the device
387: * is always enabled.
388: */
389: if (!sc->enable)
390: sc->enabled = 1;
391:
392: #if defined(COM_CONSOLE) || defined(KGDB)
393: if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE|COM_HW_KGDB))
394: com_enable_debugport(sc);
395: #endif
396: }
397:
398: void
399: com_fifo_probe(struct com_softc *sc)
400: {
401: bus_space_handle_t ioh = sc->sc_ioh;
402: bus_space_tag_t iot = sc->sc_iot;
403: u_int8_t fifo, ier;
404: int timo, len;
405:
406: if (!ISSET(sc->sc_hwflags, COM_HW_FIFO))
407: return;
408:
409: ier = 0;
410: #ifdef COM_PXA2X0
411: if (sc->sc_uarttype == COM_UART_PXA2X0)
412: ier |= IER_EUART;
413: #endif
414: bus_space_write_1(iot, ioh, com_ier, ier);
415: bus_space_write_1(iot, ioh, com_lcr, LCR_DLAB);
416: bus_space_write_1(iot, ioh, com_dlbl, 3);
417: bus_space_write_1(iot, ioh, com_dlbh, 0);
418: bus_space_write_1(iot, ioh, com_lcr, LCR_PNONE | LCR_8BITS);
419: bus_space_write_1(iot, ioh, com_mcr, MCR_LOOPBACK);
420:
421: fifo = FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST;
422: if (sc->sc_uarttype == COM_UART_TI16750)
423: fifo |= FIFO_ENABLE_64BYTE;
424:
425: bus_space_write_1(iot, ioh, com_fifo, fifo);
426:
427: for (len = 0; len < 256; len++) {
428: bus_space_write_1(iot, ioh, com_data, (len + 1));
429: timo = 2000;
430: while (!ISSET(bus_space_read_1(iot, ioh, com_lsr),
431: LSR_TXRDY) && --timo)
432: delay(1);
433: if (!timo)
434: break;
435: }
436:
437: delay(100);
438:
439: for (len = 0; len < 256; len++) {
440: timo = 2000;
441: while (!ISSET(bus_space_read_1(iot, ioh, com_lsr),
442: LSR_RXRDY) && --timo)
443: delay(1);
444: if (!timo || bus_space_read_1(iot, ioh, com_data) != (len + 1))
445: break;
446: }
447:
448: /* For safety, always use the smaller value. */
449: if (sc->sc_fifolen > len) {
450: printf("%s: probed fifo depth: %d bytes\n",
451: sc->sc_dev.dv_xname, len);
452: sc->sc_fifolen = len;
453: }
454: }
CVSweb