+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <assert.h>
#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);
+}
#ifndef VBE_H_
#define VBE_H_
+#include <stdio.h>
#include "inttypes.h"
#include "util.h"
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)
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_ */