]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/cga.c
kernel: cleanup the software mouse cursor mess
[plan9front.git] / sys / src / 9 / pc / cga.c
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
34 #define CGASCREENBASE   ((uchar*)KADDR(0xB8000))
35
36 static int cgapos;
37 static Lock cgascreenlock;
38
39 static Rune cp437[256] = {
40         0x2007,0x263A,0x263B,0x2665,0x2666,0x2663,0x2660,0x2022,
41         0x25D8,0x25CB,0x25D9,0x2642,0x2640,0x266A,0x266B,0x263C,
42         0x25BA,0x25C4,0x2195,0x203C,0x00B6,0x00A7,0x25AC,0x21A8,
43         0x2191,0x2193,0x2192,0x2190,0x221F,0x2194,0x25B2,0x25BC,
44         0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
45         0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F,
46         0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
47         0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
48         0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
49         0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F,
50         0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
51         0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F,
52         0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
53         0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
54         0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
55         0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x2302,
56         0x00C7,0x00FC,0x00E9,0x00E2,0x00E4,0x00E0,0x00E5,0x00E7,
57         0x00EA,0x00EB,0x00E8,0x00EF,0x00EE,0x00EC,0x00C4,0x00C5,
58         0x00C9,0x00E6,0x00C6,0x00F4,0x00F6,0x00F2,0x00FB,0x00F9,
59         0x00FF,0x00D6,0x00DC,0x00A2,0x00A3,0x00A5,0x20A7,0x0192,
60         0x00E1,0x00ED,0x00F3,0x00FA,0x00F1,0x00D1,0x00AA,0x00BA,
61         0x00BF,0x2310,0x00AC,0x00BD,0x00BC,0x00A1,0x00AB,0x00BB,
62         0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
63         0x2555,0x2563,0x2551,0x2557,0x255D,0x255C,0x255B,0x2510,
64         0x2514,0x2534,0x252C,0x251C,0x2500,0x253C,0x255E,0x255F,
65         0x255A,0x2554,0x2569,0x2566,0x2560,0x2550,0x256C,0x2567,
66         0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256B,
67         0x256A,0x2518,0x250C,0x2588,0x2584,0x258C,0x2590,0x2580,
68         0x03B1,0x00DF,0x0393,0x03C0,0x03A3,0x03C3,0x00B5,0x03C4,
69         0x03A6,0x0398,0x03A9,0x03B4,0x221E,0x03C6,0x03B5,0x2229,
70         0x2261,0x00B1,0x2265,0x2264,0x2320,0x2321,0x00F7,0x2248,
71         0x00B0,0x2219,0x00B7,0x221A,0x207F,0x00B2,0x25A0,0x00A0,
72 };
73
74 static uchar
75 cgaregr(int index)
76 {
77         outb(0x3D4, index);
78         return inb(0x3D4+1) & 0xFF;
79 }
80
81 static void
82 cgaregw(int index, int data)
83 {
84         outb(0x3D4, index);
85         outb(0x3D4+1, data);
86 }
87
88 static void
89 movecursor(void)
90 {
91         cgaregw(0x0E, (cgapos/2>>8) & 0xFF);
92         cgaregw(0x0F, cgapos/2 & 0xFF);
93         CGASCREENBASE[cgapos+1] = Attr;
94 }
95
96 static void
97 cgascreenputc(Rune c)
98 {
99         int i;
100         uchar *p;
101
102         if(c == '\0')
103                 return;
104         else if(c == '\n'){
105                 cgapos = cgapos/Width;
106                 cgapos = (cgapos+1)*Width;
107         }
108         else if(c == '\t'){
109                 i = 8 - ((cgapos/2)&7);
110                 while(i-->0)
111                         cgascreenputc(' ');
112         }
113         else if(c == '\b'){
114                 if(cgapos >= 2)
115                         cgapos -= 2;
116                 cgascreenputc(' ');
117                 cgapos -= 2;
118         }
119         else{
120                 for(i=0; i<nelem(cp437); i++)
121                         if(cp437[i] == c)
122                                 break;
123                 if(i == nelem(cp437))
124                         i = 0xfe; /* peter */
125                 CGASCREENBASE[cgapos++] = i;
126                 CGASCREENBASE[cgapos++] = Attr;
127         }
128         if(cgapos >= Width*Height){
129                 memmove(CGASCREENBASE, &CGASCREENBASE[Width], Width*(Height-1));
130                 p = &CGASCREENBASE[Width*(Height-1)];
131                 for(i=0; i<Width/2; i++){
132                         *p++ = ' ';
133                         *p++ = Attr;
134                 }
135                 cgapos = Width*(Height-1);
136         }
137         movecursor();
138 }
139
140 static void
141 cgascreenputs(char* s, int n)
142 {
143         static char rb[UTFmax];
144         static int nrb;
145         char *e;
146         Rune r;
147
148         if(!islo()){
149                 /*
150                  * Don't deadlock trying to
151                  * print in an interrupt.
152                  */
153                 if(!canlock(&cgascreenlock))
154                         return;
155         }
156         else
157                 lock(&cgascreenlock);
158
159         e = s + n;
160         while(s < e){
161                 rb[nrb++] = *s++;
162                 if(nrb >= UTFmax || fullrune(rb, nrb)){
163                         chartorune(&r, rb);
164                         cgascreenputc(r);
165                         nrb = 0;
166                 }
167         }
168
169         unlock(&cgascreenlock);
170 }
171
172 static void
173 cgatokmesg(void)
174 {
175         int i, n;
176         char *p;
177
178         ilock(&kmesg.lk);
179         n = kmesg.n;
180         for(i = cgapos-2; i >= 0 && n < sizeof kmesg.buf-UTFmax-1; i -= 2){
181                 if((i % Width) == Width-2)
182                         n++;
183                 n += runelen(cp437[CGASCREENBASE[i]]);
184         }
185         n -= kmesg.n;
186         if(n > 0){
187                 memmove(kmesg.buf+n, kmesg.buf, kmesg.n);
188                 kmesg.n += n;
189                 p = kmesg.buf;
190                 for(i += 2; i >= 0 && i < cgapos && p < kmesg.buf+n; i += 2){
191                         p += runetochar(p, &cp437[CGASCREENBASE[i]]);
192                         if((i % Width) == Width-2)
193                                 *p++ = '\n';
194                 }
195         }
196         iunlock(&kmesg.lk);
197 }
198
199 void
200 screeninit(void)
201 {
202         static int once;
203
204         cgapos = cgaregr(0x0E)<<8;
205         cgapos |= cgaregr(0x0F);
206         cgapos *= 2;
207
208         if(cgapos >= Width*Height){
209                 cgapos = 0;
210                 movecursor();
211         }
212
213         if(once == 0){
214                 once = 1;
215                 cgatokmesg();
216         }
217
218         screenputs = cgascreenputs;
219 }