From: John Tsiombikas Date: Thu, 14 Nov 2019 02:00:03 +0000 (+0200) Subject: more vbe X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=commitdiff_plain;h=05672cb8988cd30a798ea3fbce124695fc76f09c more vbe --- diff --git a/src/dos/inttypes.h b/src/dos/inttypes.h index 6f941ad..14d6395 100644 --- a/src/dos/inttypes.h +++ b/src/dos/inttypes.h @@ -18,7 +18,7 @@ along with this program. If not, see . #ifndef INT_TYPES_H_ #define INT_TYPES_H_ -#if defined(__DOS__) || defined(WIN32) +#if defined(__WATCOMC__) && __WATCOMC__ < 0x1200 typedef char int8_t; typedef short int16_t; typedef long int32_t; @@ -27,7 +27,8 @@ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; -typedef unsigned long intptr_t; +typedef long intptr_t; +typedef unsigned long uintptr_t; #else #include #endif diff --git a/src/dos/vbe.c b/src/dos/vbe.c index d5d75df..6225084 100644 --- a/src/dos/vbe.c +++ b/src/dos/vbe.c @@ -1,28 +1,208 @@ +#include +#include +#include +#include #include "vbe.h" #include "cdpmi.h" -int vbe_getinfo(struct vbe_info *info) + +#define FIXPTR(ptr) \ + do { \ + uint32_t paddr = (uint32_t)(ptr); \ + uint16_t pseg = paddr >> 16; \ + uint16_t poffs = paddr & 0xffff; \ + if(pseg == seg && poffs < 512) { \ + paddr = ((uint32_t)seg << 4) + poffs; \ + } else { \ + paddr = ((uint32_t)pseg << 4) + poffs; \ + } \ + (ptr) = (void*)paddr; \ + } while(0) + +/* hijack the "VESA" sig field, to pre-cache number of modes */ +#define NMODES(inf) *(uint16_t*)((inf)->sig) +#define NACCMODES(inf) *(uint16_t*)((inf)->sig + 2) + +int vbe_info(struct vbe_info *info) { + int i, num; void *lowbuf; uint16_t seg, sel; + uint16_t *modeptr; struct dpmi_regs regs = {0}; - if(!(seg = dpmi_alloc(512 / 16, &sel))) { + assert(sizeof *info == 512); + + if(!(seg = dpmi_alloc(sizeof *info / 16, &sel))) { return -1; } + lowbuf = (void*)((uint32_t)seg << 4); + + memcpy(lowbuf, "VBE2", 4); regs.eax = 0x4f00; regs.es = seg; regs.edi = 0; dpmi_int(0x10, ®s); - if(regs.eax & 0xff00) { + if((regs.eax & 0xffff) != 0x4f) { + fprintf(stderr, "vbe_get_info (4f00) failed\n"); dpmi_free(sel); return -1; } + memcpy(info, lowbuf, sizeof *info); + dpmi_free(sel); + + FIXPTR(info->oem_name); + FIXPTR(info->vendor); + FIXPTR(info->product); + FIXPTR(info->revstr); + FIXPTR(info->modes); + FIXPTR(info->accel_modes); + + modeptr = info->modes; + while(*modeptr != 0xffff) { + if(modeptr - info->modes >= 256) { + modeptr = info->modes; + break; + } + modeptr++; + } + NMODES(info) = modeptr - info->modes; + + if(info->caps & VBE_ACCEL) { + modeptr = info->accel_modes; + while(*modeptr != 0xffff) { + if(modeptr - info->accel_modes >= 256) { + modeptr = info->accel_modes; + break; + } + modeptr++; + } + NACCMODES(info) = modeptr - info->accel_modes; + } + return 0; +} + +int vbe_num_modes(struct vbe_info *info) +{ + return NMODES(info); +} + +int vbe_mode_info(int mode, struct vbe_mode_info *minf) +{ + int i, num; + void *lowbuf; + uint16_t seg, sel; + struct dpmi_regs regs = {0}; + + assert(sizeof *minf == 256); + assert(offsetof(struct vbe_mode_info, max_pixel_clock) == 0x3e); + + if(!(seg = dpmi_alloc(sizeof *minf / 16, &sel))) { + return -1; + } lowbuf = (void*)((uint32_t)seg << 4); - memcpy(info, lowbuf, sizeof info); + + regs.eax = 0x4f01; + regs.ecx = mode; + regs.es = seg; + dpmi_int(0x10, ®s); + + if((regs.eax & 0xffff) != 0x4f) { + fprintf(stderr, "vbe_mode_info (4f01) failed\n"); + dpmi_free(sel); + return -1; + } + + memcpy(minf, lowbuf, sizeof *minf); dpmi_free(sel); return 0; } + +void vbe_print_info(FILE *fp, struct vbe_info *vinf) +{ + fprintf(fp, "vbe version: %u.%u\n", VBE_VER_MAJOR(vinf->ver), VBE_VER_MINOR(vinf->ver)); + if(VBE_VER_MAJOR(vinf->ver) >= 2) { + fprintf(fp, "%s - %s (%s)\n", vinf->vendor, vinf->product, vinf->revstr); + if(vinf->caps & VBE_ACCEL) { + fprintf(fp, "vbe/af %d.%d\n", VBE_VER_MAJOR(vinf->accel_ver), VBE_VER_MINOR(vinf->accel_ver)); + } + } else { + fprintf(fp, "oem: %s\n", vinf->oem_name); + } + fprintf(fp, "video memory: %dkb\n", vinf->vmem_blk * 64); + + if(vinf->caps) { + fprintf(fp, "caps:"); + if(vinf->caps & VBE_8BIT_DAC) fprintf(fp, " dac8"); + if(vinf->caps & VBE_NON_VGA) fprintf(fp, " non-vga"); + if(vinf->caps & VBE_DAC_BLANK) fprintf(fp, " dac-blank"); + if(vinf->caps & VBE_ACCEL) fprintf(fp, " af"); + if(vinf->caps & VBE_MUSTLOCK) fprintf(fp, " af-lock"); + if(vinf->caps & VBE_HWCURSOR) fprintf(fp, " af-curs"); + if(vinf->caps & VBE_HWCLIP) fprintf(fp, " af-clip"); + if(vinf->caps & VBE_TRANSP_BLT) fprintf(fp, " af-tblt"); + fprintf(fp, "\n"); + } + + fprintf(fp, "%d video modes available\n", NMODES(vinf)); + if(vinf->caps & VBE_ACCEL) { + fprintf(fp, "%d accelerated (VBE/AF) modes available\n", NACCMODES(vinf)); + } + fflush(fp); +} + +void vbe_print_mode_info(FILE *fp, struct vbe_mode_info *minf) +{ + fprintf(fp, "%dx%d %dbpp", minf->xres, minf->yres, minf->bpp); + + switch(minf->mem_model) { + case VBE_TYPE_DIRECT: + fprintf(fp, " (rgb"); + if(0) { + case VBE_TYPE_YUV: + fprintf(fp, " (yuv"); + } + fprintf(fp, " %d%d%d)", minf->rsize, minf->gsize, minf->bsize); + break; + case VBE_TYPE_PLANAR: + fprintf(fp, " (%d planes)", minf->num_planes); + break; + case VBE_TYPE_PACKED: + fprintf(fp, " (packed)"); + break; + case VBE_TYPE_TEXT: + fprintf(fp, " (%dx%d cells)", minf->xcharsz, minf->ycharsz); + break; + case VBE_TYPE_CGA: + fprintf(fp, " (CGA)"); + break; + case VBE_TYPE_UNCHAIN: + fprintf(fp, " (unchained-%d)", minf->num_planes); + break; + } + fprintf(fp, " %dpg", minf->num_img_pages); + + if(minf->attr & VBE_ATTR_LFB) { + fprintf(fp, " lfb@%lx", (unsigned long)minf->fb_addr); + } + + fprintf(fp, " ["); + if(minf->attr & VBE_ATTR_AVAIL) fprintf(fp, " avail"); + if(minf->attr & VBE_ATTR_OPTINFO) fprintf(fp, " opt"); + if(minf->attr & VBE_ATTR_TTY) fprintf(fp, " tty"); + if(minf->attr & VBE_ATTR_COLOR) fprintf(fp, " color"); + if(minf->attr & VBE_ATTR_GFX) fprintf(fp, " gfx"); + if(minf->attr & VBE_ATTR_NOTVGA) fprintf(fp, " non-vga"); + if(minf->attr & VBE_ATTR_BANKED) fprintf(fp, " banked"); + if(minf->attr & VBE_ATTR_LFB) fprintf(fp, " lfb"); + if(minf->attr & VBE_ATTR_2XSCAN) fprintf(fp, " dblscan"); + if(minf->attr & VBE_ATTR_ILACE) fprintf(fp, " ilace"); + if(minf->attr & VBE_ATTR_TRIPLEBUF) fprintf(fp, " trplbuf"); + if(minf->attr & VBE_ATTR_STEREO) fprintf(fp, " stereo"); + if(minf->attr & VBE_ATTR_STEREO_2FB) fprintf(fp, " stdual"); + fprintf(fp, " ]\n"); + fflush(fp); +} diff --git a/src/dos/vbe.h b/src/dos/vbe.h index 73df02f..734f94d 100644 --- a/src/dos/vbe.h +++ b/src/dos/vbe.h @@ -1,6 +1,7 @@ #ifndef VBE_H_ #define VBE_H_ +#include #include "inttypes.h" #include "util.h" @@ -11,12 +12,59 @@ struct vbe_info { char *oem_name; uint32_t caps; uint16_t *modes; + uint16_t vmem_blk; /* video memory size in 64k blocks */ uint16_t oem_ver; char *vendor; char *product; char *revstr; uint16_t accel_ver; - uint16_t accel_modes; + uint16_t *accel_modes; + char reserved[216]; + char oem_data[256]; +} PACKED; + +struct vbe_mode_info { + uint16_t attr; + uint8_t wina_attr, winb_attr; + uint16_t win_gran, win_size; + uint16_t wina_seg, winb_seg; + uint32_t win_func; + uint16_t scanline_bytes; + + /* VBE 1.2 and above */ + uint16_t xres, yres; + uint8_t xcharsz, ycharsz; + uint8_t num_planes; + uint8_t bpp; + uint8_t num_banks; + uint8_t mem_model; + uint8_t bank_size; /* bank size in KB */ + uint8_t num_img_pages; + uint8_t reserved1; + + /* direct color fields */ + uint8_t rsize, rpos; + uint8_t gsize, gpos; + uint8_t bsize, bpos; + uint8_t xsize, xpos; + uint8_t cmode_info; /* direct color mode attributes */ + + /* VBE 2.0 and above */ + uint32_t fb_addr; /* physical address of the linear framebuffer */ + uint32_t os_addr; /* phys. address of off-screen memory */ + uint16_t os_size; /* size in KB of off-screen memory */ + + /* VBE 3.0 and above */ + uint16_t lfb_scanline_bytes; + uint8_t banked_num_img_pages; + uint8_t lfb_num_img_pages; + uint8_t lfb_rsize, lfb_rpos; + uint8_t lfb_gsize, lfb_gpos; + uint8_t lfb_bsize, lfb_bpos; + uint8_t lfb_xsize, lfb_xpos; + uint32_t max_pixel_clock; + + uint8_t reserved2[190]; } PACKED; #pragma pack (pop) @@ -33,6 +81,62 @@ enum { VBE_TRANSP_BLT = 0x80 }; -int vbe_getinfo(struct vbe_info *info); +#define VBE_VER_MAJOR(v) (((v) >> 8) & 0xff) +#define VBE_VER_MINOR(v) ((v) & 0xff) + +/* VBE mode attribute flags (vbe_mode_info.attr) */ +enum { + VBE_ATTR_AVAIL = 0x0001, + VBE_ATTR_OPTINFO = 0x0002, + VBE_ATTR_TTY = 0x0004, + VBE_ATTR_COLOR = 0x0008, + VBE_ATTR_GFX = 0x0010, + /* VBE 2.0 */ + VBE_ATTR_NOTVGA = 0x0020, + VBE_ATTR_BANKED = 0x0040, + VBE_ATTR_LFB = 0x0080, + VBE_ATTR_2XSCAN = 0x0100, + /* VBE 3.0 */ + VBE_ATTR_ILACE = 0x0200, /* ! */ + VBE_ATTR_TRIPLEBUF = 0x0400, + VBE_ATTR_STEREO = 0x0800, + VBE_ATTR_STEREO_2FB = 0x1000, + /* VBE/AF */ + VBE_ATTR_MUSTLOCK = 0x0200, /* ! */ +}; + +/* VBE memory model type (vbe_mode_info.mem_model) */ +enum { + VBE_TYPE_TEXT, + VBE_TYPE_CGA, + VBE_TYPE_HERCULES, + VBE_TYPE_PLANAR, + VBE_TYPE_PACKED, + VBE_TYPE_UNCHAIN, + VBE_TYPE_DIRECT, + VBE_TYPE_YUV +}; + +/* VBE window attribute (vbe_mode_info.win(a|b)_attr) */ +enum { + VBE_WIN_AVAIL = 0x01, + VBE_WIN_RD = 0x02, + VBE_WIN_WR = 0x04 +}; + +/* mode number flags */ +enum { + VBE_MODE_RATE = 0x0800, /* VBE 3.0+ user-specified refresh rate */ + VBE_MODE_ACCEL = 0x2000, /* VBE/AF */ + VBE_MODE_LFB = 0x4000, /* VBE 2.0+ */ + VBE_MODE_PRESERVE = 0x8000 +}; + +int vbe_info(struct vbe_info *info); +int vbe_num_modes(struct vbe_info *info); +int vbe_mode_info(int mode, struct vbe_mode_info *minf); + +void vbe_print_info(FILE *fp, struct vbe_info *info); +void vbe_print_mode_info(FILE *fp, struct vbe_mode_info *minf); #endif /* VBE_H_ */