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