xref: /original-bsd/sys/luna68k/dev/bmd.c (revision 3705696b)
1 /*
2  * Copyright (c) 1992 OMRON Corporation.
3  * Copyright (c) 1992, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * OMRON Corporation.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)bmd.c	8.1 (Berkeley) 06/10/93
12  */
13 
14 /*
15 
16  * bmd.c --- Bitmap-Display raw-level driver routines
17  *
18  *	by A.Fujita, SEP-09-1992
19  */
20 
21 #undef	BMD_PRINTF
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 
26 extern u_short bmdfont[][20];
27 
28 #define isprint(c)	( c < 0x20 ? 0 : 1)
29 
30 /*
31  *  Width & Hight
32  */
33 
34 #define	PB_WIDTH	2048				/* Plane Width   (Bit) */
35 #define	PB_HIGHT	1024				/* Plane Hight   (Bit) */
36 #define PL_WIDTH	64				/* Plane Width  (long) */
37 #define PS_WIDTH	128				/* Plane Width  (long) */
38 #define P_WIDTH		256				/* Plane Width  (Byte) */
39 
40 #define SB_WIDTH	1280				/* Screen Width  (Bit) */
41 #define	SB_HIGHT	1024				/* Screen Hight  (Bit) */
42 #define SL_WIDTH	40				/* Screen Width (Long) */
43 #define S_WIDTH		160				/* Screen Width (Byte) */
44 
45 #define FB_WIDTH	12				/* Font Width    (Bit) */
46 #define FB_HIGHT	20				/* Font Hight    (Bit) */
47 
48 
49 #define NEXT_LINE(addr)				( addr +  (PL_WIDTH * FB_HIGHT) )
50 #define SKIP_NEXT_LINE(addr)			( addr += (PL_WIDTH - SL_WIDTH) )
51 
52 
53 void	bmd_add_new_line();
54 
55 void	bmd_draw_char();
56 void	bmd_reverse_char();
57 void	bmd_erase_char();
58 void	bmd_erase_screen();
59 void	bmd_scroll_screen();
60 
61 void	bmd_escape();
62 
63 
64 struct bmd_linec {
65 	struct bmd_linec *bl_next;
66 	struct bmd_linec *bl_prev;
67 	int	bl_col;
68 	int	bl_end;
69 	u_char	bl_line[128];
70 };
71 
72 struct bmd_softc {
73 	int	bc_stat;
74 	char   *bc_raddr;
75 	char   *bc_waddr;
76 	int	bc_xmin;
77 	int	bc_xmax;
78 	int	bc_ymin;
79 	int	bc_ymax;
80 	int	bc_col;
81 	int	bc_row;
82 	struct bmd_linec *bc_bl;
83 	char	bc_escseq[8];
84 	char   *bc_esc;
85 	void  (*bc_escape)();
86 };
87 
88 #define	STAT_NORMAL	0x0000
89 #define	STAT_ESCAPE	0x0001
90 #define	STAT_STOP	0x0002
91 
92 struct	bmd_softc bmd_softc;
93 struct	bmd_linec bmd_linec[52];
94 
95 int	bmd_initflag = 0;
96 
97 /*
98  * Escape-Sequence
99  */
100 
101 #define push_ESC(p, c)		*(p)->bc_esc++ = c; *(p)->bc_esc = '\0'
102 
103 void
104 bmd_escape(c)
105 	int c;
106 {
107 	register struct bmd_softc *bp = &bmd_softc;
108 
109 	bp->bc_stat &= ~STAT_ESCAPE;
110 	bp->bc_esc = &bp->bc_escseq[0];
111 /*	bp->bc_escape = bmd_escape;	*/
112 }
113 
114 /*
115  * Entry Routine
116  */
117 
118 bmdinit()
119 {
120 	register struct bmd_softc *bp = &bmd_softc;
121 	register struct bmd_linec *bq;
122 	register int i;
123 
124 	bp->bc_raddr = (char *) 0xB10C0008;		/* plane-0 hardware address */
125 	bp->bc_waddr = (char *) 0xB1080008;		/* common bitmap hardware address */
126 
127 	/*
128 	 *  adjust plane position
129 	 */
130 
131 	fb_adjust(7, -27);
132 
133 	bp->bc_stat  = STAT_NORMAL;
134 
135 	bp->bc_xmin  = 8;
136 	bp->bc_xmax  = 96;
137 	bp->bc_ymin  = 2;
138 	bp->bc_ymax  = 48;
139 
140 	bp->bc_row = bp->bc_ymin;
141 
142 	for (i = bp->bc_ymin; i < bp->bc_ymax; i++) {
143 		bmd_linec[i].bl_next = &bmd_linec[i+1];
144 		bmd_linec[i].bl_prev = &bmd_linec[i-1];
145 	}
146 	bmd_linec[bp->bc_ymax-1].bl_next = &bmd_linec[bp->bc_ymin];
147 	bmd_linec[bp->bc_ymin].bl_prev = &bmd_linec[bp->bc_ymax-1];
148 
149 	bq = bp->bc_bl = &bmd_linec[bp->bc_ymin];
150 	bq->bl_col = bq->bl_end = bp->bc_xmin;
151 
152 	bp->bc_col = bp->bc_xmin;
153 
154 	bp->bc_esc = &bp->bc_escseq[0];
155 	bp->bc_escape = bmd_escape;
156 
157 	bmd_erase_screen((u_long *) bp->bc_waddr);	/* clear screen */
158 
159 							/* turn on  cursole */
160 	bmd_reverse_char(bp->bc_raddr,
161 			 bp->bc_waddr,
162 			 bq->bl_col, bp->bc_row);
163 
164 	bmd_initflag = 1;
165 }
166 
167 bmdputc(c)
168 	register int c;
169 {
170 	register struct bmd_softc *bp;
171 	register struct bmd_linec *bq;
172 	register int i;
173 
174 	if (!bmd_initflag)
175 		bmdinit();
176 
177 	bp = &bmd_softc;
178 	bq = bp->bc_bl;
179 
180 							/* skip out, if STAT_STOP */
181 	if (bp->bc_stat & STAT_STOP)
182 		return(c);
183 
184 	c &= 0x7F;
185 							/* turn off cursole */
186 	bmd_reverse_char(bp->bc_raddr,
187 			 bp->bc_waddr,
188 			 bq->bl_col, bp->bc_row);
189 							/* do escape-sequence */
190 
191 	if (bp->bc_stat & STAT_ESCAPE) {
192 		*bp->bc_esc++ = c;
193 		(*bp->bc_escape)(c);
194 		goto done;
195 	}
196 
197 	if (isprint(c)) {
198 		bmd_draw_char(bp->bc_raddr, bp->bc_waddr,
199 			      bq->bl_col, bp->bc_row, c);
200 		bq->bl_col++;
201 		bq->bl_end++;
202 		if (bq->bl_col >= bp->bc_xmax) {
203 			bq->bl_col = bq->bl_end = bp->bc_xmin;
204 			bp->bc_row++;
205 			if (bp->bc_row >= bp->bc_ymax) {
206 				bmd_scroll_screen((u_long *) bp->bc_raddr,
207 						  (u_long *) bp->bc_waddr,
208 						  bp->bc_xmin, bp->bc_xmax,
209 						  bp->bc_ymin, bp->bc_ymax);
210 
211 				bp->bc_row = bp->bc_ymax - 1;
212 			}
213 		}
214 	} else {
215 		switch (c) {
216 		case 0x08:				/* BS */
217 			if (bq->bl_col > bp->bc_xmin) {
218 				bq->bl_col--;
219 			}
220 			break;
221 
222 		case 0x09:				/* HT */
223 		case 0x0B:				/* VT */
224 			i = ((bq->bl_col / 8) + 1) * 8;
225 			if (i < bp->bc_xmax) {
226 				bq->bl_col = bq->bl_end = i;
227 			}
228 			break;
229 
230 		case 0x0A:				/* NL */
231 			bp->bc_row++;
232 			if (bp->bc_row >= bp->bc_ymax) {
233 				bmd_scroll_screen((u_long *) bp->bc_raddr,
234 						  (u_long *) bp->bc_waddr,
235 						  bp->bc_xmin, bp->bc_xmax,
236 						  bp->bc_ymin, bp->bc_ymax);
237 
238 				bp->bc_row = bp->bc_ymax - 1;
239 			}
240 			break;
241 
242 		case 0x0D:				/* CR */
243 			bq->bl_col = bp->bc_xmin;
244 			break;
245 
246 		case 0x1b:				/* ESC */
247 			bmdputc('<');
248 			bmdputc('E');
249 			bmdputc('S');
250 			bmdputc('C');
251 			bmdputc('>');
252 /*
253 			bp->bc_stat |= STAT_ESCAPE;
254 			*bp->bc_esc++ = 0x1b;
255  */
256 			break;
257 
258 		case 0x7F:				/* DEL */
259 			if (bq->bl_col > bp->bc_xmin) {
260 				bq->bl_col--;
261 				bmd_erase_char(bp->bc_raddr,
262 					       bp->bc_waddr,
263 					       bq->bl_col, bp->bc_row);
264 			}
265 			break;
266 
267 		default:
268 			break;
269 		}
270 	}
271 
272  done:
273 							/* turn on  cursole */
274 	bmd_reverse_char(bp->bc_raddr,
275 			 bp->bc_waddr,
276 			 bq->bl_col, bp->bc_row);
277 
278 	return(c);
279 }
280 
281 /*
282  *
283  */
284 
285 bmd_on()
286 {
287 	bmdinit();
288 }
289 
290 bmd_off()
291 {
292 	register struct bmd_softc *bp = &bmd_softc;
293 
294 	bp->bc_stat |= STAT_STOP;
295 	bmd_erase_screen((u_long *) bp->bc_waddr);	/* clear screen */
296 }
297 
298 bmd_clear()
299 {
300 	register struct bmd_softc *bp = &bmd_softc;
301 	register struct bmd_linec *bq = bp->bc_bl;
302 
303 	bmd_erase_screen((u_long *) bp->bc_waddr);	/* clear screen */
304 
305 	bmd_reverse_char(bp->bc_raddr,
306 			 bp->bc_waddr,
307 			 bq->bl_col, bp->bc_row);	/* turn on  cursole */
308 }
309 
310 bmd_home()
311 {
312 	register struct bmd_softc *bp = &bmd_softc;
313 	register struct bmd_linec *bq = bp->bc_bl;
314 
315 	bmd_reverse_char(bp->bc_raddr,
316 			 bp->bc_waddr,
317 			 bq->bl_col, bp->bc_row);	/* turn off cursole */
318 
319 	bq->bl_col = bq->bl_end = bp->bc_xmin;
320 	bp->bc_row = bp->bc_ymin;
321 
322 	bmd_reverse_char(bp->bc_raddr,
323 			 bp->bc_waddr,
324 			 bq->bl_col, bp->bc_row);	/* turn on  cursole */
325 }
326 
327 /*
328  *  charactor operation routines
329  */
330 
331 void
332 bmd_draw_char(raddr, waddr, col, row, c)
333 	char *raddr;
334 	char *waddr;
335 	int col;
336 	int row;
337 	int c;
338 {
339 	volatile register u_short  *p,  *q, *fp;
340 	volatile register u_long  *lp, *lq;
341 	register int i;
342 
343 	fp = &bmdfont[c][0];
344 
345 	switch (col % 4) {
346 
347 	case 0:
348 		p = (u_short *) ( raddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ));
349 		q = (u_short *) ( waddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ));
350 		for (i = 0; i < FB_HIGHT; i++) {
351 			*q = (*p & 0x000F) | (*fp & 0xFFF0);
352 			p += 128;
353 			q += 128;
354 			fp++;
355 		}
356 		break;
357 
358 	case 1:
359 		lp = (u_long *) ( raddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ));
360 		lq = (u_long *) ( waddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ));
361 		for (i = 0; i < FB_HIGHT; i++) {
362 			*lq = (*lp & 0xFFF000FF) | ((u_long)(*fp & 0xFFF0) << 4);
363 			lp += 64;
364 			lq += 64;
365 			fp++;
366 		}
367 		break;
368 
369 	case 2:
370 		lp = (u_long *) ( raddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ) + 2 );
371 		lq = (u_long *) ( waddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ) + 2 );
372 		for (i = 0; i < FB_HIGHT; i++) {
373 			*lq = (*lp & 0xFF000FFF) | ((u_long)(*fp & 0xFFF0) << 8);
374 			lp += 64;
375 			lq += 64;
376 			fp++;
377 		}
378 		break;
379 
380 	case 3:
381 		p = (u_short *) ( raddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ) + 4 );
382 		q = (u_short *) ( waddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ) + 4 );
383 		for (i = 0; i < FB_HIGHT; i++) {
384 			*q = (*p & 0xF000) | ((*fp & 0xFFF0) >> 4);
385 			p += 128;
386 			q += 128;
387 			fp++;
388 		}
389 		break;
390 
391 	default:
392 		break;
393 	}
394 }
395 
396 void
397 bmd_reverse_char(raddr, waddr, col, row)
398 	char *raddr;
399 	char *waddr;
400 	int col;
401 	int row;
402 {
403 	volatile register u_short  *p,  *q,  us;
404 	volatile register u_long  *lp, *lq,  ul;
405 	register int i;
406 
407 	switch (col%4) {
408 
409 	case 0:
410 		p = (u_short *) ( raddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ));
411 		q = (u_short *) ( waddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ));
412 		for (i = 0; i < FB_HIGHT; i++) {
413 			*q = (*p & 0x000F) | (~(*p) & 0xFFF0);
414 			p += 128;
415 			q += 128;
416 		}
417 		break;
418 
419 	case 1:
420 		lp = (u_long *) ( raddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ));
421 		lq = (u_long *) ( waddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ));
422 		for (i = 0; i < FB_HIGHT; i++) {
423 			*lq = (*lp & 0xFFF000FF) | (~(*lp) & 0x000FFF00);
424 			lp += 64;
425 			lq += 64;
426 		}
427 		break;
428 
429 	case 2:
430 		lp = (u_long *) ( raddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ) + 2 );
431 		lq = (u_long *) ( waddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ) + 2 );
432 		for (i = 0; i < FB_HIGHT; i++) {
433 			*lq = (*lp & 0xFF000FFF) | (~(*lp) & 0x00FFF000);
434 			lp += 64;
435 			lq += 64;
436 		}
437 		break;
438 
439 	case 3:
440 		p = (u_short *) ( raddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ) + 4 );
441 		q = (u_short *) ( waddr + (( row * FB_HIGHT ) << 8 ) + (( col / 4 ) * 6 ) + 4 );
442 		for (i = 0; i < FB_HIGHT; i++) {
443 			*q = (*p & 0xF000) | (~(*p) & 0x0FFF);
444 			p += 128;
445 			q += 128;
446 		}
447 		break;
448 
449 	default:
450 		break;
451 	}
452 }
453 
454 void
455 bmd_erase_char(raddr, waddr, col, row)
456 	char *raddr;
457 	char *waddr;
458 	int col;
459 	int row;
460 {
461 	bmd_draw_char(raddr, waddr, col, row, 0);
462 
463 	return;
464 }
465 
466 
467 /*
468  * screen operation routines
469  */
470 
471 void
472 bmd_erase_screen(lp)
473 	volatile register u_long *lp;
474 {
475 	register int i, j;
476 
477 	for (i = 0; i < SB_HIGHT; i++) {
478 		for (j = 0; j < SL_WIDTH; j++)
479 			*lp++ = 0;
480 		SKIP_NEXT_LINE(lp);
481 	}
482 
483 	return;
484 }
485 
486 void
487 bmd_scroll_screen(lp, lq, xmin, xmax, ymin, ymax)
488 	volatile register u_long *lp;
489 	volatile register u_long *lq;
490 	int xmin, xmax, ymin, ymax;
491 {
492 	register int i, j;
493 
494 	lp += ((PL_WIDTH * FB_HIGHT) * (ymin + 1));
495 	lq += ((PL_WIDTH * FB_HIGHT) *  ymin);
496 
497 	for (i = 0; i < ((ymax - ymin -1) * FB_HIGHT); i++) {
498 		for (j = 0; j < SL_WIDTH; j++) {
499 			*lq++ = *lp++;
500 		}
501 		lp += (PL_WIDTH - SL_WIDTH);
502 		lq += (PL_WIDTH - SL_WIDTH);
503 	}
504 
505 	for (i = 0; i < FB_HIGHT; i++) {
506 		for (j = 0; j < SL_WIDTH; j++) {
507 			*lq++ = 0;
508 		}
509 		lq += (PL_WIDTH - SL_WIDTH);
510 	}
511 
512 }
513 
514 
515 #ifdef	BMD_PRINTF
516 
517 #include <machine/stdarg.h>
518 
519 void		bmd_kprintf();
520 static char *	bmd_sprintn();
521 
522 void
523 #ifdef __STDC__
524 bmd_printf(const char *fmt, ...)
525 #else
526 bmd_printf(fmt, va_alist)
527 	char *fmt;
528 #endif
529 {
530 	va_list ap;
531 
532 	va_start(ap, fmt);
533 	bmd_kprintf(fmt, ap);
534 	va_end(ap);
535 }
536 
537 /*
538  * Scaled down version of printf(3).
539  *
540  * Two additional formats:
541  *
542  * The format %b is supported to decode error registers.
543  * Its usage is:
544  *
545  *	printf("reg=%b\n", regval, "<base><arg>*");
546  *
547  * where <base> is the output base expressed as a control character, e.g.
548  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
549  * the first of which gives the bit number to be inspected (origin 1), and
550  * the next characters (up to a control character, i.e. a character <= 32),
551  * give the name of the register.  Thus:
552  *
553  *	kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
554  *
555  * would produce output:
556  *
557  *	reg=3<BITTWO,BITONE>
558  *
559  * The format %r passes an additional format string and argument list
560  * recursively.  Its usage is:
561  *
562  * fn(char *fmt, ...)
563  * {
564  *	va_list ap;
565  *	va_start(ap, fmt);
566  *	printf("prefix: %r: suffix\n", fmt, ap);
567  *	va_end(ap);
568  * }
569  *
570  * Space or zero padding and a field width are supported for the numeric
571  * formats only.
572  */
573 void
574 bmd_kprintf(fmt, ap)
575 	register const char *fmt;
576 	va_list ap;
577 {
578 	register char *p, *q;
579 	register int ch, n;
580 	u_long ul;
581 	int base, lflag, tmp, width;
582 	char padc;
583 
584 	for (;;) {
585 		padc = ' ';
586 		width = 0;
587 		while ((ch = *(u_char *)fmt++) != '%') {
588 			if (ch == '\0')
589 				return;
590 			if (ch == '\n')
591 				bmdputc('\r');
592 			bmdputc(ch);
593 		}
594 		lflag = 0;
595 reswitch:	switch (ch = *(u_char *)fmt++) {
596 		case '0':
597 			padc = '0';
598 			goto reswitch;
599 		case '1': case '2': case '3': case '4':
600 		case '5': case '6': case '7': case '8': case '9':
601 			for (width = 0;; ++fmt) {
602 				width = width * 10 + ch - '0';
603 				ch = *fmt;
604 				if (ch < '0' || ch > '9')
605 					break;
606 			}
607 			goto reswitch;
608 		case 'l':
609 			lflag = 1;
610 			goto reswitch;
611 		case 'b':
612 			ul = va_arg(ap, int);
613 			p = va_arg(ap, char *);
614 			for (q = bmd_sprintn(ul, *p++, NULL); ch = *q--;)
615 				bmdputc(ch);
616 
617 			if (!ul)
618 				break;
619 
620 			for (tmp = 0; n = *p++;) {
621 				if (ul & (1 << (n - 1))) {
622 					bmdputc(tmp ? ',' : '<');
623 					for (; (n = *p) > ' '; ++p)
624 						bmdputc(n);
625 					tmp = 1;
626 				} else
627 					for (; *p > ' '; ++p)
628 						continue;
629 			}
630 			if (tmp)
631 				bmdputc('>');
632 			break;
633 		case 'c':
634 			bmdputc(va_arg(ap, int));
635 			break;
636 		case 'r':
637 			p = va_arg(ap, char *);
638 			bmd_kprintf(p, va_arg(ap, va_list));
639 			break;
640 		case 's':
641 			p = va_arg(ap, char *);
642 			while (ch = *p++)
643 				bmdputc(ch);
644 			break;
645 		case 'd':
646 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
647 			if ((long)ul < 0) {
648 				bmdputc('-');
649 				ul = -(long)ul;
650 			}
651 			base = 10;
652 			goto number;
653 		case 'o':
654 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
655 			base = 8;
656 			goto number;
657 		case 'u':
658 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
659 			base = 10;
660 			goto number;
661 		case 'x':
662 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
663 			base = 16;
664 number:			p = bmd_sprintn(ul, base, &tmp);
665 			if (width && (width -= tmp) > 0)
666 				while (width--)
667 					bmdputc(padc);
668 			while (ch = *p--)
669 				bmdputc(ch);
670 			break;
671 		default:
672 			bmdputc('%');
673 			if (lflag)
674 				bmdputc('l');
675 			/* FALLTHROUGH */
676 		case '%':
677 			bmdputc(ch);
678 		}
679 	}
680 }
681 
682 /*
683  * Put a number (base <= 16) in a buffer in reverse order; return an
684  * optional length and a pointer to the NULL terminated (preceded?)
685  * buffer.
686  */
687 static char *
688 bmd_sprintn(ul, base, lenp)
689 	register u_long ul;
690 	register int base, *lenp;
691 {					/* A long in base 8, plus NULL. */
692 	static char buf[sizeof(long) * NBBY / 3 + 2];
693 	register char *p;
694 
695 	p = buf;
696 	do {
697 		*++p = "0123456789abcdef"[ul % base];
698 	} while (ul /= base);
699 	if (lenp)
700 		*lenp = p - buf;
701 	return (p);
702 }
703 #endif
704