macemu/SheepShaver/src/video.cpp
asvitkine c23511080e [patch from Kelvin Delbarre]
Software cursor mode is now supported, although currently the existing hardware
cursor mode is used whenever possible. (Software mode will be used if you are
running with a recent version of SDL's Quartz video driver, since a bug in SDL
1.2.11 and later prevents the hardware cursor from working properly with that
driver.)

In hardware cursor mode, the hot-spot is now determined heuristically. Formerly
it could not be determined and was always (1,1), an annoyance for many cursors
other than the arrow.

In hardware cursor mode, the cursor will now be hidden when requested by the
emulated OS (such as when you are typing in a text field).

In hardware cursor mode, some cursor image formats that the code does not handle
correctly will now be rejected, causing the emulated OS to revert temporarily to
software cursor mode. Formerly you would just end up with random garbage for a
cursor. This typically happened for grayscale or color cursors; rejecting images
with rowBytes != 2 eliminates the worst cases.
2008-06-25 02:52:52 +00:00

1100 lines
34 KiB
C++

/*
* video.cpp - Video/graphics emulation
*
* SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* TODO
* - check for supported modes ???
*/
#include <stdio.h>
#include <string.h>
#include "sysdeps.h"
#include "video.h"
#include "video_defs.h"
#include "main.h"
#include "adb.h"
#include "macos_util.h"
#include "user_strings.h"
#include "version.h"
#include "thunks.h"
#define DEBUG 0
#include "debug.h"
// Global variables
bool video_activated = false; // Flag: video display activated, mouse and keyboard data valid
uint32 screen_base = 0; // Frame buffer base address
int cur_mode; // Number of current video mode (index in VModes array)
int display_type = DIS_INVALID; // Current display type
rgb_color mac_pal[256];
uint8 remap_mac_be[256];
uint8 MacCursor[68] = {16, 1}; // Mac cursor image
bool keyfile_valid; // Flag: Keyfile is valid, enable full-screen modes
/*
* Video mode information (constructed by VideoInit())
*/
struct VideoInfo VModes[64];
/*
* Driver local variables
*/
VidLocals *private_data = NULL; // Pointer to driver local variables (there is only one display, so this is ok)
static long save_conf_id = APPLE_W_640x480;
static long save_conf_mode = APPLE_8_BIT;
// Function pointers of imported functions
typedef int16 (*iocic_ptr)(void *, int16);
static uint32 iocic_tvect = 0;
static inline int16 IOCommandIsComplete(uintptr arg1, int16 arg2)
{
return (int16)CallMacOS2(iocic_ptr, iocic_tvect, (void *)arg1, arg2);
}
typedef int16 (*vslnewis_ptr)(void *, uint32, uint32 *);
static uint32 vslnewis_tvect = 0;
static inline int16 VSLNewInterruptService(uintptr arg1, uint32 arg2, uintptr arg3)
{
return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, (void *)arg1, arg2, (uint32 *)arg3);
}
typedef int16 (*vsldisposeis_ptr)(uint32);
static uint32 vsldisposeis_tvect = 0;
static inline int16 VSLDisposeInterruptService(uint32 arg1)
{
return (int16)CallMacOS1(vsldisposeis_ptr, vsldisposeis_tvect, arg1);
}
typedef int16 (*vsldois_ptr)(uint32);
static uint32 vsldois_tvect = 0;
int16 VSLDoInterruptService(uint32 arg1)
{
return (int16)CallMacOS1(vsldois_ptr, vsldois_tvect, arg1);
}
typedef void (*nqdmisc_ptr)(uint32, void *);
static uint32 nqdmisc_tvect = 0;
void NQDMisc(uint32 arg1, uintptr arg2)
{
CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, (void *)arg2);
}
// Prototypes
static int16 set_gamma(VidLocals *csSave, uint32 gamma);
/*
* Tell whether window/screen is activated or not (for mouse/keyboard polling)
*/
bool VideoActivated(void)
{
return video_activated;
}
/*
* Create RGB snapshot of current screen
*/
bool VideoSnapshot(int xsize, int ysize, uint8 *p)
{
if (display_type == DIS_WINDOW) {
uint8 *screen = (uint8 *)private_data->saveBaseAddr;
uint32 row_bytes = VModes[cur_mode].viRowBytes;
uint32 y2size = VModes[cur_mode].viYsize;
uint32 x2size = VModes[cur_mode].viXsize;
for (int j=0;j<ysize;j++) {
for (int i=0;i<xsize;i++) {
*p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].red;
*p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].green;
*p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].blue;
}
}
return true;
}
return false;
}
/*
* Determine whether we should use the hardware or software cursor, and return true for the former, false for the latter.
* Currently we use the hardware cursor if we can, but perhaps this can be made a preference someday.
*/
static bool UseHardwareCursor(void)
{
return video_can_change_cursor();
}
/*
* Video driver open routine
*/
static int16 VideoOpen(uint32 pb, VidLocals *csSave)
{
D(bug("Video Open\n"));
// Set up VidLocals
csSave->saveBaseAddr = screen_base;
csSave->saveData = VModes[cur_mode].viAppleID;// First mode ...
csSave->saveMode = VModes[cur_mode].viAppleMode;
csSave->savePage = 0;
csSave->saveVidParms = 0; // Add the right table
csSave->luminanceMapping = false;
csSave->cursorHardware = UseHardwareCursor();
csSave->cursorX = 0;
csSave->cursorY = 0;
csSave->cursorVisible = 0;
csSave->cursorSet = 0;
csSave->cursorHotFlag = false;
csSave->cursorHotX = 0;
csSave->cursorHotY = 0;
// Find and set default gamma table
csSave->gammaTable = 0;
csSave->maxGammaTableSize = 0;
set_gamma(csSave, 0);
// Install and activate interrupt service
SheepVar32 theServiceID = 0;
VSLNewInterruptService(csSave->regEntryID, FOURCC('v','b','l',' '), theServiceID.addr());
csSave->vslServiceID = theServiceID.value();
D(bug(" Interrupt ServiceID %08lx\n", csSave->vslServiceID));
csSave->interruptsEnabled = true;
return noErr;
}
/*
* Video driver control routine
*/
static bool allocate_gamma_table(VidLocals *csSave, uint32 size)
{
if (size > csSave->maxGammaTableSize) {
if (csSave->gammaTable) {
Mac_sysfree(csSave->gammaTable);
csSave->gammaTable = 0;
csSave->maxGammaTableSize = 0;
}
if ((csSave->gammaTable = Mac_sysalloc(size)) == 0)
return false;
csSave->maxGammaTableSize = size;
}
return true;
}
static int16 set_gamma(VidLocals *csSave, uint32 gamma)
{
return paramErr;
if (gamma == 0) { // Build linear ramp, 256 entries
// Allocate new table, if necessary
if (!allocate_gamma_table(csSave, SIZEOF_GammaTbl + 256))
return memFullErr;
// Initialize header
WriteMacInt16(csSave->gammaTable + gVersion, 0); // A version 0 style of the GammaTbl structure
WriteMacInt16(csSave->gammaTable + gType, 0); // Frame buffer hardware invariant
WriteMacInt16(csSave->gammaTable + gFormulaSize, 0); // No formula data, just correction data
WriteMacInt16(csSave->gammaTable + gChanCnt, 1); // Apply same correction to Red, Green, & Blue
WriteMacInt16(csSave->gammaTable + gDataCnt, 256); // gDataCnt == 2^^gDataWidth
WriteMacInt16(csSave->gammaTable + gDataWidth, 8); // 8 bits of significant data per entry
// Build the linear ramp
uint32 p = csSave->gammaTable + gFormulaData;
for (int i=0; i<256; i++)
WriteMacInt8(p + i, i);
} else { // User-supplied gamma table
// Validate header
if (ReadMacInt16(gamma + gVersion) != 0)
return paramErr;
if (ReadMacInt16(gamma + gType) != 0)
return paramErr;
int chan_cnt = ReadMacInt16(gamma + gChanCnt);
if (chan_cnt != 1 && chan_cnt != 3)
return paramErr;
int data_width = ReadMacInt16(gamma + gDataWidth);
if (data_width > 8)
return paramErr;
int data_cnt = ReadMacInt16(gamma + gDataWidth);
if (data_cnt != (1 << data_width))
return paramErr;
// Allocate new table, if necessary
int size = SIZEOF_GammaTbl + ReadMacInt16(gamma + gFormulaSize) + chan_cnt * data_cnt;
if (!allocate_gamma_table(csSave, size))
return memFullErr;
// Copy table
Mac2Mac_memcpy(csSave->gammaTable, gamma, size);
}
return noErr;
}
static int16 VideoControl(uint32 pb, VidLocals *csSave)
{
int16 code = ReadMacInt16(pb + csCode);
D(bug("VideoControl %d: ", code));
uint32 param = ReadMacInt32(pb + csParam);
switch (code) {
case cscReset: // VidReset
D(bug("VidReset\n"));
return controlErr;
case cscKillIO: // VidKillIO
D(bug("VidKillIO\n"));
return controlErr;
case cscSetMode: // SetVidMode
D(bug("SetVidMode\n"));
D(bug("mode:%04x page:%04x \n", ReadMacInt16(param + csMode),
ReadMacInt16(param + csPage)));
WriteMacInt32(param + csData, csSave->saveData);
return video_mode_change(csSave, param);
case cscSetEntries: { // SetEntries
D(bug("SetEntries\n"));
if (VModes[cur_mode].viAppleMode > APPLE_8_BIT) return controlErr;
uint32 s_pal = ReadMacInt32(param + csTable);
uint16 start = ReadMacInt16(param + csStart);
uint16 count = ReadMacInt16(param + csCount);
if (s_pal == 0 || count > 256) return controlErr;
// Preparations for gamma correction
bool do_gamma = false;
uint8 *red_gamma = NULL;
uint8 *green_gamma = NULL;
uint8 *blue_gamma = NULL;
int gamma_data_width = 0;
if (csSave->gammaTable) {
#ifdef __BEOS__
// Windows are gamma-corrected by BeOS
const bool can_do_gamma = (display_type == DIS_SCREEN);
#else
const bool can_do_gamma = true;
#endif
if (can_do_gamma) {
uint32 gamma_table = csSave->gammaTable;
red_gamma = Mac2HostAddr(gamma_table + gFormulaData + ReadMacInt16(gamma_table + gFormulaSize));
int chan_cnt = ReadMacInt16(gamma_table + gChanCnt);
if (chan_cnt == 1)
green_gamma = blue_gamma = red_gamma;
else {
int ofs = ReadMacInt16(gamma_table + gDataCnt);
green_gamma = red_gamma + ofs;
blue_gamma = green_gamma + ofs;
}
gamma_data_width = ReadMacInt16(gamma_table + gDataWidth);
do_gamma = true;
}
}
// Set palette
rgb_color *d_pal;
if (start == 0xffff) { // Indexed
for (int i=0; i<=count; i++) {
d_pal = mac_pal + (ReadMacInt16(s_pal + csValue) & 0xff);
uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8;
uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8;
uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8;
if (csSave->luminanceMapping)
red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
if (do_gamma) {
red = red_gamma[red >> (8 - gamma_data_width)];
green = green_gamma[green >> (8 - gamma_data_width)];
blue = blue_gamma[blue >> (8 - gamma_data_width)];
}
(*d_pal).red = red;
(*d_pal).green = green;
(*d_pal).blue = blue;
s_pal += 8;
}
} else { // Sequential
d_pal = mac_pal + start;
for (int i=0; i<=count; i++) {
uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8;
uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8;
uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8;
if (csSave->luminanceMapping)
red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
if (do_gamma) {
red = red_gamma[red >> (8 - gamma_data_width)];
green = green_gamma[green >> (8 - gamma_data_width)];
blue = blue_gamma[blue >> (8 - gamma_data_width)];
}
(*d_pal).red = red;
(*d_pal).green = green;
(*d_pal).blue = blue;
d_pal++;
s_pal += 8;
}
}
video_set_palette();
return noErr;
}
case cscSetGamma: { // SetGamma
uint32 user_table = ReadMacInt32(param + csGTable);
D(bug("SetGamma %08x\n", user_table));
return set_gamma(csSave, ReadMacInt32(user_table));
}
case cscGrayPage: { // GrayPage
D(bug("GrayPage %d\n", ReadMacInt16(param + csPage)));
if (ReadMacInt16(param + csPage))
return paramErr;
uint32 pattern[6] = {
0xaaaaaaaa, // 1 bpp
0xcccccccc, // 2 bpp
0xf0f0f0f0, // 4 bpp
0xff00ff00, // 8 bpp
0xffff0000, // 16 bpp
0xffffffff // 32 bpp
};
uint32 p = csSave->saveBaseAddr;
uint32 pat = pattern[VModes[cur_mode].viAppleMode - APPLE_1_BIT];
bool invert = (VModes[cur_mode].viAppleMode == APPLE_32_BIT);
for (uint32 y=0; y<VModes[cur_mode].viYsize; y++) {
for (uint32 x=0; x<VModes[cur_mode].viRowBytes; x+=4) {
WriteMacInt32(p + x, pat);
if (invert)
pat = ~pat;
}
p += VModes[cur_mode].viRowBytes;
pat = ~pat;
}
return noErr;
}
case cscSetGray: // SetGray
D(bug("SetGray %02x\n", ReadMacInt8(param)));
csSave->luminanceMapping = ReadMacInt8(param);
return noErr;
case cscSetInterrupt: // SetInterrupt
D(bug("SetInterrupt\n"));
csSave->interruptsEnabled = !ReadMacInt8(param);
return noErr;
case cscDirectSetEntries: // DirectSetEntries
D(bug("DirectSetEntries\n"));
return controlErr;
case cscSetDefaultMode: // SetDefaultMode
D(bug("SetDefaultMode\n"));
return controlErr;
case cscSwitchMode:
D(bug("cscSwitchMode (Display Manager support) \nMode:%02x ID:%04x Page:%d\n",
ReadMacInt16(param + csMode), ReadMacInt32(param + csData), ReadMacInt16(param + csPage)));
return video_mode_change(csSave, param);
case cscSavePreferredConfiguration:
D(bug("SavePreferredConfiguration\n"));
save_conf_id = ReadMacInt32(param + csData);
save_conf_mode = ReadMacInt16(param + csMode);
return noErr;
case cscSetHardwareCursor: {
// D(bug("SetHardwareCursor\n"));
if (!csSave->cursorHardware)
return controlErr;
csSave->cursorSet = false;
bool changed = false;
// Image
uint32 cursor = ReadMacInt32(param); // Pointer to CursorImage
uint32 pmhandle = ReadMacInt32(cursor + ciCursorPixMap);
if (pmhandle == 0 || ReadMacInt32(pmhandle) == 0)
return controlErr;
uint32 pixmap = ReadMacInt32(pmhandle);
// XXX: only certain image formats are handled properly at the moment
uint16 rowBytes = ReadMacInt16(pixmap + 4) & 0x7FFF;
if (rowBytes != 2)
return controlErr;
// Mask
uint32 bmhandle = ReadMacInt32(cursor + ciCursorBitMask);
if (bmhandle == 0 || ReadMacInt32(bmhandle) == 0)
return controlErr;
uint32 bitmap = ReadMacInt32(bmhandle);
// Get cursor data even on a screen, to set the right cursor image when switching back to a window.
// Hotspot is stale, but will be fixed by the next call to DrawHardwareCursor, which is likely to
// occur immediately hereafter.
if (memcmp(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32)) {
memcpy(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32);
changed = true;
}
if (memcmp(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32)) {
memcpy(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32);
changed = true;
}
// Set new cursor image
if (!video_can_change_cursor())
return controlErr;
if (changed)
video_set_cursor();
csSave->cursorSet = true;
csSave->cursorHotFlag = true;
return noErr;
}
case cscDrawHardwareCursor: {
// D(bug("DrawHardwareCursor\n"));
if (!csSave->cursorHardware)
return controlErr;
int32 oldX = csSave->cursorX;
int32 oldY = csSave->cursorY;
uint32 oldVisible = csSave->cursorVisible;
csSave->cursorX = ReadMacInt32(param + csCursorX);
csSave->cursorY = ReadMacInt32(param + csCursorY);
csSave->cursorVisible = ReadMacInt32(param + csCursorVisible);
bool changed = (csSave->cursorVisible != oldVisible);
// If this is the first DrawHardwareCursor call since the cursor was last set (via SetHardwareCursor),
// attempt to set an appropriate cursor hotspot. SetHardwareCursor itself does not know what the
// hotspot should be; it knows only the cursor image and mask. The hotspot is known only to the caller,
// and we have to try to infer it here. The usual sequence of calls when changing the cursor is:
//
// DrawHardwareCursor with (oldX, oldY, invisible)
// SetHardwareCursor with (cursor)
// DrawHardwareCursor with (newX, newY, visible)
//
// The key thing to note is that the sequence is intended not to change the current screen pixel location
// indicated by the hotspot. Thus, the difference between (newX, newY) and (oldX, oldY) reflects precisely
// the difference between the old cursor hotspot and the new one. For example, if you change from a
// cursor whose hotspot is (1, 1) to one whose hotspot is (7, 4), then you must adjust the cursor position
// by (-6, -3) in order for the same screen pixel to remain under the new hotspot.
//
// Alas, on rare occasions this heuristic can fail, and if you did nothing else you could even get stuck
// with the wrong hotspot from then on. To address that possibility, we force the hotspot to (1, 1)
// whenever the cursor being drawn is the standard arrow. Thus, while it is very unlikely that you will
// ever have the wrong hotspot, if you do, it is easy to recover.
if (csSave->cursorHotFlag) {
csSave->cursorHotFlag = false;
D(bug("old hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY));
static uint8 arrow[] = {
0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, 0x78, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x7F, 0x00,
0x7F, 0x80, 0x7C, 0x00, 0x6C, 0x00, 0x46, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
};
if (memcmp(MacCursor + 4, arrow, 32) == 0) {
csSave->cursorHotX = 1;
csSave->cursorHotY = 1;
} else if (csSave->cursorX != oldX || csSave->cursorY != oldY) {
int32 hotX = csSave->cursorHotX + (oldX - csSave->cursorX);
int32 hotY = csSave->cursorHotY + (oldY - csSave->cursorY);
if (0 <= hotX && hotX <= 15 && 0 <= hotY && hotY <= 15) {
csSave->cursorHotX = hotX;
csSave->cursorHotY = hotY;
}
}
if (MacCursor[2] != csSave->cursorHotX || MacCursor[3] != csSave->cursorHotY) {
MacCursor[2] = csSave->cursorHotX;
MacCursor[3] = csSave->cursorHotY;
changed = true;
}
D(bug("new hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY));
}
if (changed && video_can_change_cursor())
video_set_cursor();
return noErr;
}
case 43: { // Driver Gestalt
uint32 sel = ReadMacInt32(pb + csParam);
D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16, sel >> 8, sel));
switch (sel) {
case FOURCC('v','e','r','s'):
WriteMacInt32(pb + csParam + 4, 0x01008000);
break;
case FOURCC('i','n','t','f'):
WriteMacInt32(pb + csParam + 4, FOURCC('c','a','r','d'));
break;
case FOURCC('s','y','n','c'):
WriteMacInt32(pb + csParam + 4, 0x01000000);
break;
default:
return statusErr;
};
return noErr;
}
default:
D(bug(" unknown control code %d\n", code));
return controlErr;
}
}
/*
* Video driver status routine
*/
// Search for given AppleID in mode table
static bool has_mode(uint32 id)
{
VideoInfo *p = VModes;
while (p->viType != DIS_INVALID) {
if (p->viAppleID == id)
return true;
p++;
}
return false;
}
// Find maximum depth for given AppleID
static uint32 max_depth(uint32 id)
{
uint32 max = APPLE_1_BIT;
VideoInfo *p = VModes;
while (p->viType != DIS_INVALID) {
if (p->viAppleID == id && p->viAppleMode > max)
max = p->viAppleMode;
p++;
}
return max;
}
// Get X/Y size of specified resolution
static void get_size_of_resolution(int id, uint32 &x, uint32 &y)
{
VideoInfo *p = VModes;
while (p->viType != DIS_INVALID) {
if (p->viAppleID == id) {
x = p->viXsize;
y = p->viYsize;
return;
}
p++;
}
x = y = 0;
}
static int16 VideoStatus(uint32 pb, VidLocals *csSave)
{
int16 code = ReadMacInt16(pb + csCode);
D(bug("VideoStatus %d: ", code));
uint32 param = ReadMacInt32(pb + csParam);
switch (code) {
case cscGetMode: // GetMode
D(bug("GetMode\n"));
WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr);
WriteMacInt16(param + csMode, csSave->saveMode);
WriteMacInt16(param + csPage, csSave->savePage);
D(bug("return: mode:%04x page:%04x ", ReadMacInt16(param + csMode),
ReadMacInt16(param + csPage)));
D(bug("base adress %08lx\n", ReadMacInt32(param + csBaseAddr)));
return noErr;
case cscGetEntries: { // GetEntries
D(bug("GetEntries\n"));
uint32 d_pal = ReadMacInt32(param + csTable);
uint16 start = ReadMacInt16(param + csStart);
uint16 count = ReadMacInt16(param + csCount);
rgb_color *s_pal;
if ((VModes[cur_mode].viAppleMode == APPLE_32_BIT)||
(VModes[cur_mode].viAppleMode == APPLE_16_BIT)) {
D(bug("ERROR: GetEntries in direct mode \n"));
return statusErr;
}
if (start == 0xffff) { // Indexed
for (uint16 i=0;i<count;i++) {
s_pal = mac_pal + (ReadMacInt16(d_pal + csValue) & 0xff);
uint8 red = (*s_pal).red;
uint8 green = (*s_pal).green;
uint8 blue = (*s_pal).blue;
WriteMacInt16(d_pal + csRed, red * 0x0101);
WriteMacInt16(d_pal + csGreen, green * 0x0101);
WriteMacInt16(d_pal + csBlue, blue * 0x0101);
d_pal += 8;
}
} else { // Sequential
if (start + count > 255)
return paramErr;
s_pal = mac_pal + start;
for (uint16 i=0;i<count;i++) {
uint8 red = (*s_pal).red;
uint8 green = (*s_pal).green;
uint8 blue = (*s_pal).blue;
s_pal++;
WriteMacInt16(d_pal + csRed, red * 0x0101);
WriteMacInt16(d_pal + csGreen, green * 0x0101);
WriteMacInt16(d_pal + csBlue, blue * 0x0101);
d_pal += 8;
}
};
return noErr;
}
case cscGetPageCnt: // GetPage
D(bug("GetPage\n"));
WriteMacInt16(param + csPage, 1);
return noErr;
case cscGetPageBase: // GetPageBase
D(bug("GetPageBase\n"));
WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr);
return noErr;
case cscGetGray: // GetGray
D(bug("GetGray\n"));
WriteMacInt8(param, csSave->luminanceMapping ? 1 : 0);
return noErr;
case cscGetInterrupt: // GetInterrupt
D(bug("GetInterrupt\n"));
WriteMacInt8(param, csSave->interruptsEnabled ? 0 : 1);
return noErr;
case cscGetGamma: // GetGamma
D(bug("GetGamma\n"));
WriteMacInt32(param, (uint32)csSave->gammaTable);
return statusErr;
case cscGetDefaultMode: // GetDefaultMode
D(bug("GetDefaultMode\n"));
return statusErr;
case cscGetCurMode: // GetCurMode
D(bug("GetCurMode\n"));
WriteMacInt16(param + csMode, csSave->saveMode);
WriteMacInt32(param + csData, csSave->saveData);
WriteMacInt16(param + csPage, csSave->savePage);
WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr);
D(bug("return: mode:%04x ID:%08lx page:%04x ", ReadMacInt16(param + csMode),
ReadMacInt32(param + csData), ReadMacInt16(param + csPage)));
D(bug("base adress %08lx\n", ReadMacInt32(param + csBaseAddr)));
return noErr;
case cscGetConnection: // GetConnection
D(bug("GetConnection\n"));
WriteMacInt16(param + csDisplayType, kMultiModeCRT3Connect);
WriteMacInt8(param + csConnectTaggedType, 6);
WriteMacInt8(param + csConnectTaggedData, 0x23);
WriteMacInt32(param + csConnectFlags, (1<<kAllModesValid)|(1<<kAllModesSafe));
WriteMacInt32(param + csDisplayComponent, 0);
return noErr;
case cscGetModeBaseAddress:
D(bug("GetModeBaseAddress (obsolete !) \n"));
return statusErr;
case cscGetPreferredConfiguration:
D(bug("GetPreferredConfiguration \n"));
WriteMacInt16(param + csMode, save_conf_mode);
WriteMacInt32(param + csData, save_conf_id);
return noErr;
case cscGetNextResolution: {
D(bug("GetNextResolution \n"));
int work_id = ReadMacInt32(param + csPreviousDisplayModeID);
switch (work_id) {
case kDisplayModeIDCurrent:
work_id = csSave->saveData;
break;
case kDisplayModeIDFindFirstResolution:
work_id = APPLE_ID_MIN;
while (!has_mode(work_id))
work_id ++;
break;
default:
if (!has_mode(work_id))
return paramErr;
work_id++;
while (!has_mode(work_id)) {
work_id++;
if (work_id > APPLE_ID_MAX) {
WriteMacInt32(param + csRIDisplayModeID, kDisplayModeIDNoMoreResolutions);
return noErr;
}
}
break;
}
WriteMacInt32(param + csRIDisplayModeID, work_id);
WriteMacInt16(param + csMaxDepthMode, max_depth(work_id));
switch (work_id) {
case APPLE_640x480:
WriteMacInt32(param + csHorizontalPixels, 640);
WriteMacInt32(param + csVerticalLines, 480);
WriteMacInt32(param + csRefreshRate, 75<<16);
break;
case APPLE_W_640x480:
WriteMacInt32(param + csHorizontalPixels, 640);
WriteMacInt32(param + csVerticalLines, 480);
WriteMacInt32(param + csRefreshRate, 60<<16);
break;
case APPLE_800x600:
WriteMacInt32(param + csHorizontalPixels, 800);
WriteMacInt32(param + csVerticalLines, 600);
WriteMacInt32(param + csRefreshRate, 75<<16);
break;
case APPLE_W_800x600:
WriteMacInt32(param + csHorizontalPixels, 800);
WriteMacInt32(param + csVerticalLines, 600);
WriteMacInt32(param + csRefreshRate, 60<<16);
break;
case APPLE_1024x768:
WriteMacInt32(param + csHorizontalPixels, 1024);
WriteMacInt32(param + csVerticalLines, 768);
WriteMacInt32(param + csRefreshRate, 75<<16);
break;
case APPLE_1152x768:
WriteMacInt32(param + csHorizontalPixels, 1152);
WriteMacInt32(param + csVerticalLines, 768);
WriteMacInt32(param + csRefreshRate, 75<<16);
break;
case APPLE_1152x900:
WriteMacInt32(param + csHorizontalPixels, 1152);
WriteMacInt32(param + csVerticalLines, 900);
WriteMacInt32(param + csRefreshRate, 75<<16);
break;
case APPLE_1280x1024:
WriteMacInt32(param + csHorizontalPixels, 1280);
WriteMacInt32(param + csVerticalLines, 1024);
WriteMacInt32(param + csRefreshRate, 75<<16);
break;
case APPLE_1600x1200:
WriteMacInt32(param + csHorizontalPixels, 1600);
WriteMacInt32(param + csVerticalLines, 1200);
WriteMacInt32(param + csRefreshRate, 75<<16);
break;
case APPLE_CUSTOM: {
uint32 x, y;
get_size_of_resolution(work_id, x, y);
WriteMacInt32(param + csHorizontalPixels, x);
WriteMacInt32(param + csVerticalLines, y);
WriteMacInt32(param + csRefreshRate, 75<<16);
break;
}
}
return noErr;
}
case cscGetVideoParameters: // GetVideoParameters
D(bug("GetVideoParameters ID:%08lx Depth:%04x\n",
ReadMacInt32(param + csDisplayModeID),
ReadMacInt16(param + csDepthMode)));
// find right video mode
for (int i=0; VModes[i].viType!=DIS_INVALID; i++) {
if ((ReadMacInt16(param + csDepthMode) == VModes[i].viAppleMode) &&
(ReadMacInt32(param + csDisplayModeID) == VModes[i].viAppleID)) {
uint32 vpb = ReadMacInt32(param + csVPBlockPtr);
WriteMacInt32(vpb + vpBaseOffset, 0);
WriteMacInt16(vpb + vpRowBytes, VModes[i].viRowBytes);
WriteMacInt16(vpb + vpBounds, 0);
WriteMacInt16(vpb + vpBounds + 2, 0);
WriteMacInt16(vpb + vpBounds + 4, VModes[i].viYsize);
WriteMacInt16(vpb + vpBounds + 6, VModes[i].viXsize);
WriteMacInt16(vpb + vpVersion, 0); // Pixel Map version number
WriteMacInt16(vpb + vpPackType, 0);
WriteMacInt32(vpb + vpPackSize, 0);
WriteMacInt32(vpb + vpHRes, 0x00480000); // horiz res of the device (ppi)
WriteMacInt32(vpb + vpVRes, 0x00480000); // vert res of the device (ppi)
switch (VModes[i].viAppleMode) {
case APPLE_1_BIT:
WriteMacInt16(vpb + vpPixelType, 0);
WriteMacInt16(vpb + vpPixelSize, 1);
WriteMacInt16(vpb + vpCmpCount, 1);
WriteMacInt16(vpb + vpCmpSize, 1);
WriteMacInt32(param + csDeviceType, 0); // CLUT
break;
case APPLE_2_BIT:
WriteMacInt16(vpb + vpPixelType, 0);
WriteMacInt16(vpb + vpPixelSize, 2);
WriteMacInt16(vpb + vpCmpCount, 1);
WriteMacInt16(vpb + vpCmpSize, 2);
WriteMacInt32(param + csDeviceType, 0); // CLUT
break;
case APPLE_4_BIT:
WriteMacInt16(vpb + vpPixelType, 0);
WriteMacInt16(vpb + vpPixelSize, 4);
WriteMacInt16(vpb + vpCmpCount, 1);
WriteMacInt16(vpb + vpCmpSize, 4);
WriteMacInt32(param + csDeviceType, 0); // CLUT
break;
case APPLE_8_BIT:
WriteMacInt16(vpb + vpPixelType, 0);
WriteMacInt16(vpb + vpPixelSize, 8);
WriteMacInt16(vpb + vpCmpCount, 1);
WriteMacInt16(vpb + vpCmpSize, 8);
WriteMacInt32(param + csDeviceType, 0); // CLUT
break;
case APPLE_16_BIT:
WriteMacInt16(vpb + vpPixelType, 0x10);
WriteMacInt16(vpb + vpPixelSize, 16);
WriteMacInt16(vpb + vpCmpCount, 3);
WriteMacInt16(vpb + vpCmpSize, 5);
WriteMacInt32(param + csDeviceType, 2); // DIRECT
break;
case APPLE_32_BIT:
WriteMacInt16(vpb + vpPixelType, 0x10);
WriteMacInt16(vpb + vpPixelSize, 32);
WriteMacInt16(vpb + vpCmpCount, 3);
WriteMacInt16(vpb + vpCmpSize, 8);
WriteMacInt32(param + csDeviceType, 2); // DIRECT
break;
}
WriteMacInt32(param + csPageCount, 1);
return noErr;
}
}
return paramErr;
case cscGetModeTiming:
D(bug("GetModeTiming mode %08lx\n", ReadMacInt32(param + csTimingMode)));
WriteMacInt32(param + csTimingFormat, kDeclROMtables);
WriteMacInt32(param + csTimingFlags, (1<<kModeValid)|(1<<kModeSafe)|(1<<kShowModeNow)); // Mode valid, safe, default and shown in Monitors panel
for (int i=0; VModes[i].viType!=DIS_INVALID; i++) {
if (ReadMacInt32(param + csTimingMode) == VModes[i].viAppleID) {
uint32 timing = timingUnknown;
uint32 flags = (1<<kModeValid) | (1<<kShowModeNow);
switch (VModes[i].viAppleID) {
case APPLE_640x480:
timing = timingVESA_640x480_75hz;
flags |= (1<<kModeSafe);
break;
case APPLE_W_640x480:
timing = timingVESA_640x480_60hz;
flags |= (1<<kModeSafe);
break;
case APPLE_800x600:
timing = timingVESA_800x600_75hz;
flags |= (1<<kModeSafe);
break;
case APPLE_W_800x600:
timing = timingVESA_800x600_60hz;
flags |= (1<<kModeSafe);
break;
case APPLE_1024x768:
timing = timingVESA_1024x768_75hz;
break;
case APPLE_1152x768:
timing = timingApple_1152x870_75hz; // FIXME
break;
case APPLE_1152x900:
timing = timingApple_1152x870_75hz;
break;
case APPLE_1280x1024:
timing = timingVESA_1280x960_75hz;
break;
case APPLE_1600x1200:
timing = timingVESA_1600x1200_75hz;
break;
default:
timing = timingUnknown;
break;
}
WriteMacInt32(param + csTimingData, timing);
WriteMacInt32(param + csTimingFlags, flags);
return noErr;
}
}
return paramErr;
case cscSupportsHardwareCursor:
D(bug("SupportsHardwareCursor\n"));
WriteMacInt32(param, csSave->cursorHardware);
return noErr;
case cscGetHardwareCursorDrawState:
D(bug("GetHardwareCursorDrawState\n"));
if (!csSave->cursorHardware)
return statusErr;
WriteMacInt32(param + csCursorX, csSave->cursorX);
WriteMacInt32(param + csCursorY, csSave->cursorY);
WriteMacInt32(param + csCursorVisible, csSave->cursorVisible);
WriteMacInt32(param + csCursorSet, csSave->cursorSet);
return noErr;
default:
D(bug(" unknown status code %d\n", code));
return statusErr;
}
}
/*
* Video driver close routine
*/
static int16 VideoClose(uint32 pb, VidLocals *csSave)
{
D(bug("VideoClose\n"));
// Delete interrupt service
csSave->interruptsEnabled = false;
VSLDisposeInterruptService(csSave->vslServiceID);
return noErr;
}
/*
* Native (PCI) driver entry
*/
int16 VideoDoDriverIO(uint32 spaceID, uint32 commandID, uint32 commandContents, uint32 commandCode, uint32 commandKind)
{
// D(bug("VideoDoDriverIO space %08x, command %08x, contents %08x, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind));
int16 err = noErr;
switch (commandCode) {
case kInitializeCommand:
case kReplaceCommand:
if (private_data != NULL) { // Might be left over from a reboot
if (private_data->gammaTable)
Mac_sysfree(private_data->gammaTable);
if (private_data->regEntryID)
Mac_sysfree(private_data->regEntryID);
}
delete private_data;
iocic_tvect = FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete");
D(bug("IOCommandIsComplete TVECT at %08lx\n", iocic_tvect));
if (iocic_tvect == 0) {
printf("FATAL: VideoDoDriverIO(): Can't find IOCommandIsComplete()\n");
err = -1;
break;
}
vslnewis_tvect = FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService");
D(bug("VSLNewInterruptService TVECT at %08lx\n", vslnewis_tvect));
if (vslnewis_tvect == 0) {
printf("FATAL: VideoDoDriverIO(): Can't find VSLNewInterruptService()\n");
err = -1;
break;
}
vsldisposeis_tvect = FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService");
D(bug("VSLDisposeInterruptService TVECT at %08lx\n", vsldisposeis_tvect));
if (vsldisposeis_tvect == 0) {
printf("FATAL: VideoDoDriverIO(): Can't find VSLDisposeInterruptService()\n");
err = -1;
break;
}
vsldois_tvect = FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService");
D(bug("VSLDoInterruptService TVECT at %08lx\n", vsldois_tvect));
if (vsldois_tvect == 0) {
printf("FATAL: VideoDoDriverIO(): Can't find VSLDoInterruptService()\n");
err = -1;
break;
}
nqdmisc_tvect = FindLibSymbol("\014InterfaceLib", "\007NQDMisc");
D(bug("NQDMisc TVECT at %08lx\n", nqdmisc_tvect));
if (nqdmisc_tvect == 0) {
printf("FATAL: VideoDoDriverIO(): Can't find NQDMisc()\n");
err = -1;
break;
}
private_data = new VidLocals;
private_data->gammaTable = 0;
private_data->regEntryID = Mac_sysalloc(sizeof(RegEntryID));
if (private_data->regEntryID == 0) {
printf("FATAL: VideoDoDriverIO(): Can't allocate service owner\n");
err = -1;
break;
}
Mac2Mac_memcpy(private_data->regEntryID, commandContents + 2, 16); // DriverInitInfo.deviceEntry
private_data->interruptsEnabled = false; // Disable interrupts
break;
case kFinalizeCommand:
case kSupersededCommand:
if (private_data != NULL) {
if (private_data->gammaTable)
Mac_sysfree(private_data->gammaTable);
if (private_data->regEntryID)
Mac_sysfree(private_data->regEntryID);
}
delete private_data;
private_data = NULL;
break;
case kOpenCommand:
err = VideoOpen(commandContents, private_data);
break;
case kCloseCommand:
err = VideoClose(commandContents, private_data);
break;
case kControlCommand:
err = VideoControl(commandContents, private_data);
break;
case kStatusCommand:
err = VideoStatus(commandContents, private_data);
break;
case kReadCommand:
case kWriteCommand:
break;
case kKillIOCommand:
err = abortErr;
break;
default:
err = paramErr;
break;
}
if (commandKind == kImmediateIOCommandKind)
return err;
else
return IOCommandIsComplete(commandID, err);
}