xref: /original-bsd/sys/sparc/rcons/rcons_kern.c (revision 3705696b)
1 /*
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This software was developed by the Computer Systems Engineering group
6  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7  * contributed to Berkeley.
8  *
9  * All advertising materials mentioning features or use of this software
10  * must display the following acknowledgement:
11  *	This product includes software developed by the University of
12  *	California, Lawrence Berkeley Laboratory.
13  *
14  * %sccs.include.redist.c%
15  *
16  *	@(#)rcons_kern.c	8.1 (Berkeley) 06/11/93
17  *
18  * from: $Header: rcons_kern.c,v 1.28 93/04/20 11:15:38 torek Exp $
19  */
20 
21 #include <sys/param.h>
22 #include <sys/device.h>
23 #include <sys/fbio.h>
24 #include <sys/kernel.h>
25 #include <sys/systm.h>
26 #include <sys/ioctl.h>
27 #include <sys/tty.h>
28 
29 #include <machine/fbvar.h>
30 #include <machine/autoconf.h>
31 
32 #include <sparc/dev/kbd.h>
33 
34 #include <sparc/rcons/raster.h>
35 
36 extern struct tty *fbconstty;
37 
38 static void rcons_belltmr(void *);
39 
40 extern void rcons_puts(struct fbdevice *, char *, int);
41 extern void rcons_font(struct fbdevice *);
42 
43 extern int (*v_putc)();
44 extern void ttrstrt(void *);
45 
46 static struct fbdevice *myfbdevicep;
47 
48 static void
49 rcons_cnputc(c)
50 	int c;
51 {
52 	char buf[1];
53 
54 	if (c == '\n')
55 		rcons_puts(myfbdevicep, "\r\n", 2);
56 	else {
57 		buf[0] = c;
58 		rcons_puts(myfbdevicep, buf, 1);
59 	}
60 }
61 
62 static void
63 rcons_output(tp)
64 	register struct tty *tp;
65 {
66 	register int s, n, i;
67 	char buf[OBUFSIZ];
68 
69 	s = spltty();
70 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
71 		splx(s);
72 		return;
73 	}
74 	tp->t_state |= TS_BUSY;
75 	splx(s);
76 	n = q_to_b(&tp->t_outq, buf, sizeof(buf));
77 	for (i = 0; i < n; ++i)
78 		buf[i] &= 0177;		/* strip parity (argh) */
79 	rcons_puts(myfbdevicep, buf, n);
80 
81 	s = spltty();
82 	tp->t_state &= ~TS_BUSY;
83 	/* Come back if there's more to do */
84 	if (tp->t_outq.c_cc) {
85 		tp->t_state |= TS_TIMEOUT;
86 		timeout(ttrstrt, tp, 1);
87 	}
88 	if (tp->t_outq.c_cc <= tp->t_lowat) {
89 		if (tp->t_state&TS_ASLEEP) {
90 			tp->t_state &= ~TS_ASLEEP;
91 			wakeup((caddr_t)&tp->t_outq);
92 		}
93 		selwakeup(&tp->t_wsel);
94 	}
95 	splx(s);
96 }
97 
98 /* Ring the console bell */
99 void
100 rcons_bell(fb)
101 	register struct fbdevice *fb;
102 {
103 	register int i, s;
104 
105 	if (fb->fb_bits & FB_VISBELL) {
106 		/* invert the screen twice */
107 		for (i = 0; i < 2; ++i)
108 			raster_op(fb->fb_sp, 0, 0,
109 			    fb->fb_sp->width, fb->fb_sp->height,
110 			    RAS_INVERT, (struct raster *) 0, 0, 0);
111 	}
112 
113 	s = splhigh();
114 	if (fb->fb_belldepth++) {
115 		if (fb->fb_belldepth > 3)
116 			fb->fb_belldepth = 3;
117 		splx(s);
118 	} else {
119 		fb->fb_ringing = 1;
120 		splx(s);
121 		(void) kbd_docmd(KBD_CMD_BELL, 0);
122 		/* XXX Chris doesn't like the following divide */
123 		timeout(rcons_belltmr, fb, hz/10);
124 	}
125 }
126 
127 /* Bell timer service routine */
128 static void
129 rcons_belltmr(p)
130 	void *p;
131 {
132 	register struct fbdevice *fb = p;
133 	register int s = splhigh(), i;
134 
135 	if (fb->fb_ringing) {
136 		fb->fb_ringing = 0;
137 		i = --fb->fb_belldepth;
138 		splx(s);
139 		(void) kbd_docmd(KBD_CMD_NOBELL, 0);
140 		if (i != 0)
141 			/* XXX Chris doesn't like the following divide */
142 			timeout(rcons_belltmr, fb, hz/30);
143 	} else {
144 		fb->fb_ringing = 1;
145 		splx(s);
146 		(void) kbd_docmd(KBD_CMD_BELL, 0);
147 		timeout(rcons_belltmr, fb, hz/10);
148 	}
149 }
150 
151 static int
152 rcons_a2int(cp, deflt)
153 	register char *cp;
154 	register int deflt;
155 {
156 	register int i = 0;
157 
158 	if (*cp == '\0')
159 		return (deflt);
160 	while (*cp != '\0')
161 		i = i * 10 + *cp++ - '0';
162 	return (i);
163 }
164 
165 void
166 rcons_init(fb)
167 	register struct fbdevice *fb;
168 {
169 	/* XXX this should go away */
170 	static struct raster xxxraster;
171 	register struct raster *rp = fb->fb_sp = &xxxraster;
172 	register struct fbtype *ft = &fb->fb_type;
173 	register struct winsize *ws;
174 	register int i;
175 	static int row, col;
176 	char buf[100];
177 
178 	myfbdevicep = fb;
179 
180 	fb->fb_maxcol =
181 	    rcons_a2int(getpropstring(optionsnode, "screen-#columns"), 80);
182 	fb->fb_maxrow =
183 	    rcons_a2int(getpropstring(optionsnode, "screen-#rows"), 34);
184 
185 	/* XXX mostly duplicates of data in other places */
186 	rp->width = ft->fb_width;
187 	rp->height = ft->fb_height;
188 	rp->depth = ft->fb_depth;
189 	if (fb->fb_linebytes & 0x3) {
190 		printf("rcons_init: linebytes assumption botched (0x%x)\n",
191 		    fb->fb_linebytes);
192 		return;
193 	}
194 	rp->linelongs = fb->fb_linebytes >> 2;
195 	rp->pixels = (u_long *)fb->fb_pixels;
196 
197 	fb->fb_ras_blank = RAS_CLEAR;
198 
199 	/* Setup the static font */
200 	rcons_font(fb);
201 
202 	/* Impose upper bounds on fb_max{row,col} */
203 	i = ft->fb_height / fb->fb_font->height;
204 	if (fb->fb_maxrow > i)
205 		fb->fb_maxrow = i;
206 	i = ft->fb_width / fb->fb_font->width;
207 	if (fb->fb_maxcol > i)
208 		fb->fb_maxcol = i;
209 
210 	/* Let the system know how big the console is */
211 	ws = &fbconstty->t_winsize;
212 	ws->ws_row = fb->fb_maxrow;
213 	ws->ws_col = fb->fb_maxcol;
214 	ws->ws_xpixel = ft->fb_width;
215 	ws->ws_ypixel = ft->fb_height;
216 
217 	/* Center emulator screen (but align x origin to 32 bits) */
218 	fb->fb_xorigin =
219 	    ((ft->fb_width - fb->fb_maxcol * fb->fb_font->width) / 2) & ~0x1f;
220 	fb->fb_yorigin =
221 	    (ft->fb_height - fb->fb_maxrow * fb->fb_font->height) / 2;
222 
223 	/* Emulator width and height used for scrolling */
224 	fb->fb_emuwidth = fb->fb_maxcol * fb->fb_font->width;
225 	if (fb->fb_emuwidth & 0x1f) {
226 		/* Pad to 32 bits */
227 		i = (fb->fb_emuwidth + 0x1f) & ~0x1f;
228 		/* Make sure emulator width isn't too wide */
229 		if (fb->fb_xorigin + i <= ft->fb_width)
230 			fb->fb_emuwidth = i;
231 	}
232 	fb->fb_emuheight = fb->fb_maxrow * fb->fb_font->height;
233 
234 	/* Determine addresses of prom emulator row and column */
235 	fb->fb_row = fb->fb_col = NULL;
236 	sprintf(buf, "' line# >body >user %x !", &fb->fb_row);
237 	rominterpret(buf);
238 	sprintf(buf, "' column# >body >user %x !", &fb->fb_col);
239 	rominterpret(buf);
240 	if (fb->fb_row == NULL || fb->fb_col == NULL) {
241 		/* Can't find addresses; use private copies */
242 		fb->fb_row = &row;
243 		fb->fb_col = &col;
244 		row = col = 0;
245 		rcons_clear2eop(fb);	/* clear the display */
246 		rcons_cursor(fb);	/* and draw the initial cursor */
247 	} else {
248 		/* Prom emulator cursor is currently visible */
249 		fb->fb_bits |= FB_CURSOR;
250 	}
251 
252 	/* Initialization done; hook us up */
253 	v_putc = (int (*)())rcons_cnputc;
254 	fbconstty->t_oproc = rcons_output;
255 	fbconstty->t_stop = (void (*)()) nullop;
256 }
257