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
bmd_escape(c)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
bmdinit()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
bmdputc(c)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
bmd_on()285 bmd_on()
286 {
287 bmdinit();
288 }
289
bmd_off()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
bmd_clear()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
bmd_home()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
bmd_draw_char(raddr,waddr,col,row,c)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
bmd_reverse_char(raddr,waddr,col,row)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
bmd_erase_char(raddr,waddr,col,row)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
bmd_erase_screen(lp)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
bmd_scroll_screen(lp,lq,xmin,xmax,ymin,ymax)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__
bmd_printf(const char * fmt,...)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
bmd_kprintf(fmt,ap)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 *
bmd_sprintn(ul,base,lenp)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