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