8 static uchar vesabios[512] = {
9 0x55, 0xaa, 0x01, 0xcb, 0x60, 0x1e, 0x06, 0x8c, 0xd0, 0xba, 0xe0, 0xfe, 0xef, 0x89, 0xe0, 0xba, 0xe1, 0xfe, 0xef, 0xba, 0xe2, 0xfe, 0xed, 0x85, 0xc0, 0x7c, 0x28, 0x50, 0x25, 0x00,
10 0xf0, 0x8e, 0xc0, 0xba, 0xe3, 0xfe, 0xed, 0x89, 0xc6, 0xc3, 0x26, 0x8b, 0x04, 0xba, 0xe4, 0xfe, 0xef, 0xeb, 0xe2, 0xba, 0xe4, 0xfe, 0xed, 0x26, 0x89, 0x04, 0xeb, 0xd9, 0xba, 0xe4,
11 0xfe, 0xed, 0x26, 0x88, 0x04, 0xeb, 0xd0, 0x58, 0x58, 0x61, 0xcf,
18 typedef struct VESAIO VESAIO;
23 Channel *vesawchan, *vesarchan;
24 typedef struct Ureg16 Ureg16;
26 u16int ax, bx, cx, dx;
30 #define ESDI(u) ((u).di + ((u).es<<4))
31 typedef struct Vesa Vesa;
34 u32int oemstring, oemvendor, oemproduct, oemproductrev;
38 #define FARPTR(x) (((x)&0xf0000)<<12|(u16int)(x))
39 extern VgaMode *modes, **modeslast, *curmode, *nextmode, textmode;
40 extern int curhbytes, nexthbytes;
41 extern uintptr fbaddr, fbsz;
42 extern int maxw, maxh;
43 enum { CMAP4 = CHAN1(CMap, 4) };
51 for(p = modes; p != nil; p = p->next)
64 while(recv(vesarchan, &io), io.port != 0)
65 sendul(vesawchan, -1);
67 sendul(vesawchan, -1);
69 sendul(vesawchan, -1);
70 if(io.port != 1) goto loop;
75 vesawrite(int addr, u32int val, int sz)
79 assert(sz == 1 || sz == 2 || sz == 4);
82 no: sendul(vesawchan, -1);
85 sendul(vesawchan, (sz > 1 ? WRITEWCMD : WRITEBCMD) | addr >> 4 & 0xf000);
87 if(io.port != 0x13) goto no;
88 sendul(vesawchan, addr);
90 if(io.port != 0x14) goto no;
91 sendul(vesawchan, val);
93 return vesawrite(addr + 2, val >> 16, 2);
102 recv(vesarchan, &io);
104 no: sendul(vesawchan, -1);
107 sendul(vesawchan, READCMD);
108 recv(vesarchan, &io);
109 if(io.port != 0x13) goto no;
110 sendul(vesawchan, addr);
111 recv(vesarchan, &io);
112 if(io.port != 0x4) goto no;
113 sendul(vesawchan, -1);
118 vesaregs(u32int sp, Ureg16 *ur)
121 #define R(n, a) rc = vesaread(sp + n); if(rc < 0) return -1; ur->a = rc
123 memset(ur, 0, sizeof(*ur));
138 vesasetregs(u32int sp, Ureg16 *ur)
140 #define R(n, a) if(vesawrite(sp + n, ur->a, 2) < 0) return -1;
155 #define vesasetax(sp, val) vesawrite(sp+18, val, 2)
156 #define vesasetbx(sp, val) vesawrite(sp+12, val, 2)
159 vesapack(int addr, char *fmt, ...)
162 static u8int checksum;
167 if(addr < 0) return -1;
170 for(; *fmt != 0; fmt++)
173 case 'b': v = va_arg(va, int); if(vesawrite(addr, v, 1) < 0) return -1; addr += 1; checksum += v; break;
174 case 'w': v = va_arg(va, int); if(vesawrite(addr, v, 2) < 0) return -1; addr += 2; checksum += v + (v >> 8); break;
175 case 'd': v = va_arg(va, int); if(vesawrite(addr, v, 4) < 0) return -1; addr += 4; checksum += v + (v >> 8) + (v >> 16) + (v >> 24); break;
177 p = va_arg(va, char *);
178 for(; *p != 0; p++, addr++){
179 if(vesawrite(addr, *p, 1) < 0)
185 p = va_arg(va, char *);
188 if(vesawrite(addr++, *p, 1) < 0)
193 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
194 numb = strtol(fmt, &fmt, 10);
198 for(; numb >= 2; numb -= 2, addr += 2)
199 if(vesawrite(addr, 0, 2) < 0) return -1;
201 if(vesawrite(addr++, 0, 1) < 0) return -1;
205 case 'c': if(vesawrite(addr, -checksum, 1) < 0) return -1; addr += 1; break;
206 case 'C': checksum = 0; break;
207 default: vmerror("vesapack: unknown char %c", *fmt); return -1;
214 vesarompack(char *fmt, ...)
221 v0 = gptr(vesa.romptr, 0x8000);
225 for(; *fmt != 0; fmt++)
227 case 'b': *(u8int*)v = va_arg(va, int); v++; break;
228 case 'w': *(u16int*)v = va_arg(va, int); v += 2; break;
229 case 'd': *(u32int*)v = va_arg(va, int); v += 4; break;
230 case 'a': v = (uchar*)strecpy((char*)v, (char*)v + 0x8000, va_arg(va, char*)); *v++ = 0; break;
231 case 'S': s = va_arg(va, void *); x = va_arg(va, int); memcpy(v, s, x); v += x; break;
232 default: sysfatal("vesarompack: unknown char %c", *fmt);
236 vesa.romptr += v - v0;
241 vesamodeget(int addr, u16int mode, u16int *retv)
245 u8int nred, pred, ngreen, pgreen, nblue, pblue, nx, px;
250 vmerror("vesa: Return VBE Mode Information: unknown mode %#x", mode);
256 nred = pred = ngreen = pgreen = 0;
257 nblue = pblue = nx = px = 0;
259 for(i = 0; i < 4; i++){
260 s = p->chan >> 8 * i & 15;
262 switch(p->chan >> 8 * i + 4 & 15){
263 case CRed: nred = s; pred = pos; break;
264 case CGreen: ngreen = s; pgreen = pos; break;
265 case CBlue: nblue = s; pblue = pos; break;
266 case CAlpha: case CIgnore: nx = s; px = pos; break;
267 case CMap: model = 4; break;
271 return vesapack(addr, "wbbwwwwdw wwbbbbbbbbb bbbbbbbbb ddw wbbbbb bbbbbd 189f",
272 1<<0|1<<1|1<<3|1<<4|1<<5|1<<6|1<<7, /* attributes: color graphics, vga incompatible, linear framebuffer */
273 0, 0, 0, 0, 0, 0, 0, p->hbytes, /* windowing crap */
275 0, 0, /* character size */
276 1, chantodepth(p->chan), 1, /* 1 bank, 1 plane, N bpp */
277 model, /* memory model */
278 0, 0, 1, /* no banking/paging */
279 nred, pred, ngreen, pgreen, nblue, pblue, nx, px, /* masks */
280 0, /* no ramp, reserved bits are reserved */
284 nred, pred, ngreen, pgreen, nblue, pblue, nx, px, /* masks */
285 p->w * p->h * 60 * 2 /* max pixelclock */);
289 vesamodeset(u16int mode, u16int *retv)
296 nextmode = &textmode;
301 vmerror("vesa: Set VBE Mode: unknown mode %#x", mode);
307 nexthbytes = p->hbytes;
313 vesalinelen(Ureg16 *ur)
318 d = chantodepth(nextmode->chan);
319 if(nextmode == &textmode || d == 0) goto fail;
320 switch(ur->bx & 0xff){
322 nhb = d * ur->cx / 8;
325 vmerror("vesa: set logical length unsupported on bitdepth < 8");
326 fail: ur->ax = 0x014F;
329 if(nhb * nextmode->h > fbsz){
336 ur->cx = nhb * 8 / d;
342 ur->cx = nexthbytes * 8 / d;
343 ur->dx = fbsz / nexthbytes;
349 x = fbsz / nextmode->h;
353 ur->dx = nextmode->h;
356 vmerror("vesa: unsupported subfunction %#x of SetGetLogicalLineLength", ur->bx & 0xff);
362 vesapalformat(Ureg16 *ur)
364 switch(ur->bx & 0xff){
366 vesa.pal8 = (ur->bx >> 8) >= 8;
369 ur->bx = vesa.pal8 ? 8 : 6;
372 vmerror("vesa: unsupported subfunction %#x of SetGetDACPaletteFormat", ur->bx & 0xff);
385 switch(ur->bx & 0xff){
388 if(ur->dx >= 256 || ur->cx > 256){
394 for(i = ur->dx; i < ur->dx + ur->cx; i++){
399 r = vesaread(addr + 2);
407 vgasetpal(i, r << 24 | g << 16 | b << 8 | 0xff);
412 if(ur->dx >= 256 || ur->cx > 256){
418 for(i = ur->dx; i < ur->dx + ur->cx; i++){
420 r = c >> 24; g = c >> 16; b = c >> 8;
426 addr = vesapack(addr, "bbbb", b, g, r, 0);
428 return addr >= 0 ? 0 : -1;
430 vmerror("vesa: unsupported subfunction %#x of SetGetPaletteData", ur->bx & 0xff);
436 stdtiming(u8int *arr)
443 for(m = modes; m != nil; m = m->next){
444 if(m->w < 256 || m->w > 2288 || m->w > maxw || m->h > maxh) continue;
445 if((m->w & 7) != 0) continue;
446 if(m->w == 640 && m->h == 480) continue;
447 if(m->w == 800 && m->h == 600) continue;
448 if(m->w == 1024 && m->h == 768) continue;
449 if(m->w == 1280 && m->h == 1024) continue;
450 if(m->w * 10 == m->w * 16)
452 else if(m->w * 3 == m->h * 4)
454 else if(m->w * 4 == m->h * 5)
456 else if(m->w * 9 == m->w * 16)
461 for(i = 0; i < 16; i += 2){
462 if(arr[i] == s1 && arr[i+1] == s2)
464 if(arr[i] == 1 && arr[i+1] == 1)
467 if(i == 16) skip: continue;
474 detailtiming(int addr, VgaMode **m)
476 u32int hv, hfp, hsp, hbp, hmm;
477 u32int vv, vfp, vsp, vbp, vmm;
482 return vesapack(addr, "d14f", 0x10000000);
483 /* when in doubt, make shit up */
489 vfp = (vv + 24) / 48;
490 vsp = (vv + 120) / 240;
492 freq = (hv + hfp + hsp + hbp) * (vv + vfp + vsp + vbp) * 60;
493 hmm = hv * 254 / 960; /* assume 96 dpi */
494 vmm = vv * 254 / 960;
497 if(hv > maxw || vv > maxh || hv > 0xfff || hfp > 0x3ff || hsp > 0x3ff || vfp > 63 || vsp > 63)
499 return vesapack(addr, "w bbbbbbbbbb bbbbb b",
501 hv, hbp, hv >> 4 & 0xf0 | hbp >> 8 & 0xf,
502 vv, vbp, vv >> 4 & 0xf0 | vbp >> 8 & 0xf,
504 vfp << 4 & 0xf0 | vsp & 0xf,
505 hfp >> 2 & 0xc0 | hsp >> 4 & 0x30 | vfp >> 2 & 0x0c | vsp >> 4 & 0x03,
507 hmm >> 4 & 0xf0 | vmm >> 8 & 0xf,
520 switch(ur->bx & 0xff){
532 if(maxw >= 640 && maxh >= 480) tim |= 0x3c;
533 if(maxw >= 800 && maxh >= 600) tim |= 0xc003;
534 if(maxw >= 1024 && maxh >= 768) tim |= 0xe00;
535 if(maxw >= 1280 && maxh >= 1024) tim |= 0x100;
536 addr = vesapack(addr, "Cdd bbbbdbb bb bbbbb bbbbb bbbbb wb S",
539 0x0c, 0x34, 0xa7, 0xac, /* manufacturer & product id */
540 1701, /* serial no */
541 0xff, 27, /* model year 2017 */
542 1, 4, /* edid version */
543 0xa1, /* DVI input */
544 maxw >= maxh ? maxw * 100 / maxh - 99 : 0, /* landscape aspect ratio */
545 maxw < maxh ? maxh * 100 / maxw - 99 : 0, /* portrait aspect ratio */
546 0x78, /* gamma=2.2 */
547 7, /* srgb & have preferred timing mode */
548 0, 0, 0, 0, 0, /* chromaticity coordinates */
553 addr = detailtiming(addr, &m);
554 addr = detailtiming(addr, &m);
555 addr = detailtiming(addr, &m);
556 addr = vesapack(addr, "3fbb bbbb bbbb bbbbb",
557 0xfd, 0xa, 1, 0xff, 1, 0xff, 0xff, 0x04, 0x11,
558 maxw >> 11 & 3, maxw >> 3, 0xf8, 0x18, 0, 60);
559 addr = vesapack(addr, "bc", 0);
560 if(addr < 0) return -1;
567 vmerror("vesa: unsupported subfunction %#x of VBE/DDC", ur->bx & 0xff);
580 // vmdebug("SP = %.8ux", sp);
581 if(vesaregs(sp, &ur) < 0) continue;
582 // vmdebug("AX = %.4x BX=%.4x CX=%.4x DX=%.4x", ur.ax, ur.bx, ur.cx, ur.dx);
583 // vmdebug("SI = %.4x DI=%.4x BP=%.4x", ur.si, ur.di, ur.bp);
584 // vmdebug("DS = %.4x ES=%.4x", ur.ds, ur.es);
587 if(vesapack(ESDI(ur), "swdddwwddd",
588 "VESA", /* VbeSignature */
589 0x0300, /* VbeVersion */
590 FARPTR(vesa.oemstring), /* OemStringPtr */
591 1, /* Capabilities (support 8 bit colors) */
592 FARPTR(vesa.modetab), /* VideoModePtr */
593 fbsz >> 16, /* TotalMemory */
594 0x100 /* OemSoftwareRev */,
595 FARPTR(vesa.oemvendor), /* OemVendorNamePtr */
596 FARPTR(vesa.oemproduct), /* OemProductNamePtr */
597 FARPTR(vesa.oemproductrev) /* OemProductRevPtr */) < 0)
599 if(vesasetax(sp, 0x004F) < 0) continue;
602 if(vesamodeget(ESDI(ur), ur.cx, &ur.ax) < 0) continue;
603 if(vesasetax(sp, ur.ax) < 0) continue;
606 if(vesamodeset(ur.bx, &ur.ax) < 0 || vesasetax(sp, ur.ax) < 0) continue;
609 if(vesasetax(sp, 0x004F) < 0) continue;
610 if(vesasetbx(sp, nextmode->no | 0x4000) < 0) continue;
613 if(vesalinelen(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
616 if(vesapalformat(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
619 if(vesapal(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
622 if(vesaddc(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
625 vmerror("vesa: unsupported function %#x", ur.ax);
631 addmode(int no, int x, int y, u32int chan)
635 vm = emalloc(sizeof(VgaMode));
640 vm->hbytes = chantodepth(chan) * vm->w + 7 >> 3;
641 vm->sz = vm->hbytes * y;
643 modeslast = &vm->next;
654 v = gptr(0xc0000, sizeof(vesabios));
655 if(v == nil) sysfatal("vesainit: gptr failed");
656 for(i = 0, c = 0; i < sizeof(vesabios) - 1; i++)
658 vesabios[sizeof(vesabios) - 1] = -c;
659 vesa.romptr = 0xc0000;
660 vesarompack("S", vesabios, sizeof(vesabios));
663 if(v == nil) sysfatal("vesainit: gptr failed");
664 PUT32(v, 0x40, 0xc0000004);
666 vesa.oemstring = vesarompack("a", "9front vmx(1)");
667 vesa.oemvendor = vesarompack("a", "9front");
668 vesa.oemproduct = vesarompack("a", "cat graphics adapter");
669 vesa.oemproductrev = vesarompack("a", "∞");
671 vesa.modetab = vesa.romptr;
673 for(p = modes; p != nil; p = p->next){
675 vesarompack("w", p->no);
677 vesarompack("w", 0xffff);
679 addmode(0x100, 640, 400, CMAP8);
680 addmode(0x101, 640, 480, CMAP8);
681 addmode(0x102, 800, 600, CMAP4);
682 addmode(0x6A, 800, 600, CMAP4);
683 addmode(0x103, 800, 600, CMAP8);
684 addmode(0x104, 1024, 768, CMAP4);
685 addmode(0x105, 1024, 768, CMAP8);
686 addmode(0x106, 1280, 1024, CMAP4);
687 addmode(0x107, 1280, 1024, CMAP8);
688 addmode(0x10D, 320, 200, RGB15);
689 addmode(0x10E, 320, 200, RGB16);
690 addmode(0x10F, 320, 200, RGB24);
691 addmode(0x110, 640, 480, RGB15);
692 addmode(0x111, 640, 480, RGB16);
693 addmode(0x112, 640, 480, RGB24);
694 addmode(0x113, 800, 600, RGB15);
695 addmode(0x114, 800, 600, RGB16);
696 addmode(0x115, 800, 600, RGB24);
697 addmode(0x116, 1024, 768, RGB15);
698 addmode(0x117, 1024, 768, RGB16);
699 addmode(0x118, 1024, 768, RGB24);
700 addmode(0x119, 1280, 1024, RGB15);
701 addmode(0x11A, 1280, 1024, RGB16);
702 addmode(0x11B, 1280, 1024, RGB24);
704 vesarchan = chancreate(sizeof(VESAIO), 0);
705 vesawchan = chancreate(sizeof(ulong), 0);
706 threadcreate(vesathread, nil, 8192);
710 vesaio(int isin, u16int port, u32int val, int sz, void *)
714 if(sz != 2) return iowhine(isin, port, val, sz, nil);
715 io.port = isin << 4 | port & 0xf;
717 send(vesarchan, &io);
718 return recvul(vesawchan);