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