scn.c revision 1.1 1 1.1 rumble /* $NetBSD: scn.c,v 1.1 2009/02/10 06:04:56 rumble Exp $ */
2 1.1 rumble
3 1.1 rumble /*
4 1.1 rumble * Resurrected from the old pc532 port 1/18/2009.
5 1.1 rumble *
6 1.1 rumble * XXX- The locking in this is probably totally broken. I haven't attempted
7 1.1 rumble * to get it right, but it seems to work okay anyhow.
8 1.1 rumble */
9 1.1 rumble
10 1.1 rumble /*
11 1.1 rumble * Copyright (c) 1991, 1992, 1993
12 1.1 rumble * The Regents of the University of California. All rights reserved.
13 1.1 rumble *
14 1.1 rumble * Portions of this software were developed by the Computer Systems
15 1.1 rumble * Engineering group at Lawrence Berkeley Laboratory under DARPA
16 1.1 rumble * contract BG 91-66 and contributed to Berkeley.
17 1.1 rumble *
18 1.1 rumble * All advertising materials mentioning features or use of this software
19 1.1 rumble * must display the following acknowledgement:
20 1.1 rumble * This product includes software developed by the University of
21 1.1 rumble * California, Lawrence Berkeley Laboratory.
22 1.1 rumble *
23 1.1 rumble * Redistribution and use in source and binary forms, with or without
24 1.1 rumble * modification, are permitted provided that the following conditions
25 1.1 rumble * are met:
26 1.1 rumble * 1. Redistributions of source code must retain the above copyright
27 1.1 rumble * notice, this list of conditions and the following disclaimer.
28 1.1 rumble * 2. Redistributions in binary form must reproduce the above copyright
29 1.1 rumble * notice, this list of conditions and the following disclaimer in the
30 1.1 rumble * documentation and/or other materials provided with the distribution.
31 1.1 rumble * 3. Neither the name of the University nor the names of its contributors
32 1.1 rumble * may be used to endorse or promote products derived from this software
33 1.1 rumble * without specific prior written permission.
34 1.1 rumble *
35 1.1 rumble * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36 1.1 rumble * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 1.1 rumble * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 1.1 rumble * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39 1.1 rumble * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 1.1 rumble * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 1.1 rumble * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 1.1 rumble * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 1.1 rumble * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 1.1 rumble * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 1.1 rumble * SUCH DAMAGE.
46 1.1 rumble *
47 1.1 rumble * from: @(#)com.c 7.5 (Berkeley) 5/16/91
48 1.1 rumble */
49 1.1 rumble
50 1.1 rumble /*
51 1.1 rumble * Copyright (c) 1996, 1997 Philip L. Budne.
52 1.1 rumble * Copyright (c) 1993 Philip A. Nelson.
53 1.1 rumble *
54 1.1 rumble * Portions of this software were developed by the Computer Systems
55 1.1 rumble * Engineering group at Lawrence Berkeley Laboratory under DARPA
56 1.1 rumble * contract BG 91-66 and contributed to Berkeley.
57 1.1 rumble *
58 1.1 rumble * All advertising materials mentioning features or use of this software
59 1.1 rumble * must display the following acknowledgement:
60 1.1 rumble * This product includes software developed by the University of
61 1.1 rumble * California, Lawrence Berkeley Laboratory.
62 1.1 rumble *
63 1.1 rumble * Redistribution and use in source and binary forms, with or without
64 1.1 rumble * modification, are permitted provided that the following conditions
65 1.1 rumble * are met:
66 1.1 rumble * 1. Redistributions of source code must retain the above copyright
67 1.1 rumble * notice, this list of conditions and the following disclaimer.
68 1.1 rumble * 2. Redistributions in binary form must reproduce the above copyright
69 1.1 rumble * notice, this list of conditions and the following disclaimer in the
70 1.1 rumble * documentation and/or other materials provided with the distribution.
71 1.1 rumble * 3. All advertising materials mentioning features or use of this software
72 1.1 rumble * must display the following acknowledgement:
73 1.1 rumble * This product includes software developed by the University of
74 1.1 rumble * California, Berkeley and its contributors.
75 1.1 rumble * 4. Neither the name of the University nor the names of its contributors
76 1.1 rumble * may be used to endorse or promote products derived from this software
77 1.1 rumble * without specific prior written permission.
78 1.1 rumble *
79 1.1 rumble * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
80 1.1 rumble * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
81 1.1 rumble * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
82 1.1 rumble * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
83 1.1 rumble * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
84 1.1 rumble * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
85 1.1 rumble * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
86 1.1 rumble * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
87 1.1 rumble * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
88 1.1 rumble * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
89 1.1 rumble * SUCH DAMAGE.
90 1.1 rumble *
91 1.1 rumble * from: @(#)com.c 7.5 (Berkeley) 5/16/91
92 1.1 rumble */
93 1.1 rumble
94 1.1 rumble #include <sys/cdefs.h>
95 1.1 rumble __KERNEL_RCSID(0, "$NetBSD: scn.c,v 1.1 2009/02/10 06:04:56 rumble Exp $");
96 1.1 rumble
97 1.1 rumble #include "opt_ddb.h"
98 1.1 rumble #include "opt_kgdb.h"
99 1.1 rumble #include "scn.h"
100 1.1 rumble
101 1.1 rumble #include <sys/param.h>
102 1.1 rumble #include <sys/systm.h>
103 1.1 rumble #include <sys/ioctl.h>
104 1.1 rumble #include <sys/select.h>
105 1.1 rumble #include <sys/tty.h>
106 1.1 rumble #include <sys/proc.h>
107 1.1 rumble #include <sys/user.h>
108 1.1 rumble #include <sys/file.h>
109 1.1 rumble #include <sys/uio.h>
110 1.1 rumble #include <sys/kernel.h>
111 1.1 rumble #include <sys/syslog.h>
112 1.1 rumble #include <sys/types.h>
113 1.1 rumble #include <sys/device.h>
114 1.1 rumble #include <sys/malloc.h>
115 1.1 rumble #include <sys/conf.h>
116 1.1 rumble #include <sys/intr.h>
117 1.1 rumble #ifdef KGDB
118 1.1 rumble #include <sys/kgdb.h>
119 1.1 rumble #endif
120 1.1 rumble #include <sys/kauth.h>
121 1.1 rumble
122 1.1 rumble #include <dev/cons.h>
123 1.1 rumble
124 1.1 rumble #include <machine/autoconf.h>
125 1.1 rumble #include <machine/machtype.h>
126 1.1 rumble
127 1.1 rumble #include <sgimips/dev/scnreg.h>
128 1.1 rumble #include <sgimips/dev/scnvar.h>
129 1.1 rumble
130 1.1 rumble int scn_match(device_t, struct cfdata *, void *);
131 1.1 rumble void scn_attach(device_t, device_t, void *);
132 1.1 rumble int scnparam(struct tty *, struct termios *);
133 1.1 rumble void scnstart(struct tty *);
134 1.1 rumble int scnhwiflow(struct tty *, int);
135 1.1 rumble
136 1.1 rumble void scncnprobe(struct consdev *);
137 1.1 rumble void scncninit(struct consdev *);
138 1.1 rumble int scncngetc(dev_t);
139 1.1 rumble void scncnputc(dev_t, int);
140 1.1 rumble void scncnpollc(dev_t, int);
141 1.1 rumble int scninit(dev_t, int);
142 1.1 rumble void scncnreinit(void *);
143 1.1 rumble
144 1.1 rumble CFATTACH_DECL(scn, sizeof(struct scn_softc),
145 1.1 rumble scn_match, scn_attach, NULL, NULL);
146 1.1 rumble
147 1.1 rumble extern struct cfdriver scn_cd;
148 1.1 rumble
149 1.1 rumble dev_type_open(scnopen);
150 1.1 rumble dev_type_close(scnclose);
151 1.1 rumble dev_type_read(scnread);
152 1.1 rumble dev_type_write(scnwrite);
153 1.1 rumble dev_type_ioctl(scnioctl);
154 1.1 rumble dev_type_stop(scnstop);
155 1.1 rumble dev_type_tty(scntty);
156 1.1 rumble dev_type_poll(scnpoll);
157 1.1 rumble
158 1.1 rumble const struct cdevsw scn_cdevsw = {
159 1.1 rumble scnopen, scnclose, scnread, scnwrite, scnioctl,
160 1.1 rumble scnstop, scntty, scnpoll, nommap, ttykqfilter, D_TTY
161 1.1 rumble };
162 1.1 rumble
163 1.1 rumble struct consdev scn_cn = {
164 1.1 rumble scncnprobe,
165 1.1 rumble scncninit,
166 1.1 rumble scncngetc,
167 1.1 rumble scncnputc,
168 1.1 rumble scncnpollc,
169 1.1 rumble NULL,
170 1.1 rumble NULL,
171 1.1 rumble NULL,
172 1.1 rumble NODEV,
173 1.1 rumble CN_NORMAL
174 1.1 rumble };
175 1.1 rumble
176 1.1 rumble #ifndef CONSOLE_SPEED
177 1.1 rumble #define CONSOLE_SPEED TTYDEF_SPEED
178 1.1 rumble #endif
179 1.1 rumble
180 1.1 rumble #ifndef SCNDEF_CFLAG
181 1.1 rumble #define SCNDEF_CFLAG TTYDEF_CFLAG
182 1.1 rumble #endif
183 1.1 rumble
184 1.1 rumble #ifdef CPU30MHZ
185 1.1 rumble #define RECOVER() __asm volatile("bispsrw 0x800" : : : "cc")
186 1.1 rumble #else
187 1.1 rumble #define RECOVER()
188 1.1 rumble #endif
189 1.1 rumble
190 1.1 rumble int scndefaultrate = TTYDEF_SPEED;
191 1.1 rumble int scnconsrate = CONSOLE_SPEED;
192 1.1 rumble
193 1.1 rumble static inline struct scn_softc *
194 1.1 rumble SOFTC(int unit)
195 1.1 rumble {
196 1.1 rumble if (unit < 0 || unit >= scn_cd.cd_ndevs)
197 1.1 rumble return (NULL);
198 1.1 rumble return ((struct scn_softc *)scn_cd.cd_devs[unit]);
199 1.1 rumble }
200 1.1 rumble
201 1.1 rumble static int scnintr(void *);
202 1.1 rumble static void scnrxintr(void *);
203 1.1 rumble static int scn_rxintr(struct scn_softc *);
204 1.1 rumble static void scnsoft(void *);
205 1.1 rumble static void scn_setchip(struct scn_softc *sc);
206 1.1 rumble static int scniter(int *, int, int*, int*, struct chan *, int);
207 1.1 rumble static int scn_config(int, int, int, int, u_char, u_char);
208 1.1 rumble static void scn_rxenable(struct scn_softc *);
209 1.1 rumble static void scn_rxdisable(struct scn_softc *);
210 1.1 rumble static void dcd_int(struct scn_softc *, struct tty *, u_char);
211 1.1 rumble static void scnoverrun(int, long *, const char *);
212 1.1 rumble static u_char opbits(struct scn_softc *, int);
213 1.1 rumble
214 1.1 rumble static void *scnsir = NULL; /* s/w intr cookie */
215 1.1 rumble #define setsoftscn() softint_schedule(scnsir)
216 1.1 rumble
217 1.1 rumble #ifdef SCN_TIMING
218 1.1 rumble /*
219 1.1 rumble * Keep timing info on latency of software interrupt used by
220 1.1 rumble * the ringbuf code to empty ring buffer.
221 1.1 rumble * "getinfo" program reads data from /dev/kmem.
222 1.1 rumble */
223 1.1 rumble static struct timeval tstart;
224 1.1 rumble #define NJITTER 100
225 1.1 rumble int scn_njitter = NJITTER;
226 1.1 rumble int scn_jitter[NJITTER];
227 1.1 rumble #endif
228 1.1 rumble
229 1.1 rumble #define SCN_CLOCK 3686400 /* input clock */
230 1.1 rumble
231 1.1 rumble /* speed table groups ACR[7] */
232 1.1 rumble #define GRP_A 0
233 1.1 rumble #define GRP_B ACR_BRG
234 1.1 rumble
235 1.1 rumble /* combo of MR0[2:0] and ACR[7] */
236 1.1 rumble #define MODE0A MR0_MODE_0
237 1.1 rumble #define MODE0B (MR0_MODE_0|ACR_BRG)
238 1.1 rumble #define MODE1A MR0_MODE_1
239 1.1 rumble #define MODE1B (MR0_MODE_1|ACR_BRG)
240 1.1 rumble #define MODE2A MR0_MODE_2
241 1.1 rumble #define MODE2B (MR0_MODE_2|ACR_BRG)
242 1.1 rumble
243 1.1 rumble #define ANYMODE -1
244 1.1 rumble #define DEFMODE(C92) MODE0A /* use MODE4A if 26c92? */
245 1.1 rumble
246 1.1 rumble /* speed code for Counter/Timer (all modes, groups) */
247 1.1 rumble #define USE_CT 0xd
248 1.1 rumble
249 1.1 rumble /*
250 1.1 rumble * Rate table, ordered by speed, then mode.
251 1.1 rumble * NOTE: ordering of modes must be done carefully!
252 1.1 rumble */
253 1.1 rumble struct tabent {
254 1.1 rumble int32_t speed;
255 1.1 rumble int16_t code;
256 1.1 rumble int16_t mode;
257 1.1 rumble } table[] = {
258 1.1 rumble { 50, 0x0, MODE0A },
259 1.1 rumble { 75, 0x0, MODE0B },
260 1.1 rumble { 110, 0x1, MODE0A },
261 1.1 rumble { 110, 0x1, MODE0B },
262 1.1 rumble { 110, 0x1, MODE1A },
263 1.1 rumble { 110, 0x1, MODE1B },
264 1.1 rumble { 134, 0x2, MODE0A }, /* 134.5 */
265 1.1 rumble { 134, 0x2, MODE0B }, /* 134.5 */
266 1.1 rumble { 134, 0x2, MODE1A }, /* 134.5 */
267 1.1 rumble { 134, 0x2, MODE1B }, /* 134.5 */
268 1.1 rumble { 150, 0x3, MODE0A },
269 1.1 rumble { 150, 0x3, MODE0A },
270 1.1 rumble { 200, 0x3, MODE0A },
271 1.1 rumble { 300, 0x4, MODE0A },
272 1.1 rumble { 300, 0x4, MODE0B },
273 1.1 rumble { 300, 0x0, MODE1A },
274 1.1 rumble { 450, 0x0, MODE1B },
275 1.1 rumble { 600, 0x5, MODE0A },
276 1.1 rumble { 600, 0x5, MODE0B },
277 1.1 rumble { 880, 0x1, MODE2A },
278 1.1 rumble { 880, 0x1, MODE2B },
279 1.1 rumble { 900, 0x3, MODE1B },
280 1.1 rumble { 1050, 0x7, MODE0A },
281 1.1 rumble { 1050, 0x7, MODE1A },
282 1.1 rumble { 1076, 0x2, MODE2A },
283 1.1 rumble { 1076, 0x2, MODE2B },
284 1.1 rumble { 1200, 0x6, MODE0A },
285 1.1 rumble { 1200, 0x6, MODE0B },
286 1.1 rumble { 1200, 0x3, MODE1A },
287 1.1 rumble { 1800, 0xa, MODE0B },
288 1.1 rumble { 1800, 0x4, MODE1A },
289 1.1 rumble { 1800, 0x4, MODE1B },
290 1.1 rumble { 2000, 0x7, MODE0B },
291 1.1 rumble { 2000, 0x7, MODE1B },
292 1.1 rumble { 2400, 0x8, MODE0A },
293 1.1 rumble { 2400, 0x8, MODE0B },
294 1.1 rumble { 3600, 0x5, MODE1A },
295 1.1 rumble { 3600, 0x5, MODE1B },
296 1.1 rumble { 4800, 0x9, MODE2A },
297 1.1 rumble { 4800, 0x9, MODE2B },
298 1.1 rumble { 4800, 0x9, MODE0A },
299 1.1 rumble { 4800, 0x9, MODE0B },
300 1.1 rumble { 7200, 0xa, MODE0A },
301 1.1 rumble { 7200, 0x0, MODE2B },
302 1.1 rumble { 7200, 0x6, MODE1A },
303 1.1 rumble { 7200, 0x6, MODE1B },
304 1.1 rumble { 9600, 0xb, MODE2A },
305 1.1 rumble { 9600, 0xb, MODE2B },
306 1.1 rumble { 9600, 0xb, MODE0A },
307 1.1 rumble { 9600, 0xb, MODE0B },
308 1.1 rumble { 9600, 0xd, MODE1A }, /* use C/T as entre' to mode1 */
309 1.1 rumble { 9600, 0xd, MODE1B }, /* use C/T as entre' to mode1 */
310 1.1 rumble { 14400, 0x3, MODE2B },
311 1.1 rumble { 14400, 0x8, MODE1A },
312 1.1 rumble { 14400, 0x8, MODE1B },
313 1.1 rumble { 19200, 0x3, MODE2A },
314 1.1 rumble { 19200, 0xc, MODE2B },
315 1.1 rumble { 19200, 0xc, MODE0B },
316 1.1 rumble { 19200, 0xd, MODE1A }, /* use C/T as entre' to mode1 */
317 1.1 rumble { 19200, 0xd, MODE1B }, /* use C/T as entre' to mode1 */
318 1.1 rumble { 28800, 0x4, MODE2A },
319 1.1 rumble { 28800, 0x4, MODE2B },
320 1.1 rumble { 28800, 0x9, MODE1A },
321 1.1 rumble { 28800, 0x9, MODE1B },
322 1.1 rumble { 38400, 0xc, MODE2A },
323 1.1 rumble { 38400, 0xc, MODE0A },
324 1.1 rumble { 57600, 0x5, MODE2A },
325 1.1 rumble { 57600, 0x5, MODE2B },
326 1.1 rumble { 57600, 0xb, MODE1A },
327 1.1 rumble { 57600, 0xb, MODE1B },
328 1.1 rumble { 115200, 0x6, MODE2A },
329 1.1 rumble { 115200, 0x6, MODE2B },
330 1.1 rumble { 115200, 0xc, MODE1B },
331 1.1 rumble { 230400, 0xc, MODE1A }
332 1.1 rumble };
333 1.1 rumble #define TABENTRIES (sizeof(table)/sizeof(table[0]))
334 1.1 rumble
335 1.1 rumble /*
336 1.1 rumble * boolean for speed codes which are identical in both A/B BRG groups
337 1.1 rumble * in all modes
338 1.1 rumble */
339 1.1 rumble static u_char bothgroups[16] = {
340 1.1 rumble 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1
341 1.1 rumble };
342 1.1 rumble
343 1.1 rumble /*
344 1.1 rumble * Manually constructed divisors table
345 1.1 rumble * for minimum error (from some of Dave Rand's code)
346 1.1 rumble */
347 1.1 rumble const struct {
348 1.1 rumble uint16_t speed;
349 1.1 rumble uint16_t div;
350 1.1 rumble } divs[] = {
351 1.1 rumble { 50, 2303 }, /* 2304 is exact?? */
352 1.1 rumble { 110, 1047 }, /* Should be 1047.27 */
353 1.1 rumble { 134, 857 }, /* Should be 856.505576 */
354 1.1 rumble { 1050, 110 }, /* Should be 109.7142857 */
355 1.1 rumble { 2000, 57 } /* Should be 57.6 */
356 1.1 rumble };
357 1.1 rumble #define DIVS (sizeof(divs)/sizeof(divs[0]))
358 1.1 rumble
359 1.1 rumble /*
360 1.1 rumble * minor unit bit decode:
361 1.1 rumble * CxxxUUU
362 1.1 rumble *
363 1.1 rumble * C - carrier
364 1.1 rumble * 0 - delay open until carrier high
365 1.1 rumble * 1 - allow open with carrier low
366 1.1 rumble * UUU - unit 0-7
367 1.1 rumble */
368 1.1 rumble
369 1.1 rumble #define DEV_UNIT(x) (minor(x) & 0x7)
370 1.1 rumble #define DEV_DIALOUT(x) (minor(x) & 0x80)
371 1.1 rumble
372 1.1 rumble extern struct tty *constty;
373 1.1 rumble
374 1.1 rumble #define SCN_MAXDUART 4
375 1.1 rumble static struct duart scn_duart[SCN_MAXDUART];
376 1.1 rumble
377 1.1 rumble #ifdef KGDB
378 1.1 rumble extern int kgdb_dev;
379 1.1 rumble extern int kgdb_rate;
380 1.1 rumble extern int kgdb_debug_init;
381 1.1 rumble #endif
382 1.1 rumble
383 1.1 rumble /* XXXXX - fix this */
384 1.1 rumble #define splrtty() spltty()
385 1.1 rumble
386 1.1 rumble /* RS-232 configuration routines */
387 1.1 rumble
388 1.1 rumble /*
389 1.1 rumble * set chip parameters, or mark for delayed change.
390 1.1 rumble * called at spltty() or on TxEMPTY interrupt.
391 1.1 rumble *
392 1.1 rumble * Reads current values to avoid glitches from redundant sets.
393 1.1 rumble * Perhaps should save last value set to avoid read/write? NOTE:
394 1.1 rumble * Would still need to do read if write not needed to advance MR
395 1.1 rumble * pointer.
396 1.1 rumble *
397 1.1 rumble * new 2/97 -plb
398 1.1 rumble */
399 1.1 rumble
400 1.1 rumble static void
401 1.1 rumble scn_setchip(struct scn_softc *sc)
402 1.1 rumble {
403 1.1 rumble struct duart *dp;
404 1.1 rumble u_char acr, csr, mr1, mr2;
405 1.1 rumble int chan;
406 1.1 rumble
407 1.1 rumble if (sc->sc_tty && (sc->sc_tty->t_state & TS_BUSY)) {
408 1.1 rumble sc->sc_heldchanges = 1;
409 1.1 rumble return;
410 1.1 rumble }
411 1.1 rumble
412 1.1 rumble chan = sc->sc_channel;
413 1.1 rumble dp = sc->sc_duart;
414 1.1 rumble if (dp->type == SC26C92) {
415 1.1 rumble u_char nmr0a, mr0a;
416 1.1 rumble
417 1.1 rumble /* input rate high enough so 64 bit time watchdog not
418 1.1 rumble * onerous? */
419 1.1 rumble if (dp->chan[chan].ispeed >= 1200) {
420 1.1 rumble /* set FIFO threshold at 6 for other
421 1.1 rumble * thresholds we could have to set MR1_FFULL
422 1.1 rumble */
423 1.1 rumble dp->chan[chan].mr0 |= MR0_RXWD | MR0_RXINT;
424 1.1 rumble } else {
425 1.1 rumble dp->chan[chan].mr0 &= ~(MR0_RXWD | MR0_RXINT);
426 1.1 rumble }
427 1.1 rumble
428 1.1 rumble /* select BRG mode (MR0A only) */
429 1.1 rumble nmr0a = dp->chan[0].mr0 | (dp->mode & MR0_MODE);
430 1.1 rumble
431 1.1 rumble dp->base[CH_CR] = CR_CMD_MR0;
432 1.1 rumble RECOVER();
433 1.1 rumble
434 1.1 rumble mr0a = dp->base[CH_MR];
435 1.1 rumble if (mr0a != nmr0a) {
436 1.1 rumble dp->base[CH_CR] = CR_CMD_MR0;
437 1.1 rumble RECOVER();
438 1.1 rumble dp->base[CH_MR] = nmr0a;
439 1.1 rumble }
440 1.1 rumble
441 1.1 rumble if (chan) { /* channel B? */
442 1.1 rumble u_char mr0b;
443 1.1 rumble
444 1.1 rumble sc->sc_chbase[CH_CR] = CR_CMD_MR0;
445 1.1 rumble RECOVER();
446 1.1 rumble mr0b = dp->base[CH_MR];
447 1.1 rumble
448 1.1 rumble if (dp->chan[chan].mr0 != mr0b) {
449 1.1 rumble sc->sc_chbase[CH_CR] = CR_CMD_MR0;
450 1.1 rumble RECOVER();
451 1.1 rumble sc->sc_chbase[CH_MR] = dp->chan[chan].mr0;
452 1.1 rumble }
453 1.1 rumble }
454 1.1 rumble } else {
455 1.1 rumble sc->sc_chbase[CH_CR] = CR_CMD_MR1;
456 1.1 rumble RECOVER();
457 1.1 rumble }
458 1.1 rumble
459 1.1 rumble mr1 = sc->sc_chbase[CH_MR];
460 1.1 rumble mr2 = sc->sc_chbase[CH_MR];
461 1.1 rumble if (mr1 != dp->chan[chan].new_mr1 ||
462 1.1 rumble mr2 != dp->chan[chan].new_mr2) {
463 1.1 rumble sc->sc_chbase[CH_CR] = CR_CMD_MR1;
464 1.1 rumble RECOVER();
465 1.1 rumble sc->sc_chbase[CH_MR] = dp->chan[chan].new_mr1;
466 1.1 rumble sc->sc_chbase[CH_MR] = dp->chan[chan].new_mr2;
467 1.1 rumble }
468 1.1 rumble
469 1.1 rumble acr = dp->acr | (dp->mode & ACR_BRG);
470 1.1 rumble dp->base[DU_ACR] = acr; /* write-only reg! */
471 1.1 rumble
472 1.1 rumble /* set speed codes */
473 1.1 rumble csr = (dp->chan[chan].icode<<4) | dp->chan[chan].ocode;
474 1.1 rumble if (sc->sc_chbase[CH_CSR] != csr) {
475 1.1 rumble sc->sc_chbase[CH_CSR] = csr;
476 1.1 rumble }
477 1.1 rumble
478 1.1 rumble /* see if counter/timer in use */
479 1.1 rumble if (dp->counter &&
480 1.1 rumble (dp->chan[0].icode == USE_CT || dp->chan[0].ocode == USE_CT ||
481 1.1 rumble dp->chan[1].icode == USE_CT || dp->chan[1].ocode == USE_CT)) {
482 1.1 rumble
483 1.1 rumble /* program counter/timer only if necessary */
484 1.1 rumble if (dp->counter != dp->ocounter) {
485 1.1 rumble uint16_t div;
486 1.1 rumble #ifdef DIVS
487 1.1 rumble int i;
488 1.1 rumble
489 1.1 rumble /* look for precalculated rate, for minimum error */
490 1.1 rumble for (i = 0; i < DIVS && divs[i].speed <= dp->counter; i++) {
491 1.1 rumble if (divs[i].speed == dp->counter) {
492 1.1 rumble div = divs[i].div;
493 1.1 rumble goto found;
494 1.1 rumble }
495 1.1 rumble }
496 1.1 rumble #endif
497 1.1 rumble
498 1.1 rumble /* not found in table; calculate a value (rounding up) */
499 1.1 rumble div = ((long)SCN_CLOCK/16/2 + dp->counter/2) / dp->counter;
500 1.1 rumble
501 1.1 rumble found:
502 1.1 rumble /* halt before loading? may ALWAYS glitch?
503 1.1 rumble * reload race may only sometimes glitch??
504 1.1 rumble */
505 1.1 rumble dp->base[DU_CTUR] = div >> 8;
506 1.1 rumble dp->base[DU_CTLR] = div & 255;
507 1.1 rumble if (dp->ocounter == 0) {
508 1.1 rumble /* not previously used? */
509 1.1 rumble u_char temp;
510 1.1 rumble /* start C/T running */
511 1.1 rumble temp = dp->base[DU_CSTRT];
512 1.1 rumble }
513 1.1 rumble dp->ocounter = dp->counter;
514 1.1 rumble }
515 1.1 rumble } else {
516 1.1 rumble /* counter not in use; mark as free */
517 1.1 rumble dp->counter = 0;
518 1.1 rumble }
519 1.1 rumble sc->sc_heldchanges = 0;
520 1.1 rumble
521 1.1 rumble /*
522 1.1 rumble * delay a tiny bit to try and avoid tx glitching.
523 1.1 rumble * I know we're at spltty(), but this is much better than the
524 1.1 rumble * old version used DELAY((96000 / out_speed) * 10000)
525 1.1 rumble * -plb
526 1.1 rumble */
527 1.1 rumble DELAY(10);
528 1.1 rumble }
529 1.1 rumble
530 1.1 rumble /*
531 1.1 rumble * iterator function for speeds.
532 1.1 rumble * (could be called "findnextcode")
533 1.1 rumble * Returns sequence of possible speed codes for a given rate.
534 1.1 rumble * should set index to zero before first call.
535 1.1 rumble *
536 1.1 rumble * Could be implemented as a "checkspeed()" function called
537 1.1 rumble * to evaluate table entries, BUT this allows more variety in
538 1.1 rumble * use of C/T with fewer table entries.
539 1.1 rumble */
540 1.1 rumble
541 1.1 rumble static int
542 1.1 rumble scniter(int *index, int wanted, int *counter, int *mode, struct chan *other,
543 1.1 rumble int c92)
544 1.1 rumble {
545 1.1 rumble
546 1.1 rumble while (*index < TABENTRIES) {
547 1.1 rumble struct tabent *tp;
548 1.1 rumble
549 1.1 rumble tp = table + (*index)++;
550 1.1 rumble if (tp->speed != wanted)
551 1.1 rumble continue;
552 1.1 rumble
553 1.1 rumble /* if not a 26C92 only look at MODE0 entries */
554 1.1 rumble if (!c92 && (tp->mode & MR0_MODE) != MR0_MODE_0)
555 1.1 rumble continue;
556 1.1 rumble
557 1.1 rumble /*
558 1.1 rumble * check mode;
559 1.1 rumble * OK if this table entry for current mode, or mode not
560 1.1 rumble * yet set, or other channel's rates are available in both
561 1.1 rumble * A and B groups.
562 1.1 rumble */
563 1.1 rumble
564 1.1 rumble if (tp->mode == *mode || *mode == ANYMODE ||
565 1.1 rumble (other != NULL && (tp->mode & MR0_MODE) == (*mode & MR0_MODE) &&
566 1.1 rumble bothgroups[other->icode] && bothgroups[other->ocode])) {
567 1.1 rumble /*
568 1.1 rumble * for future table entries specifying
569 1.1 rumble * use of counter/timer
570 1.1 rumble */
571 1.1 rumble if (tp->code == USE_CT) {
572 1.1 rumble if (*counter != wanted && *counter != 0)
573 1.1 rumble continue; /* counter busy */
574 1.1 rumble *counter = wanted;
575 1.1 rumble }
576 1.1 rumble *mode = tp->mode;
577 1.1 rumble return tp->code;
578 1.1 rumble }
579 1.1 rumble }
580 1.1 rumble
581 1.1 rumble /* here after returning all applicable table entries */
582 1.1 rumble /* XXX return sequence of USE_CT with all possible modes?? */
583 1.1 rumble if ((*index)++ == TABENTRIES) {
584 1.1 rumble /* Max C/T rate (even on 26C92?) is 57600 */
585 1.1 rumble if (wanted <= 57600 && (*counter == wanted || *counter == 0)) {
586 1.1 rumble *counter = wanted;
587 1.1 rumble return USE_CT;
588 1.1 rumble }
589 1.1 rumble }
590 1.1 rumble
591 1.1 rumble return -1; /* FAIL */
592 1.1 rumble }
593 1.1 rumble
594 1.1 rumble /*
595 1.1 rumble * calculate configuration
596 1.1 rumble * rewritten 2/97 -plb
597 1.1 rumble */
598 1.1 rumble static int
599 1.1 rumble scn_config(int unit, int chan, int ispeed, int ospeed, u_char mr1, u_char mr2)
600 1.1 rumble {
601 1.1 rumble struct scn_softc *sc;
602 1.1 rumble struct duart *dp;
603 1.1 rumble int other; /* opposite of chan */
604 1.1 rumble int mode;
605 1.1 rumble int counter;
606 1.1 rumble int i, o; /* input, output iterator indexes */
607 1.1 rumble int ic, oc; /* input, output codes */
608 1.1 rumble struct chan *ocp; /* other duart channel */
609 1.1 rumble struct tty *otp; /* other channel tty struct */
610 1.1 rumble int c92; /* true if duart is sc26c92 */
611 1.1 rumble int s;
612 1.1 rumble
613 1.1 rumble /* Set up softc pointer. */
614 1.1 rumble if (unit >= scn_cd.cd_ndevs)
615 1.1 rumble return ENXIO;
616 1.1 rumble sc = SOFTC(unit);
617 1.1 rumble chan = sc->sc_channel;
618 1.1 rumble other = chan ^ 1;
619 1.1 rumble dp = sc->sc_duart;
620 1.1 rumble ocp = &dp->chan[other];
621 1.1 rumble otp = ocp->tty;
622 1.1 rumble c92 = (dp->type == SC26C92);
623 1.1 rumble
624 1.1 rumble /*
625 1.1 rumble * Right now the first combination that works is used.
626 1.1 rumble * Perhaps it should search entire solution space for "best"
627 1.1 rumble * combination. For example, use heuristic weighting of mode
628 1.1 rumble * preferences, and use of counter timer?
629 1.1 rumble *
630 1.1 rumble * For example right now with 2681/2692 when default rate is
631 1.1 rumble * 9600 and other channel is closed setting 19200 will pick
632 1.1 rumble * mode 0a and use counter/timer. Better solution might be
633 1.1 rumble * mode 0b, leaving counter/timer free!
634 1.1 rumble *
635 1.1 rumble * When other channel is open might want to prefer
636 1.1 rumble * leaving counter timer free, or not flipping A/B group?
637 1.1 rumble */
638 1.1 rumble if (otp && (otp->t_state & TS_ISOPEN)) {
639 1.1 rumble
640 1.1 rumble /*
641 1.1 rumble * Other channel open;
642 1.1 rumble * Find speed codes compatible with current mode/counter.
643 1.1 rumble */
644 1.1 rumble
645 1.1 rumble i = 0;
646 1.1 rumble for (;;) {
647 1.1 rumble mode = dp->mode;
648 1.1 rumble counter = dp->counter;
649 1.1 rumble
650 1.1 rumble /* NOTE: pass other chan pointer to allow group flipping */
651 1.1 rumble ic = scniter(&i, ispeed, &counter, &mode, ocp, c92);
652 1.1 rumble if (ic == -1)
653 1.1 rumble break;
654 1.1 rumble
655 1.1 rumble o = 0;
656 1.1 rumble if ((oc = scniter(&o, ospeed, &counter,
657 1.1 rumble &mode, NULL, c92)) != -1) {
658 1.1 rumble /*
659 1.1 rumble * take first match
660 1.1 rumble *
661 1.1 rumble * Perhaps calculate heuristic "score",
662 1.1 rumble * save score,codes,mode,counter if score
663 1.1 rumble * better than previous best?
664 1.1 rumble */
665 1.1 rumble goto gotit;
666 1.1 rumble }
667 1.1 rumble }
668 1.1 rumble /* XXX try looping for ospeed? */
669 1.1 rumble } else {
670 1.1 rumble /* other channel closed */
671 1.1 rumble int oo, oi; /* other input, output iterators */
672 1.1 rumble int oic, ooc; /* other input, output codes */
673 1.1 rumble
674 1.1 rumble /*
675 1.1 rumble * Here when other channel closed. Finds first
676 1.1 rumble * combination that will allow other channel to be opened
677 1.1 rumble * (with defaults) and fits our needs.
678 1.1 rumble */
679 1.1 rumble oi = 0;
680 1.1 rumble for (;;) {
681 1.1 rumble mode = ANYMODE;
682 1.1 rumble counter = 0;
683 1.1 rumble
684 1.1 rumble oic = scniter(&oi, ocp->ispeed, &counter, &mode, NULL, c92);
685 1.1 rumble if (oic == -1)
686 1.1 rumble break;
687 1.1 rumble
688 1.1 rumble oo = 0;
689 1.1 rumble while ((ooc = scniter(&oo, ocp->ospeed, &counter,
690 1.1 rumble &mode, NULL, c92)) != -1) {
691 1.1 rumble i = 0;
692 1.1 rumble while ((ic = scniter(&i, ispeed, &counter,
693 1.1 rumble &mode, NULL, c92)) != -1) {
694 1.1 rumble o = 0;
695 1.1 rumble if ((oc = scniter(&o, ospeed, &counter,
696 1.1 rumble &mode, NULL, c92)) != -1) {
697 1.1 rumble /*
698 1.1 rumble * take first match
699 1.1 rumble *
700 1.1 rumble * Perhaps calculate heuristic
701 1.1 rumble * "score", save
702 1.1 rumble * score,codes,mode,counter
703 1.1 rumble * if score better than
704 1.1 rumble * previous best?
705 1.1 rumble */
706 1.1 rumble s = spltty();
707 1.1 rumble dp->chan[other].icode = oic;
708 1.1 rumble dp->chan[other].ocode = ooc;
709 1.1 rumble goto gotit2;
710 1.1 rumble }
711 1.1 rumble }
712 1.1 rumble }
713 1.1 rumble }
714 1.1 rumble }
715 1.1 rumble return EINVAL;
716 1.1 rumble
717 1.1 rumble gotit:
718 1.1 rumble s = spltty();
719 1.1 rumble gotit2:
720 1.1 rumble dp->chan[chan].new_mr1 = mr1;
721 1.1 rumble dp->chan[chan].new_mr2 = mr2;
722 1.1 rumble dp->chan[chan].ispeed = ispeed;
723 1.1 rumble dp->chan[chan].ospeed = ospeed;
724 1.1 rumble dp->chan[chan].icode = ic;
725 1.1 rumble dp->chan[chan].ocode = oc;
726 1.1 rumble if (mode == ANYMODE) /* no mode selected?? */
727 1.1 rumble mode = DEFMODE(c92);
728 1.1 rumble dp->mode = mode;
729 1.1 rumble dp->counter = counter;
730 1.1 rumble
731 1.1 rumble scn_setchip(sc); /* set chip now, if possible */
732 1.1 rumble splx(s);
733 1.1 rumble return (0);
734 1.1 rumble }
735 1.1 rumble
736 1.1 rumble int
737 1.1 rumble scn_match(device_t parent, struct cfdata *cf, void *aux)
738 1.1 rumble {
739 1.1 rumble struct mainbus_attach_args *ma = aux;
740 1.1 rumble
741 1.1 rumble if ((mach_type == MACH_SGI_IP6 || mach_type == MACH_SGI_IP10) &&
742 1.1 rumble ma->ma_addr == 0x1fb80004)
743 1.1 rumble return (1);
744 1.1 rumble
745 1.1 rumble return (0);
746 1.1 rumble }
747 1.1 rumble
748 1.1 rumble /*
749 1.1 rumble * No need to make scn_rx{en,dis}able too efficient,
750 1.1 rumble * they're only called on setup, open & close!
751 1.1 rumble */
752 1.1 rumble static inline void
753 1.1 rumble scn_rxenable(struct scn_softc *sc)
754 1.1 rumble {
755 1.1 rumble struct duart *dp;
756 1.1 rumble int channel;
757 1.1 rumble
758 1.1 rumble dp = sc->sc_duart;
759 1.1 rumble channel = sc->sc_channel;
760 1.1 rumble
761 1.1 rumble /* Outputs wire-ored and connected to ICU input for fast rx interrupt. */
762 1.1 rumble if (channel == 0)
763 1.1 rumble dp->opcr |= OPCR_OP4_RXRDYA;
764 1.1 rumble else
765 1.1 rumble dp->opcr |= OPCR_OP5_RXRDYB;
766 1.1 rumble dp->base[DU_OPCR] = dp->opcr;
767 1.1 rumble dp->imr |= sc->sc_rx_int;
768 1.1 rumble dp->base[DU_IMR] = dp->imr;
769 1.1 rumble }
770 1.1 rumble
771 1.1 rumble static inline void
772 1.1 rumble scn_rxdisable(struct scn_softc *sc)
773 1.1 rumble {
774 1.1 rumble struct duart *dp;
775 1.1 rumble int channel;
776 1.1 rumble
777 1.1 rumble dp = sc->sc_duart;
778 1.1 rumble channel = sc->sc_channel;
779 1.1 rumble
780 1.1 rumble /* Outputs wire-ored and connected to ICU input for fast rx interrupt. */
781 1.1 rumble if (channel == 0)
782 1.1 rumble dp->opcr &= ~OPCR_OP4_RXRDYA;
783 1.1 rumble else
784 1.1 rumble dp->opcr &= ~OPCR_OP5_RXRDYB;
785 1.1 rumble dp->base[DU_OPCR] = dp->opcr;
786 1.1 rumble dp->imr &= ~sc->sc_rx_int;
787 1.1 rumble dp->base[DU_IMR] = dp->imr;
788 1.1 rumble }
789 1.1 rumble
790 1.1 rumble void
791 1.1 rumble scn_attach(device_t parent, device_t self, void *aux)
792 1.1 rumble {
793 1.1 rumble struct mainbus_attach_args *ma = aux;
794 1.1 rumble struct scn_softc *sc;
795 1.1 rumble struct duart *duart;
796 1.1 rumble volatile u_char *ch_base;
797 1.1 rumble volatile u_char *duart_base;
798 1.1 rumble int channel;
799 1.1 rumble int speed;
800 1.1 rumble int s;
801 1.1 rumble int maj;
802 1.1 rumble u_char unit;
803 1.1 rumble u_char duartno;
804 1.1 rumble u_char delim = ':';
805 1.1 rumble u_char mr1, mr2;
806 1.1 rumble enum scntype scntype = SCNUNK;
807 1.1 rumble const char *duart_type = "Unknown";
808 1.1 rumble char *intrname;
809 1.1 rumble bool console, first;
810 1.1 rumble devmajor_t major;
811 1.1 rumble
812 1.1 rumble (void)major;
813 1.1 rumble
814 1.1 rumble sc = device_private(self);
815 1.1 rumble unit = device_unit(self);
816 1.1 rumble
817 1.1 rumble /* XXX - hard-coded */
818 1.1 rumble if (ma->ma_addr == 0x1fb80004)
819 1.1 rumble duartno = 1;
820 1.1 rumble else
821 1.1 rumble duartno = 0;
822 1.1 rumble channel = 0;
823 1.1 rumble console = 1;
824 1.1 rumble
825 1.1 rumble duart = sc->sc_duart = &scn_duart[duartno];
826 1.1 rumble duart->chan[channel].sc = sc;
827 1.1 rumble first = (duart->base == NULL);
828 1.1 rumble
829 1.1 rumble if (console) {
830 1.1 rumble sc->sc_isconsole = 1;
831 1.1 rumble sc->sc_swflags |= SCN_SW_SOFTCAR; /* ignore carrier */
832 1.1 rumble }
833 1.1 rumble
834 1.1 rumble duart_base = (volatile u_char *)MIPS_PHYS_TO_KSEG1(ma->ma_addr);
835 1.1 rumble ch_base = duart_base; /* XXX */
836 1.1 rumble
837 1.1 rumble if (first) {
838 1.1 rumble /* Probe DUART type */
839 1.1 rumble s = spltty();
840 1.1 rumble if (console) {
841 1.1 rumble ch_base[CH_CR] = CR_DIS_TX;
842 1.1 rumble delay(5 * 10000);
843 1.1 rumble }
844 1.1 rumble ch_base[CH_CR] = CR_CMD_MR1;
845 1.1 rumble RECOVER();
846 1.1 rumble mr1 = ch_base[CH_MR];
847 1.1 rumble mr2 = ch_base[CH_MR];
848 1.1 rumble ch_base[CH_CR] = CR_CMD_MR1;
849 1.1 rumble RECOVER();
850 1.1 rumble ch_base[CH_MR] = 1;
851 1.1 rumble ch_base[CH_MR] = 0;
852 1.1 rumble ch_base[CH_CR] = CR_CMD_MR1;
853 1.1 rumble RECOVER();
854 1.1 rumble if (ch_base[CH_MR] == 1) {
855 1.1 rumble /* MR 2 selected */
856 1.1 rumble ch_base[CH_CR] = CR_CMD_MR0;
857 1.1 rumble RECOVER();
858 1.1 rumble /* if 2681, MR2 still selected */
859 1.1 rumble ch_base[CH_MR] = 1;
860 1.1 rumble ch_base[CH_CR] = CR_CMD_MR1;
861 1.1 rumble RECOVER();
862 1.1 rumble ch_base[CH_MR] = 0; /* MR1 */
863 1.1 rumble ch_base[CH_MR] = 0; /* MR2 */
864 1.1 rumble ch_base[CH_CR] = CR_CMD_MR0;
865 1.1 rumble RECOVER();
866 1.1 rumble /* if 2681, MR2 still selected */
867 1.1 rumble if((ch_base[CH_MR] & 1) == 1) {
868 1.1 rumble duart_type = "sc26c92";
869 1.1 rumble scntype = SC26C92;
870 1.1 rumble } else {
871 1.1 rumble /* 2681 treats as MR1 Select */
872 1.1 rumble ch_base[CH_CR] = CR_CMD_RTS_OFF;
873 1.1 rumble RECOVER();
874 1.1 rumble ch_base[CH_MR] = 1;
875 1.1 rumble ch_base[CH_MR] = 0;
876 1.1 rumble ch_base[CH_CR] = CR_CMD_RTS_OFF;
877 1.1 rumble RECOVER();
878 1.1 rumble if (ch_base[CH_MR] == 1) {
879 1.1 rumble duart_type = "scn2681";
880 1.1 rumble scntype = SCN2681;
881 1.1 rumble } else {
882 1.1 rumble duart_type = "scn2692";
883 1.1 rumble scntype = SCN2692;
884 1.1 rumble }
885 1.1 rumble }
886 1.1 rumble }
887 1.1 rumble
888 1.1 rumble /* If a 2681, the CR_CMD_MR0 is interpreted as a TX_RESET */
889 1.1 rumble if (console) {
890 1.1 rumble ch_base[CH_CR] = CR_ENA_TX;
891 1.1 rumble RECOVER();
892 1.1 rumble }
893 1.1 rumble ch_base[CH_CR] = CR_CMD_MR1;
894 1.1 rumble RECOVER();
895 1.1 rumble ch_base[CH_MR] = mr1;
896 1.1 rumble ch_base[CH_MR] = mr2;
897 1.1 rumble splx(s);
898 1.1 rumble
899 1.1 rumble intrname = malloc(sizeof("scnXX"), M_DEVBUF, M_NOWAIT);
900 1.1 rumble snprintf(intrname, sizeof("scnXX"), "scn%d", unit);
901 1.1 rumble
902 1.1 rumble /*
903 1.1 rumble * On IP6 the console chip is duart1. The keyboard/mouse
904 1.1 rumble * is duart0. Each chip has two channels and the channels
905 1.1 rumble * share an interrupt. Duart0 is interrupt 0, duart1 is
906 1.1 rumble * interrupt 1.
907 1.1 rumble */
908 1.1 rumble if (duartno != 0 && duartno != 1)
909 1.1 rumble panic("scn_attach: bad duartno: %d", duartno);
910 1.1 rumble cpu_intr_establish(duartno, IPL_TTY, scnintr, duart);
911 1.1 rumble
912 1.1 rumble printf("%c %s", delim, duart_type);
913 1.1 rumble delim = ',';
914 1.1 rumble
915 1.1 rumble duart->base = duart_base;
916 1.1 rumble duart->type = scntype;
917 1.1 rumble }
918 1.1 rumble /* Record channel, uart */
919 1.1 rumble sc->sc_channel = channel;
920 1.1 rumble sc->sc_chbase = ch_base;
921 1.1 rumble
922 1.1 rumble /* Initialize modem/interrupt bit masks */
923 1.1 rumble if (channel == 0) {
924 1.1 rumble sc->sc_op_rts = OP_RTSA;
925 1.1 rumble sc->sc_op_dtr = OP_DTRA;
926 1.1 rumble sc->sc_ip_cts = IP_CTSA;
927 1.1 rumble sc->sc_ip_dcd = IP_DCDA;
928 1.1 rumble
929 1.1 rumble sc->sc_tx_int = INT_TXA;
930 1.1 rumble sc->sc_rx_int = INT_RXA;
931 1.1 rumble } else {
932 1.1 rumble sc->sc_op_rts = OP_RTSB;
933 1.1 rumble sc->sc_op_dtr = OP_DTRB;
934 1.1 rumble sc->sc_ip_cts = IP_CTSB;
935 1.1 rumble sc->sc_ip_dcd = IP_DCDB;
936 1.1 rumble
937 1.1 rumble sc->sc_tx_int = INT_TXB;
938 1.1 rumble sc->sc_rx_int = INT_RXB;
939 1.1 rumble }
940 1.1 rumble
941 1.1 rumble /* Initialize counters */
942 1.1 rumble sc->sc_framing_errors = 0;
943 1.1 rumble sc->sc_fifo_overruns = 0;
944 1.1 rumble sc->sc_parity_errors = 0;
945 1.1 rumble sc->sc_breaks = 0;
946 1.1 rumble
947 1.1 rumble if (console) {
948 1.1 rumble DELAY(5 * 10000); /* Let the output go out.... */
949 1.1 rumble }
950 1.1 rumble
951 1.1 rumble /*
952 1.1 rumble * Set up the hardware to a base state, in particular:
953 1.1 rumble * o reset transmitter and receiver
954 1.1 rumble * o set speeds and configurations
955 1.1 rumble * o receiver interrupts only (RxRDY and BREAK)
956 1.1 rumble */
957 1.1 rumble
958 1.1 rumble s = spltty();
959 1.1 rumble /* RTS off... */
960 1.1 rumble SCN_OP_BIC(sc, sc->sc_op_rts); /* "istop" */
961 1.1 rumble
962 1.1 rumble ch_base[CH_CR] = CR_DIS_RX | CR_DIS_TX;
963 1.1 rumble RECOVER();
964 1.1 rumble ch_base[CH_CR] = CR_CMD_RESET_RX;
965 1.1 rumble RECOVER();
966 1.1 rumble ch_base[CH_CR] = CR_CMD_RESET_TX;
967 1.1 rumble RECOVER();
968 1.1 rumble ch_base[CH_CR] = CR_CMD_RESET_ERR;
969 1.1 rumble RECOVER();
970 1.1 rumble ch_base[CH_CR] = CR_CMD_RESET_BRK;
971 1.1 rumble RECOVER();
972 1.1 rumble ch_base[CH_CR] = CR_CMD_MR1;
973 1.1 rumble RECOVER();
974 1.1 rumble
975 1.1 rumble /* No receiver control of RTS. */
976 1.1 rumble ch_base[CH_MR] = 0;
977 1.1 rumble ch_base[CH_MR] = 0;
978 1.1 rumble
979 1.1 rumble /* Initialize the uart structure if this is channel A. */
980 1.1 rumble if (first) {
981 1.1 rumble /* Disable all interrupts. */
982 1.1 rumble duart_base[DU_IMR] = duart->imr = 0;
983 1.1 rumble
984 1.1 rumble /* Output port config */
985 1.1 rumble duart_base[DU_OPCR] = duart->opcr = 0;
986 1.1 rumble
987 1.1 rumble /* Speeds... */
988 1.1 rumble duart->mode = 0;
989 1.1 rumble
990 1.1 rumble /*
991 1.1 rumble * Set initial speed to an illegal code that can be changed to
992 1.1 rumble * any other baud.
993 1.1 rumble */
994 1.1 rumble duart->chan[0].icode = duart->chan[0].ocode = 0x2f;
995 1.1 rumble duart->chan[1].icode = duart->chan[1].ocode = 0x2f;
996 1.1 rumble duart->chan[0].ispeed = duart->chan[0].ospeed = 0;
997 1.1 rumble duart->chan[1].ispeed = duart->chan[1].ospeed = 0;
998 1.1 rumble
999 1.1 rumble duart->acr = 0;
1000 1.1 rumble duart->acr |= ACR_CT_TCLK1; /* timer mode 1x clk */
1001 1.1 rumble }
1002 1.1 rumble
1003 1.1 rumble if (channel == 0) {
1004 1.1 rumble duart->acr |= ACR_DELTA_DCDA; /* Set CD int */
1005 1.1 rumble } else {
1006 1.1 rumble duart->acr |= ACR_DELTA_DCDB; /* Set CD int */
1007 1.1 rumble }
1008 1.1 rumble
1009 1.1 rumble if (scnsir == NULL) {
1010 1.1 rumble /* software intr: calls tty code, hence IPL_TTY */
1011 1.1 rumble scnsir = softint_establish(SOFTINT_SERIAL, scnsoft, NULL);
1012 1.1 rumble }
1013 1.1 rumble
1014 1.1 rumble duart_base[DU_ACR] = (duart->mode & ACR_BRG) | duart->acr;
1015 1.1 rumble
1016 1.1 rumble if (console)
1017 1.1 rumble speed = scnconsrate;
1018 1.1 rumble else
1019 1.1 rumble speed = scndefaultrate;
1020 1.1 rumble
1021 1.1 rumble scn_config(unit, channel, speed, speed, MR1_PNONE | MR1_CS8, MR2_STOP1);
1022 1.1 rumble if (console) {
1023 1.1 rumble maj = cdevsw_lookup_major(&scn_cdevsw);
1024 1.1 rumble KASSERT(maj != NODEVMAJOR);
1025 1.1 rumble shutdownhook_establish(scncnreinit, NULL);
1026 1.1 rumble /* Make sure console can do scncngetc */
1027 1.1 rumble duart_base[DU_OPSET] = channel ? (OP_RTSB | OP_DTRB) :
1028 1.1 rumble (OP_RTSA | OP_DTRA);
1029 1.1 rumble }
1030 1.1 rumble
1031 1.1 rumble /* Turn on the receiver and transmitters */
1032 1.1 rumble ch_base[CH_CR] = CR_ENA_RX | CR_ENA_TX;
1033 1.1 rumble
1034 1.1 rumble /* Set up the interrupts. */
1035 1.1 rumble duart->imr |= INT_IP;
1036 1.1 rumble scn_rxdisable(sc);
1037 1.1 rumble splx(s);
1038 1.1 rumble
1039 1.1 rumble if (sc->sc_swflags) {
1040 1.1 rumble printf("%c flags %d", delim, sc->sc_swflags);
1041 1.1 rumble delim = ',';
1042 1.1 rumble }
1043 1.1 rumble
1044 1.1 rumble #ifdef KGDB
1045 1.1 rumble major = cdevsw_lookup_major(&scn_cdevsw);
1046 1.1 rumble KASSERT(major != NODEVMAJOR);
1047 1.1 rumble if (kgdb_dev == makedev(major, unit)) {
1048 1.1 rumble if (console)
1049 1.1 rumble kgdb_dev = NODEV; /* can't debug over console port */
1050 1.1 rumble else {
1051 1.1 rumble scninit(kgdb_dev, kgdb_rate);
1052 1.1 rumble scn_rxenable(sc);
1053 1.1 rumble scn->sc_iskgdb = 1;
1054 1.1 rumble kgdb_attach(scncngetc, scncnputc, kgdb_dev);
1055 1.1 rumble if (kgdb_debug_init) {
1056 1.1 rumble printf("%c ", delim);
1057 1.1 rumble kgdb_connect(1);
1058 1.1 rumble } else
1059 1.1 rumble printf("%c kgdb enabled", delim);
1060 1.1 rumble delim = ',';
1061 1.1 rumble }
1062 1.1 rumble }
1063 1.1 rumble #endif
1064 1.1 rumble printf("\n");
1065 1.1 rumble }
1066 1.1 rumble
1067 1.1 rumble /* ARGSUSED */
1068 1.1 rumble int
1069 1.1 rumble scnopen(dev_t dev, int flags, int mode, struct lwp *l)
1070 1.1 rumble {
1071 1.1 rumble struct tty *tp;
1072 1.1 rumble int unit = DEV_UNIT(dev);
1073 1.1 rumble struct scn_softc *sc;
1074 1.1 rumble int error = 0;
1075 1.1 rumble int hwset = 0;
1076 1.1 rumble
1077 1.1 rumble if (unit >= scn_cd.cd_ndevs)
1078 1.1 rumble return ENXIO;
1079 1.1 rumble sc = SOFTC(unit);
1080 1.1 rumble if (!sc)
1081 1.1 rumble return ENXIO;
1082 1.1 rumble
1083 1.1 rumble tp = sc->sc_tty;
1084 1.1 rumble if (!tp) {
1085 1.1 rumble tp = ttymalloc();
1086 1.1 rumble sc->sc_tty = sc->sc_duart->chan[sc->sc_channel].tty = tp;
1087 1.1 rumble tty_attach(tp);
1088 1.1 rumble }
1089 1.1 rumble
1090 1.1 rumble tp->t_oproc = scnstart;
1091 1.1 rumble tp->t_param = scnparam;
1092 1.1 rumble tp->t_hwiflow = scnhwiflow;
1093 1.1 rumble tp->t_dev = dev;
1094 1.1 rumble
1095 1.1 rumble if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
1096 1.1 rumble return (EBUSY);
1097 1.1 rumble
1098 1.1 rumble mutex_spin_enter(&tty_lock);
1099 1.1 rumble
1100 1.1 rumble if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
1101 1.1 rumble ttychars(tp);
1102 1.1 rumble tp->t_iflag = TTYDEF_IFLAG;
1103 1.1 rumble tp->t_oflag = TTYDEF_OFLAG;
1104 1.1 rumble tp->t_cflag = SCNDEF_CFLAG;
1105 1.1 rumble
1106 1.1 rumble sc->sc_rx_blocked = 0;
1107 1.1 rumble
1108 1.1 rumble if (sc->sc_swflags & SCN_SW_CLOCAL)
1109 1.1 rumble tp->t_cflag |= CLOCAL;
1110 1.1 rumble if (sc->sc_swflags & SCN_SW_CRTSCTS)
1111 1.1 rumble tp->t_cflag |= CCTS_OFLOW | CRTS_IFLOW;
1112 1.1 rumble tp->t_lflag = TTYDEF_LFLAG;
1113 1.1 rumble if (sc->sc_isconsole)
1114 1.1 rumble tp->t_ispeed = tp->t_ospeed = scnconsrate;
1115 1.1 rumble else
1116 1.1 rumble tp->t_ispeed = tp->t_ospeed = scndefaultrate;
1117 1.1 rumble scnparam(tp, &tp->t_termios);
1118 1.1 rumble ttsetwater(tp);
1119 1.1 rumble
1120 1.1 rumble /* Turn on DTR and RTS. */
1121 1.1 rumble SCN_OP_BIS(sc, sc->sc_op_rts | sc->sc_op_dtr);
1122 1.1 rumble
1123 1.1 rumble /* enable receiver interrupts */
1124 1.1 rumble scn_rxenable(sc);
1125 1.1 rumble hwset = 1;
1126 1.1 rumble
1127 1.1 rumble /* set carrier state; */
1128 1.1 rumble if ((sc->sc_swflags & SCN_SW_SOFTCAR) || /* check ttyflags */
1129 1.1 rumble SCN_DCD(sc) || /* check h/w */
1130 1.1 rumble DEV_DIALOUT(dev))
1131 1.1 rumble tp->t_state |= TS_CARR_ON;
1132 1.1 rumble else
1133 1.1 rumble tp->t_state &= ~TS_CARR_ON;
1134 1.1 rumble }
1135 1.1 rumble
1136 1.1 rumble mutex_spin_exit(&tty_lock);
1137 1.1 rumble
1138 1.1 rumble error = ttyopen(tp, SCN_DIALOUT(sc), flags & O_NONBLOCK);
1139 1.1 rumble if (error) printf("ttyopen failed line %d, error %d\n", __LINE__, error);
1140 1.1 rumble if (error)
1141 1.1 rumble goto bad;
1142 1.1 rumble
1143 1.1 rumble error = (*tp->t_linesw->l_open) (dev, tp);
1144 1.1 rumble if (error) printf("l_open failed line %d, error %d\n", __LINE__, error);
1145 1.1 rumble if (error)
1146 1.1 rumble goto bad;
1147 1.1 rumble
1148 1.1 rumble return (0);
1149 1.1 rumble
1150 1.1 rumble bad:
1151 1.1 rumble if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
1152 1.1 rumble scn_rxdisable(sc);
1153 1.1 rumble SCN_OP_BIC(sc, sc->sc_op_rts | sc->sc_op_dtr);
1154 1.1 rumble }
1155 1.1 rumble
1156 1.1 rumble return (error);
1157 1.1 rumble }
1158 1.1 rumble
1159 1.1 rumble
1160 1.1 rumble /*ARGSUSED*/
1161 1.1 rumble int
1162 1.1 rumble scnclose(dev_t dev, int flags, int mode, struct lwp *l)
1163 1.1 rumble {
1164 1.1 rumble int unit = DEV_UNIT(dev);
1165 1.1 rumble struct scn_softc *sc = SOFTC(unit);
1166 1.1 rumble struct tty *tp = sc->sc_tty;
1167 1.1 rumble devmajor_t major;
1168 1.1 rumble
1169 1.1 rumble (void)major;
1170 1.1 rumble
1171 1.1 rumble if ((tp->t_state & TS_ISOPEN) == 0)
1172 1.1 rumble return 0;
1173 1.1 rumble
1174 1.1 rumble (*tp->t_linesw->l_close) (tp, flags);
1175 1.1 rumble
1176 1.1 rumble #ifdef KGDB
1177 1.1 rumble /* do not disable interrupts if debugging */
1178 1.1 rumble major = cdevsw_lookup_major(&scn_devsw);
1179 1.1 rumble KASSERT(major != cdevsw_lookup_major);
1180 1.1 rumble if (kgdb_dev != makedev(major, unit))
1181 1.1 rumble #endif
1182 1.1 rumble if ((tp->t_state & TS_ISOPEN) == 0) {
1183 1.1 rumble scn_rxdisable(sc);
1184 1.1 rumble }
1185 1.1 rumble if ((tp->t_cflag & HUPCL) && (sc->sc_swflags & SCN_SW_SOFTCAR) == 0) {
1186 1.1 rumble SCN_OP_BIC(sc, sc->sc_op_dtr);
1187 1.1 rumble /* hold low for 1 second */
1188 1.1 rumble tsleep(sc, TTIPRI, ttclos, hz);
1189 1.1 rumble }
1190 1.1 rumble SCN_CLRDIALOUT(sc);
1191 1.1 rumble ttyclose(tp);
1192 1.1 rumble
1193 1.1 rumble #if 0
1194 1.1 rumble if ((tp->t_state & TS_ISOPEN) == 0) {
1195 1.1 rumble ttyfree(tp);
1196 1.1 rumble sc->sc_tty = (struct tty *) NULL;
1197 1.1 rumble }
1198 1.1 rumble #endif
1199 1.1 rumble
1200 1.1 rumble return (0);
1201 1.1 rumble }
1202 1.1 rumble
1203 1.1 rumble int
1204 1.1 rumble scnread(dev_t dev, struct uio *uio, int flags)
1205 1.1 rumble {
1206 1.1 rumble struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
1207 1.1 rumble struct tty *tp = sc->sc_tty;
1208 1.1 rumble
1209 1.1 rumble return ((*tp->t_linesw->l_read) (tp, uio, flags));
1210 1.1 rumble }
1211 1.1 rumble
1212 1.1 rumble int
1213 1.1 rumble scnwrite(dev_t dev, struct uio *uio, int flags)
1214 1.1 rumble {
1215 1.1 rumble struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
1216 1.1 rumble struct tty *tp = sc->sc_tty;
1217 1.1 rumble
1218 1.1 rumble return ((*tp->t_linesw->l_write) (tp, uio, flags));
1219 1.1 rumble }
1220 1.1 rumble
1221 1.1 rumble int
1222 1.1 rumble scnpoll(dev_t dev, int events, struct lwp *l)
1223 1.1 rumble {
1224 1.1 rumble struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
1225 1.1 rumble struct tty *tp = sc->sc_tty;
1226 1.1 rumble
1227 1.1 rumble return ((*tp->t_linesw->l_poll)(tp, events, l));
1228 1.1 rumble }
1229 1.1 rumble
1230 1.1 rumble struct tty *
1231 1.1 rumble scntty(dev_t dev)
1232 1.1 rumble {
1233 1.1 rumble struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
1234 1.1 rumble
1235 1.1 rumble return sc->sc_tty;
1236 1.1 rumble }
1237 1.1 rumble
1238 1.1 rumble /* Worker routines for interrupt processing */
1239 1.1 rumble static inline void
1240 1.1 rumble dcd_int(struct scn_softc *sc, struct tty *tp, u_char new)
1241 1.1 rumble {
1242 1.1 rumble
1243 1.1 rumble if (sc->sc_swflags & SCN_SW_SOFTCAR)
1244 1.1 rumble return;
1245 1.1 rumble
1246 1.1 rumble #if 0
1247 1.1 rumble printf("scn%d: dcd_int ip %x SCN_DCD %x new %x ipcr %x\n",
1248 1.1 rumble sc->unit,
1249 1.1 rumble sc->sc_duart->base[DU_IP],
1250 1.1 rumble SCN_DCD(sc),
1251 1.1 rumble new,
1252 1.1 rumble sc->sc_duart->base[DU_IPCR]
1253 1.1 rumble );
1254 1.1 rumble #endif
1255 1.1 rumble
1256 1.1 rumble /* XXX set some flag to have some lower (soft) int call line discipline? */
1257 1.1 rumble if (!(*tp->t_linesw->l_modem) (tp, new == 0? 1: 0)) {
1258 1.1 rumble SCN_OP_BIC(sc, sc->sc_op_rts | sc->sc_op_dtr);
1259 1.1 rumble }
1260 1.1 rumble }
1261 1.1 rumble
1262 1.1 rumble /*
1263 1.1 rumble * Print out a ring or fifo overrun error message.
1264 1.1 rumble */
1265 1.1 rumble static void
1266 1.1 rumble scnoverrun(int unit, long *ptime, const char *what)
1267 1.1 rumble {
1268 1.1 rumble
1269 1.1 rumble if (*ptime != time_second) {
1270 1.1 rumble *ptime = time_second;
1271 1.1 rumble log(LOG_WARNING, "scn%d: %s overrun\n", unit, what);
1272 1.1 rumble }
1273 1.1 rumble }
1274 1.1 rumble
1275 1.1 rumble /*
1276 1.1 rumble * Try to block or unblock input using hardware flow-control.
1277 1.1 rumble * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
1278 1.1 rumble * if this function returns non-zero, the TS_TBLOCK flag will
1279 1.1 rumble * be set or cleared according to the "stop" arg passed.
1280 1.1 rumble */
1281 1.1 rumble int
1282 1.1 rumble scnhwiflow(struct tty *tp, int stop)
1283 1.1 rumble {
1284 1.1 rumble int unit = DEV_UNIT(tp->t_dev);
1285 1.1 rumble struct scn_softc *sc = SOFTC(unit);
1286 1.1 rumble int s;
1287 1.1 rumble
1288 1.1 rumble s = splrtty();
1289 1.1 rumble if (!stop) {
1290 1.1 rumble if (sc->sc_rbput - sc->sc_rbget - 1) {
1291 1.1 rumble setsoftscn();
1292 1.1 rumble }
1293 1.1 rumble }
1294 1.1 rumble splx(s);
1295 1.1 rumble return 1;
1296 1.1 rumble }
1297 1.1 rumble
1298 1.1 rumble static int
1299 1.1 rumble scnintr(void *arg)
1300 1.1 rumble {
1301 1.1 rumble struct duart *duart = arg;
1302 1.1 rumble struct scn_softc *sc0 = duart->chan[0].sc;
1303 1.1 rumble struct scn_softc *sc1 = duart->chan[1].sc;
1304 1.1 rumble
1305 1.1 rumble struct tty *tp0 = (sc0 != NULL) ? sc0->sc_tty : NULL;
1306 1.1 rumble struct tty *tp1 = (sc1 != NULL) ? sc1->sc_tty : NULL;
1307 1.1 rumble
1308 1.1 rumble char rs_work;
1309 1.1 rumble u_char rs_stat;
1310 1.1 rumble u_char rs_ipcr;
1311 1.1 rumble
1312 1.1 rumble /* Check for RX interrupts first, since we cannot distinguish by irq. */
1313 1.1 rumble scnrxintr(duart);
1314 1.1 rumble
1315 1.1 rumble do {
1316 1.1 rumble /* Loop to pick up ALL pending interrupts for device. */
1317 1.1 rumble rs_work = false;
1318 1.1 rumble rs_stat = duart->base[DU_ISR];
1319 1.1 rumble
1320 1.1 rumble /* channel a */
1321 1.1 rumble if (tp0 != NULL) {
1322 1.1 rumble if ((rs_stat & INT_TXA) && (tp0->t_state & TS_BUSY)) {
1323 1.1 rumble /* output char done. */
1324 1.1 rumble tp0->t_state &= ~(TS_BUSY | TS_FLUSH);
1325 1.1 rumble
1326 1.1 rumble /* disable tx ints */
1327 1.1 rumble duart->imr &= ~sc0->sc_tx_int;
1328 1.1 rumble duart->base[DU_IMR] = duart->imr;
1329 1.1 rumble
1330 1.1 rumble if (sc0->sc_heldchanges) {
1331 1.1 rumble scn_setchip(sc0);
1332 1.1 rumble }
1333 1.1 rumble
1334 1.1 rumble (*tp0->t_linesw->l_start) (tp0);
1335 1.1 rumble rs_work = true;
1336 1.1 rumble }
1337 1.1 rumble }
1338 1.1 rumble /* channel b */
1339 1.1 rumble if (tp1 != NULL) {
1340 1.1 rumble if ((rs_stat & INT_TXB) && (tp1->t_state & TS_BUSY)) {
1341 1.1 rumble /* output char done. */
1342 1.1 rumble tp1->t_state &= ~(TS_BUSY | TS_FLUSH);
1343 1.1 rumble
1344 1.1 rumble /* disable tx ints */
1345 1.1 rumble duart->imr &= ~sc1->sc_tx_int;
1346 1.1 rumble duart->base[DU_IMR] = duart->imr;
1347 1.1 rumble
1348 1.1 rumble if (sc1->sc_heldchanges) {
1349 1.1 rumble scn_setchip(sc1);
1350 1.1 rumble }
1351 1.1 rumble
1352 1.1 rumble (*tp1->t_linesw->l_start) (tp1);
1353 1.1 rumble rs_work = true;
1354 1.1 rumble }
1355 1.1 rumble }
1356 1.1 rumble if (rs_stat & INT_IP) {
1357 1.1 rumble rs_work = true;
1358 1.1 rumble rs_ipcr = duart->base[DU_IPCR];
1359 1.1 rumble
1360 1.1 rumble if (rs_ipcr & IPCR_DELTA_DCDA && tp0 != NULL) {
1361 1.1 rumble dcd_int(sc0, tp0, rs_ipcr & IPCR_DCDA);
1362 1.1 rumble }
1363 1.1 rumble if (rs_ipcr & IPCR_DELTA_DCDB && tp1 != NULL) {
1364 1.1 rumble dcd_int(sc1, tp1, rs_ipcr & IPCR_DCDB);
1365 1.1 rumble }
1366 1.1 rumble }
1367 1.1 rumble } while (rs_work);
1368 1.1 rumble
1369 1.1 rumble return (1); /* ? */
1370 1.1 rumble }
1371 1.1 rumble
1372 1.1 rumble /*
1373 1.1 rumble * Handle rxrdy/ffull interrupt: QUICKLY poll both channels (checking
1374 1.1 rumble * status first) and stash data in a ring buffer. Ring buffer scheme
1375 1.1 rumble * borowed from sparc/zs.c requires NO interlock on data!
1376 1.1 rumble *
1377 1.1 rumble * This interrupt should NOT be included in spltty() mask since it
1378 1.1 rumble * invokes NO tty code! The whole point is to allow tty input as much
1379 1.1 rumble * of the time as possible, while deferring "heavy" character
1380 1.1 rumble * processing until later.
1381 1.1 rumble *
1382 1.1 rumble * see scn.hw.README and scnsoft() for more info.
1383 1.1 rumble *
1384 1.1 rumble * THIS ROUTINE SHOULD BE KEPT AS CLEAN AS POSSIBLE!!
1385 1.1 rumble * IT'S A CANDIDATE FOR RECODING IN ASSEMBLER!!
1386 1.1 rumble */
1387 1.1 rumble static inline int
1388 1.1 rumble scn_rxintr(struct scn_softc *sc)
1389 1.1 rumble {
1390 1.1 rumble char sr;
1391 1.1 rumble int i, n;
1392 1.1 rumble int work;
1393 1.1 rumble
1394 1.1 rumble work = 0;
1395 1.1 rumble i = sc->sc_rbput;
1396 1.1 rumble while (work <= 10) {
1397 1.1 rumble #define SCN_GETCH(SC) \
1398 1.1 rumble sr = (SC)->sc_chbase[CH_SR]; \
1399 1.1 rumble if ((sr & SR_RX_RDY) == 0) \
1400 1.1 rumble break; \
1401 1.1 rumble if (sr & (SR_PARITY | SR_FRAME | SR_BREAK | SR_OVERRUN)) \
1402 1.1 rumble goto exception; \
1403 1.1 rumble work++; \
1404 1.1 rumble (SC)->sc_rbuf[i++ & SCN_RING_MASK] = (SC)->sc_chbase[CH_DAT]
1405 1.1 rumble
1406 1.1 rumble SCN_GETCH(sc); SCN_GETCH(sc); SCN_GETCH(sc);
1407 1.1 rumble /* XXX more here if 26C92? -plb */
1408 1.1 rumble continue;
1409 1.1 rumble exception:
1410 1.1 rumble #if defined(DDB)
1411 1.1 rumble if (sc->sc_isconsole && (sr & SR_BREAK)) {
1412 1.1 rumble Debugger();
1413 1.1 rumble sr = sc->sc_chbase[CH_SR];
1414 1.1 rumble }
1415 1.1 rumble #endif
1416 1.1 rumble #if defined(KGDB)
1417 1.1 rumble if (sc->sc_iskgdb && (sr & SR_RX_RDY)) {
1418 1.1 rumble kgdb_connect(1);
1419 1.1 rumble sr = sc->sc_chbase[CH_SR];
1420 1.1 rumble }
1421 1.1 rumble #endif
1422 1.1 rumble work++;
1423 1.1 rumble sc->sc_rbuf[i++ & SCN_RING_MASK] = (sr << 8) | sc->sc_chbase[CH_DAT];
1424 1.1 rumble sc->sc_chbase[CH_CR] = CR_CMD_RESET_ERR; /* resets break? */
1425 1.1 rumble RECOVER();
1426 1.1 rumble }
1427 1.1 rumble /*
1428 1.1 rumble * If ring is getting too full, try to block input.
1429 1.1 rumble */
1430 1.1 rumble n = i - sc->sc_rbget;
1431 1.1 rumble if (sc->sc_rbhiwat && (n > sc->sc_rbhiwat)) {
1432 1.1 rumble /* If not CRTSCTS sc_rbhiwat is such that this
1433 1.1 rumble * never happens.
1434 1.1 rumble * Clear RTS
1435 1.1 rumble */
1436 1.1 rumble SCN_OP_BIC(sc, sc->sc_op_rts);
1437 1.1 rumble sc->sc_rx_blocked = 1;
1438 1.1 rumble }
1439 1.1 rumble sc->sc_rbput = i;
1440 1.1 rumble
1441 1.1 rumble return work;
1442 1.1 rumble }
1443 1.1 rumble
1444 1.1 rumble static void
1445 1.1 rumble scnrxintr(void *arg)
1446 1.1 rumble {
1447 1.1 rumble struct duart *duart = arg;
1448 1.1 rumble int work = 0;
1449 1.1 rumble
1450 1.1 rumble if (duart->chan[0].sc != NULL)
1451 1.1 rumble work += scn_rxintr(duart->chan[0].sc);
1452 1.1 rumble if (duart->chan[1].sc != NULL)
1453 1.1 rumble work += scn_rxintr(duart->chan[1].sc);
1454 1.1 rumble if (work > 0) {
1455 1.1 rumble setsoftscn(); /* trigger s/w intr */
1456 1.1 rumble #ifdef SCN_TIMING
1457 1.1 rumble microtime(&tstart);
1458 1.1 rumble #endif
1459 1.1 rumble }
1460 1.1 rumble }
1461 1.1 rumble
1462 1.1 rumble /*
1463 1.1 rumble * Here on soft interrupt (at spltty) to empty ring buffers.
1464 1.1 rumble *
1465 1.1 rumble * Dave's original scheme was to use the DUART receiver timeout
1466 1.1 rumble * interrupt. This requires 2692's (which my board doesn't have), and
1467 1.1 rumble * I also liked the idea of using the C/T to generate alternate and/or
1468 1.1 rumble * arbitrary bauds. -plb
1469 1.1 rumble *
1470 1.1 rumble * The ringbuffer code comes from Chris Torek's SPARC 44bsd zs driver
1471 1.1 rumble * (hence the LBL notice on top of this file), DOES NOT require
1472 1.1 rumble * interlocking with interrupt levels!
1473 1.1 rumble *
1474 1.1 rumble * The 44bsd sparc/zs driver reads the ring buffer from a separate
1475 1.1 rumble * zssoftint, while the SunOS 4.x zs driver appears to use
1476 1.1 rumble * timeout()'s. timeouts seem to be too slow to deal with high data
1477 1.1 rumble * rates. I know, I tried them.
1478 1.1 rumble * -plb.
1479 1.1 rumble */
1480 1.1 rumble static void
1481 1.1 rumble scnsoft(void *arg)
1482 1.1 rumble {
1483 1.1 rumble int s, unit;
1484 1.1 rumble #ifdef SCN_TIMING
1485 1.1 rumble struct timeval tend;
1486 1.1 rumble u_long t;
1487 1.1 rumble
1488 1.1 rumble microtime(&tend);
1489 1.1 rumble t = (tend.tv_sec - tstart.tv_sec) * 1000000 + (tend.tv_usec - tstart.tv_usec);
1490 1.1 rumble t = (t + tick / 20) / (tick / 10);
1491 1.1 rumble if (t >= NJITTER - 1) {
1492 1.1 rumble t = NJITTER - 1;
1493 1.1 rumble }
1494 1.1 rumble scn_jitter[t]++;
1495 1.1 rumble #endif
1496 1.1 rumble
1497 1.1 rumble for (unit = 0; unit < scn_cd.cd_ndevs; unit++) {
1498 1.1 rumble struct scn_softc *sc;
1499 1.1 rumble struct tty *tp;
1500 1.1 rumble int n, get;
1501 1.1 rumble
1502 1.1 rumble sc = SOFTC(unit);
1503 1.1 rumble if (sc == NULL) {
1504 1.1 rumble continue;
1505 1.1 rumble }
1506 1.1 rumble tp = sc->sc_tty;
1507 1.1 rumble #ifdef KGDB
1508 1.1 rumble if (tp == NULL) {
1509 1.1 rumble sc->sc_rbget = sc->sc_rbput;
1510 1.1 rumble continue;
1511 1.1 rumble }
1512 1.1 rumble #endif
1513 1.1 rumble if (tp == NULL || tp->t_state & TS_TBLOCK) {
1514 1.1 rumble continue;
1515 1.1 rumble }
1516 1.1 rumble
1517 1.1 rumble
1518 1.1 rumble get = sc->sc_rbget;
1519 1.1 rumble
1520 1.1 rumble /* NOTE: fetch from rbput is atomic */
1521 1.1 rumble while (get != (n = sc->sc_rbput)) {
1522 1.1 rumble /*
1523 1.1 rumble * Compute the number of interrupts in the receive ring.
1524 1.1 rumble * If the count is overlarge, we lost some events, and
1525 1.1 rumble * must advance to the first valid one. It may get
1526 1.1 rumble * overwritten if more data are arriving, but this is
1527 1.1 rumble * too expensive to check and gains nothing (we already
1528 1.1 rumble * lost out; all we can do at this point is trade one
1529 1.1 rumble * kind of loss for another).
1530 1.1 rumble */
1531 1.1 rumble n -= get;
1532 1.1 rumble if (n > SCN_RING_SIZE) {
1533 1.1 rumble scnoverrun(unit, &sc->sc_rotime, "ring");
1534 1.1 rumble get += n - SCN_RING_SIZE;
1535 1.1 rumble n = SCN_RING_SIZE;
1536 1.1 rumble sc->sc_ring_overruns++;
1537 1.1 rumble }
1538 1.1 rumble while (--n >= 0) {
1539 1.1 rumble int c, sr;
1540 1.1 rumble
1541 1.1 rumble if (tp->t_state & TS_TBLOCK) {
1542 1.1 rumble sc->sc_rbget = get;
1543 1.1 rumble goto done;
1544 1.1 rumble }
1545 1.1 rumble /* Race to keep ahead of incoming interrupts. */
1546 1.1 rumble c = sc->sc_rbuf[get++ & SCN_RING_MASK];
1547 1.1 rumble
1548 1.1 rumble sr = c >> 8; /* extract status */
1549 1.1 rumble c &= 0xff; /* leave just character */
1550 1.1 rumble
1551 1.1 rumble if (sr & SR_OVERRUN) {
1552 1.1 rumble scnoverrun(unit, &sc->sc_fotime, "fifo");
1553 1.1 rumble sc->sc_fifo_overruns++;
1554 1.1 rumble }
1555 1.1 rumble if (sr & SR_PARITY) {
1556 1.1 rumble c |= TTY_PE;
1557 1.1 rumble sc->sc_parity_errors++;
1558 1.1 rumble }
1559 1.1 rumble if (sr & SR_FRAME) {
1560 1.1 rumble c |= TTY_FE;
1561 1.1 rumble sc->sc_framing_errors++;
1562 1.1 rumble }
1563 1.1 rumble if (sr & SR_BREAK) {
1564 1.1 rumble #if 0
1565 1.1 rumble /*
1566 1.1 rumble * See DDB_CHECK() comments in
1567 1.1 rumble * scnrxintr()
1568 1.1 rumble */
1569 1.1 rumble if (sc->sc_isconsole)
1570 1.1 rumble Debugger();
1571 1.1 rumble #endif
1572 1.1 rumble c = TTY_FE | 0;
1573 1.1 rumble sc->sc_breaks++;
1574 1.1 rumble }
1575 1.1 rumble
1576 1.1 rumble (*tp->t_linesw->l_rint) (c, tp);
1577 1.1 rumble
1578 1.1 rumble if (sc->sc_rx_blocked && n < SCN_RING_THRESH) {
1579 1.1 rumble s = splrtty();
1580 1.1 rumble sc->sc_rx_blocked = 0;
1581 1.1 rumble SCN_OP_BIS(sc, sc->sc_op_rts);
1582 1.1 rumble splx(s);
1583 1.1 rumble }
1584 1.1 rumble
1585 1.1 rumble }
1586 1.1 rumble sc->sc_rbget = get;
1587 1.1 rumble }
1588 1.1 rumble done: ;
1589 1.1 rumble }
1590 1.1 rumble }
1591 1.1 rumble
1592 1.1 rumble /* Convert TIOCM_xxx bits to output port bits. */
1593 1.1 rumble static unsigned char
1594 1.1 rumble opbits(struct scn_softc *sc, int tioc_bits)
1595 1.1 rumble {
1596 1.1 rumble
1597 1.1 rumble return ((((tioc_bits) & TIOCM_DTR) ? sc->sc_op_dtr : 0) |
1598 1.1 rumble (((tioc_bits) & TIOCM_RTS) ? sc->sc_op_rts : 0));
1599 1.1 rumble }
1600 1.1 rumble
1601 1.1 rumble int
1602 1.1 rumble scnioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
1603 1.1 rumble {
1604 1.1 rumble int unit = DEV_UNIT(dev);
1605 1.1 rumble struct scn_softc *sc = SOFTC(unit);
1606 1.1 rumble struct tty *tp = sc->sc_tty;
1607 1.1 rumble int error;
1608 1.1 rumble
1609 1.1 rumble error = (*tp->t_linesw->l_ioctl) (tp, cmd, data, flags, l);
1610 1.1 rumble if (error != EPASSTHROUGH)
1611 1.1 rumble return (error);
1612 1.1 rumble
1613 1.1 rumble error = ttioctl(tp, cmd, data, flags, l);
1614 1.1 rumble if (error != EPASSTHROUGH)
1615 1.1 rumble return (error);
1616 1.1 rumble
1617 1.1 rumble switch (cmd) {
1618 1.1 rumble case TIOCSBRK:
1619 1.1 rumble sc->sc_chbase[CH_CR] = CR_CMD_START_BRK;
1620 1.1 rumble break;
1621 1.1 rumble
1622 1.1 rumble case TIOCCBRK:
1623 1.1 rumble sc->sc_chbase[CH_CR] = CR_CMD_STOP_BRK;
1624 1.1 rumble break;
1625 1.1 rumble
1626 1.1 rumble case TIOCSDTR:
1627 1.1 rumble SCN_OP_BIS(sc, sc->sc_op_dtr | sc->sc_op_rts);
1628 1.1 rumble break;
1629 1.1 rumble
1630 1.1 rumble case TIOCCDTR:
1631 1.1 rumble SCN_OP_BIC(sc, sc->sc_op_dtr | sc->sc_op_rts);
1632 1.1 rumble break;
1633 1.1 rumble
1634 1.1 rumble case TIOCMSET: {
1635 1.1 rumble int s;
1636 1.1 rumble unsigned char sbits, cbits;
1637 1.1 rumble
1638 1.1 rumble /* set bits */
1639 1.1 rumble sbits = opbits(sc, *(int *) data);
1640 1.1 rumble
1641 1.1 rumble /* get bits to clear */
1642 1.1 rumble cbits = ~sbits & (sc->sc_op_dtr | sc->sc_op_rts);
1643 1.1 rumble
1644 1.1 rumble s = spltty();
1645 1.1 rumble if (sbits) {
1646 1.1 rumble SCN_OP_BIS(sc, sbits);
1647 1.1 rumble }
1648 1.1 rumble if (cbits) {
1649 1.1 rumble SCN_OP_BIC(sc, cbits);
1650 1.1 rumble }
1651 1.1 rumble splx(s);
1652 1.1 rumble break;
1653 1.1 rumble }
1654 1.1 rumble
1655 1.1 rumble case TIOCMBIS:
1656 1.1 rumble SCN_OP_BIS(sc, opbits(sc, *(int *) data));
1657 1.1 rumble break;
1658 1.1 rumble
1659 1.1 rumble case TIOCMBIC:
1660 1.1 rumble SCN_OP_BIC(sc, opbits(sc, *(int *) data));
1661 1.1 rumble break;
1662 1.1 rumble
1663 1.1 rumble case TIOCMGET: {
1664 1.1 rumble int bits;
1665 1.1 rumble unsigned char ip, op;
1666 1.1 rumble
1667 1.1 rumble /* s = spltty(); */
1668 1.1 rumble ip = sc->sc_duart->base[DU_IP];
1669 1.1 rumble /*
1670 1.1 rumble * XXX sigh; cannot get op current state!! even if
1671 1.1 rumble * maintained in private, RTS is done in h/w!!
1672 1.1 rumble */
1673 1.1 rumble op = 0;
1674 1.1 rumble /* splx(s); */
1675 1.1 rumble
1676 1.1 rumble bits = 0;
1677 1.1 rumble if (ip & sc->sc_ip_dcd)
1678 1.1 rumble bits |= TIOCM_CD;
1679 1.1 rumble if (ip & sc->sc_ip_cts)
1680 1.1 rumble bits |= TIOCM_CTS;
1681 1.1 rumble
1682 1.1 rumble #if 0
1683 1.1 rumble if (op & sc->sc_op_dtr)
1684 1.1 rumble bits |= TIOCM_DTR;
1685 1.1 rumble if (op & sc->sc_op_rts)
1686 1.1 rumble bits |= TIOCM_RTS;
1687 1.1 rumble #endif
1688 1.1 rumble
1689 1.1 rumble *(int *) data = bits;
1690 1.1 rumble break;
1691 1.1 rumble }
1692 1.1 rumble
1693 1.1 rumble case TIOCGFLAGS:{
1694 1.1 rumble int bits = 0;
1695 1.1 rumble
1696 1.1 rumble if (sc->sc_swflags & SCN_SW_SOFTCAR)
1697 1.1 rumble bits |= TIOCFLAG_SOFTCAR;
1698 1.1 rumble if (sc->sc_swflags & SCN_SW_CLOCAL)
1699 1.1 rumble bits |= TIOCFLAG_CLOCAL;
1700 1.1 rumble if (sc->sc_swflags & SCN_SW_CRTSCTS)
1701 1.1 rumble bits |= TIOCFLAG_CRTSCTS;
1702 1.1 rumble if (sc->sc_swflags & SCN_SW_MDMBUF)
1703 1.1 rumble bits |= TIOCFLAG_MDMBUF;
1704 1.1 rumble
1705 1.1 rumble *(int *) data = bits;
1706 1.1 rumble break;
1707 1.1 rumble }
1708 1.1 rumble case TIOCSFLAGS:{
1709 1.1 rumble int userbits, driverbits = 0;
1710 1.1 rumble
1711 1.1 rumble error = kauth_authorize_device_tty(l->l_cred,
1712 1.1 rumble KAUTH_DEVICE_TTY_PRIVSET, tp);
1713 1.1 rumble if (error != 0)
1714 1.1 rumble return (EPERM);
1715 1.1 rumble
1716 1.1 rumble userbits = *(int *) data;
1717 1.1 rumble if (userbits & TIOCFLAG_SOFTCAR)
1718 1.1 rumble driverbits |= SCN_SW_SOFTCAR;
1719 1.1 rumble if (userbits & TIOCFLAG_CLOCAL)
1720 1.1 rumble driverbits |= SCN_SW_CLOCAL;
1721 1.1 rumble if (userbits & TIOCFLAG_CRTSCTS)
1722 1.1 rumble driverbits |= SCN_SW_CRTSCTS;
1723 1.1 rumble if (userbits & TIOCFLAG_MDMBUF)
1724 1.1 rumble driverbits |= SCN_SW_MDMBUF;
1725 1.1 rumble
1726 1.1 rumble sc->sc_swflags = driverbits;
1727 1.1 rumble
1728 1.1 rumble break;
1729 1.1 rumble }
1730 1.1 rumble
1731 1.1 rumble default:
1732 1.1 rumble return (EPASSTHROUGH);
1733 1.1 rumble }
1734 1.1 rumble return (0);
1735 1.1 rumble }
1736 1.1 rumble
1737 1.1 rumble int
1738 1.1 rumble scnparam(struct tty *tp, struct termios *t)
1739 1.1 rumble {
1740 1.1 rumble int cflag = t->c_cflag;
1741 1.1 rumble int unit = DEV_UNIT(tp->t_dev);
1742 1.1 rumble char mr1, mr2;
1743 1.1 rumble int error;
1744 1.1 rumble struct scn_softc *sc = SOFTC(unit);
1745 1.1 rumble
1746 1.1 rumble /* Is this a hang up? */
1747 1.1 rumble if (t->c_ospeed == B0) {
1748 1.1 rumble SCN_OP_BIC(sc, sc->sc_op_dtr);
1749 1.1 rumble /* leave DTR down. see comment in scnclose() -plb */
1750 1.1 rumble return (0);
1751 1.1 rumble }
1752 1.1 rumble mr1 = mr2 = 0;
1753 1.1 rumble
1754 1.1 rumble /* Parity? */
1755 1.1 rumble if (cflag & PARENB) {
1756 1.1 rumble if ((cflag & PARODD) == 0)
1757 1.1 rumble mr1 |= MR1_PEVEN;
1758 1.1 rumble else
1759 1.1 rumble mr1 |= MR1_PODD;
1760 1.1 rumble } else
1761 1.1 rumble mr1 |= MR1_PNONE;
1762 1.1 rumble
1763 1.1 rumble /* Stop bits. */
1764 1.1 rumble if (cflag & CSTOPB)
1765 1.1 rumble mr2 |= MR2_STOP2;
1766 1.1 rumble else
1767 1.1 rumble mr2 |= MR2_STOP1;
1768 1.1 rumble
1769 1.1 rumble /* Data bits. */
1770 1.1 rumble switch (cflag & CSIZE) {
1771 1.1 rumble case CS5:
1772 1.1 rumble mr1 |= MR1_CS5;
1773 1.1 rumble break;
1774 1.1 rumble case CS6:
1775 1.1 rumble mr1 |= MR1_CS6;
1776 1.1 rumble break;
1777 1.1 rumble case CS7:
1778 1.1 rumble mr1 |= MR1_CS7;
1779 1.1 rumble break;
1780 1.1 rumble case CS8:
1781 1.1 rumble default:
1782 1.1 rumble mr1 |= MR1_CS8;
1783 1.1 rumble break;
1784 1.1 rumble }
1785 1.1 rumble
1786 1.1 rumble if (cflag & CCTS_OFLOW)
1787 1.1 rumble mr2 |= MR2_TXCTS;
1788 1.1 rumble
1789 1.1 rumble if (cflag & CRTS_IFLOW) {
1790 1.1 rumble mr1 |= MR1_RXRTS;
1791 1.1 rumble sc->sc_rbhiwat = SCN_RING_HIWAT;
1792 1.1 rumble } else {
1793 1.1 rumble sc->sc_rbhiwat = 0;
1794 1.1 rumble }
1795 1.1 rumble
1796 1.1 rumble error = scn_config(unit, sc->sc_channel, t->c_ispeed,
1797 1.1 rumble t->c_ospeed, mr1, mr2);
1798 1.1 rumble
1799 1.1 rumble /* If successful, copy to tty */
1800 1.1 rumble if (!error) {
1801 1.1 rumble tp->t_ispeed = t->c_ispeed;
1802 1.1 rumble tp->t_ospeed = t->c_ospeed;
1803 1.1 rumble tp->t_cflag = cflag;
1804 1.1 rumble }
1805 1.1 rumble return (error);
1806 1.1 rumble }
1807 1.1 rumble
1808 1.1 rumble /*
1809 1.1 rumble * Start or restart a transmission.
1810 1.1 rumble */
1811 1.1 rumble void
1812 1.1 rumble scnstart(struct tty *tp)
1813 1.1 rumble {
1814 1.1 rumble int s, c;
1815 1.1 rumble int unit = DEV_UNIT(tp->t_dev);
1816 1.1 rumble struct scn_softc *sc = SOFTC(unit);
1817 1.1 rumble
1818 1.1 rumble s = spltty();
1819 1.1 rumble if (tp->t_state & (TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
1820 1.1 rumble goto out;
1821 1.1 rumble if (!ttypull(tp))
1822 1.1 rumble goto out;
1823 1.1 rumble
1824 1.1 rumble tp->t_state |= TS_BUSY;
1825 1.1 rumble
1826 1.1 rumble while (sc->sc_chbase[CH_SR] & SR_TX_RDY) {
1827 1.1 rumble if ((c = getc(&tp->t_outq)) == -1)
1828 1.1 rumble break;
1829 1.1 rumble sc->sc_chbase[CH_DAT] = c;
1830 1.1 rumble }
1831 1.1 rumble sc->sc_duart->imr |= (sc->sc_tx_int | sc->sc_rx_int);
1832 1.1 rumble sc->sc_duart->base[DU_IMR] = sc->sc_duart->imr;
1833 1.1 rumble
1834 1.1 rumble out:
1835 1.1 rumble splx(s);
1836 1.1 rumble }
1837 1.1 rumble
1838 1.1 rumble /*
1839 1.1 rumble * Stop output on a line.
1840 1.1 rumble */
1841 1.1 rumble /*ARGSUSED*/
1842 1.1 rumble void
1843 1.1 rumble scnstop(struct tty *tp, int flags)
1844 1.1 rumble {
1845 1.1 rumble int s;
1846 1.1 rumble
1847 1.1 rumble s = spltty();
1848 1.1 rumble if (tp->t_state & TS_BUSY) {
1849 1.1 rumble if ((tp->t_state & TS_TTSTOP) == 0)
1850 1.1 rumble tp->t_state |= TS_FLUSH;
1851 1.1 rumble }
1852 1.1 rumble splx(s);
1853 1.1 rumble }
1854 1.1 rumble
1855 1.1 rumble /*
1856 1.1 rumble * Following are all routines needed for SCN to act as console.
1857 1.1 rumble */
1858 1.1 rumble
1859 1.1 rumble void
1860 1.1 rumble scncnprobe(struct consdev *cn)
1861 1.1 rumble {
1862 1.1 rumble }
1863 1.1 rumble
1864 1.1 rumble void
1865 1.1 rumble scncnreinit(void *v)
1866 1.1 rumble {
1867 1.1 rumble volatile u_char *du_base =
1868 1.1 rumble (volatile u_char *)MIPS_PHYS_TO_KSEG1(0x1fb80004);
1869 1.1 rumble
1870 1.1 rumble du_base[DU_OPSET] =
1871 1.1 rumble SCN_CONSCHAN ? (OP_RTSB | OP_DTRB) : (OP_RTSA | OP_DTRA);
1872 1.1 rumble }
1873 1.1 rumble
1874 1.1 rumble void
1875 1.1 rumble scncninit(struct consdev *cn)
1876 1.1 rumble {
1877 1.1 rumble devmajor_t major;
1878 1.1 rumble
1879 1.1 rumble /* initialize required fields */
1880 1.1 rumble major = cdevsw_lookup_major(&scn_cdevsw);
1881 1.1 rumble KASSERT(major != NODEV);
1882 1.1 rumble cn->cn_dev = makedev(major, SCN_CONSOLE);
1883 1.1 rumble cn->cn_pri = CN_REMOTE;
1884 1.1 rumble
1885 1.1 rumble scninit(cn->cn_dev, scnconsrate);
1886 1.1 rumble }
1887 1.1 rumble
1888 1.1 rumble /* Used by scncninit and kgdb startup. */
1889 1.1 rumble int
1890 1.1 rumble scninit(dev_t dev, int rate)
1891 1.1 rumble {
1892 1.1 rumble /* XXX - maintain PROM's settings */
1893 1.1 rumble #if 0
1894 1.1 rumble volatile u_char *du_base =
1895 1.1 rumble (volatile u_char *)MIPS_PHYS_TO_KSEG1(0x1fb80004);
1896 1.1 rumble int unit = DEV_UNIT(dev);
1897 1.1 rumble
1898 1.1 rumble du_base[DU_OPSET] =
1899 1.1 rumble SCN_CONSCHAN ? (OP_RTSB | OP_DTRB) : (OP_RTSA | OP_DTRA);
1900 1.1 rumble scn_config(unit, SCN_CONSCHAN, rate, rate,
1901 1.1 rumble MR1_PNONE | MR1_CS8, MR2_STOP1);
1902 1.1 rumble #endif
1903 1.1 rumble return (0);
1904 1.1 rumble }
1905 1.1 rumble
1906 1.1 rumble /*
1907 1.1 rumble * Console kernel input character routine.
1908 1.1 rumble */
1909 1.1 rumble int
1910 1.1 rumble scncngetc(dev_t dev)
1911 1.1 rumble {
1912 1.1 rumble volatile u_char *ch_base =
1913 1.1 rumble (volatile u_char *)MIPS_PHYS_TO_KSEG1(0x1fb80004);
1914 1.1 rumble char c;
1915 1.1 rumble int s;
1916 1.1 rumble
1917 1.1 rumble s = spltty();
1918 1.1 rumble
1919 1.1 rumble while ((ch_base[CH_SR] & SR_RX_RDY) == 0)
1920 1.1 rumble ;
1921 1.1 rumble c = ch_base[CH_DAT];
1922 1.1 rumble
1923 1.1 rumble splx(s);
1924 1.1 rumble return c;
1925 1.1 rumble }
1926 1.1 rumble
1927 1.1 rumble void
1928 1.1 rumble scncnpollc(dev_t dev, int on)
1929 1.1 rumble {
1930 1.1 rumble }
1931 1.1 rumble
1932 1.1 rumble /*
1933 1.1 rumble * Console kernel output character routine.
1934 1.1 rumble */
1935 1.1 rumble void
1936 1.1 rumble scncnputc(dev_t dev, int c)
1937 1.1 rumble {
1938 1.1 rumble volatile u_char *ch_base =
1939 1.1 rumble (volatile u_char *)MIPS_PHYS_TO_KSEG1(0x1fb80004);
1940 1.1 rumble volatile u_char *du_base =
1941 1.1 rumble (volatile u_char *)MIPS_PHYS_TO_KSEG1(0x1fb80004);
1942 1.1 rumble int s;
1943 1.1 rumble
1944 1.1 rumble s = spltty();
1945 1.1 rumble
1946 1.1 rumble if (c == '\n')
1947 1.1 rumble scncnputc(dev, '\r');
1948 1.1 rumble
1949 1.1 rumble while ((ch_base[CH_SR] & SR_TX_RDY) == 0)
1950 1.1 rumble ;
1951 1.1 rumble ch_base[CH_DAT] = c;
1952 1.1 rumble while ((ch_base[CH_SR] & SR_TX_RDY) == 0)
1953 1.1 rumble ;
1954 1.1 rumble du_base[DU_ISR];
1955 1.1 rumble
1956 1.1 rumble splx(s);
1957 1.1 rumble }
1958