--- /dev/null
+#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, ®s, ®s);
+ 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, ®s, ®s);
+ 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, ®s, ®s);
+ 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);
+}