xref: /plan9-contrib/sys/src/9/pc/cga.c (revision 1045bea11e2fdfc8e23a3be73ec6cf07aa628e91)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 
8 enum {
9 	Black,
10 	Blue,
11 	Green,
12 	Cyan,
13 	Red,
14 	Magenta,
15 	Brown,
16 	Grey,
17 
18 	Bright = 0x08,
19 	Blinking = 0x80,
20 
21 	Yellow = Bright|Brown,
22 	White = Bright|Grey,
23 };
24 
25 enum {
26 	Width		= 80*2,
27 	Height		= 25,
28 
29 	Attr		= (Black<<4)|Grey,	/* high nibble background
30 						 * low foreground
31 						 */
32 
33 	Poststrlen	= 0,
34 	Postcodelen	= 2,
35 	Postlen		= Poststrlen+Postcodelen,
36 };
37 
38 #define CGASCREENBASE	((uchar*)KADDR(0xB8000))
39 #define CGA		CGASCREENBASE
40 
41 static int cgapos;
42 static Lock cgascreenlock;
43 
44 static uchar
cgaregr(int index)45 cgaregr(int index)
46 {
47 	outb(0x3D4, index);
48 	return inb(0x3D4+1) & 0xFF;
49 }
50 
51 static void
cgaregw(int index,int data)52 cgaregw(int index, int data)
53 {
54 	outb(0x3D4, index);
55 	outb(0x3D4+1, data);
56 }
57 
58 static void
movecursor(void)59 movecursor(void)
60 {
61 	cgaregw(0x0E, (cgapos/2>>8) & 0xFF);
62 	cgaregw(0x0F, cgapos/2 & 0xFF);
63 	CGASCREENBASE[cgapos+1] = Attr;
64 }
65 
66 static void
cgascreenputc(int c)67 cgascreenputc(int c)
68 {
69 	int i;
70 	uchar *p;
71 
72 	if(c == '\n'){
73 		cgapos = cgapos/Width;
74 		cgapos = (cgapos+1)*Width;
75 	}
76 	else if(c == '\t'){
77 		i = 8 - ((cgapos/2)&7);
78 		while(i-->0)
79 			cgascreenputc(' ');
80 	}
81 	else if(c == '\b'){
82 		if(cgapos >= 2)
83 			cgapos -= 2;
84 		cgascreenputc(' ');
85 		cgapos -= 2;
86 	}
87 	else{
88 		CGASCREENBASE[cgapos++] = c;
89 		CGASCREENBASE[cgapos++] = Attr;
90 	}
91 	if(cgapos >= Width*Height){
92 		memmove(CGASCREENBASE, &CGASCREENBASE[Width], Width*(Height-1));
93 		p = &CGASCREENBASE[Width*(Height-1)];
94 		for(i=0; i<Width/2; i++){
95 			*p++ = ' ';
96 			*p++ = Attr;
97 		}
98 		cgapos = Width*(Height-1);
99 	}
100 	movecursor();
101 }
102 
103 static void
cgascreenputs(char * s,int n)104 cgascreenputs(char* s, int n)
105 {
106 	if(!islo()){
107 		/*
108 		 * Don't deadlock trying to
109 		 * print in an interrupt.
110 		 */
111 		if(!canlock(&cgascreenlock))
112 			return;
113 	}
114 	else
115 		lock(&cgascreenlock);
116 
117 	while(n-- > 0)
118 		cgascreenputc(*s++);
119 
120 	unlock(&cgascreenlock);
121 }
122 
123 char hex[] = "0123456789ABCDEF";
124 
125 void
cgapost(int code)126 cgapost(int code)
127 {
128 	uchar *cga;
129 
130 	cga = CGA;
131 	cga[Width*Height-Postcodelen*2] = hex[(code>>4) & 0x0F];
132 	cga[Width*Height-Postcodelen*2+1] = Attr;
133 	cga[Width*Height-Postcodelen*2+2] = hex[code & 0x0F];
134 	cga[Width*Height-Postcodelen*2+3] = Attr;
135 }
136 
137 void
screeninit(void)138 screeninit(void)
139 {
140 
141 	cgapos = cgaregr(0x0E)<<8;
142 	cgapos |= cgaregr(0x0F);
143 	cgapos *= 2;
144 
145 	screenputs = cgascreenputs;
146 }
147