Adding SVGA checks
This commit is contained in:
parent
8b01cc8538
commit
8c37936d56
7 changed files with 338 additions and 2 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,6 +1,7 @@
|
||||||
# ---> C
|
# ---> C
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
*.d
|
*.d
|
||||||
|
deploy_image.sh
|
||||||
|
|
||||||
# Object files
|
# Object files
|
||||||
*.o
|
*.o
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,9 @@
|
||||||
#define _UTIL_H_
|
#define _UTIL_H_
|
||||||
|
|
||||||
void displayMessage(int n);
|
void displayMessage(int n);
|
||||||
|
int check_trio_chip();
|
||||||
|
int get_trio_memory();
|
||||||
|
int int386x_real(int intnum, union REGS *in, union REGS *out, struct SREGS *sregs);
|
||||||
|
const char *vbe_mode_description(unsigned mode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
7
include/vbe12gr.h
Normal file
7
include/vbe12gr.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef _VBE12GR_H_
|
||||||
|
#define _VBE12GR_H_
|
||||||
|
|
||||||
|
int get_current_vbe_mode(unsigned *mode_out);
|
||||||
|
int get_vbe_version(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
3
main.err
Normal file
3
main.err
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
src/main.c(56): Warning! E1178: Type qualifier mismatch
|
||||||
|
src/main.c(56): Note! I2003: source conversion type is 'char const *'
|
||||||
|
src/main.c(56): Note! I2004: target conversion type is 'char *'
|
||||||
50
src/main.c
50
src/main.c
|
|
@ -1,14 +1,60 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "vbe12gr.h"
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
unsigned prevMode = 0xFFFF;
|
||||||
|
char *descr;
|
||||||
|
|
||||||
printf("DSPACE starting...\n");
|
printf("DSPACE starting...\n");
|
||||||
|
|
||||||
for (i = 0; i < 10; i++) {
|
if (check_trio_chip()) {
|
||||||
displayMessage(i + 1);
|
printf("S3 Trio64 detected\n");
|
||||||
|
} else {
|
||||||
|
printf("S3 Trio64 video card not found, exiting.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = get_trio_memory();
|
||||||
|
|
||||||
|
printf("Video DRAM: ");
|
||||||
|
switch (i) {
|
||||||
|
case 7:
|
||||||
|
printf("0.5 MB\n");
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
printf("1 MB\n");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
printf("2 MB\n");
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
printf("4 MB\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unable to determine ram\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
i = get_vbe_version();
|
||||||
|
if (i < 0) {
|
||||||
|
printf("Error on determining VBE version: %d\n", i);
|
||||||
|
return;
|
||||||
|
} else if (i == 0) {
|
||||||
|
printf("VBE not supported, exiting\n");
|
||||||
|
return;
|
||||||
|
} else if (i < 200) {
|
||||||
|
printf("VBE 1.2 supported\n");
|
||||||
|
} else {
|
||||||
|
printf("VBE 2.0 supported\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_current_vbe_mode(&prevMode)) {
|
||||||
|
printf("Unable to get current mode\n");
|
||||||
|
} else {
|
||||||
|
descr = vbe_mode_description(prevMode);
|
||||||
|
printf("Current mode = %s\n", descr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
178
src/util.c
178
src/util.c
|
|
@ -1,5 +1,183 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <conio.h>
|
||||||
|
#include <i86.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
void displayMessage(int n) {
|
void displayMessage(int n) {
|
||||||
printf("%02d: Hello MS-DOS!\n", n);
|
printf("%02d: Hello MS-DOS!\n", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int check_trio_chip() {
|
||||||
|
unsigned char cr30_value;
|
||||||
|
|
||||||
|
/* 1. Unlock the S3 VGA Registers (CR30-CR3F) */
|
||||||
|
// Select the CR38 index register via the address port (0x3D4)
|
||||||
|
outp(0x3D4, 0x38);
|
||||||
|
// Write the unlocking code (0x48) to the data port (0x3D5)
|
||||||
|
outp(0x3D5, 0x48);
|
||||||
|
|
||||||
|
/* 2. Read the Chip ID/REV register (CR30) */
|
||||||
|
// Select the CR30 index register via the address port (0x3D4)
|
||||||
|
outp(0x3D4, 0x30);
|
||||||
|
// Read the contents of CR30 from the data port (0x3D5)
|
||||||
|
cr30_value = inp(0x3D5);
|
||||||
|
|
||||||
|
/* 3. Check the Chip ID */
|
||||||
|
// Mask out the lower nibble (revision status) and compare to 0xE0
|
||||||
|
if ((cr30_value & 0xF0) == 0xE0) {
|
||||||
|
return 1; // Chip ID matches
|
||||||
|
} else {
|
||||||
|
return 0; // Chip ID does not match, abort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_trio_memory() {
|
||||||
|
/* 1. Read the Chip ID/REV register (CR36) */
|
||||||
|
// Select the CR30 index register via the address port (0x3D4)
|
||||||
|
outp(0x3D4, 0x36);
|
||||||
|
// Read the contents of CR36 from the data port (0x3D5)
|
||||||
|
return inp(0x3D5) >> 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct {
|
||||||
|
unsigned long edi;
|
||||||
|
unsigned long esi;
|
||||||
|
unsigned long ebp;
|
||||||
|
unsigned long reserved;
|
||||||
|
unsigned long ebx;
|
||||||
|
unsigned long edx;
|
||||||
|
unsigned long ecx;
|
||||||
|
unsigned long eax;
|
||||||
|
unsigned short flags;
|
||||||
|
unsigned short es;
|
||||||
|
unsigned short ds;
|
||||||
|
unsigned short fs;
|
||||||
|
unsigned short gs;
|
||||||
|
unsigned short ip;
|
||||||
|
unsigned short cs;
|
||||||
|
unsigned short sp;
|
||||||
|
unsigned short ss;
|
||||||
|
} RMCS;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* int386x_real - simulate a real-mode interrupt via DPMI (int 0x31, AX=0x0300).
|
||||||
|
* Same calling shape as int386x(), but intnum is dispatched in real mode
|
||||||
|
* (BIOS/DOS calls), not as a protected-mode interrupt.
|
||||||
|
*
|
||||||
|
* Returns 0 on success, -1 if the DPMI call itself failed (check regs
|
||||||
|
* are otherwise untouched in that case).
|
||||||
|
*/
|
||||||
|
int int386x_real(int intnum, union REGS *in, union REGS *out, struct SREGS *sregs)
|
||||||
|
{
|
||||||
|
RMCS rmi;
|
||||||
|
union REGS dregs;
|
||||||
|
struct SREGS dsregs;
|
||||||
|
|
||||||
|
memset(&rmi, 0, sizeof(rmi));
|
||||||
|
|
||||||
|
rmi.eax = in->x.eax;
|
||||||
|
rmi.ebx = in->x.ebx;
|
||||||
|
rmi.ecx = in->x.ecx;
|
||||||
|
rmi.edx = in->x.edx;
|
||||||
|
rmi.esi = in->x.esi;
|
||||||
|
rmi.edi = in->x.edi;
|
||||||
|
rmi.es = sregs->es;
|
||||||
|
rmi.ds = sregs->ds;
|
||||||
|
rmi.fs = sregs->fs;
|
||||||
|
rmi.gs = sregs->gs;
|
||||||
|
|
||||||
|
/* SS:SP left as 0:0 -> DPMI host provides a temporary real-mode stack */
|
||||||
|
|
||||||
|
memset(&dregs, 0, sizeof(dregs));
|
||||||
|
memset(&dsregs, 0, sizeof(dsregs));
|
||||||
|
|
||||||
|
dregs.w.ax = 0x0300; /* DPMI: Simulate Real Mode Interrupt */
|
||||||
|
dregs.h.bl = (unsigned char)intnum;
|
||||||
|
dregs.h.bh = 0;
|
||||||
|
dregs.w.cx = 0; /* no words to copy onto real-mode stack */
|
||||||
|
dsregs.es = FP_SEG(&rmi);
|
||||||
|
dregs.x.edi = FP_OFF(&rmi);
|
||||||
|
|
||||||
|
int386x(0x31, &dregs, &dregs, &dsregs);
|
||||||
|
|
||||||
|
if (dregs.w.cflag) {
|
||||||
|
return -1; /* DPMI call itself failed */
|
||||||
|
}
|
||||||
|
|
||||||
|
out->x.eax = rmi.eax;
|
||||||
|
out->x.ebx = rmi.ebx;
|
||||||
|
out->x.ecx = rmi.ecx;
|
||||||
|
out->x.edx = rmi.edx;
|
||||||
|
out->x.esi = rmi.esi;
|
||||||
|
out->x.edi = rmi.edi;
|
||||||
|
out->w.cflag = rmi.flags & 0x0001; /* real-mode call's own carry flag */
|
||||||
|
sregs->es = rmi.es;
|
||||||
|
sregs->ds = rmi.ds;
|
||||||
|
sregs->fs = rmi.fs;
|
||||||
|
sregs->gs = rmi.gs;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *vbe_mode_description(unsigned mode)
|
||||||
|
{
|
||||||
|
/* Strip VBE mode-set flag bits (bit 15 = LFB request, bit 14 =
|
||||||
|
refresh rate control) before lookup -- these aren't part of
|
||||||
|
the mode number itself. */
|
||||||
|
unsigned base_mode = mode & 0x01FF;
|
||||||
|
|
||||||
|
switch (base_mode) {
|
||||||
|
/* Standard VGA modes */
|
||||||
|
case 0x00: return "40x25 16-color (mono) text";
|
||||||
|
case 0x01: return "40x25 16-color text";
|
||||||
|
case 0x02: return "80x25 16-color (mono) text";
|
||||||
|
case 0x03: return "80x25 16-color text";
|
||||||
|
case 0x04: return "320x200 4-color graphics (CGA)";
|
||||||
|
case 0x05: return "320x200 4-color (mono) graphics";
|
||||||
|
case 0x06: return "640x200 2-color graphics";
|
||||||
|
case 0x07: return "80x25 monochrome text";
|
||||||
|
case 0x0D: return "320x200 16-color graphics (EGA)";
|
||||||
|
case 0x0E: return "640x200 16-color graphics";
|
||||||
|
case 0x0F: return "640x350 monochrome graphics";
|
||||||
|
case 0x10: return "640x350 16-color graphics (EGA/VGA)";
|
||||||
|
case 0x11: return "640x480 2-color (mono) graphics (VGA)";
|
||||||
|
case 0x12: return "640x480 16-color graphics (VGA)";
|
||||||
|
case 0x13: return "320x200 256-color graphics (Mode 13h)";
|
||||||
|
|
||||||
|
/* VESA SVGA modes */
|
||||||
|
case 0x100: return "640x400 256-color (VESA)";
|
||||||
|
case 0x101: return "640x480 256-color (VESA)";
|
||||||
|
case 0x102: return "800x600 16-color (VESA)";
|
||||||
|
case 0x103: return "800x600 256-color (VESA)";
|
||||||
|
case 0x104: return "1024x768 16-color (VESA)";
|
||||||
|
case 0x105: return "1024x768 256-color (VESA)";
|
||||||
|
case 0x106: return "1280x1024 16-color (VESA)";
|
||||||
|
case 0x107: return "1280x1024 256-color (VESA)";
|
||||||
|
case 0x108: return "80x60 text (VESA)";
|
||||||
|
case 0x109: return "132x25 text (VESA)";
|
||||||
|
case 0x10A: return "132x43 text (VESA)";
|
||||||
|
case 0x10B: return "132x50 text (VESA)";
|
||||||
|
case 0x10C: return "132x60 text (VESA)";
|
||||||
|
|
||||||
|
/* VBE 1.2 direct color modes */
|
||||||
|
case 0x10D: return "320x200 15bpp direct color (VESA)";
|
||||||
|
case 0x10E: return "320x200 16bpp direct color (VESA)";
|
||||||
|
case 0x10F: return "320x200 24bpp direct color (VESA)";
|
||||||
|
case 0x110: return "640x480 15bpp direct color (VESA)";
|
||||||
|
case 0x111: return "640x480 16bpp direct color (VESA)";
|
||||||
|
case 0x112: return "640x480 24bpp direct color (VESA)";
|
||||||
|
case 0x113: return "800x600 15bpp direct color (VESA)";
|
||||||
|
case 0x114: return "800x600 16bpp direct color (VESA)";
|
||||||
|
case 0x115: return "800x600 24bpp direct color (VESA)";
|
||||||
|
case 0x116: return "1024x768 15bpp direct color (VESA)";
|
||||||
|
case 0x117: return "1024x768 16bpp direct color (VESA)";
|
||||||
|
case 0x118: return "1024x768 24bpp direct color (VESA)";
|
||||||
|
case 0x119: return "1280x1024 15bpp direct color (VESA)";
|
||||||
|
case 0x11A: return "1280x1024 16bpp direct color (VESA)";
|
||||||
|
case 0x11B: return "1280x1024 24bpp direct color (VESA)";
|
||||||
|
|
||||||
|
default: return "Unknown/unsupported mode";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
97
src/vbe12gr.c
Normal file
97
src/vbe12gr.c
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include <i86.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define VBE_SIG_SIZE 4
|
||||||
|
|
||||||
|
int get_current_vbe_mode(unsigned *mode_out) {
|
||||||
|
union REGS regs;
|
||||||
|
struct SREGS sregs;
|
||||||
|
|
||||||
|
memset(®s, 0, sizeof(regs));
|
||||||
|
memset(&sregs, 0, sizeof(sregs));
|
||||||
|
|
||||||
|
regs.w.ax = 0x4F03;
|
||||||
|
|
||||||
|
int386x_real(0x10, ®s, ®s, &sregs);
|
||||||
|
|
||||||
|
if (regs.w.ax != 0x004F) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*mode_out = regs.w.bx;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_vbe_version(void)
|
||||||
|
{
|
||||||
|
union REGS regs;
|
||||||
|
struct SREGS sregs;
|
||||||
|
unsigned dos_segment;
|
||||||
|
unsigned dos_selector;
|
||||||
|
unsigned char *buf;
|
||||||
|
unsigned version_bcd;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
memset(®s, 0, sizeof(regs));
|
||||||
|
memset(&sregs, 0, sizeof(sregs));
|
||||||
|
|
||||||
|
regs.w.ax = 0x0100; /* DPMI: Allocate DOS Memory Block */
|
||||||
|
regs.w.bx = 0x0020; /* 0x20 paragraphs = 512 bytes */
|
||||||
|
int386x(0x31, ®s, ®s, &sregs); /* direct DPMI call, not _real */
|
||||||
|
|
||||||
|
if (regs.w.cflag) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dos_segment = regs.w.ax;
|
||||||
|
dos_selector = regs.w.dx;
|
||||||
|
|
||||||
|
buf = (unsigned char *)(dos_segment << 4);
|
||||||
|
|
||||||
|
memset(buf, 0, 512);
|
||||||
|
memcpy(buf, "VBE2", 4);
|
||||||
|
|
||||||
|
memset(®s, 0, sizeof(regs));
|
||||||
|
memset(&sregs, 0, sizeof(sregs));
|
||||||
|
regs.w.ax = 0x4F00;
|
||||||
|
sregs.es = dos_segment;
|
||||||
|
regs.w.di = 0x0000;
|
||||||
|
|
||||||
|
int386x_real(0x10, ®s, ®s, &sregs); /* real BIOS call - correct as-is */
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
if ((regs.w.ax & 0x00FF) != 0x4F) {
|
||||||
|
result = 0;
|
||||||
|
} else if (((regs.w.ax >> 8) & 0xFF) != 0x00) {
|
||||||
|
result = 0;
|
||||||
|
} else {
|
||||||
|
if (memcmp(buf, "VESA", 4) != 0) {
|
||||||
|
result = 0;
|
||||||
|
} else {
|
||||||
|
version_bcd = *(unsigned short *)(buf + 4);
|
||||||
|
|
||||||
|
if (version_bcd >= 0x0200) {
|
||||||
|
result = 200;
|
||||||
|
} else if (version_bcd >= 0x0102) {
|
||||||
|
result = 102;
|
||||||
|
} else {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(®s, 0, sizeof(regs));
|
||||||
|
memset(&sregs, 0, sizeof(sregs));
|
||||||
|
regs.w.ax = 0x0101; /* DPMI: Free DOS Memory Block */
|
||||||
|
regs.w.dx = dos_selector;
|
||||||
|
int386x(0x31, ®s, ®s, &sregs); /* direct DPMI call, not _real */
|
||||||
|
|
||||||
|
if (regs.w.cflag && result == 0) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue