X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fdos%2Fdrv_vbe.c;fp=src%2Fdos%2Fdrv_vbe.c;h=d6394177b070265815463e99cfe1e02ba331adac;hb=4e4ac855a9d53fd7dee3d640f3ab46740b991b5c;hp=0000000000000000000000000000000000000000;hpb=f87f51babcc2d9c15e1ecaca19c26acf58292bf7;p=retroray diff --git a/src/dos/drv_vbe.c b/src/dos/drv_vbe.c new file mode 100644 index 0000000..d639417 --- /dev/null +++ b/src/dos/drv_vbe.c @@ -0,0 +1,379 @@ +#include +#include +#include +#include "vidsys.h" +#include "drv.h" +#include "vbe.h" +#include "vga.h" +#include "cdpmi.h" + +#define farptr_to_linear(rmaddr) \ + ((((intptr_t)(rmaddr) >> 12) & 0xffff0) + ((intptr_t)(rmaddr) & 0xffff)) + +static int init(void); +static void cleanup(void); +static struct vid_modeinfo *find_mode(int mode); +static int setmode(int mode); +static int getmode(void); +static const char *memsize_str(long sz); +static int get_mode_info(int mode, struct vbe_mode_info *mi); +static int conv_vbeinfo(int mode, struct vid_modeinfo *mi, struct vbe_mode_info *vbemi); +static unsigned int calc_mask(int nbits, int pos); + +static void pack(uint32_t *pix, int r, int g, int b); +static void unpack(uint32_t pix, int *r, int *g, int *b); +static void clear(uint32_t color); +static void blitfb_lfb(void *fb, int pitch); +static void blitfb_banked(void *fb, int pitch); +static void flip(int vsync); + +static struct vid_driver drv; +static struct vid_drvops drvops = {init, cleanup, setmode, getmode}; +static unsigned int vbe_ver; + +static int cur_mode; +static struct vid_modeinfo *cur_mi; +static int cur_pgsize; + + +void vid_register_vbe(void) +{ + drv.name = "vbe"; + drv.prio = 2; + drv.ops = &drvops; + + vid_drvlist[vid_numdrv++] = &drv; +} + + +static int init(void) +{ + struct dpmi_regs regs = {0}; + struct vbe_info *vbe; + struct vbe_mode_info vbemi; + unsigned short bufseg; + uint16_t *vbe_modelist, *modelist; + int i, count; + struct vid_modeinfo modeinf; + + cur_mode = -1; + cur_mi = 0; + + vbe = dpmi_lowbuf(); + bufseg = (intptr_t)vbe >> 4; + + /* call VBE function 00 (get controller information) */ + memcpy(vbe->sig, "VBE2", 4); /* denote we want VBE 2.0 info */ + regs.eax = 0x4f00; + regs.es = bufseg; + dpmi_rmint(0x10, ®s); + if((regs.eax & 0xffff) != 0x4f || memcmp(vbe->sig, "VESA", 4) != 0) { + fprintf(stderr, "failed to get VBE controller information\n"); + return -1; + } + + vbe_ver = vbe->ver; + + printf("Found VBE %d.%d\n", VBE_VER_MAJOR(vbe_ver), VBE_VER_MINOR(vbe_ver)); + printf("OEM: %s\n", (char*)farptr_to_linear(vbe->oem_name)); + if(vbe_ver >= 0x0200) { + printf("%s - %s (%s)\n", (char*)farptr_to_linear(vbe->vendor), + (char*)farptr_to_linear(vbe->product), + (char*)farptr_to_linear(vbe->revstr)); + } + printf("Video RAM: %s\n", memsize_str((long)vbe->vmem_blk * 65536)); + + vbe_modelist = (uint16_t*)farptr_to_linear(vbe->modelist_addr); + count = 0; + for(i=0; i<1024; i++) { + if(vbe_modelist[i] == 0xffff) break; + count++; + } + + if(!(modelist = malloc(count * sizeof *modelist))) { + fprintf(stderr, "failed to allocate mode list\n"); + return -1; + } + for(i=0; ilfb) { + mode |= VBE_MODE_LFB; + } + +retry: + regs.eax = 0x4f02; + regs.ebx = mode; + dpmi_rmint(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + if(mode & VBE_MODE_LFB) { + mode &= ~VBE_MODE_LFB; + goto retry; + } + return -1; + } + cur_mode = mode; + + if(!(cur_mi = minf)) return 0; + + cur_pgsize = minf->height * minf->pitch; + + if(mode & VBE_MODE_LFB) { + minf->ops.blitfb = blitfb_lfb; + } else { + minf->ops.blitfb = blitfb_banked; + } + return 0; +} + +static int getmode(void) +{ + return cur_mode; +} + +static const char *memsize_str(long sz) +{ + static const char *suffix[] = {"bytes", "kb", "mb", "gb", 0}; + static int cnt = 0; + static char buf[64]; + + while(sz > 1024 && suffix[cnt + 1]) { + sz >>= 10; + cnt++; + } + + sprintf(buf, "%ld %s", sz, suffix[cnt]); + return buf; +} + +static int get_mode_info(int mode, struct vbe_mode_info *mi) +{ + struct dpmi_regs regs = {0}; + struct vbe_mode_info *miptr; + uint16_t bufseg; + + miptr = dpmi_lowbuf(); + bufseg = (intptr_t)miptr >> 4; + + regs.eax = 0x4f01; + regs.ecx = mode; + regs.es = bufseg; + dpmi_rmint(0x10, ®s); + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + + *mi = *miptr; + return 0; +} + +int vid_setwin(int wid, int pos) +{ + struct dpmi_regs regs = {0}; + + regs.eax = 0x4f05; + regs.ebx = wid; + regs.edx = pos; + dpmi_rmint(0x10, ®s); + if((regs.eax & 0xffff) != 0x4f) { + return -1; + } + return 0; +} + +static int conv_vbeinfo(int mode, struct vid_modeinfo *mi, struct vbe_mode_info *vbemi) +{ + static int gran_shift; + static const struct { int width, height, bpp; } stdmode[] = { + {640, 400, 8}, /* 100h */ + {640, 480, 8}, /* 101h */ + {800, 600, 4}, {800, 600, 8}, /* 102h - 103h */ + {1024, 768, 4}, {1024, 768, 8}, /* 104h - 105h */ + {1280, 1024, 4}, {1280, 1024, 8}, /* 106h - 107h */ + {80, 60, 4}, {132, 25, 4}, {132, 43, 4}, {132, 50, 4}, {132, 60, 4}, + {320, 200, 15}, {320, 200, 16}, {320, 200, 24}, /* 10dh - 10fh */ + {640, 480, 15}, {640, 480, 16}, {640, 480, 24}, /* 110h - 112h */ + {800, 600, 15}, {800, 600, 16}, {800, 600, 24}, /* 113h - 115h */ + {1024, 768, 15}, {1024, 768, 16}, {1024, 768, 24}, /* 116h - 118h */ + {1280, 1024, 15}, {1280, 1024, 16}, {1280, 1024, 24} /* 119h - 11bh */ + }; + + if(!(vbemi->attr & VBE_ATTR_AVAIL)) { + return -1; /* ignore unsupported modes */ + } + if(!(vbemi->attr & VBE_ATTR_GFX)) { + return -1; /* ignore text modes */ + } + if(vbemi->attr & VBE_ATTR_LFB) { + mi->lfb = 1; + } + + mi->drv = &drv; + mi->modeno = mode; + mi->vmem_addr = 0xa0000; + + if(vbe_ver >= 0x0102) { + mi->width = vbemi->xres; + mi->height = vbemi->yres; + mi->bpp = vbemi->bpp; + mi->rshift = vbemi->rpos; + mi->gshift = vbemi->gpos; + mi->bshift = vbemi->bpos; + mi->rmask = calc_mask(vbemi->rsize, vbemi->rpos); + mi->gmask = calc_mask(vbemi->gsize, vbemi->gpos); + mi->bmask = calc_mask(vbemi->bsize, vbemi->bpos); + mi->pages = vbemi->num_img_pages + 1; + + if(vbe_ver >= 0x0200) { + mi->vmem_addr = vbemi->fb_addr; + mi->vmem_size = vbemi->scanline_bytes * mi->height * mi->pages; + } + } else { + if((mode & 0xff) > 7) { + return -1; + } + mi->width = stdmode[mode & 0xff].width; + mi->height = stdmode[mode & 0xff].height; + mi->bpp = stdmode[mode & 0xff].bpp; + } + mi->ncolors = 1 << mi->bpp; + mi->pitch = vbemi->scanline_bytes; + mi->win_size = vbemi->win_size; + mi->win_gran = vbemi->win_gran; + + gran_shift = 0; + mi->win_step = 1; + if(mi->win_gran > 0 && mi->win_gran < 64) { + int gran = mi->win_gran; + while(gran < 64) { + gran_shift++; + gran <<= 1; + } + mi->win_step = 1 << gran_shift; + } + + mi->ops.pack = pack; + mi->ops.unpack = unpack; + mi->ops.setpal = vga_setpal; + mi->ops.getpal = vga_getpal; + mi->ops.vsync = vid_vsync; + mi->ops.clear = clear; + mi->ops.blitfb = 0; + mi->ops.flip = flip; + return 0; +} + +static unsigned int calc_mask(int nbits, int pos) +{ + int i; + unsigned int mask = 0; + + for(i=0; irshift) & cur_mi->rmask) | + (((uint32_t)g << cur_mi->gshift) & cur_mi->gmask) | + (((uint32_t)b << cur_mi->bshift) & cur_mi->bmask); +} + +static void unpack(uint32_t pix, int *r, int *g, int *b) +{ + *r = (pix & cur_mi->rmask) >> cur_mi->rshift; + *g = (pix & cur_mi->gmask) >> cur_mi->gshift; + *b = (pix & cur_mi->bmask) >> cur_mi->bshift; +} + +static void clear(uint32_t color) +{ +} + +static void blitfb_lfb(void *fb, int pitch) +{ + int i; + unsigned char *dest, *src; + + dest = vid_vmem; + src = fb; + + for(i=0; iheight; i++) { + memcpy(dest, src, cur_mi->pitch); + dest += cur_mi->pitch; + src += pitch; + } +} + +static void blitfb_banked(void *fb, int pitch) +{ + int sz, offs, pending; + unsigned char *pptr = fb; + + /* assume initial window offset at 0 */ + offs = 0; + pending = cur_pgsize; + while(pending > 0) { + sz = pending > 65536 ? 65536 : pending; + memcpy((void*)0xa0000, pptr, sz); + pptr += sz; + pending -= sz; + offs += cur_mi->win_step; + vid_setwin(0, offs); + } + vid_setwin(0, 0); +} + +static void flip(int vsync) +{ + /* TODO */ +}