16 static ulong screenchan;
18 static int picw, pich, hbytes;
19 static Image *img, *bg;
21 static Rectangle picr;
22 Channel *kbdch, *mousech;
26 typedef struct VGA VGA;
30 u8int aidx; /* bit 7: access flipflop */
31 u16int rdidx, wdidx; /* bit 0-1: color */
39 .attr { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
42 0x000000ff, 0x0000a8ff, 0x00a800ff, 0x00a8a8ff, 0xa80000ff, 0xa800a8ff, 0xa85400ff, 0xa8a8a8ff,
43 0x545454ff, 0x5454fcff, 0x54fc54ff, 0x54fcfcff, 0xfc5454ff, 0xfc54fcff, 0xfcfc54ff, 0xfcfcfcff,
44 0x000000ff, 0x141414ff, 0x202020ff, 0x2c2c2cff, 0x383838ff, 0x444444ff, 0x505050ff, 0x606060ff,
45 0x707070ff, 0x808080ff, 0x909090ff, 0xa0a0a0ff, 0xb4b4b4ff, 0xc8c8c8ff, 0xe0e0e0ff, 0xfcfcfcff,
46 0x0000fcff, 0x4000fcff, 0x7c00fcff, 0xbc00fcff, 0xfc00fcff, 0xfc00bcff, 0xfc007cff, 0xfc0040ff,
47 0xfc0000ff, 0xfc4000ff, 0xfc7c00ff, 0xfcbc00ff, 0xfcfc00ff, 0xbcfc00ff, 0x7cfc00ff, 0x40fc00ff,
48 0x00fc00ff, 0x00fc40ff, 0x00fc7cff, 0x00fcbcff, 0x00fcfcff, 0x00bcfcff, 0x007cfcff, 0x0040fcff,
49 0x7c7cfcff, 0x9c7cfcff, 0xbc7cfcff, 0xdc7cfcff, 0xfc7cfcff, 0xfc7cdcff, 0xfc7cbcff, 0xfc7c9cff,
50 0xfc7c7cff, 0xfc9c7cff, 0xfcbc7cff, 0xfcdc7cff, 0xfcfc7cff, 0xdcfc7cff, 0xbcfc7cff, 0x9cfc7cff,
51 0x7cfc7cff, 0x7cfc9cff, 0x7cfcbcff, 0x7cfcdcff, 0x7cfcfcff, 0x7cdcfcff, 0x7cbcfcff, 0x7c9cfcff,
52 0xb4b4fcff, 0xc4b4fcff, 0xd8b4fcff, 0xe8b4fcff, 0xfcb4fcff, 0xfcb4e8ff, 0xfcb4d8ff, 0xfcb4c4ff,
53 0xfcb4b4ff, 0xfcc4b4ff, 0xfcd8b4ff, 0xfce8b4ff, 0xfcfcb4ff, 0xe8fcb4ff, 0xd8fcb4ff, 0xc4fcb4ff,
54 0xb4fcb4ff, 0xb4fcc4ff, 0xb4fcd8ff, 0xb4fce8ff, 0xb4fcfcff, 0xb4e8fcff, 0xb4d8fcff, 0xb4c4fcff,
55 0x000070ff, 0x1c0070ff, 0x380070ff, 0x540070ff, 0x700070ff, 0x700054ff, 0x700038ff, 0x70001cff,
56 0x700000ff, 0x701c00ff, 0x703800ff, 0x705400ff, 0x707000ff, 0x547000ff, 0x387000ff, 0x1c7000ff,
57 0x007000ff, 0x00701cff, 0x007038ff, 0x007054ff, 0x007070ff, 0x005470ff, 0x003870ff, 0x001c70ff,
58 0x383870ff, 0x443870ff, 0x543870ff, 0x603870ff, 0x703870ff, 0x703860ff, 0x703854ff, 0x703844ff,
59 0x703838ff, 0x704438ff, 0x705438ff, 0x706038ff, 0x707038ff, 0x607038ff, 0x547038ff, 0x447038ff,
60 0x387038ff, 0x387044ff, 0x387054ff, 0x387060ff, 0x387070ff, 0x386070ff, 0x385470ff, 0x384470ff,
61 0x505070ff, 0x585070ff, 0x605070ff, 0x685070ff, 0x705070ff, 0x705068ff, 0x705060ff, 0x705058ff,
62 0x705050ff, 0x705850ff, 0x706050ff, 0x706850ff, 0x707050ff, 0x687050ff, 0x607050ff, 0x587050ff,
63 0x507050ff, 0x507058ff, 0x507060ff, 0x507068ff, 0x507070ff, 0x506870ff, 0x506070ff, 0x505870ff,
64 0x000040ff, 0x100040ff, 0x200040ff, 0x300040ff, 0x400040ff, 0x400030ff, 0x400020ff, 0x400010ff,
65 0x400000ff, 0x401000ff, 0x402000ff, 0x403000ff, 0x404000ff, 0x304000ff, 0x204000ff, 0x104000ff,
66 0x004000ff, 0x004010ff, 0x004020ff, 0x004030ff, 0x004040ff, 0x003040ff, 0x002040ff, 0x001040ff,
67 0x202040ff, 0x282040ff, 0x302040ff, 0x382040ff, 0x402040ff, 0x402038ff, 0x402030ff, 0x402028ff,
68 0x402020ff, 0x402820ff, 0x403020ff, 0x403820ff, 0x404020ff, 0x384020ff, 0x304020ff, 0x284020ff,
69 0x204020ff, 0x204028ff, 0x204030ff, 0x204038ff, 0x204040ff, 0x203840ff, 0x203040ff, 0x202840ff,
70 0x2c2c40ff, 0x302c40ff, 0x342c40ff, 0x3c2c40ff, 0x402c40ff, 0x402c3cff, 0x402c34ff, 0x402c30ff,
71 0x402c2cff, 0x40302cff, 0x40342cff, 0x403c2cff, 0x40402cff, 0x3c402cff, 0x34402cff, 0x30402cff,
72 0x2c402cff, 0x2c4030ff, 0x2c4034ff, 0x2c403cff, 0x2c4040ff, 0x2c3c40ff, 0x2c3440ff, 0x2c3040ff,
73 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
78 newpal(int l, int n, int dofree)
84 freeimage(vga.col[l]);
85 vga.col[l] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, vga.pal[l]);
87 for(l = 0; l < 16; l++){
88 x = vga.attr[0x14] << 4 & 0xc0 | vga.attr[l] & 0x3f;
89 if((vga.attr[0x10] & 0x80) != 0)
90 x = x & 0xcf | vga.attr[0x14] << 4 & 0x30;
91 vga.acol[l] = vga.col[x];
100 p = divpt(addpt(screen->r.min, screen->r.max), 2);
101 picr = (Rectangle){subpt(p, Pt(picw/2, pich/2)), addpt(p, Pt((picw+1)/2, (pich+1)/2))};
102 bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
103 img = allocimage(display, Rect(0, 0, picw, pich), screenchan == 0 ? screen->chan : screenchan, 0, 0);
104 draw(screen, screen->r, bg, nil, ZP);
109 vgaio(int isin, u16int port, u32int val, int sz, void *)
113 iowhine(isin, port, val, sz, "vga");
114 if(sz != 1) vmdebug("vga: non-byte access to port %#ux, sz=%d", port, sz);
116 switch(isin << 16 | port){
118 if((vga.aidx & 0x80) != 0){
119 vmdebug("vga: attribute write %#.2x = %#.2x", vga.aidx & 0x1f, val);
120 vga.attr[vga.aidx & 0x1f] = val;
123 vga.aidx = val & 0x3f;
126 case 0x3c2: vga.miscout = val; return 0;
127 case 0x3c7: vga.rdidx = val << 2; return 0;
128 case 0x3c8: vga.wdidx = val << 2; return 0;
130 vga.pal[vga.wdidx >> 2] = vga.pal[vga.wdidx >> 2] & ~(0xff << (~vga.wdidx << 3 & 24)) | val << 2 + (~vga.wdidx << 3 & 24);
131 newpal(vga.wdidx >> 2, 1, 1);
132 vga.wdidx = vga.wdidx + 1 + (vga.wdidx >> 1 & 1) & 0x3ff;
134 case 0x3d4: vga.cidx = val; return 0;
137 case 10: case 11: case 12: case 13: case 14: case 15:
138 vga.crtc[vga.cidx] = val;
141 vmerror("write to unknown VGA register, 3d5/%#ux (val=%#ux)", vga.cidx, val);
144 case 0x103c0: return vga.aidx & 0x3f;
145 case 0x103c1: return vga.attr[vga.aidx & 0x1f];
146 case 0x103c7: return vga.rdidx >> 2;
147 case 0x103c8: return vga.wdidx >> 2;
149 m = vga.pal[vga.rdidx >> 2] >> (~vga.rdidx << 3 & 24) + 2;
150 vga.rdidx = vga.rdidx + 1 + (vga.rdidx >> 1 & 1) & 0x3ff;
152 case 0x103cc: return vga.miscout;
153 case 0x103d4: return vga.cidx;
156 case 10: case 11: case 12: case 13: case 14: case 15:
157 return vga.crtc[vga.cidx];
159 vmerror("read from unknown VGA register, 3d5/%#ux", vga.cidx);
166 return iowhine(isin, port, val, sz, "vga");
169 typedef struct Key Key;
178 defkey(Rune r, int code)
182 for(kp = &kbdmap[r % nelem(kbdmap)]; *kp != nil; kp = &(*kp)->next)
185 k = emalloc(sizeof(Key));
199 defkey(Kshift, 0x2a);
203 defkey(Kprint, 0x137);
204 defkey(Kaltgr, 0x138);
205 defkey(Kbreak, 0x146);
206 defkey(Khome, 0x147);
208 defkey(Kpgup, 0x149);
209 defkey(Kleft, 0x14b);
210 defkey(Kright, 0x14d);
212 defkey(Kdown, 0x150);
213 defkey(Kpgdown, 0x151);
218 bp = Bopen(fn, OREAD);
220 vmerror("kbdlayout: %r");
224 s = Brdstr(bp, '\n', 1);
226 nf = getfields(s, f, nelem(f), 1, " \t");
228 x = strtol(f[0], &p, 0);
229 if(*p != 0) continue;
230 y = strtol(f[1], &p, 0);
231 if(*p != 0) continue;
232 if(*f[2] == '\'' || *f[2] == '^'){
233 chartorune(&z, f[2]+1);
234 if(*f[2] == '^') z -= '@';
236 z = strtol(f[2], &p, 0);
237 if(*p != 0) continue;
240 if(x != 0 || z == 0) continue;
250 static char buf[256];
251 static uvlong kdown[8], nkdown[8];
258 threadsetname("keyproc");
259 fd = open("/dev/kbd", OREAD);
261 sysfatal("open: %r");
265 memmove(buf, buf+n, sizeof(buf)-n);
268 n = read(fd, buf, sizeof(buf)-1);
270 sysfatal("read /dev/kbd: %r");
274 if(buf[0] != 'k' && buf[0] != 'K')
277 memset(nkdown, 0, sizeof(nkdown));
279 s += chartorune(&r, s);
280 for(k = kbdmap[r % nelem(kbdmap)]; k != nil; k = k->next)
282 nkdown[k->code >> 6] |= 1ULL<<(k->code&63);
285 if(k == nil) vmerror("unknown key %d", r);
287 if(mousegrab && (nkdown[0]>>29 & 1) != 0 && (nkdown[0]>>56 & 1) != 0){
291 for(i = 0; i < 8; i++){
292 if(nkdown[i] == kdown[i]) continue;
293 set = nkdown[i] & ~kdown[i];
294 rls = ~nkdown[i] & kdown[i];
295 for(j = 0; j < 64; j++, set>>=1, rls >>= 1)
296 if(((set|rls) & 1) != 0){
299 sendul(kbdch, j | i<<6&0xff | ((rls&1) != 0 ? 0x80 : 0));
300 sendnotif(i8042kick, nil);
302 kdown[i] = nkdown[i];
322 {mc->c, &m, CHANRCV},
323 {mousech, &mm, gotm ? CHANSND : CHANNOP},
329 mid = divpt(addpt(picr.max, picr.min), 2);
330 grabout = insetrect(Rpt(mid, mid), -50);
331 if(!ptinrect(m.xy, picr)){
336 if(clicked && (m.buttons & 1) == 0 && !textmode){
338 setcursor(mc, &blank);
340 clicked = m.buttons & 1;
344 if(!ptinrect(m.xy, grabout)){
349 mm.xy = addpt(mm.xy, subpt(m.xy, om.xy));
351 mm.buttons = m.buttons;
354 sendnotif(i8042kick, nil);
362 static Rune cp437[256] = {
363 0x0020, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
364 0x25ba, 0x25c4, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
365 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
366 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
367 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
368 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
369 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
370 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
371 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
372 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
373 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
374 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
375 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
376 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
377 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
378 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0,
389 static uchar rbuf[80*25*2];
392 sa = vga.crtc[12] << 8 | vga.crtc[13];
393 if(sa + 80*25 >= 0x10000){
394 memset(rbuf, 0, sizeof(rbuf));
395 memmove(rbuf, fb + sa * 2, 0x10000 - 80*25 - sa);
399 for(y = 0; y < 25; y++){
400 for(x = 0; x < 80; x++)
401 buf[x] = cp437[p[2*x]];
402 for(x = 0; x < 80; x = x1){
404 for(x1 = x; x1 < 80 && p[2*x1+1] == attr; x1++)
406 r = Rect(x * 8, y * 16, x1 * 8, (y + 1) * 16);
407 draw(img, r, vga.acol[attr >> 4], nil, ZP);
408 runestringn(img, r.min, vga.acol[attr & 0xf], ZP, display->defaultfont, buf + x, x1 - x);
412 cp = (vga.crtc[14] << 8 | vga.crtc[15]);
413 if(cp >= sa && cp < sa + 80*25 && (vga.crtc[10] & 0x20) == 0){
414 buf[0] = cp437[fb[cp*2]];
416 r.min = Pt((cp - sa) % 80 * 8, (cp - sa) / 80 * 16);
417 r.max = Pt(r.min.x + 8, r.min.y + (vga.crtc[11] & 0x1f) + 1);
418 r.min.y += vga.crtc[10] & 0x1f;
419 draw(img, r, vga.acol[attr & 0xf], nil, ZP);
421 draw(screen, picr, img, nil, ZP);
422 flushimage(display, 1);
434 upd.min.y = upd.max.y = -1;
437 while(p < (u32int*)(fb + fbsz)){
439 if(upd.min.y < 0) upd.min.y = y;
440 upd.max.y = y + 1 + (xb + 4 > hbytes);
451 if(upd.min.y == upd.max.y) return;
454 if(screenchan != screen->chan){
455 loadimage(img, upd, sfb + upd.min.y * hbytes, (upd.max.y - upd.min.y) * hbytes);
456 draw(screen, rectaddpt(upd, picr.min), img, nil, upd.min);
458 loadimage(screen, rectaddpt(upd, picr.min), sfb + upd.min.y * hbytes, (upd.max.y - upd.min.y) * hbytes);
459 flushimage(display, 1);
467 threadsetname("draw");
470 while(nbrecv(mc->resizec, &ul) > 0){
471 if(getwindow(display, Refnone) < 0)
472 sysfatal("resize failed: %r");
483 vgafbparse(char *fbstring)
489 if(picw != 0) sysfatal("vga specified twice");
490 if(strcmp(fbstring, "text") == 0){
498 strecpy(buf, buf + nelem(buf), fbstring);
499 picw = strtol(buf, &p, 10);
502 sysfatal("vgafbparse: invalid framebuffer specifier: %#q (should be WxHxCHAN@ADDR or 'text')", fbstring);
503 pich = strtol(p+1, &p, 10);
504 if(*p != 'x') goto nope;
505 q = strchr(p+1, '@');
506 if(q == nil) goto nope;
508 screenchan = strtochan(p+1);
509 if(screenchan == 0) goto nope;
511 if(*p == 0) goto nope;
512 addr = strtoull(p, &p, 0);
514 if(fbaddr != addr) goto nope;
515 if(*p != 0) goto nope;
516 hbytes = chantodepth(screenchan) * picw + 7 >> 3;
517 fbsz = hbytes * pich;
527 if(picw == 0) return;
528 fb = gptr(fbaddr, fbsz);
530 sysfatal("got nil ptr for framebuffer");
532 for(i = 0; i < 0x8000; i += 2)
533 PUT16(fb, i, 0x0700);
534 snprint(buf, sizeof(buf), "-dx %d -dy %d", picw+50, pich+50);
536 initdraw(nil, nil, "vmx");
538 flushimage(display, 1);
539 kbdlayout("/sys/lib/kbmap/us");
540 mc = initmouse(nil, screen);
541 kbdch = chancreate(sizeof(ulong), 128);
542 mousech = chancreate(sizeof(Mouse), 32);
543 proccreate(mousethread, nil, 4096);
544 proccreate(keyproc, nil, 4096);
545 proccreate(drawproc, nil, 4096);