/* * 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 #include #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]; rgb_color mac_gamma[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;jsaveBaseAddr = 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 inline uint8 max(uint8 a, uint8 b) { return a > b? a : b; } static int16 set_gamma(VidLocals *csSave, uint32 gamma) { 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); mac_gamma[i].red = mac_gamma[i].green = mac_gamma[i].blue = i; } video_set_gamma(256); } 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 + gDataCnt); 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); // Save new gamma data for video impl if (data_width != 8) { // FIXME: handle bit-packed data } else { uint32 p = csSave->gammaTable + gFormulaData + gFormulaSize; uint32 p_red; uint32 p_green; uint32 p_blue; // make values increasing as some implementations really don't like it when gamma tables aren't uint8 max_red = 0; uint8 max_green = 0; uint8 max_blue = 0; if (chan_cnt == 3) { p_red = p; p_green = p + data_cnt; p_blue = p + data_cnt * 2; } else { p_red = p_green = p_blue = p; } for (int i=0; i < data_cnt; i++) { max_red = max(max_red, ReadMacInt8(p_red++)); max_green = max(max_green, ReadMacInt8(p_green++)); max_blue = max(max_blue, ReadMacInt8(p_blue++)); mac_gamma[i].red = max_red; mac_gamma[i].green = max_green; mac_gamma[i].blue = max_blue; } } video_set_gamma(data_cnt); } 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, 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; yluminanceMapping = 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 255) return paramErr; s_pal = mac_pal + start; for (uint16 i=0;isaveBaseAddr); 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 noErr; 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<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 + vpPlaneBytes, 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<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); }