foo
[eightysix] / kern / src / vid.c
diff --git a/kern/src/vid.c b/kern/src/vid.c
new file mode 100644 (file)
index 0000000..f4eb723
--- /dev/null
@@ -0,0 +1,255 @@
+#include <string.h>
+#include "vid.h"
+#include "asmutil.h"
+
+#define CRTC_ADDR_PORT (iobase | 4)
+#define CRTC_DATA_PORT (iobase | 5)
+
+/* CRTC registers */
+#define CRTC_START_H   0x0c
+#define CRTC_START_L   0x0d
+#define CRTC_CURPOS_H  0x0e
+#define CRTC_CURPOS_L  0x0f
+
+static void detect_video(void);
+static int detect_vgainfo(void);
+static int detect_egainfo(void);
+static void detect_eqlist(void);
+static void crtc_write(int reg, unsigned char val);
+
+//struct console con_vid = { con_clear, con_putc, 0 };
+
+static uint16_t __far *vmem;
+static int iobase;
+
+static uint16_t cur_attr;
+static int cur_x, cur_y;
+static int cur_scroll;
+static int mono;
+
+void vid_init(void)
+{
+       detect_video();
+       if(mono) {
+               vmem = MK_FP(0xb000, 0);
+               iobase = 0x3b0;
+       } else {
+               vmem = MK_FP(0xb800, 0);
+               iobase = 0x3d0;
+       }
+
+       vid_reset();
+}
+
+static void detect_video(void)
+{
+       mono = 0;
+       vid_type = VID_UNK;
+
+       if(detect_vgainfo() == 0) {
+               return;
+       }
+       if(detect_egainfo() == 0) {
+               return;
+       }
+       detect_eqlist();
+}
+
+static int detect_vgainfo(void)
+{
+       union regs regs;
+
+       regs.w.ax = 0x1a00;
+       int86(0x10, &regs, &regs);
+       if(regs.h.al != 0x1a) {
+               return -1;
+       }
+
+       switch(regs.h.bl) {
+       case 1:
+               vid_type = VID_MDA;
+               mono = 1;
+               break;
+       case 2:
+               vid_type = VID_CGA;
+               break;
+       case 4:
+               vid_type = VID_EGA;
+               break;
+       case 5:
+               vid_type = VID_EGA;
+               mono = 1;
+               break;
+       case 6:
+               vid_type = VID_PGA;
+               break;
+       case 7:
+               vid_type = VID_VGA;
+               mono = 1;
+               break;
+       case 8:
+               vid_type = VID_VGA;
+               break;
+       case 0xa:
+       case 0xc:
+               vid_type = VID_MCGA;
+               break;
+       case 0xb:
+               vid_type = VID_MCGA;
+               mono = 1;
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+}
+
+static int detect_egainfo(void)
+{
+       union regs regs;
+
+       regs.w.ax = 0x1200;
+       regs.w.bx = 0xff10;
+       int86(0x10, &regs, &regs);
+       if(regs.h.bh == 0xff) {
+               return -1;
+       }
+
+       vid_type = VID_EGA;
+       mono = regs.h.bh;
+       return 0;
+}
+
+static void detect_eqlist(void)
+{
+       union regs regs;
+
+       int86(0x11, &regs, &regs);
+       switch(regs.w.ax & 0x30) {
+       case 0:
+               vid_type = VID_EGA;
+               break;
+
+       case 0x10:
+       case 0x20:
+               vid_type = VID_CGA;
+               break;
+
+       case 0x30:
+               vid_type = VID_MDA;
+               mono = 1;
+               break;
+       }
+}
+
+void vid_reset(void)
+{
+       vid_fgcolor(WHITE);
+       vid_bgcolor(BLACK);
+       vid_scroll(0);
+       vid_setcursor(0, 0);
+       fmemset(vmem, 0, 80 * 25 * 2);
+}
+
+void vid_clearline(int row)
+{
+       int i;
+       uint16_t __far *ptr;
+
+       row += cur_scroll;
+
+       ptr = vmem + row * 80;
+       for(i=0; i<80; i++) {
+               ptr[i] = cur_attr;
+       }
+
+       if(row - 32 >= 0) {
+               /* write a copy to wrap-around future scrolling */
+               ptr -= 80 * 32;
+               for(i=0; i<80; i++) {
+                       ptr[i] = cur_attr;
+               }
+       }
+}
+
+void vid_clear(void)
+{
+       int i;
+       for(i=0; i<25; i++) {
+               vid_clearline(i);
+       }
+}
+
+void vid_scroll(int line)
+{
+       int offs;
+       cur_scroll = line & 0x1f;
+       offs = cur_scroll * 80;
+       crtc_write(CRTC_START_H, offs >> 8);
+       crtc_write(CRTC_START_L, offs);
+}
+
+void vid_setcursor(int x, int y)
+{
+       int loc = (y + cur_scroll) * 80 + x;
+       cur_x = x;
+       cur_y = y;
+       crtc_write(CRTC_CURPOS_H, loc >> 8);
+       crtc_write(CRTC_CURPOS_L, loc);
+}
+
+void vid_fgcolor(int color)
+{
+       cur_attr = (cur_attr & 0xf0) | color;
+}
+
+void vid_bgcolor(int color)
+{
+       cur_attr = (cur_attr & 0x0f) | (color << 4);
+}
+
+void vid_glyph(int x, int y, int c, int attr)
+{
+       uint16_t __far *ptr;
+       uint16_t val = (c & 0xff) | attr;
+
+       y += cur_scroll;
+
+       ptr = vmem + y * 80 + x;
+       *ptr = val;
+
+       if(y - 32 >= 0) {
+               /* write a copy to wrap-around future scrolling */
+               ptr -= 80 * 32;
+               *ptr = val;
+       }
+}
+
+void vid_text(int x, int y, const char *s, int attr)
+{
+       int len = 0;
+       uint16_t __far *ptr;
+
+       y += cur_scroll;
+
+       ptr = vmem + y * 80 + x;
+       while(*s) {
+               *ptr++ = (*s++ & 0xff) | attr;
+               len++;
+       }
+
+       if(y - 32 >= 0) {
+               /* write a copy to wrap-around future scrolling */
+               ptr -= 80 * 32 + len;
+               s -= len;
+               while(*s) {
+                       *ptr++ = (*s++ & 0xff) | attr;
+               }
+       }
+}
+
+static void crtc_write(int reg, unsigned char val)
+{
+       outp(CRTC_ADDR_PORT, reg);
+       outp(CRTC_DATA_PORT, val);
+}