xref: /csrg-svn/sys/sparc/rcons/rcons_subr.c (revision 55133)
1 /*
2  * Copyright (c) 1991 The Regents of the University of California.
3  * 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  * %sccs.include.redist.c%
10  *
11  *	@(#)rcons_subr.c	7.1 (Berkeley) 07/13/92
12  *
13  * from: $Header: rcons_subr.c,v 1.36 92/06/17 06:23:39 torek Exp $
14  */
15 
16 #ifdef KERNEL
17 #include "sys/param.h"
18 #include "sys/fbio.h"
19 #include "sys/device.h"
20 #include "machine/fbvar.h"
21 #else
22 #include <sys/types.h>
23 #include "myfbdevice.h"
24 #endif
25 
26 #include "raster.h"
27 
28 void rcons_text(struct fbdevice *, char *, int);
29 void rcons_pctrl(struct fbdevice *, int);
30 void rcons_esc(struct fbdevice *, int);
31 void rcons_doesc(struct fbdevice *, int);
32 void rcons_cursor(struct fbdevice *);
33 void rcons_invert(struct fbdevice *, int);
34 void rcons_clear2eop(struct fbdevice *);
35 void rcons_clear2eol(struct fbdevice *);
36 void rcons_scroll(struct fbdevice *, int);
37 void rcons_delchar(struct fbdevice *, int);
38 void rcons_delline(struct fbdevice *, int);
39 void rcons_insertchar(struct fbdevice *, int);
40 void rcons_insertline(struct fbdevice *, int);
41 
42 extern void rcons_bell(struct fbdevice *);
43 
44 #define RCONS_ISPRINT(c) ((c) >= ' ' && (c) <= '~')
45 #define RCONS_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
46 
47 /* Output (or at least handle) a string sent to the console */
48 void
49 rcons_puts(fb, str, n)
50 	register struct fbdevice *fb;
51 	register char *str;
52 	register int n;
53 {
54 	register int c, i, j;
55 	register char *cp;
56 
57 	/* Jump scroll */
58 	/* XXX maybe this should be an option? */
59 	if ((fb->fb_bits & FB_INESC) == 0) {
60 		/* Count newlines up to an escape sequence */
61 		i = 0;
62 		j = 0;
63 		for (cp = str; j++ < n && *cp != '\033'; ++cp) {
64 			if (*cp == '\n')
65 				++i;
66 			else if (*cp == '\013')
67 				--i;
68 		}
69 
70 		/* Only jump scroll two or more rows */
71 		if (*fb->fb_row + i >= fb->fb_maxrow + 1) {
72 			/* Erase the cursor (if necessary) */
73 			if (fb->fb_bits & FB_CURSOR)
74 				rcons_cursor(fb);
75 
76 			rcons_scroll(fb, i);
77 		}
78 	}
79 
80 	/* Process characters */
81 	while (--n >= 0) {
82 		c = *str;
83 		if (c == '\033') {
84 			/* Start an escape (perhaps aborting one in progress) */
85 			fb->fb_bits |= FB_INESC | FB_P0_DEFAULT | FB_P1_DEFAULT;
86 			fb->fb_bits &= ~(FB_P0 | FB_P1);
87 
88 			/* Most parameters default to 1 */
89 			fb->fb_p0 = fb->fb_p1 = 1;
90 		} else if (fb->fb_bits & FB_INESC) {
91 			rcons_esc(fb, c);
92 		} else {
93 			/* Erase the cursor (if necessary) */
94 			if (fb->fb_bits & FB_CURSOR)
95 				rcons_cursor(fb);
96 
97 			/* Display the character */
98 			if (RCONS_ISPRINT(c)) {
99 				/* Try to output as much as possible */
100 				j = fb->fb_maxcol - (*fb->fb_col + 1);
101 				if (j > n)
102 					j = n;
103 				for (i = 1; i < j && RCONS_ISPRINT(str[i]); ++i)
104 					continue;
105 				rcons_text(fb, str, i);
106 				--i;
107 				str += i;
108 				n -= i;
109 			} else
110 				rcons_pctrl(fb, c);
111 		}
112 		++str;
113 	}
114 	/* Redraw the cursor (if necessary) */
115 	if ((fb->fb_bits & FB_CURSOR) == 0)
116 		rcons_cursor(fb);
117 }
118 
119 /* Actually write a string to the frame buffer */
120 void
121 rcons_text(fb, str, n)
122 	register struct fbdevice *fb;
123 	register char *str;
124 	register int n;
125 {
126 	register int x, y, op;
127 
128 	x = *fb->fb_col * fb->fb_font->width + fb->fb_xorigin;
129 	y = *fb->fb_row * fb->fb_font->height +
130 	    fb->fb_font_ascent + fb->fb_yorigin;
131 	op = RAS_SRC;
132 	if (((fb->fb_bits & FB_STANDOUT) != 0) ^
133 	    ((fb->fb_bits & FB_INVERT) != 0))
134 		op = RAS_NOT(op);
135 	raster_textn(fb->fb_sp, x, y, op, fb->fb_font, str, n);
136 	*fb->fb_col += n;
137 	if (*fb->fb_col >= fb->fb_maxcol) {
138 		*fb->fb_col = 0;
139 		(*fb->fb_row)++;
140 	}
141 	if (*fb->fb_row >= fb->fb_maxrow)
142 		rcons_scroll(fb, 1);
143 }
144 
145 /* Handle a control character sent to the console */
146 void
147 rcons_pctrl(fb, c)
148 	register struct fbdevice *fb;
149 	register int c;
150 {
151 
152 	switch (c) {
153 
154 	case '\r':	/* Carriage return */
155 		*fb->fb_col = 0;
156 		break;
157 
158 	case '\b':	/* Backspace */
159 		if (*fb->fb_col > 0)
160 			(*fb->fb_col)--;
161 		break;
162 
163 	case '\013':	/* Vertical tab */
164 		if (*fb->fb_row > 0)
165 			(*fb->fb_row)--;
166 		break;
167 
168 	case '\f':	/* Formfeed */
169 		*fb->fb_row = *fb->fb_col = 0;
170 		rcons_clear2eop(fb);
171 		break;
172 
173 	case '\n':	/* Linefeed */
174 		(*fb->fb_row)++;
175 		if (*fb->fb_row >= fb->fb_maxrow)
176 			rcons_scroll(fb, 1);
177 		break;
178 
179 	case '\007':	/* Bell */
180 		rcons_bell(fb);
181 		break;
182 
183 	case '\t':	/* Horizontal tab */
184 		*fb->fb_col = (*fb->fb_col + 8) & ~7;
185 		if (*fb->fb_col >= fb->fb_maxcol)
186 			*fb->fb_col = fb->fb_maxcol - 1;
187 		break;
188 	}
189 }
190 
191 /* Handle the next character in an escape sequence */
192 void
193 rcons_esc(fb, c)
194 	register struct fbdevice *fb;
195 	register int c;
196 {
197 
198 	if (c == '[') {
199 		/* Parameter 0 */
200 		fb->fb_bits &= ~FB_P1;
201 		fb->fb_bits |= FB_P0;
202 	} else if (c == ';') {
203 		/* Parameter 1 */
204 		fb->fb_bits &= ~FB_P0;
205 		fb->fb_bits |= FB_P1;
206 	} else if (RCONS_ISDIGIT(c)) {
207 		/* Add a digit to a parameter */
208 		if (fb->fb_bits & FB_P0) {
209 			/* Parameter 0 */
210 			if (fb->fb_bits & FB_P0_DEFAULT) {
211 				fb->fb_bits &= ~FB_P0_DEFAULT;
212 				fb->fb_p0 = 0;
213 			}
214 			fb->fb_p0 *= 10;
215 			fb->fb_p0 += c - '0';
216 		} else if (fb->fb_bits & FB_P1) {
217 			/* Parameter 1 */
218 			if (fb->fb_bits & FB_P1_DEFAULT) {
219 				fb->fb_bits &= ~FB_P1_DEFAULT;
220 				fb->fb_p1 = 0;
221 			}
222 			fb->fb_p1 *= 10;
223 			fb->fb_p1 += c - '0';
224 		}
225 	} else {
226 		/* Erase the cursor (if necessary) */
227 		if (fb->fb_bits & FB_CURSOR)
228 			rcons_cursor(fb);
229 
230 		/* Process the completed escape sequence */
231 		rcons_doesc(fb, c);
232 		fb->fb_bits &= ~FB_INESC;
233 	}
234 }
235 
236 /* Process a complete escape sequence */
237 void
238 rcons_doesc(fb, c)
239 	register struct fbdevice *fb;
240 	register int c;
241 {
242 
243 #ifdef notdef
244 	/* XXX add escape sequence to enable visual (and audible) bell */
245 	fb->fb_bits = FB_VISBELL;
246 #endif
247 
248 	switch (c) {
249 
250 	case '@':
251 		/* Insert Character (ICH) */
252 		rcons_insertchar(fb, fb->fb_p0);
253 		break;
254 
255 	case 'A':
256 		/* Cursor Up (CUU) */
257 		*fb->fb_row -= fb->fb_p0;
258 		if (*fb->fb_row < 0)
259 			*fb->fb_row = 0;
260 		break;
261 
262 	case 'B':
263 		/* Cursor Down (CUD) */
264 		*fb->fb_row += fb->fb_p0;
265 		if (*fb->fb_row >= fb->fb_maxrow)
266 			*fb->fb_row = fb->fb_maxrow - 1;
267 		break;
268 
269 	case 'C':
270 		/* Cursor Forward (CUF) */
271 		*fb->fb_col += fb->fb_p0;
272 		if (*fb->fb_col >= fb->fb_maxcol)
273 			*fb->fb_col = fb->fb_maxcol - 1;
274 		break;
275 
276 	case 'D':
277 		/* Cursor Backward (CUB) */
278 		*fb->fb_col -= fb->fb_p0;
279 		if (*fb->fb_col < 0)
280 			*fb->fb_col = 0;
281 		break;
282 
283 	case 'E':
284 		/* Cursor Next Line (CNL) */
285 		*fb->fb_col = 0;
286 		*fb->fb_row += fb->fb_p0;
287 		if (*fb->fb_row >= fb->fb_maxrow)
288 			*fb->fb_row = fb->fb_maxrow - 1;
289 		break;
290 
291 	case 'f':
292 		/* Horizontal And Vertical Position (HVP) */
293 	case 'H':
294 		/* Cursor Position (CUP) */
295 		*fb->fb_col = fb->fb_p1 - 1;
296 		if (*fb->fb_col < 0)
297 			*fb->fb_col = 0;
298 		else if (*fb->fb_col >= fb->fb_maxcol)
299 			*fb->fb_col = fb->fb_maxcol - 1;
300 
301 		*fb->fb_row = fb->fb_p0 - 1;
302 		if (*fb->fb_row < 0)
303 			*fb->fb_row = 0;
304 		else if (*fb->fb_row >= fb->fb_maxrow)
305 			*fb->fb_row = fb->fb_maxrow - 1;
306 		break;
307 
308 	case 'J':
309 		/* Erase in Display (ED) */
310 		rcons_clear2eop(fb);
311 		break;
312 
313 	case 'K':
314 		/* Erase in Line (EL) */
315 		rcons_clear2eol(fb);
316 		break;
317 
318 	case 'L':
319 		/* Insert Line (IL) */
320 		rcons_insertline(fb, fb->fb_p0);
321 		break;
322 
323 	case 'M':
324 		/* Delete Line (DL) */
325 		rcons_delline(fb, fb->fb_p0);
326 		break;
327 
328 	case 'P':
329 		/* Delete Character (DCH) */
330 		rcons_delchar(fb, fb->fb_p0);
331 		break;
332 
333 	case 'm':
334 		/* Select Graphic Rendition (SGR); */
335 		/* (defaults to zero) */
336 		if (fb->fb_bits & FB_P0_DEFAULT)
337 			fb->fb_p0 = 0;
338 		if (fb->fb_p0)
339 			fb->fb_bits |= FB_STANDOUT;
340 		else
341 			fb->fb_bits &= ~FB_STANDOUT;
342 		break;
343 
344 	case 'p':
345 		/* Black On White (SUNBOW) */
346 		rcons_invert(fb, 0);
347 		break;
348 
349 	case 'q':
350 		/* White On Black (SUNWOB) */
351 		rcons_invert(fb, 1);
352 		break;
353 
354 	case 'r':
355 		/* Set scrolling (SUNSCRL) */
356 		/* (defaults to zero) */
357 		if (fb->fb_bits & FB_P0_DEFAULT)
358 			fb->fb_p0 = 0;
359 		/* XXX not implemented yet */
360 		fb->fb_scroll = fb->fb_p0;
361 		break;
362 
363 	case 's':
364 		/* Reset terminal emulator (SUNRESET) */
365 		fb->fb_bits &= ~FB_STANDOUT;
366 		fb->fb_scroll = 0;
367 		if (fb->fb_bits & FB_INVERT)
368 			rcons_invert(fb, 0);
369 		break;
370 	}
371 }
372 
373 /* Paint (or unpaint) the cursor */
374 void
375 rcons_cursor(fb)
376 	register struct fbdevice *fb;
377 {
378 	register int x, y;
379 
380 	x = *fb->fb_col * fb->fb_font->width + fb->fb_xorigin;
381 	y = *fb->fb_row * fb->fb_font->height + fb->fb_yorigin;
382 	raster_op(fb->fb_sp, x, y,
383 #ifdef notdef
384 	    /* XXX This is the right way but too slow */
385 	    fb->fb_font->chars[(int)' '].r->width,
386 	    fb->fb_font->chars[(int)' '].r->height,
387 #else
388 	    fb->fb_font->width, fb->fb_font->height,
389 #endif
390 	    RAS_INVERT, (struct raster *) 0, 0, 0);
391 	fb->fb_bits ^= FB_CURSOR;
392 }
393 
394 /* Possibly change to SUNWOB or SUNBOW mode */
395 void
396 rcons_invert(fb, wob)
397 	struct fbdevice *fb;
398 	int wob;
399 {
400 	if (((fb->fb_bits & FB_INVERT) != 0) ^ wob) {
401 		/* Invert the display */
402 		raster_op(fb->fb_sp, 0, 0, fb->fb_sp->width, fb->fb_sp->height,
403 		    RAS_INVERT, (struct raster *) 0, 0, 0);
404 
405 		/* Swap things around */
406 		fb->fb_ras_blank = RAS_NOT(fb->fb_ras_blank);
407 		fb->fb_bits ^= FB_INVERT;
408 	}
409 }
410 
411 /* Clear to the end of the page */
412 void
413 rcons_clear2eop(fb)
414 	register struct fbdevice *fb;
415 {
416 	register int y;
417 
418 	if (*fb->fb_col == 0 && *fb->fb_row == 0) {
419 		/* Clear the entire frame buffer */
420 		raster_op(fb->fb_sp, 0, 0,
421 		    fb->fb_sp->width, fb->fb_sp->height,
422 		    fb->fb_ras_blank, (struct raster *) 0, 0, 0);
423 	} else {
424 		/* Only clear what needs to be cleared */
425 		rcons_clear2eol(fb);
426 		y = (*fb->fb_row + 1) * fb->fb_font->height;
427 
428 		raster_op(fb->fb_sp, fb->fb_xorigin, fb->fb_yorigin + y,
429 		    fb->fb_emuwidth, fb->fb_emuheight - y,
430 		    fb->fb_ras_blank, (struct raster *) 0, 0, 0);
431 	}
432 }
433 
434 /* Clear to the end of the line */
435 void
436 rcons_clear2eol(fb)
437 	register struct fbdevice *fb;
438 {
439 	register int x;
440 
441 	x = *fb->fb_col * fb->fb_font->width;
442 
443 	raster_op(fb->fb_sp,
444 	    fb->fb_xorigin + x,
445 	    *fb->fb_row * fb->fb_font->height + fb->fb_yorigin,
446 	    fb->fb_emuwidth - x, fb->fb_font->height,
447 	    fb->fb_ras_blank, (struct raster *) 0, 0, 0);
448 }
449 
450 /* Scroll up one line */
451 void
452 rcons_scroll(fb, n)
453 	register struct fbdevice *fb;
454 	register int n;
455 {
456 	register int ydiv;
457 
458 	/* Can't scroll more than the whole screen */
459 	if (n > fb->fb_maxrow)
460 		n = fb->fb_maxrow;
461 
462 	/* Calculate new row */
463 	*fb->fb_row -= n;
464 	if (*fb->fb_row < 0)
465 		*fb->fb_row  = 0;
466 
467 	/* Calculate number of pixels to scroll */
468 	ydiv = fb->fb_font->height * n;
469 
470 	raster_op(fb->fb_sp, fb->fb_xorigin, fb->fb_yorigin,
471 	    fb->fb_emuwidth, fb->fb_emuheight - ydiv,
472 	    RAS_SRC, fb->fb_sp, fb->fb_xorigin, ydiv + fb->fb_yorigin);
473 
474 	raster_op(fb->fb_sp,
475 	    fb->fb_xorigin, fb->fb_yorigin + fb->fb_emuheight - ydiv,
476 	    fb->fb_emuwidth, ydiv, fb->fb_ras_blank, (struct raster *) 0, 0, 0);
477 }
478 
479 /* Delete characters */
480 void
481 rcons_delchar(fb, n)
482 	register struct fbdevice *fb;
483 	register int n;
484 {
485 	register int tox, fromx, y, width;
486 
487 	/* Can't delete more chars than there are */
488 	if (n > fb->fb_maxcol - *fb->fb_col)
489 		n = fb->fb_maxcol - *fb->fb_col;
490 
491 	fromx = (*fb->fb_col + n) * fb->fb_font->width;
492 	tox = *fb->fb_col * fb->fb_font->width;
493 	y = *fb->fb_row * fb->fb_font->height;
494 	width = n * fb->fb_font->width;
495 
496 	raster_op(fb->fb_sp, tox + fb->fb_xorigin, y + fb->fb_yorigin,
497 	    fb->fb_emuwidth - fromx, fb->fb_font->height,
498 	    RAS_SRC, fb->fb_sp, fromx + fb->fb_xorigin, y + fb->fb_yorigin);
499 
500 	raster_op(fb->fb_sp,
501 	    fb->fb_emuwidth - width + fb->fb_xorigin, y + fb->fb_yorigin,
502 	    width, fb->fb_font->height,
503 	    fb->fb_ras_blank, (struct raster *) 0, 0, 0);
504 }
505 
506 /* Delete a number of lines */
507 void
508 rcons_delline(fb, n)
509 	register struct fbdevice *fb;
510 	register int n;
511 {
512 	register int fromy, toy, height;
513 
514 	/* Can't delete more lines than there are */
515 	if (n > fb->fb_maxrow - *fb->fb_row)
516 		n = fb->fb_maxrow - *fb->fb_row;
517 
518 	fromy = (*fb->fb_row + n) * fb->fb_font->height;
519 	toy = *fb->fb_row * fb->fb_font->height;
520 	height = fb->fb_font->height * n;
521 
522 	raster_op(fb->fb_sp, fb->fb_xorigin, toy + fb->fb_yorigin,
523 	    fb->fb_emuwidth, fb->fb_emuheight - fromy, RAS_SRC,
524 	    fb->fb_sp, fb->fb_xorigin, fromy + fb->fb_yorigin);
525 
526 	raster_op(fb->fb_sp,
527 	    fb->fb_xorigin, fb->fb_emuheight - height + fb->fb_yorigin,
528 	    fb->fb_emuwidth, height,
529 	    fb->fb_ras_blank, (struct raster *) 0, 0, 0);
530 }
531 
532 /* Insert some characters */
533 void
534 rcons_insertchar(fb, n)
535 	register struct fbdevice *fb;
536 	register int n;
537 {
538 	register int tox, fromx, y;
539 
540 	/* Can't insert more chars than can fit */
541 	if (n > fb->fb_maxcol - *fb->fb_col)
542 		n = fb->fb_maxcol - *fb->fb_col;
543 
544 	tox = (*fb->fb_col + n) * fb->fb_font->width;
545 	fromx = *fb->fb_col * fb->fb_font->width;
546 	y = *fb->fb_row * fb->fb_font->height;
547 
548 	raster_op(fb->fb_sp, tox + fb->fb_xorigin, y + fb->fb_yorigin,
549 	    fb->fb_emuwidth - tox, fb->fb_font->height,
550 	    RAS_SRC, fb->fb_sp, fromx + fb->fb_xorigin, y + fb->fb_yorigin);
551 
552 	raster_op(fb->fb_sp, fromx + fb->fb_xorigin, y + fb->fb_yorigin,
553 	    fb->fb_font->width * n, fb->fb_font->height,
554 	    fb->fb_ras_blank, (struct raster *) 0, 0, 0);
555 }
556 
557 /* Insert some lines */
558 void
559 rcons_insertline(fb, n)
560 	register struct fbdevice *fb;
561 	register int n;
562 {
563 	register int fromy, toy;
564 
565 	/* Can't insert more lines than can fit */
566 	if (n > fb->fb_maxrow - *fb->fb_row)
567 		n = fb->fb_maxrow - *fb->fb_row;
568 
569 	toy = (*fb->fb_row + n) * fb->fb_font->height;
570 	fromy = *fb->fb_row * fb->fb_font->height;
571 
572 	raster_op(fb->fb_sp, fb->fb_xorigin, toy + fb->fb_yorigin,
573 	    fb->fb_emuwidth, fb->fb_emuheight - toy,
574 	    RAS_SRC, fb->fb_sp, fb->fb_xorigin, fromy + fb->fb_yorigin);
575 
576 	raster_op(fb->fb_sp, fb->fb_xorigin, fromy + fb->fb_yorigin,
577 	    fb->fb_emuwidth, fb->fb_font->height * n,
578 	    fb->fb_ras_blank, (struct raster *) 0, 0, 0);
579 }
580