aboutsummaryrefslogtreecommitdiff
path: root/device/cons.c
diff options
context:
space:
mode:
Diffstat (limited to 'device/cons.c')
-rw-r--r--device/cons.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/device/cons.c b/device/cons.c
new file mode 100644
index 0000000..3f7cb9d
--- /dev/null
+++ b/device/cons.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 1988-1994, The University of Utah and
+ * the Computer Systems Laboratory (CSL). All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Utah $Hdr: cons.c 1.14 94/12/14$
+ */
+
+#include <string.h>
+#include <kern/debug.h>
+#include <sys/types.h>
+#include <device/conf.h>
+#include <mach/boolean.h>
+#include <device/cons.h>
+
+#ifdef MACH_KMSG
+#include <device/io_req.h>
+#include <device/kmsg.h>
+#endif /* MACH_KMSG */
+
+static boolean_t cn_inited = FALSE;
+static struct consdev *cn_tab = 0; /* physical console device info */
+
+/*
+ * ROM getc/putc primitives.
+ * On some architectures, the boot ROM provides basic character input/output
+ * routines that can be used before devices are configured or virtual memory
+ * is enabled. This can be useful to debug (or catch panics from) code early
+ * in the bootstrap procedure.
+ */
+int (*romgetc)(char c) = 0;
+void (*romputc)(char c) = 0;
+
+#if CONSBUFSIZE > 0
+/*
+ * Temporary buffer to store console output before a console is selected.
+ * This is statically allocated so it can be called before malloc/kmem_alloc
+ * have been initialized. It is initialized so it won't be clobbered as
+ * part of the zeroing of BSS (on PA/Mach).
+ */
+static char consbuf[CONSBUFSIZE] = { 0 };
+static char *consbp = consbuf;
+static boolean_t consbufused = FALSE;
+#endif /* CONSBUFSIZE > 0 */
+
+void
+cninit(void)
+{
+ struct consdev *cp;
+ dev_ops_t cn_ops;
+ int x;
+
+ if (cn_inited)
+ return;
+
+ /*
+ * Collect information about all possible consoles
+ * and find the one with highest priority
+ */
+ for (cp = constab; cp->cn_probe; cp++) {
+ (*cp->cn_probe)(cp);
+ if (cp->cn_pri > CN_DEAD &&
+ (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri))
+ cn_tab = cp;
+ }
+
+ /*
+ * Found a console, initialize it.
+ */
+ if ((cp = cn_tab)) {
+ /*
+ * Initialize as console
+ */
+ (*cp->cn_init)(cp);
+ /*
+ * Look up its dev_ops pointer in the device table and
+ * place it in the device indirection table.
+ */
+ if (dev_name_lookup(cp->cn_name, &cn_ops, &x) == FALSE)
+ panic("cninit: dev_name_lookup failed");
+ dev_set_indirection("console", cn_ops, minor(cp->cn_dev));
+#if CONSBUFSIZE > 0
+ /*
+ * Now that the console is initialized, dump any chars in
+ * the temporary console buffer.
+ */
+ if (consbufused) {
+ char *cbp = consbp;
+ do {
+ if (*cbp)
+ cnputc(*cbp);
+ if (++cbp == &consbuf[CONSBUFSIZE])
+ cbp = consbuf;
+ } while (cbp != consbp);
+ consbufused = FALSE;
+ }
+#endif /* CONSBUFSIZE > 0 */
+ cn_inited = TRUE;
+ return;
+ }
+ /*
+ * No console device found, not a problem for BSD, fatal for Mach
+ */
+ panic("can't find a console device");
+}
+
+
+int
+cngetc(void)
+{
+ if (cn_tab)
+ return ((*cn_tab->cn_getc)(cn_tab->cn_dev, 1));
+ if (romgetc)
+ return ((*romgetc)(1));
+ return (0);
+}
+
+int
+cnmaygetc(void)
+{
+ if (cn_tab)
+ return((*cn_tab->cn_getc)(cn_tab->cn_dev, 0));
+ if (romgetc)
+ return ((*romgetc)(0));
+ return (0);
+}
+
+void
+cnputc(char c)
+{
+ if (c == 0)
+ return;
+
+#ifdef MACH_KMSG
+ /* XXX: Assume that All output routines always use cnputc. */
+ kmsg_putchar (c);
+#endif
+
+#if defined(MACH_HYP) && 0
+ {
+ /* Also output on hypervisor's emergency console, for
+ * debugging */
+ unsigned char d = c;
+ hyp_console_write(&d, 1);
+ }
+#endif /* MACH_HYP */
+
+ if (cn_tab) {
+ (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
+ if (c == '\n')
+ (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
+ } else if (romputc) {
+ (*romputc)(c);
+ if (c == '\n')
+ (*romputc)('\r');
+ }
+#if CONSBUFSIZE > 0
+ else {
+ if (consbufused == FALSE) {
+ consbp = consbuf;
+ consbufused = TRUE;
+ memset(consbuf, 0, CONSBUFSIZE);
+ }
+ *consbp++ = c;
+ if (consbp >= &consbuf[CONSBUFSIZE])
+ consbp = consbuf;
+ }
+#endif /* CONSBUFSIZE > 0 */
+}