summaryrefslogtreecommitdiff
path: root/device/cons.c
blob: 285fb99ec7885155c4ab0d29cd3d1619d09cc347 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
 * 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()
{
	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()
{
	if (cn_tab)
		return ((*cn_tab->cn_getc)(cn_tab->cn_dev, 1));
	if (romgetc)
		return ((*romgetc)(1));
	return (0);
}

int
cnmaygetc()
{
	if (cn_tab)
		return((*cn_tab->cn_getc)(cn_tab->cn_dev, 0));
	if (romgetc)
		return ((*romgetc)(0));
	return (0);
}

void
cnputc(c)
	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 */
}