795 lines
24 KiB
C
795 lines
24 KiB
C
/*
|
|
* Roo/E, the Kangaroo Punch Portable GUI Toolkit
|
|
* Copyright (C) 2022 Scott Duensing
|
|
*
|
|
* http://kangaroopunch.com
|
|
*
|
|
*
|
|
* This file is part of Roo/E.
|
|
*
|
|
* Roo/E is free software: you can redistribute it and/or modify it under the
|
|
* terms of the GNU Affero General Public License as published by the Free
|
|
* Software Foundation, either version 3 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* Roo/E is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with Roo/E. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
|
|
#ifdef BACKEND_DJGPP
|
|
|
|
|
|
#include "os.h"
|
|
|
|
#include <dos.h>
|
|
#include <dpmi.h>
|
|
#include <go32.h>
|
|
#include <bios.h>
|
|
#include <conio.h>
|
|
#include <sys/farptr.h>
|
|
#include <sys/nearptr.h>
|
|
|
|
#include "platform.h"
|
|
|
|
|
|
// These are all we support
|
|
#define VBE_MM_PACKED 4
|
|
#define VBE_MM_DCOLOR 6
|
|
|
|
|
|
// Based on http://www.brackeen.com/vga/source/djgpp20/mouse.c.html
|
|
#define MOUSE_INT 0x33
|
|
|
|
#define MOUSE_RESET 0x00
|
|
#define MOUSE_STATUS 0x03
|
|
#define MOUSE_GETMOTION 0x0B
|
|
|
|
#define MOUSE_LEFT_BUTTON 0x01
|
|
#define MOUSE_RIGHT_BUTTON 0x02
|
|
#define MOUSE_MIDDLE_BUTTON 0x04
|
|
|
|
|
|
#define KEYBOARD_READ_EXTENDED 0x10
|
|
#define KEYBOARD_CHECK_EXTENDED 0x11
|
|
#define KEYBOARD_META_EXTENDED 0x12
|
|
|
|
|
|
enum MetaBitsE {
|
|
KEY_META_SHIFT_RIGHT = 0,
|
|
KEY_META_SHIFT_LEFT,
|
|
KEY_META_CONTROL,
|
|
KEY_META_ALT,
|
|
KEY_META_SCROLL_LOCKED,
|
|
KEY_META_NUM_LOCKED,
|
|
KEY_META_CAPS_LOCKED,
|
|
KEY_META_INSERT_LOCKED,
|
|
KEY_META_CONTROL_LEFT,
|
|
KEY_META_ALT_LEFT,
|
|
KEY_META_CONTROL_RIGHT,
|
|
KEY_META_ALT_RIGHT,
|
|
KEY_META_SCROLL_LOCK,
|
|
KEY_META_NUM_LOCK,
|
|
KEY_META_CAPS_LOCK,
|
|
KEY_META_SYSREQ
|
|
};
|
|
|
|
|
|
typedef struct VBEInfoS {
|
|
char vbeSignature[4]; // 'VESA' 4 byte signature
|
|
int16_t vbeVersion; // VBE version number
|
|
char *oemStringPtr; // Pointer to OEM string
|
|
uint32_t capabilities; // Capabilities of video card
|
|
uint16_t *videoModePtr; // Pointer to supported modes
|
|
uint16_t totalMemory; // Number of 64kb memory blocks
|
|
// added for VBE 2.0
|
|
uint16_t oemSoftwareRev; // OEM Software revision number
|
|
char *oemVendorNamePtr; // Pointer to Vendor Name string
|
|
char *oemProductNamePtr; // Pointer to Product Name string
|
|
char *oemProductRevPtr; // Pointer to Product Revision str
|
|
char reserved[222]; // Pad to 256 byte block size
|
|
char oemData[256]; // Scratch pad for OEM data
|
|
} __attribute__ ((packed)) VBEInfoT;
|
|
|
|
|
|
typedef struct VBEModeInfoS {
|
|
// Mandatory information for all VBE revisions:
|
|
uint16_t modeAttributes; // mode attributes
|
|
uint8_t winAAttributes; // window A attributes
|
|
uint8_t winBAttributes; // window B attributes
|
|
uint16_t winGranularity; // window granularity
|
|
uint16_t winSize; // window size
|
|
uint16_t winASegment; // window A start segment
|
|
uint16_t winBSegment; // window B start segment
|
|
uint32_t winFuncPtr; // pointer to window function
|
|
uint16_t bytesPerScanLine; // bytes per scan line
|
|
// Mandatory information for VBE 1.2 and above:
|
|
uint16_t xResolution; // horizontal resolution in pixels or chars
|
|
uint16_t yResolution; // vertical resolution in pixels or chars
|
|
uint8_t xCharSize; // character cell width in pixels
|
|
uint8_t yCharSize; // character cell height in pixels
|
|
uint8_t numberOfPlanes; // number of memory planes
|
|
uint8_t bitsPerPixel; // bits per pixel
|
|
uint8_t numberOfBanks; // number of banks
|
|
uint8_t memoryModel; // memory model type
|
|
uint8_t bankSize; // bank size in KB
|
|
uint8_t numberOfImagePages; // number of images
|
|
uint8_t reserved; // reserved for page function
|
|
// Direct Color fields (required for direct/6 and YUV/7 memory models)
|
|
uint8_t redMaskSize; // size of direct color red mask in bits
|
|
uint8_t redFieldPosition; // bit position of lsb of red mask
|
|
uint8_t greenMaskSize; // size of direct color green mask in bits
|
|
uint8_t greenFieldPosition; // bit position of lsb of green mask
|
|
uint8_t blueMaskSize; // size of direct color blue mask in bits
|
|
uint8_t blueFieldPosition; // bit position of lsb of blue mask
|
|
uint8_t rsvdMaskSize; // size of direct color reserved mask in bits
|
|
uint8_t rsvdFieldPosition; // bit position of lsb of reserved mask
|
|
uint8_t directColorModeInfo; // direct color mode attributes
|
|
// Mandatory information for VBE 2.0 and above:
|
|
uint32_t physBasePtr; // physical address for flat frame buffer
|
|
uint32_t offScreenMemOffset; // pointer to start of off screen memory
|
|
uint16_t offScreenMemSize; // amount of off screen memory in 1k units
|
|
char reservedBuf[206];
|
|
} __attribute__ ((packed)) VBEModeInfoT;
|
|
|
|
|
|
typedef struct PModeInterfaceS {
|
|
int16_t setWindow;
|
|
int16_t setDisplayStart;
|
|
int16_t setPalette;
|
|
int16_t ioInfo;
|
|
} __attribute__ ((packed)) PModeInterfaceT;
|
|
|
|
|
|
typedef struct VBESurfaceS {
|
|
uint32_t lfbLinearAddress;
|
|
uint16_t lfbSelector;
|
|
void *lfbNearPtr;
|
|
uint32_t lfbMemSize;
|
|
uint16_t xResolution;
|
|
uint16_t yResolution;
|
|
uint32_t bitsPerPixel;
|
|
uint16_t virtualXResolution;
|
|
uint32_t bytesPerPixel;
|
|
uint32_t screenBytes;
|
|
uint32_t screenDWords;
|
|
uint32_t centerX;
|
|
uint32_t centerY;
|
|
uint16_t numberOfOffscreens;
|
|
uint8_t vbeBoolean;
|
|
uint8_t vbeInitBoolean;
|
|
int32_t ioSegment;
|
|
uint32_t ioLinear;
|
|
uint32_t rMask;
|
|
uint32_t gMask;
|
|
uint32_t bMask;
|
|
uint32_t aMask;
|
|
uint8_t rShift;
|
|
uint8_t gShift;
|
|
uint8_t bShift;
|
|
uint8_t aShift;
|
|
uint8_t rPos;
|
|
uint8_t gPos;
|
|
uint8_t bPos;
|
|
uint8_t aPos;
|
|
} VBESurfaceT;
|
|
|
|
|
|
static VBESurfaceT _vbeSurface;
|
|
static VBEInfoT _vbeInfo;
|
|
static VBEModeInfoT _vbeModeInfo;
|
|
static PModeInterfaceT *_pmodeInterfacePtr;
|
|
static uint32_t *_yTable;
|
|
|
|
|
|
static void vbeCreatePalette(void);
|
|
static VBEInfoT *vbeGetInfo(void);
|
|
static VBEModeInfoT *vbeGetModeInfo(uint16_t vbeModeNumber);
|
|
static void *vbeGetPmodeInterface(void);
|
|
static uint8_t vbeIsDesiredMode(void);
|
|
static uint16_t vbeSelectModeNumber(uint16_t xRes, uint16_t yRes, uint8_t bpp);
|
|
static VBESurfaceT *vbeSetMode(uint16_t vbeModeNumber);
|
|
static uint16_t vbeSetScanlineLength(uint16_t pixelLength);
|
|
|
|
|
|
static void (*pmVBESetDisplayStart)(void);
|
|
|
|
|
|
void platformEventGet(EventT *event) {
|
|
int32_t x;
|
|
int32_t y;
|
|
int16_t dx;
|
|
int16_t dy;
|
|
int16_t h = videoDisplayHeightGet();
|
|
int16_t w = videoDisplayWidthGet();
|
|
int16_t ext = bioskey(KEYBOARD_CHECK_EXTENDED);
|
|
int16_t meta = bioskey(KEYBOARD_META_EXTENDED);
|
|
int16_t key = 0;
|
|
union REGS regs;
|
|
static int32_t lastX = 0;
|
|
static int32_t lastY = 0;
|
|
static int32_t lastButtons = 0;
|
|
|
|
event->buttons = lastButtons;
|
|
|
|
// Read mouse motion.
|
|
regs.x.ax = MOUSE_GETMOTION;
|
|
int86(MOUSE_INT, ®s, ®s);
|
|
dx = regs.x.cx; // Temporary assignment changes values to signed.
|
|
dy = regs.x.dx; // Don't skip this step. :-)
|
|
x = lastX + dx;
|
|
y = lastY + dy;
|
|
if (x < 0) x = 0;
|
|
if (x > w - 1) x = w - 1;
|
|
if (y < 0) y = 0;
|
|
if (y > h - 1) y = h - 1;
|
|
lastX = x;
|
|
lastY = y;
|
|
event->x = x;
|
|
event->y = y;
|
|
|
|
// Read mouse buttons.
|
|
regs.x.ax = MOUSE_STATUS;
|
|
int86(MOUSE_INT, ®s, ®s);
|
|
|
|
// Was the left button down?
|
|
if (event->buttons & BUTTON_LEFT) {
|
|
// Yes. Is it still down?
|
|
if ((regs.x.bx & MOUSE_LEFT_BUTTON) > 0) {
|
|
// Yes. Do nothing.
|
|
} else {
|
|
// No! Clear it and set UP event.
|
|
event->buttons &= ~BUTTON_LEFT;
|
|
event->flags |= EVENT_FLAG_LEFT_UP;
|
|
}
|
|
} else {
|
|
// No. Is it down now?
|
|
if ((regs.x.bx & MOUSE_LEFT_BUTTON) > 0) {
|
|
// Yes! Set bit and DOWN event.
|
|
event->buttons |= BUTTON_LEFT;
|
|
event->flags |= EVENT_FLAG_LEFT_DOWN;
|
|
} else {
|
|
// No. Do nothing.
|
|
}
|
|
}
|
|
|
|
// Was the right button down?
|
|
if (event->buttons & BUTTON_RIGHT) {
|
|
// Yes. Is it still down?
|
|
if ((regs.x.bx & MOUSE_RIGHT_BUTTON) > 0) {
|
|
// Yes. Do nothing.
|
|
} else {
|
|
// No! Clear it and set UP event.
|
|
event->buttons &= ~BUTTON_RIGHT;
|
|
event->flags |= EVENT_FLAG_RIGHT_UP;
|
|
}
|
|
} else {
|
|
// No. Is it down now?
|
|
if ((regs.x.bx & MOUSE_RIGHT_BUTTON) > 0) {
|
|
// Yes! Set bit and DOWN event.
|
|
event->buttons |= BUTTON_RIGHT;
|
|
event->flags |= EVENT_FLAG_RIGHT_DOWN;
|
|
} else {
|
|
// No. Do nothing.
|
|
}
|
|
}
|
|
|
|
// Read keyboard.
|
|
event->key = 0;
|
|
event->kbstat = 0;
|
|
if (ext > 0) {
|
|
key = bioskey(KEYBOARD_READ_EXTENDED);
|
|
// The value returned is a combination of the key's scan code in the high 8 bits
|
|
// and its ASCII code in the low 8 bits. For non-alphanumeric keys, such as the
|
|
// arrow keys, the low 8 bits are zeroed.
|
|
// Extended keys have the E0h prefix in the low 8 bits.
|
|
event->flags |= EVENT_FLAG_KEYPRESS;
|
|
if (LOW_BYTE(key) == 0xE0) {
|
|
//_extended = 1;
|
|
event->key = HIGH_BYTE(key);
|
|
} else {
|
|
//_extended = 0;
|
|
event->key = LOW_BYTE(key);
|
|
}
|
|
if ((meta & (1 << KEY_META_ALT)) + (meta & (1 << KEY_META_ALT_LEFT)) + (meta & (1 << KEY_META_ALT_RIGHT))) event->kbstat |= META_ALT;
|
|
if ((meta & (1 << KEY_META_CONTROL)) + (meta & (1 << KEY_META_CONTROL_LEFT)) + (meta & (1 << KEY_META_CONTROL_RIGHT))) event->kbstat |= META_CTRL;
|
|
if ((meta & (1 << KEY_META_SHIFT_LEFT)) + (meta & (1 << KEY_META_SHIFT_RIGHT))) event->kbstat |= META_SHIFT;
|
|
}
|
|
|
|
lastButtons = event->buttons;
|
|
}
|
|
|
|
|
|
void platformShutdown(void) {
|
|
__dpmi_regs r;
|
|
__dpmi_meminfo m;
|
|
|
|
surfaceShutdown();
|
|
|
|
if (_vbeSurface.vbeInitBoolean == 0) {
|
|
r.x.ax = 0x03; // make sure we're in 3h
|
|
__dpmi_int(0x10, &r); // for buggy vesa implementations
|
|
//return(1);
|
|
}
|
|
|
|
if (_yTable) free(_yTable);
|
|
|
|
// free mapping etc.
|
|
m.size = (_vbeInfo.totalMemory * 64 * 1024);
|
|
m.address = _vbeSurface.lfbLinearAddress;
|
|
__dpmi_unlock_linear_region(&m);
|
|
__dpmi_free_physical_address_mapping(&m);
|
|
__dpmi_free_ldt_descriptor(_vbeSurface.lfbSelector);
|
|
|
|
// get rid of PMI interface
|
|
if (_pmodeInterfacePtr) free(_pmodeInterfacePtr);
|
|
if (_vbeSurface.ioSegment) {
|
|
m.address = _vbeSurface.ioLinear;
|
|
__dpmi_free_physical_address_mapping(&m);
|
|
__dpmi_free_ldt_descriptor(_vbeSurface.ioSegment);
|
|
}
|
|
|
|
// return do DOS
|
|
r.x.ax = 0x03;
|
|
__dpmi_int(0x10, &r);
|
|
|
|
// deinit VBE surface
|
|
_vbeSurface.vbeInitBoolean = 0;
|
|
_vbeSurface.vbeBoolean = 0;
|
|
|
|
// dealloc mode list
|
|
free(_vbeInfo.videoModePtr);
|
|
}
|
|
|
|
|
|
uint8_t platformStartup(int16_t width, int16_t height, int16_t depth) {
|
|
uint16_t vbeModeNumber;
|
|
|
|
if (vbeGetInfo() == NULL) {
|
|
logWrite("No VESA BIOS Extensions found.\n");
|
|
platformShutdown();
|
|
return FAIL;
|
|
}
|
|
|
|
if (_vbeInfo.vbeVersion < 0x0200) {
|
|
logWrite("VBE Version 2.0 or better required.\n");
|
|
platformShutdown();
|
|
return FAIL;
|
|
}
|
|
|
|
vbeGetPmodeInterface();
|
|
|
|
if ((vbeModeNumber = vbeSelectModeNumber(width, height, depth)) == 0) {
|
|
logWrite("No appropriate video mode available.\n");
|
|
platformShutdown();
|
|
return FAIL;
|
|
}
|
|
|
|
if (vbeSetMode(vbeModeNumber) == NULL) {
|
|
platformShutdown();
|
|
return FAIL;
|
|
}
|
|
|
|
surfaceStartup(_vbeSurface.bitsPerPixel);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
static void vbeCreatePalette(void) {
|
|
uint8_t color = 0;
|
|
uint8_t red;
|
|
uint8_t green;
|
|
uint8_t blue;
|
|
|
|
// Create palette for 3:3:2 true color emulation
|
|
for (red = 4; red < 68; red += 8) {
|
|
for (green = 4; green < 68; green += 8) {
|
|
for (blue = 4; blue < 68; blue += 16) {
|
|
outportb(0x3C8, color);
|
|
outportb(0x3C9, red);
|
|
outportb(0x3C9, green);
|
|
outportb(0x3C9, blue);
|
|
color++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static VBEInfoT *vbeGetInfo(void) {
|
|
uint16_t counter = 0;
|
|
uint16_t offset = 0;
|
|
uint16_t vbeMode = 0xFFFF;
|
|
uint16_t *vbeModeList = 0;
|
|
__dpmi_regs r;
|
|
|
|
// we want VBE 2.0+ info
|
|
memcpy(_vbeInfo.vbeSignature, "VBE2", 4);
|
|
|
|
// request info
|
|
r.x.ax = 0x4F00;
|
|
r.x.di = __tb & 0x0F;
|
|
r.x.es = (__tb >> 4) & 0xFFFF;
|
|
dosmemput(&_vbeInfo, sizeof(VBEInfoT), __tb);
|
|
__dpmi_int(0x10, &r);
|
|
if (r.x.ax != 0x004F) return NULL;
|
|
dosmemget(__tb, sizeof(VBEInfoT), &_vbeInfo);
|
|
|
|
if (strncmp(_vbeInfo.vbeSignature, "VESA", 4) != 0) return NULL; // VESA ?
|
|
|
|
// get the videomode list
|
|
do {
|
|
dosmemget(((((long)_vbeInfo.videoModePtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.videoModePtr & 0xFFFF) + (counter * sizeof(short)), sizeof(short), &vbeMode);
|
|
counter++;
|
|
} while (vbeMode != 0xFFFF);
|
|
vbeModeList = malloc((counter + 1) * sizeof(short));
|
|
|
|
counter = 0;
|
|
do {
|
|
dosmemget(((((long)_vbeInfo.videoModePtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.videoModePtr & 0xFFFF) + (counter * sizeof(short)), sizeof(short), &vbeModeList[counter]);
|
|
counter++;
|
|
} while (vbeModeList[counter - 1] != 0xFFFF);
|
|
_vbeInfo.videoModePtr = vbeModeList;
|
|
|
|
// get the OEM string
|
|
counter = 0;
|
|
do {
|
|
dosmemget(((((long)_vbeInfo.oemStringPtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.oemStringPtr & 0xFFFF) + counter, sizeof(char), &_vbeInfo.oemData[counter]);
|
|
counter++;
|
|
} while (_vbeInfo.oemData[counter - 1] != 0);
|
|
_vbeInfo.oemStringPtr = &_vbeInfo.oemData[0];
|
|
offset = counter;
|
|
|
|
if (_vbeInfo.vbeVersion >= 0x0200) {
|
|
// get the vendor name
|
|
counter = 0;
|
|
do {
|
|
dosmemget(((((long)_vbeInfo.oemVendorNamePtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.oemVendorNamePtr & 0xFFFF) + counter, sizeof(char), &_vbeInfo.oemData[counter + offset]);
|
|
counter++;
|
|
} while (_vbeInfo.oemData[counter + offset - 1] != 0);
|
|
_vbeInfo.oemVendorNamePtr = &_vbeInfo.oemData[offset];
|
|
offset = offset + counter;
|
|
|
|
// get the product name
|
|
counter = 0;
|
|
do {
|
|
dosmemget(((((long)_vbeInfo.oemProductNamePtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.oemProductNamePtr & 0xFFFF) + counter, sizeof(char), &_vbeInfo.oemData[counter + offset]);
|
|
counter++;
|
|
} while (_vbeInfo.oemData[counter + offset - 1] != 0);
|
|
_vbeInfo.oemProductNamePtr = &_vbeInfo.oemData[offset];
|
|
offset = offset + counter;
|
|
|
|
//get the product revision
|
|
counter = 0;
|
|
do {
|
|
dosmemget(((((long)_vbeInfo.oemProductRevPtr >> 16) & 0xFFFF) << 4) + ((long)_vbeInfo.oemProductRevPtr & 0xFFFF) + counter, sizeof(char), &_vbeInfo.oemData[counter + offset]);
|
|
counter++;
|
|
} while (_vbeInfo.oemData[counter + offset - 1] != 0);
|
|
_vbeInfo.oemProductRevPtr = &_vbeInfo.oemData[offset];
|
|
}
|
|
|
|
_vbeSurface.vbeBoolean = 1;
|
|
|
|
return(&_vbeInfo);
|
|
}
|
|
|
|
|
|
static VBEModeInfoT *vbeGetModeInfo(uint16_t vbeModeNumber) {
|
|
__dpmi_regs r;
|
|
|
|
if (_vbeSurface.vbeBoolean == 0) return NULL;
|
|
|
|
r.x.ax = 0x4F01;
|
|
r.x.cx = vbeModeNumber;
|
|
r.x.di = __tb & 0x0F;
|
|
r.x.es = (__tb >> 4) & 0xFFFF;
|
|
__dpmi_int(0x10, &r);
|
|
|
|
if (r.x.ax != 0x004F) return NULL;
|
|
|
|
dosmemget(__tb, sizeof(VBEModeInfoT), &_vbeModeInfo);
|
|
|
|
// Fake 3:3:2 true color for packed modes.
|
|
if (_vbeModeInfo.bitsPerPixel == 8) {
|
|
_vbeModeInfo.blueMaskSize = 2;
|
|
_vbeModeInfo.greenMaskSize = 3;
|
|
_vbeModeInfo.redMaskSize = 3;
|
|
}
|
|
|
|
if (_vbeModeInfo.bitsPerPixel == 16) {
|
|
// for buggy VBE implementations
|
|
_vbeModeInfo.bitsPerPixel = _vbeModeInfo.redMaskSize + _vbeModeInfo.greenMaskSize + _vbeModeInfo.blueMaskSize;
|
|
}
|
|
|
|
return(&_vbeModeInfo);
|
|
}
|
|
|
|
|
|
static void *vbeGetPmodeInterface(void) {
|
|
__dpmi_regs r;
|
|
__dpmi_meminfo m;
|
|
uint16_t *ptr;
|
|
|
|
// only available in VBE 2.0+
|
|
if (_vbeInfo.vbeVersion < 0x200) return NULL;
|
|
|
|
r.x.ax = 0x4F0A;
|
|
r.x.bx = 0;
|
|
__dpmi_int(0x10, &r);
|
|
if (r.x.ax != 0x004F) return NULL;
|
|
|
|
// copy interface
|
|
_pmodeInterfacePtr = (PModeInterfaceT *)malloc(r.x.cx);
|
|
dosmemget((r.x.es * 16) + r.x.di, r.x.cx, _pmodeInterfacePtr);
|
|
_go32_dpmi_lock_data(_pmodeInterfacePtr, r.x.cx);
|
|
|
|
// need memory-mapped IO?
|
|
if (_pmodeInterfacePtr->ioInfo) {
|
|
ptr = (uint16_t *)((char *)_pmodeInterfacePtr + _pmodeInterfacePtr->ioInfo);
|
|
// skip the port table...
|
|
while (*ptr != 0xFFFF)
|
|
ptr++;
|
|
ptr++;
|
|
// ...and get descriptor
|
|
if (*ptr != 0xFFFF) {
|
|
m.address = *((uint32_t *)ptr);
|
|
m.size = *(ptr + 2);
|
|
if (__dpmi_physical_address_mapping(&m) != 0) return NULL;
|
|
_vbeSurface.ioLinear = m.address;
|
|
__dpmi_lock_linear_region(&m);
|
|
_vbeSurface.ioSegment = __dpmi_allocate_ldt_descriptors(1);
|
|
if (_vbeSurface.ioSegment < 0) {
|
|
__dpmi_unlock_linear_region(&m);
|
|
__dpmi_free_physical_address_mapping(&m);
|
|
return NULL;
|
|
}
|
|
__dpmi_set_segment_base_address(_vbeSurface.ioSegment, _vbeSurface.ioLinear);
|
|
__dpmi_set_segment_limit(_vbeSurface.ioSegment, m.size - 1);
|
|
}
|
|
}
|
|
|
|
pmVBESetDisplayStart = (void *)((char *)_pmodeInterfacePtr + _pmodeInterfacePtr->setDisplayStart);
|
|
|
|
return pmVBESetDisplayStart;
|
|
}
|
|
|
|
|
|
static uint8_t vbeIsDesiredMode(void) {
|
|
// This is a custom filter to remove modes not supported by the calling application.
|
|
|
|
// Must be linear.
|
|
if (((_vbeModeInfo.modeAttributes) & (1<<7)) >> 7) {
|
|
// Packed or Direct Color mode.
|
|
if (_vbeModeInfo.memoryModel == VBE_MM_PACKED || _vbeModeInfo.memoryModel == VBE_MM_DCOLOR) {
|
|
// We only handle these bit depths.
|
|
if ((_vbeModeInfo.bitsPerPixel == 8) || (_vbeModeInfo.bitsPerPixel == 16) || (_vbeModeInfo.bitsPerPixel == 32)) {
|
|
// Resolution minimum of 640x480.
|
|
if (_vbeModeInfo.xResolution >= 640 && _vbeModeInfo.yResolution >= 480) {
|
|
// Multiple of 8
|
|
if (DIVISIBLE_BY_EIGHT(_vbeModeInfo.xResolution) && DIVISIBLE_BY_EIGHT(_vbeModeInfo.yResolution)) {
|
|
// Valid mode!
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Rejected!
|
|
return 0;
|
|
}
|
|
|
|
|
|
static uint16_t vbeSelectModeNumber(uint16_t xRes, uint16_t yRes, uint8_t bpp) {
|
|
uint16_t counter;
|
|
|
|
if (_vbeSurface.vbeBoolean == 0) return(0);
|
|
|
|
for (counter = 0; ; counter++) {
|
|
if (_vbeInfo.videoModePtr[counter] == 0xFFFF) return(0);
|
|
vbeGetModeInfo(_vbeInfo.videoModePtr[counter]);
|
|
if (vbeIsDesiredMode()) {
|
|
if (_vbeModeInfo.xResolution == xRes && _vbeModeInfo.yResolution == yRes && _vbeModeInfo.bitsPerPixel == bpp)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(_vbeInfo.videoModePtr[counter]);
|
|
}
|
|
|
|
|
|
static VBESurfaceT *vbeSetMode(uint16_t vbeModeNumber) {
|
|
__dpmi_regs r;
|
|
__dpmi_meminfo m;
|
|
uint32_t counter;
|
|
|
|
if (_vbeSurface.vbeBoolean == 0) return NULL;
|
|
if (_vbeSurface.vbeInitBoolean == 1) return NULL;
|
|
if (vbeGetModeInfo(vbeModeNumber) == 0) return NULL;
|
|
|
|
if (_yTable) free(_yTable);
|
|
if ((_yTable = malloc(4 * (_vbeModeInfo.yResolution + 1))) == 0) return NULL;
|
|
for (counter = 0; counter <= _vbeModeInfo.yResolution; counter++) {
|
|
_yTable[counter] = _vbeModeInfo.xResolution * counter;// * ((_vbeModeInfo.bitsPerPixel + 1) / 8);
|
|
}
|
|
|
|
// request frame buffer
|
|
r.x.ax = 0x4F02;
|
|
r.x.bx = (vbeModeNumber | 0x4000);
|
|
__dpmi_int(0x10, &r);
|
|
if (r.x.ax != 0x004F) return(0);
|
|
|
|
m.size = (_vbeInfo.totalMemory * 64 * 1024);
|
|
m.address = _vbeModeInfo.physBasePtr;
|
|
__dpmi_physical_address_mapping(&m);
|
|
__dpmi_lock_linear_region(&m);
|
|
|
|
_vbeSurface.lfbLinearAddress = m.address;
|
|
_vbeSurface.lfbSelector = __dpmi_allocate_ldt_descriptors(1);
|
|
|
|
__dpmi_set_segment_base_address(_vbeSurface.lfbSelector, _vbeSurface.lfbLinearAddress);
|
|
__dpmi_set_segment_limit(_vbeSurface.lfbSelector, (_vbeInfo.totalMemory * 64 * 1024) - 1);
|
|
|
|
_vbeSurface.lfbNearPtr = (void *)(_vbeSurface.lfbLinearAddress + __djgpp_conventional_base);
|
|
_vbeSurface.xResolution = _vbeModeInfo.xResolution;
|
|
_vbeSurface.yResolution = _vbeModeInfo.yResolution;
|
|
_vbeSurface.bitsPerPixel = _vbeModeInfo.bitsPerPixel;
|
|
_vbeSurface.virtualXResolution = _vbeModeInfo.xResolution;
|
|
_vbeSurface.bytesPerPixel = (_vbeModeInfo.bitsPerPixel + 1) / 8;
|
|
_vbeSurface.centerX = _vbeSurface.virtualXResolution / 2;
|
|
_vbeSurface.centerY = _vbeSurface.yResolution / 2;
|
|
_vbeSurface.numberOfOffscreens = vbeSetScanlineLength(_vbeModeInfo.xResolution) / _vbeModeInfo.yResolution;
|
|
_vbeSurface.vbeInitBoolean = 1;
|
|
_vbeSurface.screenBytes = (_vbeSurface.xResolution * _vbeSurface.yResolution * _vbeSurface.bytesPerPixel);
|
|
_vbeSurface.screenDWords = _vbeSurface.screenBytes / 4;
|
|
_vbeSurface.lfbMemSize = (_vbeSurface.xResolution * _vbeSurface.yResolution * _vbeSurface.bytesPerPixel) / 1024 + _vbeModeInfo.offScreenMemSize;
|
|
|
|
for (counter = 0; counter < (_vbeSurface.lfbMemSize * 1024); counter++) {
|
|
_farpokeb(_vbeSurface.lfbSelector, counter, 0x0); // clear Lfb
|
|
}
|
|
|
|
if (_vbeModeInfo.memoryModel == VBE_MM_PACKED) {
|
|
vbeCreatePalette();
|
|
|
|
_vbeModeInfo.redFieldPosition = 5;
|
|
_vbeModeInfo.greenFieldPosition = 2;
|
|
_vbeModeInfo.blueFieldPosition = 0;
|
|
_vbeModeInfo.rsvdFieldPosition = 8;
|
|
|
|
_vbeModeInfo.redMaskSize = 3;
|
|
_vbeModeInfo.greenMaskSize = 3;
|
|
_vbeModeInfo.blueMaskSize = 2;
|
|
_vbeModeInfo.rsvdMaskSize = 0;
|
|
}
|
|
|
|
_vbeSurface.rMask = ((1UL << _vbeModeInfo.redMaskSize) - 1) << _vbeModeInfo.redFieldPosition;
|
|
_vbeSurface.gMask = ((1UL << _vbeModeInfo.greenMaskSize) - 1) << _vbeModeInfo.greenFieldPosition;
|
|
_vbeSurface.bMask = ((1UL << _vbeModeInfo.blueMaskSize) - 1) << _vbeModeInfo.blueFieldPosition;
|
|
_vbeSurface.aMask = ((1UL << _vbeModeInfo.rsvdMaskSize) - 1) << _vbeModeInfo.rsvdFieldPosition;
|
|
|
|
_vbeSurface.rShift = 8 - _vbeModeInfo.redMaskSize;
|
|
_vbeSurface.gShift = 8 - _vbeModeInfo.greenMaskSize;
|
|
_vbeSurface.bShift = 8 - _vbeModeInfo.blueMaskSize;
|
|
_vbeSurface.aShift = 8 - _vbeModeInfo.rsvdMaskSize;
|
|
|
|
_vbeSurface.rPos = _vbeModeInfo.redFieldPosition;
|
|
_vbeSurface.gPos = _vbeModeInfo.greenFieldPosition;
|
|
_vbeSurface.bPos = _vbeModeInfo.blueFieldPosition;
|
|
_vbeSurface.aPos = _vbeModeInfo.rsvdFieldPosition;
|
|
|
|
/*
|
|
logWrite("VESA Red Mask %u Shift %u Loss %u\n", _vbeSurface.rMask, _vbeSurface.rPos, _vbeSurface.rShift);
|
|
logWrite("VESA Green Mask %u Shift %u Loss %u\n", _vbeSurface.gMask, _vbeSurface.gPos, _vbeSurface.gShift);
|
|
logWrite("VESA Blue Mask %u Shift %u Loss %u\n", _vbeSurface.bMask, _vbeSurface.bPos, _vbeSurface.bShift);
|
|
logWrite("VESA Alpha Mask %u Shift %u Loss %u\n\n", _vbeSurface.aMask, _vbeSurface.aPos, _vbeSurface.aShift);
|
|
*/
|
|
|
|
return(&_vbeSurface);
|
|
}
|
|
|
|
|
|
static uint16_t vbeSetScanlineLength(uint16_t pixelLength) {
|
|
__dpmi_regs r;
|
|
|
|
if (_vbeSurface.vbeBoolean == 0) return(0);
|
|
|
|
r.x.ax = 0x4F06;
|
|
r.x.bx = 0x0000;
|
|
r.x.cx = pixelLength;
|
|
__dpmi_int(0x10, &r);
|
|
if (r.h.ah != 0) return(0);
|
|
if (r.x.cx != pixelLength) return(0);
|
|
|
|
_vbeSurface.virtualXResolution = pixelLength;
|
|
|
|
return(r.x.dx);
|
|
}
|
|
|
|
|
|
void videoBlit(int16_t targetX, int16_t targetY, SurfaceT *source) {
|
|
|
|
//***TODO*** Does not handle partial blits at this time.
|
|
(void)targetX;
|
|
(void)targetY;
|
|
|
|
_movedatal(_my_ds(), (int32_t)source->buffer.bits32, _vbeSurface.lfbSelector, 0x0, _vbeSurface.screenDWords);
|
|
}
|
|
|
|
|
|
uint16_t videoDisplayHeightGet(void) {
|
|
return _vbeSurface.yResolution;
|
|
}
|
|
|
|
|
|
uint16_t videoDisplayWidthGet(void) {
|
|
return _vbeSurface.xResolution;
|
|
}
|
|
|
|
|
|
void videoModesShow(void) {
|
|
int8_t counter;
|
|
|
|
// 0 1 2 3 4 5 6 7 8
|
|
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
|
//printf("VBE 2.0 driver v1.0 (c) 2021, Scott Duensing <scott@kangaroopunch.com>\n");
|
|
//printf("Based on: VBE 2.0 driver v1.0 (c) 1999, Tobias Koch <tobias.koch@gmail.com>\n\n");
|
|
|
|
if (vbeGetInfo() == NULL) {
|
|
logWrite("No VESA BIOS Extensions found.\n");
|
|
platformShutdown();
|
|
return;
|
|
}
|
|
logWrite(
|
|
"Video Memory - %d KB\n"
|
|
"VBE Version - %d.%d detected\n"
|
|
"OEM Specification - %s\n",
|
|
_vbeInfo.totalMemory * 64,
|
|
_vbeInfo.vbeVersion >> 8, _vbeInfo.vbeVersion & 0x00FF,
|
|
_vbeInfo.oemStringPtr);
|
|
|
|
if (_vbeInfo.vbeVersion >= 0x0200) {
|
|
logWrite(
|
|
"OEM Software Revision - %d.%d\n"
|
|
"OEM Vendor Name - %s\n"
|
|
"OEM Product Name - %s\n"
|
|
"OEM Product Revision - %s\n"
|
|
"Protected Mode Interface - %s\n\n",
|
|
_vbeInfo.oemSoftwareRev >> 8, _vbeInfo.oemSoftwareRev & 0x00FF,
|
|
_vbeInfo.oemVendorNamePtr,
|
|
_vbeInfo.oemProductNamePtr,
|
|
_vbeInfo.oemProductRevPtr,
|
|
vbeGetPmodeInterface() ? "Found" : "Missing");
|
|
} else {
|
|
logWrite("VESA BIOS Extension 2.0 or better required!\n");
|
|
platformShutdown();
|
|
return;
|
|
}
|
|
|
|
for (counter=0; ; counter++) {
|
|
if (_vbeInfo.videoModePtr[counter] == 0xFFFF) break;
|
|
vbeGetModeInfo(_vbeInfo.videoModePtr[counter]);
|
|
if (vbeIsDesiredMode()) {
|
|
logWrite("Mode %Xh - %4d x %4d x %2d - RGB %d:%d:%d - %s\n",
|
|
_vbeInfo.videoModePtr[counter],
|
|
_vbeModeInfo.xResolution,
|
|
_vbeModeInfo.yResolution,
|
|
_vbeModeInfo.bitsPerPixel,
|
|
_vbeModeInfo.redMaskSize,
|
|
_vbeModeInfo.greenMaskSize,
|
|
_vbeModeInfo.blueMaskSize,
|
|
((_vbeModeInfo.memoryModel / 2) - 2) ? "DCOLOR" : "PACKED");
|
|
}
|
|
}
|
|
|
|
platformShutdown();
|
|
}
|
|
|
|
|
|
#endif // BACKEND_DJGPP
|