1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: serial_console.c,v $
29 * Revision 2.11 93/11/17 16:14:26 dbg
30 * Added ANSI function prototypes.
31 * [93/10/13 dbg]
32 *
33 * Revision 2.10 93/05/30 21:07:33 rvb
34 * Some modem code was moved up in chario.c.
35 * Added cons_mctl.
36 * [93/05/29 09:48:06 af]
37 *
38 * Revision 2.9 93/05/20 19:32:49 rvb
39 * We were dropping HUPCLS. And since 0==DM_HUP we were not
40 * taking modem bits right.
41 * [93/05/16 23:19:29 af]
42 *
43 * Add rcoff function to be called from debugger.
44 *
45 * Revision 2.8 93/05/15 19:38:53 mrt
46 * machparam.h -> machspl.h
47 *
48 * Revision 2.7 93/05/10 20:08:47 rvb
49 * No sys/types.h.
50 * [93/05/06 09:54:21 af]
51 *
52 * Revision 2.6 93/03/26 17:58:23 mrt
53 * cleaned up minor/makedev/dev_t.
54 * [93/03/17 af]
55 *
56 * Revision 2.5 93/02/05 08:07:02 danner
57 * Flamingo. Mods to be ~~debuggable.
58 * [93/02/04 01:49:37 af]
59 *
60 * Proper typing.
61 * [92/11/30 af]
62 *
63 * Revision 2.4 92/05/05 10:05:03 danner
64 * Check for existance of a line at open time. When
65 * using the same chip we might or not have the same
66 * number of lines.
67 * [92/05/04 11:23:52 af]
68 *
69 * Changed cons_simple_tint() interface to take an extra all_sent
70 * argument, which controls the unsetting of the BUSY flag.
71 * This way we do not call the start routine too often.
72 * Also, optimized frequent case where a set-status is done but
73 * does not really change anything at all: it is *not* ok to
74 * go off reset a chip if you do not have to, esp if modems.
75 * [92/04/14 11:51:17 af]
76 *
77 * Revision 2.3 92/02/19 16:46:20 elf
78 * Bury rconsole-finding code down in machdep land.
79 * [92/02/10 17:09:35 af]
80 *
81 * Revision 2.2 91/08/24 11:53:18 af
82 * Created, splitting out most code from dz_tty.c file.
83 * [91/07/07 af]
84 *
85 */
86 /*
87 * File: serial_console.c
88 * Author: Alessandro Forin, Carnegie Mellon University
89 * Date: 7/91
90 *
91 * Console driver for serial-line based consoles.
92 */
93
94 #include <constty.h>
95 #if NCONSTTY > 0
96 #include <bm.h>
97 #include <platforms.h>
98
99 #include <mach_kdb.h>
100
101 #include <machine/machspl.h> /* spl definitions */
102 #include <device/io_req.h>
103 #include <device/tty.h>
104 #include <sys/syslog.h>
105
106 #include <chips/busses.h>
107 #include <chips/screen_defs.h>
108 #include <chips/serial_defs.h>
109
110 #ifdef DECSTATION
111 #include <mips/prom_interface.h>
112 #define find_rconsole(p) dec_check_rcline(p)
113 #define CONSOLE_SERIAL_LINE_NO 3
114 #endif /*DECSTATION*/
115
116 #ifdef VAXSTATION
117 #define find_rconsole(p)
118 #define cnputc ser_putc
119 #define cngetc ser_getc
120 #define cnpollc ser_pollc
121 #define cnmaygetc ser_maygetc
122 #define CONSOLE_SERIAL_LINE_NO 3
123 #endif /*VAXSTATION*/
124
125 #ifdef FLAMINGO
126 #define CONSOLE_SERIAL_LINE_NO 3
127 #endif
128
129 #ifndef CONSOLE_SERIAL_LINE_NO
130 #define CONSOLE_SERIAL_LINE_NO 0
131 #endif
132
133 /* Size this as max possible number of lines in any serial chip we might use */
134 static struct tty console_tty_data[NCONSTTY];
135 struct tty *console_tty[NCONSTTY]; /* exported */
136
137 #define DEFAULT_SPEED B9600
138 #define DEFAULT_FLAGS (TF_EVENP|TF_ODDP|TF_ECHO)
139
140
141 /*
142 * A machine MUST have a console. In our case
143 * things are a little complicated by the graphic
144 * display: people expect it to be their "console",
145 * but we'd like to be able to live without it.
146 * This is not to be confused with the "rconsole" thing:
147 * that just duplicates the console I/O to
148 * another place (for debugging/logging purposes).
149 *
150 * There is then another historical kludge: if
151 * there is a graphic display it is assumed that
152 * the minor "1" is the mouse, with some more
153 * magic attached to it. And again, one might like to
154 * use the serial line 1 as a regular one.
155 *
156 */
157 #define user_console 0
158
159 int console = 0;
160
161 boolean_t (*console_probe)(
162 vm_offset_t addr,
163 struct bus_device *d) = 0;
164
165 void (*console_param)(
166 struct tty *tp,
167 int line) = 0;
168
169 void (*console_start)(
170 struct tty *tp) = 0;
171
172 void (*console_putc)(
173 int unit,
174 int line,
175 int ch) = 0;
176
177 int (*console_getc)(
178 int unit,
179 int line,
180 boolean_t wait,
181 boolean_t raw) = 0;
182
183 void (*console_pollc)(
184 int unit,
185 boolean_t poll) = 0;
186
187 int (*console_mctl)(
188 int dev,
189 int bits,
190 int how) = 0;
191
192 void (*console_softCAR)(
193 int unit,
194 int line,
195 boolean_t on) = 0;
196
197
198 /*
199 * Lower-level (internal) interfaces, for printf and gets
200 */
201 int cnunit = 0; /* which unit owns the 'console' */
202 int cnline = 0; /* which line of that unit */
203 int rcline = 3; /* alternate, "remote console" line */
204
205 void rcoff(void)
206 {
207 spl_t s = splhigh();
208 cnpollc(FALSE);
209 rcline = 0;
210 cnpollc(TRUE);
211 splx(s);
212 }
213
214 void rcputc(int c)
215 {
216 if (rcline)
217 (*console_putc)( cnunit, rcline, c);
218 }
219
220 void cnputc(int c)
221 {
222 #if NBM > 0
223 if (SCREEN_ISA_CONSOLE()) {
224 /* this does its own rcputc */
225 screen_blitc(SCREEN_CONS_UNIT(), c);
226 } else
227 #endif /* NBM > 0 */
228 {
229 rcputc(c);
230 (*console_putc)( cnunit, cnline, c);
231 /* insist on a console still */
232 }
233 if (c == '\n')
234 cnputc('\r');
235 }
236
237 int cngetc(void)
238 {
239 return (*console_getc)( cnunit, cnline, TRUE, FALSE);
240 }
241
242 void cnpollc(
243 boolean_t on)
244 {
245 (*console_pollc)(cnunit, on);
246 }
247
248
249 /* Debugger support */
250 int cnmaygetc(void)
251 {
252 return (*console_getc)( cnunit, cnline, FALSE, FALSE);
253 }
254
255
256 #if NBM > 0
257 boolean_t
258 screen_captures(
259 register int line)
260 {
261 return (SCREEN_ISA_CONSOLE() &&
262 ((line == SCREEN_LINE_KEYBOARD) ||
263 (line == SCREEN_LINE_POINTER)));
264 }
265 #endif
266
267 /*
268 * Higher level (external) interface, for GP use
269 */
270
271
272 /*
273 * This is basically a special form of autoconf,
274 * to get printf() going before true autoconf.
275 */
276 void cons_find(
277 boolean_t tube)
278 {
279 static struct bus_device d;
280 register int i;
281 struct tty *tp;
282
283 for (i = 0; i < NCONSTTY; i++)
284 console_tty[i] = &console_tty_data[i];
285 /* the hardware device will set tp->t_addr for valid ttys */
286
287 d.unit = 0;
288
289 if ((console_probe == 0) ||
290 ((*console_probe)(0, &d) == 0)) {
291 /* we have no console, but maybe that's ok */
292 #if defined(DECSTATION) || defined(FLAMINGO)
293 /* no, it is not */
294 dprintf("%s", "no console!\n");
295 halt();
296 #endif
297 return;
298 }
299
300 /*
301 * Remote console line
302 */
303 find_rconsole(&rcline);
304
305 /*
306 * Console always on unit 0. Fix if you need to
307 */
308 cnunit = 0;
309
310 #if NBM > 0
311 if (tube && screen_probe(0)) {
312
313 /* associate screen to console iff */
314 if (console == user_console)
315 screen_console = cnunit | SCREEN_CONS_ENBL;
316 cnline = SCREEN_LINE_KEYBOARD;
317
318 /* mouse and keybd */
319 tp = console_tty[SCREEN_LINE_KEYBOARD];
320 tp->t_ispeed = B4800;
321 tp->t_ospeed = B4800;
322 tp->t_flags = TF_LITOUT|TF_EVENP|TF_ECHO|TF_XTABS|TF_CRMOD;
323 tp->t_dev = SCREEN_LINE_KEYBOARD;
324 (*console_param)(tp, SCREEN_LINE_KEYBOARD);
325
326 tp = console_tty[SCREEN_LINE_POINTER];
327 tp->t_ispeed = B4800;
328 tp->t_ospeed = B4800;
329 tp->t_flags = TF_LITOUT|TF_ODDP;
330 tp->t_dev = SCREEN_LINE_POINTER;
331 (*console_param)(tp, SCREEN_LINE_POINTER);
332 /* console_scan will turn on carrier */
333
334 } else {
335 #endif /* NBM > 0 */
336 /* use non-graphic console as console */
337 cnline = CONSOLE_SERIAL_LINE_NO;
338
339 tp = console_tty[cnline];
340 tp->t_ispeed = B9600;
341 tp->t_ospeed = B9600;
342 tp->t_flags = TF_LITOUT|TF_EVENP|TF_ECHO|TF_XTABS|TF_CRMOD;
343 (*console_softCAR)(cnunit, cnline, TRUE);
344 console = cnline;
345 tp->t_dev = console;
346 (*console_param)(tp, SCREEN_LINE_OTHER);
347 #if NBM > 0
348 }
349
350 /*
351 * Enable rconsole interrupts for KDB
352 */
353 if (tube && rcline != cnline) {
354 tp = console_tty[rcline];
355 tp->t_ispeed = B9600;
356 tp->t_ospeed = B9600;
357 tp->t_flags = TF_LITOUT|TF_EVENP|TF_ECHO|TF_XTABS|TF_CRMOD;
358 tp->t_dev = rcline;
359 (*console_softCAR)(cnunit, rcline, TRUE);
360 (*console_param)(tp, SCREEN_LINE_OTHER);
361 } else
362 rcline = 0;
363 #endif /* NBM > 0 */
364 }
365
366 /*
367 * Open routine
368 */
369 void cons_start(
370 register struct tty *tp); /* forward */
371 void cons_stop(
372 register struct tty *tp,
373 int flag);
374 int cons_mctl(
375 struct tty *tp,
376 int bits,
377 int how);
378
379 io_return_t
380 cons_open(
381 int dev,
382 int flag,
383 io_req_t ior)
384 {
385 register struct tty *tp;
386 register int ttyno;
387
388 if (dev == user_console)
389 dev = console;
390
391 ttyno = dev;
392 if (ttyno >= NCONSTTY)
393 return D_NO_SUCH_DEVICE;
394 tp = console_tty[ttyno];
395
396 /* But was it there at probe time */
397 if (tp->t_addr == 0)
398 return D_NO_SUCH_DEVICE;
399
400 tp->t_start = cons_start;
401 tp->t_stop = cons_stop;
402 tp->t_mctl = cons_mctl;
403
404 #if NBM > 0
405 if (screen_captures(ttyno))
406 screen_open(SCREEN_CONS_UNIT(), ttyno==SCREEN_LINE_KEYBOARD);
407 #endif /* NBM > 0 */
408
409 if ((tp->t_state & TS_ISOPEN) == 0) {
410 if (tp->t_ispeed == 0) {
411 tp->t_ispeed = DEFAULT_SPEED;
412 tp->t_ospeed = DEFAULT_SPEED;
413 tp->t_flags = DEFAULT_FLAGS;
414 }
415 tp->t_dev = dev;
416 (*console_param)(tp, ttyno);
417 }
418
419 return char_open(dev, tp, flag, ior);
420 }
421
422
423 /*
424 * Close routine
425 */
426 io_return_t
427 cons_close(
428 int dev)
429 {
430 register struct tty *tp;
431 register int ttyno;
432 spl_t s;
433
434 if (dev == user_console)
435 dev = console;
436
437 ttyno = dev;
438
439 #if NBM > 0
440 if (screen_captures(ttyno))
441 screen_close(SCREEN_CONS_UNIT(), ttyno==SCREEN_LINE_KEYBOARD);
442 #endif /* NBM > 0 */
443
444 tp = console_tty[ttyno];
445
446 s = spltty();
447 simple_lock(&tp->t_lock);
448
449 ttyclose(tp);
450
451 simple_unlock(&tp->t_lock);
452 splx(s);
453
454 return D_SUCCESS;
455 }
456
457 io_return_t
458 cons_read(
459 int dev,
460 register io_req_t ior)
461 {
462 register struct tty *tp;
463 register ttyno;
464
465 if (dev == user_console)
466 dev = console;
467
468 ttyno = dev;
469 #if NBM > 0
470 if (SCREEN_ISA_CONSOLE() && (ttyno == SCREEN_LINE_POINTER))
471 return screen_read(SCREEN_CONS_UNIT(), ior);
472 #endif NBM > 0
473
474 tp = console_tty[ttyno];
475 return char_read(tp, ior);
476 }
477
478
479 io_return_t
480 cons_write(
481 int dev,
482 register io_req_t ior)
483 {
484 register struct tty *tp;
485 register ttyno;
486
487 if (dev == user_console)
488 dev = console;
489
490 ttyno = dev;
491 #if NBM > 0
492 if (screen_captures(ttyno))
493 return screen_write(SCREEN_CONS_UNIT(), ior);
494 #endif NBM > 0
495
496 tp = console_tty[ttyno];
497 return char_write(tp, ior);
498 }
499
500 /*
501 * Start output on a line
502 */
503 void cons_start(
504 register struct tty *tp)
505 {
506 spl_t s;
507
508 s = spltty();
509 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
510 goto out;
511
512 if (tp->t_outq.c_cc == 0)
513 goto out;
514
515 tp->t_state |= TS_BUSY;
516
517 (*console_start)(tp);
518
519 out:
520 splx(s);
521 }
522
523 /*
524 * Stop output on a line.
525 */
526 void cons_stop(
527 register struct tty *tp,
528 int flag)
529 {
530 register spl_t s;
531
532 s = spltty();
533 if (tp->t_state & TS_BUSY) {
534 if ((tp->t_state&TS_TTSTOP)==0)
535 tp->t_state |= TS_FLUSH;
536 }
537 splx(s);
538 }
539
540
541 /*
542 * Modem control
543 */
544 int cons_mctl(
545 struct tty *tp,
546 int bits,
547 int how)
548 {
549 return (*console_mctl)(tp->t_dev, bits, how);
550 }
551
552 /*
553 * Abnormal close
554 */
555 boolean_t
556 cons_portdeath(
557 int dev,
558 mach_port_t port)
559 {
560 if (dev == user_console)
561 dev = console;
562 return tty_portdeath(console_tty[dev], port);
563 }
564
565 /*
566 * Get/Set status rotuines
567 */
568 io_return_t
569 cons_get_status(
570 int dev,
571 dev_flavor_t flavor,
572 int * data, /* pointer to OUT array */
573 natural_t *status_count) /* out */
574 {
575 register struct tty *tp;
576 register int ttyno;
577
578 if (dev == user_console)
579 dev = console;
580
581 ttyno = dev;
582
583 #if NBM > 0
584 if (screen_captures(ttyno) &&
585 (screen_get_status(SCREEN_CONS_UNIT(),
586 flavor, data, status_count) == D_SUCCESS))
587 return D_SUCCESS;
588 #endif /* NBM > 0 */
589
590 tp = console_tty[ttyno];
591
592 switch (flavor) {
593 case TTY_MODEM:
594 /* Take all bits */
595 *data = (*console_mctl)(dev, -1, DMGET);
596 *status_count = 1;
597 break;
598 default:
599 return tty_get_status(tp, flavor, data, status_count);
600 }
601 return D_SUCCESS;
602 }
603
604 io_return_t
605 cons_set_status(
606 int dev,
607 dev_flavor_t flavor,
608 int * data,
609 natural_t status_count)
610 {
611 register struct tty *tp;
612 register int ttyno;
613
614 if (dev == user_console)
615 dev = console;
616
617 ttyno = dev;
618
619 #if NBM > 0
620 if (screen_captures(ttyno) &&
621 (screen_set_status(SCREEN_CONS_UNIT(),
622 flavor, data, status_count) == D_SUCCESS))
623 return D_SUCCESS;
624 #endif /* NBM > 0 */
625
626 tp = console_tty[ttyno];
627
628 switch (flavor) {
629 case TTY_MODEM:
630 if (status_count < TTY_MODEM_COUNT)
631 return (D_INVALID_OPERATION);
632 (void) (*console_mctl)(dev, *data, DMSET);
633 break;
634
635 case TTY_SET_BREAK:
636 (void) (*console_mctl)(dev, TM_BRK, DMBIS);
637 break;
638
639 case TTY_CLEAR_BREAK:
640 (void) (*console_mctl)(dev, TM_BRK, DMBIC);
641 break;
642
643 case TTY_STATUS:
644 {
645 register int error = D_SUCCESS;
646 struct tty_status *tsp;
647
648 /*
649 * Defend from noise. The cshell...
650 */
651 tsp = (struct tty_status *)data;
652 if ((tsp->tt_ispeed != tp->t_ispeed) ||
653 (tsp->tt_ospeed != tp->t_ospeed) ||
654 (tsp->tt_breakc != tp->t_breakc) ||
655 ((tsp->tt_flags & ~TF_HUPCLS) != tp->t_flags)) {
656
657 error = tty_set_status(tp, flavor, data, status_count);
658 if (error == 0) {
659 spl_t s = spltty();
660 tp->t_state &= ~(TS_BUSY|TS_FLUSH);
661 (*console_param)(tp, ttyno);
662 splx(s);
663 }
664 } else
665 if (tsp->tt_flags & TF_HUPCLS)
666 tp->t_state |= TS_HUPCLS;
667 return error;
668 }
669 default:
670 return tty_set_status(tp, flavor, data, status_count);
671 }
672 return D_SUCCESS;
673 }
674
675
676 /*
677 * A simple scheme to dispatch interrupts.
678 *
679 * This deals with the fairly common case where we get an
680 * interrupt on each rx/tx character. A more elaborate
681 * scheme [someday here too..] would handle instead many
682 * characters per interrupt, perhaps using a DMA controller
683 * or a large SILO. Note that it is also possible to simulate
684 * a DMA chip with 'pseudo-dma' code that runs directly down
685 * in the interrupt routine.
686 */
687
688 /*
689 * We just received a character, ship it up for further processing.
690 * Arguments are the tty number for which it is meant, a flag that
691 * indicates a keyboard or mouse is potentially attached to that
692 * tty (-1 if not), the character proper stripped down to 8 bits,
693 * and an indication of any error conditions associated with the
694 * receipt of the character.
695 * We deal here with rconsole input handling and dispatching to
696 * mouse or keyboard translation routines. cons_input() does
697 * the rest.
698 */
699 #if MACH_KDB
700 int l3break = 0x10; /* dear old ^P, we miss you so bad. */
701 #endif /* MACH_KDB */
702
703 void cons_input(
704 int ttyno,
705 int c,
706 int err); /* forward */
707
708 void cons_simple_rint(
709 int ttyno,
710 int line,
711 int c,
712 int err)
713 {
714 /*
715 * Rconsole. Drop in the debugger on break or ^P.
716 * Otherwise pretend input came from keyboard.
717 */
718 if (rcline && ttyno == rcline) {
719 #if MACH_KDB
720 if ((err & CONS_ERR_BREAK) ||
721 ((c & 0x7f) == l3break))
722 {
723 gimmeabreak();
724 return;
725 }
726 #endif /* MACH_KDB */
727 ttyno = console;
728 goto process_it;
729 }
730
731 #if NBM > 0
732 if (screen_captures(line)) {
733 if (line == SCREEN_LINE_POINTER) {
734 mouse_input(SCREEN_CONS_UNIT(), c);
735 return;
736 }
737 if (line == SCREEN_LINE_KEYBOARD) {
738 c = lk201_rint(SCREEN_CONS_UNIT(), c, FALSE, FALSE);
739 if (c == -1)
740 return; /* shift or bad char */
741 }
742 }
743 #endif NBM > 0
744 process_it:
745 cons_input(ttyno, c, err);
746 }
747
748 /*
749 * Send along a character on a tty. If we were waiting for
750 * this char to complete the open procedure do so; check
751 * for errors; if all is well proceed to ttyinput().
752 */
753 void cons_input(
754 int ttyno,
755 int c,
756 int err)
757 {
758 register struct tty *tp;
759
760 tp = console_tty[ttyno];
761
762 if ((tp->t_state & TS_ISOPEN) == 0) {
763 tt_open_wakeup(tp);
764 return;
765 }
766 if (err) {
767 if (err & CONS_ERR_OVERRUN)
768 log(LOG_WARNING, "sl%d: silo overflow\n", ttyno);
769
770 if (err & CONS_ERR_PARITY)
771 if (((tp->t_flags & (TF_EVENP|TF_ODDP)) == TF_EVENP)
772 || ((tp->t_flags & (TF_EVENP|TF_ODDP)) == TF_ODDP))
773 return;
774 if (err & CONS_ERR_BREAK) /* XXX autobaud XXX */
775 c = tp->t_breakc;
776 }
777 ttyinput(c, tp);
778 }
779
780 /*
781 * Transmission of a character is complete.
782 * Return the next character or -1 if none.
783 */
784 int cons_simple_tint(
785 int ttyno,
786 boolean_t all_sent)
787 {
788 register struct tty *tp;
789
790 tp = console_tty[ttyno];
791 if ((tp->t_addr == 0) || /* not probed --> stray */
792 (tp->t_state & TS_TTSTOP))
793 return -1;
794
795 if (all_sent) {
796 tp->t_state &= ~TS_BUSY;
797 if (tp->t_state & TS_FLUSH)
798 tp->t_state &= ~TS_FLUSH;
799
800 cons_start(tp);
801 }
802
803 if (tp->t_outq.c_cc == 0 || (tp->t_state&TS_BUSY)==0)
804 return -1;
805
806 return getc(&tp->t_outq);
807 }
808
809 #endif /* NCONSTTY > 0*/
Cache object: 98bd3ec9cd6da6eafa01658a8156e196
|