ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/video.cpp
Revision: 1.18
Committed: 2012-03-28T03:30:49Z (12 years, 1 month ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.17: +2 -2 lines
Log Message:
fix gamma code so that fades in Ferazel's Wand actually work

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * video.cpp - Video/graphics emulation
3     *
4 gbeauche 1.15 * SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     /*
22     * TODO
23     * - check for supported modes ???
24     */
25    
26     #include <stdio.h>
27     #include <string.h>
28    
29     #include "sysdeps.h"
30     #include "video.h"
31     #include "video_defs.h"
32     #include "main.h"
33     #include "adb.h"
34     #include "macos_util.h"
35     #include "user_strings.h"
36     #include "version.h"
37 gbeauche 1.4 #include "thunks.h"
38 cebix 1.1
39     #define DEBUG 0
40     #include "debug.h"
41    
42    
43     // Global variables
44     bool video_activated = false; // Flag: video display activated, mouse and keyboard data valid
45     uint32 screen_base = 0; // Frame buffer base address
46     int cur_mode; // Number of current video mode (index in VModes array)
47     int display_type = DIS_INVALID; // Current display type
48     rgb_color mac_pal[256];
49     uint8 remap_mac_be[256];
50     uint8 MacCursor[68] = {16, 1}; // Mac cursor image
51    
52    
53     bool keyfile_valid; // Flag: Keyfile is valid, enable full-screen modes
54    
55    
56     /*
57     * Video mode information (constructed by VideoInit())
58     */
59    
60     struct VideoInfo VModes[64];
61    
62    
63     /*
64     * Driver local variables
65     */
66    
67     VidLocals *private_data = NULL; // Pointer to driver local variables (there is only one display, so this is ok)
68    
69     static long save_conf_id = APPLE_W_640x480;
70     static long save_conf_mode = APPLE_8_BIT;
71    
72    
73     // Function pointers of imported functions
74     typedef int16 (*iocic_ptr)(void *, int16);
75     static uint32 iocic_tvect = 0;
76 gbeauche 1.9 static inline int16 IOCommandIsComplete(uintptr arg1, int16 arg2)
77 cebix 1.1 {
78 gbeauche 1.9 return (int16)CallMacOS2(iocic_ptr, iocic_tvect, (void *)arg1, arg2);
79 cebix 1.1 }
80     typedef int16 (*vslnewis_ptr)(void *, uint32, uint32 *);
81     static uint32 vslnewis_tvect = 0;
82 gbeauche 1.9 static inline int16 VSLNewInterruptService(uintptr arg1, uint32 arg2, uintptr arg3)
83 cebix 1.1 {
84 gbeauche 1.9 return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, (void *)arg1, arg2, (uint32 *)arg3);
85 cebix 1.1 }
86     typedef int16 (*vsldisposeis_ptr)(uint32);
87     static uint32 vsldisposeis_tvect = 0;
88     static inline int16 VSLDisposeInterruptService(uint32 arg1)
89     {
90     return (int16)CallMacOS1(vsldisposeis_ptr, vsldisposeis_tvect, arg1);
91     }
92     typedef int16 (*vsldois_ptr)(uint32);
93     static uint32 vsldois_tvect = 0;
94     int16 VSLDoInterruptService(uint32 arg1)
95     {
96     return (int16)CallMacOS1(vsldois_ptr, vsldois_tvect, arg1);
97     }
98     typedef void (*nqdmisc_ptr)(uint32, void *);
99     static uint32 nqdmisc_tvect = 0;
100 gbeauche 1.9 void NQDMisc(uint32 arg1, uintptr arg2)
101 cebix 1.1 {
102 gbeauche 1.9 CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, (void *)arg2);
103 cebix 1.1 }
104    
105    
106     // Prototypes
107     static int16 set_gamma(VidLocals *csSave, uint32 gamma);
108    
109    
110     /*
111     * Tell whether window/screen is activated or not (for mouse/keyboard polling)
112     */
113    
114     bool VideoActivated(void)
115     {
116     return video_activated;
117     }
118    
119    
120     /*
121     * Create RGB snapshot of current screen
122     */
123    
124     bool VideoSnapshot(int xsize, int ysize, uint8 *p)
125     {
126     if (display_type == DIS_WINDOW) {
127     uint8 *screen = (uint8 *)private_data->saveBaseAddr;
128     uint32 row_bytes = VModes[cur_mode].viRowBytes;
129     uint32 y2size = VModes[cur_mode].viYsize;
130     uint32 x2size = VModes[cur_mode].viXsize;
131     for (int j=0;j<ysize;j++) {
132     for (int i=0;i<xsize;i++) {
133     *p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].red;
134     *p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].green;
135     *p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].blue;
136     }
137     }
138     return true;
139     }
140     return false;
141     }
142    
143    
144     /*
145 asvitkine 1.16 * Determine whether we should use the hardware or software cursor, and return true for the former, false for the latter.
146     * Currently we use the hardware cursor if we can, but perhaps this can be made a preference someday.
147     */
148    
149     static bool UseHardwareCursor(void)
150     {
151     return video_can_change_cursor();
152     }
153    
154    
155     /*
156 cebix 1.1 * Video driver open routine
157     */
158    
159     static int16 VideoOpen(uint32 pb, VidLocals *csSave)
160     {
161     D(bug("Video Open\n"));
162    
163     // Set up VidLocals
164     csSave->saveBaseAddr = screen_base;
165     csSave->saveData = VModes[cur_mode].viAppleID;// First mode ...
166     csSave->saveMode = VModes[cur_mode].viAppleMode;
167     csSave->savePage = 0;
168     csSave->saveVidParms = 0; // Add the right table
169     csSave->luminanceMapping = false;
170 asvitkine 1.16 csSave->cursorHardware = UseHardwareCursor();
171 cebix 1.1 csSave->cursorX = 0;
172     csSave->cursorY = 0;
173     csSave->cursorVisible = 0;
174     csSave->cursorSet = 0;
175 asvitkine 1.16 csSave->cursorHotFlag = false;
176     csSave->cursorHotX = 0;
177     csSave->cursorHotY = 0;
178 cebix 1.1
179 gbeauche 1.11 // Find and set default gamma table
180     csSave->gammaTable = 0;
181     csSave->maxGammaTableSize = 0;
182 cebix 1.1 set_gamma(csSave, 0);
183    
184     // Install and activate interrupt service
185 gbeauche 1.4 SheepVar32 theServiceID = 0;
186 gbeauche 1.12 VSLNewInterruptService(csSave->regEntryID, FOURCC('v','b','l',' '), theServiceID.addr());
187 gbeauche 1.4 csSave->vslServiceID = theServiceID.value();
188 cebix 1.1 D(bug(" Interrupt ServiceID %08lx\n", csSave->vslServiceID));
189     csSave->interruptsEnabled = true;
190    
191     return noErr;
192     }
193    
194    
195     /*
196     * Video driver control routine
197     */
198    
199 gbeauche 1.11 static bool allocate_gamma_table(VidLocals *csSave, uint32 size)
200     {
201     if (size > csSave->maxGammaTableSize) {
202     if (csSave->gammaTable) {
203     Mac_sysfree(csSave->gammaTable);
204     csSave->gammaTable = 0;
205     csSave->maxGammaTableSize = 0;
206     }
207     if ((csSave->gammaTable = Mac_sysalloc(size)) == 0)
208     return false;
209     csSave->maxGammaTableSize = size;
210     }
211     return true;
212     }
213    
214 cebix 1.1 static int16 set_gamma(VidLocals *csSave, uint32 gamma)
215     {
216 gbeauche 1.11 if (gamma == 0) { // Build linear ramp, 256 entries
217    
218     // Allocate new table, if necessary
219     if (!allocate_gamma_table(csSave, SIZEOF_GammaTbl + 256))
220     return memFullErr;
221    
222     // Initialize header
223     WriteMacInt16(csSave->gammaTable + gVersion, 0); // A version 0 style of the GammaTbl structure
224     WriteMacInt16(csSave->gammaTable + gType, 0); // Frame buffer hardware invariant
225     WriteMacInt16(csSave->gammaTable + gFormulaSize, 0); // No formula data, just correction data
226     WriteMacInt16(csSave->gammaTable + gChanCnt, 1); // Apply same correction to Red, Green, & Blue
227     WriteMacInt16(csSave->gammaTable + gDataCnt, 256); // gDataCnt == 2^^gDataWidth
228     WriteMacInt16(csSave->gammaTable + gDataWidth, 8); // 8 bits of significant data per entry
229 cebix 1.1
230     // Build the linear ramp
231 gbeauche 1.11 uint32 p = csSave->gammaTable + gFormulaData;
232     for (int i=0; i<256; i++)
233     WriteMacInt8(p + i, i);
234 cebix 1.1
235 gbeauche 1.11 } else { // User-supplied gamma table
236 cebix 1.1
237 gbeauche 1.11 // Validate header
238     if (ReadMacInt16(gamma + gVersion) != 0)
239 cebix 1.1 return paramErr;
240 gbeauche 1.11 if (ReadMacInt16(gamma + gType) != 0)
241 cebix 1.1 return paramErr;
242 gbeauche 1.11 int chan_cnt = ReadMacInt16(gamma + gChanCnt);
243     if (chan_cnt != 1 && chan_cnt != 3)
244 cebix 1.1 return paramErr;
245 gbeauche 1.11 int data_width = ReadMacInt16(gamma + gDataWidth);
246     if (data_width > 8)
247 cebix 1.1 return paramErr;
248 asvitkine 1.18 int data_cnt = ReadMacInt16(gamma + gDataCnt);
249 gbeauche 1.11 if (data_cnt != (1 << data_width))
250 cebix 1.1 return paramErr;
251    
252 gbeauche 1.11 // Allocate new table, if necessary
253     int size = SIZEOF_GammaTbl + ReadMacInt16(gamma + gFormulaSize) + chan_cnt * data_cnt;
254     if (!allocate_gamma_table(csSave, size))
255     return memFullErr;
256 cebix 1.1
257 gbeauche 1.11 // Copy table
258     Mac2Mac_memcpy(csSave->gammaTable, gamma, size);
259 cebix 1.1 }
260     return noErr;
261     }
262    
263     static int16 VideoControl(uint32 pb, VidLocals *csSave)
264     {
265     int16 code = ReadMacInt16(pb + csCode);
266     D(bug("VideoControl %d: ", code));
267     uint32 param = ReadMacInt32(pb + csParam);
268     switch (code) {
269    
270     case cscReset: // VidReset
271     D(bug("VidReset\n"));
272     return controlErr;
273    
274     case cscKillIO: // VidKillIO
275     D(bug("VidKillIO\n"));
276     return controlErr;
277    
278     case cscSetMode: // SetVidMode
279     D(bug("SetVidMode\n"));
280     D(bug("mode:%04x page:%04x \n", ReadMacInt16(param + csMode),
281     ReadMacInt16(param + csPage)));
282     WriteMacInt32(param + csData, csSave->saveData);
283     return video_mode_change(csSave, param);
284    
285     case cscSetEntries: { // SetEntries
286     D(bug("SetEntries\n"));
287     if (VModes[cur_mode].viAppleMode > APPLE_8_BIT) return controlErr;
288 gbeauche 1.6 uint32 s_pal = ReadMacInt32(param + csTable);
289     uint16 start = ReadMacInt16(param + csStart);
290     uint16 count = ReadMacInt16(param + csCount);
291     if (s_pal == 0 || count > 256) return controlErr;
292 cebix 1.1
293     // Preparations for gamma correction
294     bool do_gamma = false;
295     uint8 *red_gamma = NULL;
296     uint8 *green_gamma = NULL;
297     uint8 *blue_gamma = NULL;
298     int gamma_data_width = 0;
299 gbeauche 1.11 if (csSave->gammaTable) {
300     #ifdef __BEOS__
301     // Windows are gamma-corrected by BeOS
302     const bool can_do_gamma = (display_type == DIS_SCREEN);
303     #else
304     const bool can_do_gamma = true;
305     #endif
306     if (can_do_gamma) {
307     uint32 gamma_table = csSave->gammaTable;
308     red_gamma = Mac2HostAddr(gamma_table + gFormulaData + ReadMacInt16(gamma_table + gFormulaSize));
309     int chan_cnt = ReadMacInt16(gamma_table + gChanCnt);
310     if (chan_cnt == 1)
311     green_gamma = blue_gamma = red_gamma;
312     else {
313     int ofs = ReadMacInt16(gamma_table + gDataCnt);
314     green_gamma = red_gamma + ofs;
315     blue_gamma = green_gamma + ofs;
316     }
317     gamma_data_width = ReadMacInt16(gamma_table + gDataWidth);
318     do_gamma = true;
319 cebix 1.1 }
320     }
321    
322     // Set palette
323     rgb_color *d_pal;
324 gbeauche 1.6 if (start == 0xffff) { // Indexed
325 cebix 1.1 for (int i=0; i<=count; i++) {
326 gbeauche 1.6 d_pal = mac_pal + (ReadMacInt16(s_pal + csValue) & 0xff);
327     uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8;
328     uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8;
329     uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8;
330 cebix 1.1 if (csSave->luminanceMapping)
331     red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
332     if (do_gamma) {
333     red = red_gamma[red >> (8 - gamma_data_width)];
334     green = green_gamma[green >> (8 - gamma_data_width)];
335     blue = blue_gamma[blue >> (8 - gamma_data_width)];
336     }
337     (*d_pal).red = red;
338     (*d_pal).green = green;
339     (*d_pal).blue = blue;
340 gbeauche 1.6 s_pal += 8;
341 cebix 1.1 }
342 gbeauche 1.6 } else { // Sequential
343     d_pal = mac_pal + start;
344 cebix 1.1 for (int i=0; i<=count; i++) {
345 gbeauche 1.6 uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8;
346     uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8;
347     uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8;
348 cebix 1.1 if (csSave->luminanceMapping)
349     red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
350     if (do_gamma) {
351     red = red_gamma[red >> (8 - gamma_data_width)];
352     green = green_gamma[green >> (8 - gamma_data_width)];
353     blue = blue_gamma[blue >> (8 - gamma_data_width)];
354     }
355     (*d_pal).red = red;
356     (*d_pal).green = green;
357     (*d_pal).blue = blue;
358 gbeauche 1.6 d_pal++;
359     s_pal += 8;
360 cebix 1.1 }
361     }
362     video_set_palette();
363     return noErr;
364     }
365    
366 gbeauche 1.11 case cscSetGamma: { // SetGamma
367     uint32 user_table = ReadMacInt32(param + csGTable);
368     D(bug("SetGamma %08x\n", user_table));
369 asvitkine 1.18 return set_gamma(csSave, user_table);
370 gbeauche 1.11 }
371 cebix 1.1
372     case cscGrayPage: { // GrayPage
373 gbeauche 1.6 D(bug("GrayPage %d\n", ReadMacInt16(param + csPage)));
374     if (ReadMacInt16(param + csPage))
375     return paramErr;
376    
377     uint32 pattern[6] = {
378     0xaaaaaaaa, // 1 bpp
379     0xcccccccc, // 2 bpp
380     0xf0f0f0f0, // 4 bpp
381     0xff00ff00, // 8 bpp
382     0xffff0000, // 16 bpp
383     0xffffffff // 32 bpp
384     };
385     uint32 p = csSave->saveBaseAddr;
386     uint32 pat = pattern[VModes[cur_mode].viAppleMode - APPLE_1_BIT];
387     bool invert = (VModes[cur_mode].viAppleMode == APPLE_32_BIT);
388     for (uint32 y=0; y<VModes[cur_mode].viYsize; y++) {
389     for (uint32 x=0; x<VModes[cur_mode].viRowBytes; x+=4) {
390     WriteMacInt32(p + x, pat);
391     if (invert)
392     pat = ~pat;
393     }
394     p += VModes[cur_mode].viRowBytes;
395     pat = ~pat;
396 cebix 1.1 }
397     return noErr;
398     }
399    
400     case cscSetGray: // SetGray
401     D(bug("SetGray %02x\n", ReadMacInt8(param)));
402     csSave->luminanceMapping = ReadMacInt8(param);
403     return noErr;
404    
405     case cscSetInterrupt: // SetInterrupt
406     D(bug("SetInterrupt\n"));
407     csSave->interruptsEnabled = !ReadMacInt8(param);
408     return noErr;
409    
410     case cscDirectSetEntries: // DirectSetEntries
411     D(bug("DirectSetEntries\n"));
412     return controlErr;
413    
414     case cscSetDefaultMode: // SetDefaultMode
415     D(bug("SetDefaultMode\n"));
416     return controlErr;
417    
418     case cscSwitchMode:
419     D(bug("cscSwitchMode (Display Manager support) \nMode:%02x ID:%04x Page:%d\n",
420     ReadMacInt16(param + csMode), ReadMacInt32(param + csData), ReadMacInt16(param + csPage)));
421     return video_mode_change(csSave, param);
422    
423     case cscSavePreferredConfiguration:
424     D(bug("SavePreferredConfiguration\n"));
425     save_conf_id = ReadMacInt32(param + csData);
426     save_conf_mode = ReadMacInt16(param + csMode);
427     return noErr;
428    
429     case cscSetHardwareCursor: {
430     // D(bug("SetHardwareCursor\n"));
431 asvitkine 1.16
432     if (!csSave->cursorHardware)
433     return controlErr;
434    
435 cebix 1.1 csSave->cursorSet = false;
436     bool changed = false;
437    
438     // Image
439     uint32 cursor = ReadMacInt32(param); // Pointer to CursorImage
440     uint32 pmhandle = ReadMacInt32(cursor + ciCursorPixMap);
441     if (pmhandle == 0 || ReadMacInt32(pmhandle) == 0)
442     return controlErr;
443     uint32 pixmap = ReadMacInt32(pmhandle);
444 asvitkine 1.16
445     // XXX: only certain image formats are handled properly at the moment
446     uint16 rowBytes = ReadMacInt16(pixmap + 4) & 0x7FFF;
447     if (rowBytes != 2)
448     return controlErr;
449 cebix 1.1
450     // Mask
451     uint32 bmhandle = ReadMacInt32(cursor + ciCursorBitMask);
452     if (bmhandle == 0 || ReadMacInt32(bmhandle) == 0)
453     return controlErr;
454     uint32 bitmap = ReadMacInt32(bmhandle);
455 asvitkine 1.16
456     // Get cursor data even on a screen, to set the right cursor image when switching back to a window.
457     // Hotspot is stale, but will be fixed by the next call to DrawHardwareCursor, which is likely to
458     // occur immediately hereafter.
459    
460     if (memcmp(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32)) {
461     memcpy(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32);
462     changed = true;
463     }
464 cebix 1.1 if (memcmp(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32)) {
465     memcpy(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32);
466     changed = true;
467     }
468    
469     // Set new cursor image
470 gbeauche 1.8 if (!video_can_change_cursor())
471 cebix 1.1 return controlErr;
472     if (changed)
473     video_set_cursor();
474    
475     csSave->cursorSet = true;
476 asvitkine 1.16 csSave->cursorHotFlag = true;
477 cebix 1.1 return noErr;
478     }
479    
480 asvitkine 1.16 case cscDrawHardwareCursor: {
481 cebix 1.1 // D(bug("DrawHardwareCursor\n"));
482 asvitkine 1.16
483     if (!csSave->cursorHardware)
484     return controlErr;
485    
486     int32 oldX = csSave->cursorX;
487     int32 oldY = csSave->cursorY;
488     uint32 oldVisible = csSave->cursorVisible;
489    
490 cebix 1.1 csSave->cursorX = ReadMacInt32(param + csCursorX);
491     csSave->cursorY = ReadMacInt32(param + csCursorY);
492     csSave->cursorVisible = ReadMacInt32(param + csCursorVisible);
493 asvitkine 1.16 bool changed = (csSave->cursorVisible != oldVisible);
494    
495     // If this is the first DrawHardwareCursor call since the cursor was last set (via SetHardwareCursor),
496     // attempt to set an appropriate cursor hotspot. SetHardwareCursor itself does not know what the
497     // hotspot should be; it knows only the cursor image and mask. The hotspot is known only to the caller,
498     // and we have to try to infer it here. The usual sequence of calls when changing the cursor is:
499     //
500     // DrawHardwareCursor with (oldX, oldY, invisible)
501     // SetHardwareCursor with (cursor)
502     // DrawHardwareCursor with (newX, newY, visible)
503     //
504     // The key thing to note is that the sequence is intended not to change the current screen pixel location
505     // indicated by the hotspot. Thus, the difference between (newX, newY) and (oldX, oldY) reflects precisely
506     // the difference between the old cursor hotspot and the new one. For example, if you change from a
507     // cursor whose hotspot is (1, 1) to one whose hotspot is (7, 4), then you must adjust the cursor position
508     // by (-6, -3) in order for the same screen pixel to remain under the new hotspot.
509     //
510     // Alas, on rare occasions this heuristic can fail, and if you did nothing else you could even get stuck
511     // with the wrong hotspot from then on. To address that possibility, we force the hotspot to (1, 1)
512     // whenever the cursor being drawn is the standard arrow. Thus, while it is very unlikely that you will
513     // ever have the wrong hotspot, if you do, it is easy to recover.
514    
515     if (csSave->cursorHotFlag) {
516     csSave->cursorHotFlag = false;
517     D(bug("old hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY));
518    
519     static uint8 arrow[] = {
520     0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, 0x78, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x7F, 0x00,
521     0x7F, 0x80, 0x7C, 0x00, 0x6C, 0x00, 0x46, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
522     };
523     if (memcmp(MacCursor + 4, arrow, 32) == 0) {
524     csSave->cursorHotX = 1;
525     csSave->cursorHotY = 1;
526     } else if (csSave->cursorX != oldX || csSave->cursorY != oldY) {
527     int32 hotX = csSave->cursorHotX + (oldX - csSave->cursorX);
528     int32 hotY = csSave->cursorHotY + (oldY - csSave->cursorY);
529    
530     if (0 <= hotX && hotX <= 15 && 0 <= hotY && hotY <= 15) {
531     csSave->cursorHotX = hotX;
532     csSave->cursorHotY = hotY;
533     }
534     }
535     if (MacCursor[2] != csSave->cursorHotX || MacCursor[3] != csSave->cursorHotY) {
536     MacCursor[2] = csSave->cursorHotX;
537     MacCursor[3] = csSave->cursorHotY;
538     changed = true;
539     }
540     D(bug("new hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY));
541     }
542    
543     if (changed && video_can_change_cursor())
544     video_set_cursor();
545    
546 cebix 1.1 return noErr;
547 asvitkine 1.16 }
548 cebix 1.1
549     case 43: { // Driver Gestalt
550     uint32 sel = ReadMacInt32(pb + csParam);
551     D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16, sel >> 8, sel));
552     switch (sel) {
553     case FOURCC('v','e','r','s'):
554     WriteMacInt32(pb + csParam + 4, 0x01008000);
555     break;
556     case FOURCC('i','n','t','f'):
557     WriteMacInt32(pb + csParam + 4, FOURCC('c','a','r','d'));
558     break;
559     case FOURCC('s','y','n','c'):
560     WriteMacInt32(pb + csParam + 4, 0x01000000);
561     break;
562     default:
563     return statusErr;
564     };
565     return noErr;
566     }
567    
568     default:
569     D(bug(" unknown control code %d\n", code));
570     return controlErr;
571     }
572     }
573    
574    
575     /*
576     * Video driver status routine
577     */
578    
579     // Search for given AppleID in mode table
580     static bool has_mode(uint32 id)
581     {
582     VideoInfo *p = VModes;
583     while (p->viType != DIS_INVALID) {
584     if (p->viAppleID == id)
585     return true;
586     p++;
587     }
588     return false;
589     }
590    
591     // Find maximum depth for given AppleID
592     static uint32 max_depth(uint32 id)
593     {
594     uint32 max = APPLE_1_BIT;
595     VideoInfo *p = VModes;
596     while (p->viType != DIS_INVALID) {
597     if (p->viAppleID == id && p->viAppleMode > max)
598     max = p->viAppleMode;
599     p++;
600     }
601     return max;
602     }
603    
604 gbeauche 1.14 // Get X/Y size of specified resolution
605     static void get_size_of_resolution(int id, uint32 &x, uint32 &y)
606     {
607     VideoInfo *p = VModes;
608     while (p->viType != DIS_INVALID) {
609     if (p->viAppleID == id) {
610     x = p->viXsize;
611     y = p->viYsize;
612     return;
613     }
614     p++;
615     }
616     x = y = 0;
617     }
618    
619 cebix 1.1 static int16 VideoStatus(uint32 pb, VidLocals *csSave)
620     {
621     int16 code = ReadMacInt16(pb + csCode);
622     D(bug("VideoStatus %d: ", code));
623     uint32 param = ReadMacInt32(pb + csParam);
624     switch (code) {
625    
626     case cscGetMode: // GetMode
627     D(bug("GetMode\n"));
628     WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr);
629     WriteMacInt16(param + csMode, csSave->saveMode);
630     WriteMacInt16(param + csPage, csSave->savePage);
631     D(bug("return: mode:%04x page:%04x ", ReadMacInt16(param + csMode),
632     ReadMacInt16(param + csPage)));
633     D(bug("base adress %08lx\n", ReadMacInt32(param + csBaseAddr)));
634     return noErr;
635    
636     case cscGetEntries: { // GetEntries
637     D(bug("GetEntries\n"));
638 gbeauche 1.6 uint32 d_pal = ReadMacInt32(param + csTable);
639     uint16 start = ReadMacInt16(param + csStart);
640     uint16 count = ReadMacInt16(param + csCount);
641 cebix 1.1 rgb_color *s_pal;
642     if ((VModes[cur_mode].viAppleMode == APPLE_32_BIT)||
643     (VModes[cur_mode].viAppleMode == APPLE_16_BIT)) {
644     D(bug("ERROR: GetEntries in direct mode \n"));
645     return statusErr;
646     }
647 gbeauche 1.6
648     if (start == 0xffff) { // Indexed
649 cebix 1.1 for (uint16 i=0;i<count;i++) {
650 gbeauche 1.6 s_pal = mac_pal + (ReadMacInt16(d_pal + csValue) & 0xff);
651     uint8 red = (*s_pal).red;
652     uint8 green = (*s_pal).green;
653     uint8 blue = (*s_pal).blue;
654     WriteMacInt16(d_pal + csRed, red * 0x0101);
655     WriteMacInt16(d_pal + csGreen, green * 0x0101);
656     WriteMacInt16(d_pal + csBlue, blue * 0x0101);
657     d_pal += 8;
658 cebix 1.1 }
659 gbeauche 1.6 } else { // Sequential
660     if (start + count > 255)
661     return paramErr;
662     s_pal = mac_pal + start;
663 cebix 1.1 for (uint16 i=0;i<count;i++) {
664 gbeauche 1.6 uint8 red = (*s_pal).red;
665     uint8 green = (*s_pal).green;
666     uint8 blue = (*s_pal).blue;
667     s_pal++;
668     WriteMacInt16(d_pal + csRed, red * 0x0101);
669     WriteMacInt16(d_pal + csGreen, green * 0x0101);
670     WriteMacInt16(d_pal + csBlue, blue * 0x0101);
671     d_pal += 8;
672 cebix 1.1 }
673     };
674     return noErr;
675     }
676    
677     case cscGetPageCnt: // GetPage
678     D(bug("GetPage\n"));
679     WriteMacInt16(param + csPage, 1);
680     return noErr;
681    
682     case cscGetPageBase: // GetPageBase
683     D(bug("GetPageBase\n"));
684     WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr);
685     return noErr;
686    
687     case cscGetGray: // GetGray
688     D(bug("GetGray\n"));
689     WriteMacInt8(param, csSave->luminanceMapping ? 1 : 0);
690     return noErr;
691    
692     case cscGetInterrupt: // GetInterrupt
693     D(bug("GetInterrupt\n"));
694     WriteMacInt8(param, csSave->interruptsEnabled ? 0 : 1);
695     return noErr;
696    
697     case cscGetGamma: // GetGamma
698     D(bug("GetGamma\n"));
699     WriteMacInt32(param, (uint32)csSave->gammaTable);
700 asvitkine 1.17 return noErr;
701 cebix 1.1
702     case cscGetDefaultMode: // GetDefaultMode
703     D(bug("GetDefaultMode\n"));
704     return statusErr;
705    
706     case cscGetCurMode: // GetCurMode
707     D(bug("GetCurMode\n"));
708     WriteMacInt16(param + csMode, csSave->saveMode);
709     WriteMacInt32(param + csData, csSave->saveData);
710     WriteMacInt16(param + csPage, csSave->savePage);
711     WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr);
712    
713     D(bug("return: mode:%04x ID:%08lx page:%04x ", ReadMacInt16(param + csMode),
714     ReadMacInt32(param + csData), ReadMacInt16(param + csPage)));
715     D(bug("base adress %08lx\n", ReadMacInt32(param + csBaseAddr)));
716     return noErr;
717    
718     case cscGetConnection: // GetConnection
719     D(bug("GetConnection\n"));
720     WriteMacInt16(param + csDisplayType, kMultiModeCRT3Connect);
721     WriteMacInt8(param + csConnectTaggedType, 6);
722     WriteMacInt8(param + csConnectTaggedData, 0x23);
723     WriteMacInt32(param + csConnectFlags, (1<<kAllModesValid)|(1<<kAllModesSafe));
724     WriteMacInt32(param + csDisplayComponent, 0);
725     return noErr;
726    
727     case cscGetModeBaseAddress:
728     D(bug("GetModeBaseAddress (obsolete !) \n"));
729     return statusErr;
730    
731     case cscGetPreferredConfiguration:
732     D(bug("GetPreferredConfiguration \n"));
733     WriteMacInt16(param + csMode, save_conf_mode);
734     WriteMacInt32(param + csData, save_conf_id);
735     return noErr;
736    
737     case cscGetNextResolution: {
738     D(bug("GetNextResolution \n"));
739     int work_id = ReadMacInt32(param + csPreviousDisplayModeID);
740     switch (work_id) {
741     case kDisplayModeIDCurrent:
742     work_id = csSave->saveData;
743     break;
744     case kDisplayModeIDFindFirstResolution:
745     work_id = APPLE_ID_MIN;
746     while (!has_mode(work_id))
747     work_id ++;
748     break;
749     default:
750     if (!has_mode(work_id))
751     return paramErr;
752     work_id++;
753     while (!has_mode(work_id)) {
754     work_id++;
755     if (work_id > APPLE_ID_MAX) {
756     WriteMacInt32(param + csRIDisplayModeID, kDisplayModeIDNoMoreResolutions);
757     return noErr;
758     }
759     }
760     break;
761     }
762     WriteMacInt32(param + csRIDisplayModeID, work_id);
763     WriteMacInt16(param + csMaxDepthMode, max_depth(work_id));
764     switch (work_id) {
765     case APPLE_640x480:
766     WriteMacInt32(param + csHorizontalPixels, 640);
767     WriteMacInt32(param + csVerticalLines, 480);
768     WriteMacInt32(param + csRefreshRate, 75<<16);
769     break;
770     case APPLE_W_640x480:
771     WriteMacInt32(param + csHorizontalPixels, 640);
772     WriteMacInt32(param + csVerticalLines, 480);
773     WriteMacInt32(param + csRefreshRate, 60<<16);
774     break;
775     case APPLE_800x600:
776     WriteMacInt32(param + csHorizontalPixels, 800);
777     WriteMacInt32(param + csVerticalLines, 600);
778     WriteMacInt32(param + csRefreshRate, 75<<16);
779     break;
780     case APPLE_W_800x600:
781     WriteMacInt32(param + csHorizontalPixels, 800);
782     WriteMacInt32(param + csVerticalLines, 600);
783     WriteMacInt32(param + csRefreshRate, 60<<16);
784     break;
785     case APPLE_1024x768:
786     WriteMacInt32(param + csHorizontalPixels, 1024);
787     WriteMacInt32(param + csVerticalLines, 768);
788     WriteMacInt32(param + csRefreshRate, 75<<16);
789     break;
790 gbeauche 1.7 case APPLE_1152x768:
791     WriteMacInt32(param + csHorizontalPixels, 1152);
792     WriteMacInt32(param + csVerticalLines, 768);
793     WriteMacInt32(param + csRefreshRate, 75<<16);
794     break;
795 cebix 1.1 case APPLE_1152x900:
796     WriteMacInt32(param + csHorizontalPixels, 1152);
797     WriteMacInt32(param + csVerticalLines, 900);
798     WriteMacInt32(param + csRefreshRate, 75<<16);
799     break;
800     case APPLE_1280x1024:
801     WriteMacInt32(param + csHorizontalPixels, 1280);
802     WriteMacInt32(param + csVerticalLines, 1024);
803     WriteMacInt32(param + csRefreshRate, 75<<16);
804     break;
805     case APPLE_1600x1200:
806     WriteMacInt32(param + csHorizontalPixels, 1600);
807     WriteMacInt32(param + csVerticalLines, 1200);
808     WriteMacInt32(param + csRefreshRate, 75<<16);
809     break;
810 gbeauche 1.14 case APPLE_CUSTOM: {
811     uint32 x, y;
812     get_size_of_resolution(work_id, x, y);
813     WriteMacInt32(param + csHorizontalPixels, x);
814     WriteMacInt32(param + csVerticalLines, y);
815     WriteMacInt32(param + csRefreshRate, 75<<16);
816     break;
817     }
818 cebix 1.1 }
819     return noErr;
820     }
821    
822     case cscGetVideoParameters: // GetVideoParameters
823     D(bug("GetVideoParameters ID:%08lx Depth:%04x\n",
824     ReadMacInt32(param + csDisplayModeID),
825     ReadMacInt16(param + csDepthMode)));
826    
827     // find right video mode
828     for (int i=0; VModes[i].viType!=DIS_INVALID; i++) {
829     if ((ReadMacInt16(param + csDepthMode) == VModes[i].viAppleMode) &&
830     (ReadMacInt32(param + csDisplayModeID) == VModes[i].viAppleID)) {
831     uint32 vpb = ReadMacInt32(param + csVPBlockPtr);
832     WriteMacInt32(vpb + vpBaseOffset, 0);
833     WriteMacInt16(vpb + vpRowBytes, VModes[i].viRowBytes);
834     WriteMacInt16(vpb + vpBounds, 0);
835     WriteMacInt16(vpb + vpBounds + 2, 0);
836     WriteMacInt16(vpb + vpBounds + 4, VModes[i].viYsize);
837     WriteMacInt16(vpb + vpBounds + 6, VModes[i].viXsize);
838     WriteMacInt16(vpb + vpVersion, 0); // Pixel Map version number
839     WriteMacInt16(vpb + vpPackType, 0);
840     WriteMacInt32(vpb + vpPackSize, 0);
841     WriteMacInt32(vpb + vpHRes, 0x00480000); // horiz res of the device (ppi)
842     WriteMacInt32(vpb + vpVRes, 0x00480000); // vert res of the device (ppi)
843     switch (VModes[i].viAppleMode) {
844     case APPLE_1_BIT:
845     WriteMacInt16(vpb + vpPixelType, 0);
846     WriteMacInt16(vpb + vpPixelSize, 1);
847     WriteMacInt16(vpb + vpCmpCount, 1);
848     WriteMacInt16(vpb + vpCmpSize, 1);
849     WriteMacInt32(param + csDeviceType, 0); // CLUT
850     break;
851     case APPLE_2_BIT:
852     WriteMacInt16(vpb + vpPixelType, 0);
853     WriteMacInt16(vpb + vpPixelSize, 2);
854     WriteMacInt16(vpb + vpCmpCount, 1);
855     WriteMacInt16(vpb + vpCmpSize, 2);
856     WriteMacInt32(param + csDeviceType, 0); // CLUT
857     break;
858     case APPLE_4_BIT:
859     WriteMacInt16(vpb + vpPixelType, 0);
860     WriteMacInt16(vpb + vpPixelSize, 4);
861     WriteMacInt16(vpb + vpCmpCount, 1);
862     WriteMacInt16(vpb + vpCmpSize, 4);
863     WriteMacInt32(param + csDeviceType, 0); // CLUT
864     break;
865     case APPLE_8_BIT:
866     WriteMacInt16(vpb + vpPixelType, 0);
867     WriteMacInt16(vpb + vpPixelSize, 8);
868     WriteMacInt16(vpb + vpCmpCount, 1);
869     WriteMacInt16(vpb + vpCmpSize, 8);
870     WriteMacInt32(param + csDeviceType, 0); // CLUT
871     break;
872     case APPLE_16_BIT:
873     WriteMacInt16(vpb + vpPixelType, 0x10);
874     WriteMacInt16(vpb + vpPixelSize, 16);
875     WriteMacInt16(vpb + vpCmpCount, 3);
876     WriteMacInt16(vpb + vpCmpSize, 5);
877     WriteMacInt32(param + csDeviceType, 2); // DIRECT
878     break;
879     case APPLE_32_BIT:
880     WriteMacInt16(vpb + vpPixelType, 0x10);
881     WriteMacInt16(vpb + vpPixelSize, 32);
882     WriteMacInt16(vpb + vpCmpCount, 3);
883     WriteMacInt16(vpb + vpCmpSize, 8);
884     WriteMacInt32(param + csDeviceType, 2); // DIRECT
885     break;
886     }
887     WriteMacInt32(param + csPageCount, 1);
888     return noErr;
889     }
890     }
891     return paramErr;
892    
893     case cscGetModeTiming:
894     D(bug("GetModeTiming mode %08lx\n", ReadMacInt32(param + csTimingMode)));
895     WriteMacInt32(param + csTimingFormat, kDeclROMtables);
896     WriteMacInt32(param + csTimingFlags, (1<<kModeValid)|(1<<kModeSafe)|(1<<kShowModeNow)); // Mode valid, safe, default and shown in Monitors panel
897     for (int i=0; VModes[i].viType!=DIS_INVALID; i++) {
898     if (ReadMacInt32(param + csTimingMode) == VModes[i].viAppleID) {
899     uint32 timing = timingUnknown;
900     uint32 flags = (1<<kModeValid) | (1<<kShowModeNow);
901     switch (VModes[i].viAppleID) {
902     case APPLE_640x480:
903     timing = timingVESA_640x480_75hz;
904     flags |= (1<<kModeSafe);
905     break;
906     case APPLE_W_640x480:
907     timing = timingVESA_640x480_60hz;
908     flags |= (1<<kModeSafe);
909     break;
910     case APPLE_800x600:
911     timing = timingVESA_800x600_75hz;
912     flags |= (1<<kModeSafe);
913     break;
914     case APPLE_W_800x600:
915     timing = timingVESA_800x600_60hz;
916     flags |= (1<<kModeSafe);
917     break;
918     case APPLE_1024x768:
919     timing = timingVESA_1024x768_75hz;
920 gbeauche 1.7 break;
921     case APPLE_1152x768:
922     timing = timingApple_1152x870_75hz; // FIXME
923 cebix 1.1 break;
924     case APPLE_1152x900:
925     timing = timingApple_1152x870_75hz;
926     break;
927     case APPLE_1280x1024:
928     timing = timingVESA_1280x960_75hz;
929     break;
930     case APPLE_1600x1200:
931     timing = timingVESA_1600x1200_75hz;
932     break;
933     default:
934     timing = timingUnknown;
935     break;
936     }
937     WriteMacInt32(param + csTimingData, timing);
938     WriteMacInt32(param + csTimingFlags, flags);
939     return noErr;
940     }
941     }
942     return paramErr;
943    
944     case cscSupportsHardwareCursor:
945     D(bug("SupportsHardwareCursor\n"));
946 asvitkine 1.16 WriteMacInt32(param, csSave->cursorHardware);
947 cebix 1.1 return noErr;
948    
949     case cscGetHardwareCursorDrawState:
950     D(bug("GetHardwareCursorDrawState\n"));
951 asvitkine 1.16
952     if (!csSave->cursorHardware)
953     return statusErr;
954    
955 cebix 1.1 WriteMacInt32(param + csCursorX, csSave->cursorX);
956     WriteMacInt32(param + csCursorY, csSave->cursorY);
957     WriteMacInt32(param + csCursorVisible, csSave->cursorVisible);
958     WriteMacInt32(param + csCursorSet, csSave->cursorSet);
959     return noErr;
960    
961     default:
962     D(bug(" unknown status code %d\n", code));
963     return statusErr;
964     }
965     }
966    
967    
968     /*
969     * Video driver close routine
970     */
971    
972     static int16 VideoClose(uint32 pb, VidLocals *csSave)
973     {
974     D(bug("VideoClose\n"));
975    
976     // Delete interrupt service
977     csSave->interruptsEnabled = false;
978     VSLDisposeInterruptService(csSave->vslServiceID);
979    
980     return noErr;
981     }
982    
983    
984     /*
985     * Native (PCI) driver entry
986     */
987    
988 gbeauche 1.9 int16 VideoDoDriverIO(uint32 spaceID, uint32 commandID, uint32 commandContents, uint32 commandCode, uint32 commandKind)
989 cebix 1.1 {
990 gbeauche 1.9 // D(bug("VideoDoDriverIO space %08x, command %08x, contents %08x, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind));
991 cebix 1.1 int16 err = noErr;
992    
993     switch (commandCode) {
994     case kInitializeCommand:
995     case kReplaceCommand:
996 gbeauche 1.11 if (private_data != NULL) { // Might be left over from a reboot
997     if (private_data->gammaTable)
998     Mac_sysfree(private_data->gammaTable);
999 gbeauche 1.12 if (private_data->regEntryID)
1000     Mac_sysfree(private_data->regEntryID);
1001 gbeauche 1.11 }
1002 cebix 1.1 delete private_data;
1003    
1004 gbeauche 1.10 iocic_tvect = FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete");
1005 cebix 1.1 D(bug("IOCommandIsComplete TVECT at %08lx\n", iocic_tvect));
1006     if (iocic_tvect == 0) {
1007     printf("FATAL: VideoDoDriverIO(): Can't find IOCommandIsComplete()\n");
1008     err = -1;
1009     break;
1010     }
1011 gbeauche 1.10 vslnewis_tvect = FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService");
1012 cebix 1.1 D(bug("VSLNewInterruptService TVECT at %08lx\n", vslnewis_tvect));
1013     if (vslnewis_tvect == 0) {
1014     printf("FATAL: VideoDoDriverIO(): Can't find VSLNewInterruptService()\n");
1015     err = -1;
1016     break;
1017     }
1018 gbeauche 1.10 vsldisposeis_tvect = FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService");
1019 cebix 1.1 D(bug("VSLDisposeInterruptService TVECT at %08lx\n", vsldisposeis_tvect));
1020     if (vsldisposeis_tvect == 0) {
1021     printf("FATAL: VideoDoDriverIO(): Can't find VSLDisposeInterruptService()\n");
1022     err = -1;
1023     break;
1024     }
1025 gbeauche 1.10 vsldois_tvect = FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService");
1026 cebix 1.1 D(bug("VSLDoInterruptService TVECT at %08lx\n", vsldois_tvect));
1027     if (vsldois_tvect == 0) {
1028     printf("FATAL: VideoDoDriverIO(): Can't find VSLDoInterruptService()\n");
1029     err = -1;
1030     break;
1031     }
1032 gbeauche 1.10 nqdmisc_tvect = FindLibSymbol("\014InterfaceLib", "\007NQDMisc");
1033 cebix 1.1 D(bug("NQDMisc TVECT at %08lx\n", nqdmisc_tvect));
1034     if (nqdmisc_tvect == 0) {
1035     printf("FATAL: VideoDoDriverIO(): Can't find NQDMisc()\n");
1036     err = -1;
1037     break;
1038     }
1039    
1040     private_data = new VidLocals;
1041 gbeauche 1.11 private_data->gammaTable = 0;
1042 gbeauche 1.12 private_data->regEntryID = Mac_sysalloc(sizeof(RegEntryID));
1043     if (private_data->regEntryID == 0) {
1044     printf("FATAL: VideoDoDriverIO(): Can't allocate service owner\n");
1045     err = -1;
1046     break;
1047     }
1048     Mac2Mac_memcpy(private_data->regEntryID, commandContents + 2, 16); // DriverInitInfo.deviceEntry
1049 cebix 1.1 private_data->interruptsEnabled = false; // Disable interrupts
1050     break;
1051    
1052     case kFinalizeCommand:
1053     case kSupersededCommand:
1054 gbeauche 1.12 if (private_data != NULL) {
1055     if (private_data->gammaTable)
1056     Mac_sysfree(private_data->gammaTable);
1057     if (private_data->regEntryID)
1058     Mac_sysfree(private_data->regEntryID);
1059     }
1060 cebix 1.1 delete private_data;
1061     private_data = NULL;
1062     break;
1063    
1064     case kOpenCommand:
1065 gbeauche 1.9 err = VideoOpen(commandContents, private_data);
1066 cebix 1.1 break;
1067    
1068     case kCloseCommand:
1069 gbeauche 1.9 err = VideoClose(commandContents, private_data);
1070 cebix 1.1 break;
1071    
1072     case kControlCommand:
1073 gbeauche 1.9 err = VideoControl(commandContents, private_data);
1074 cebix 1.1 break;
1075    
1076     case kStatusCommand:
1077 gbeauche 1.9 err = VideoStatus(commandContents, private_data);
1078 cebix 1.1 break;
1079    
1080     case kReadCommand:
1081     case kWriteCommand:
1082     break;
1083    
1084     case kKillIOCommand:
1085     err = abortErr;
1086     break;
1087    
1088     default:
1089     err = paramErr;
1090     break;
1091     }
1092    
1093     if (commandKind == kImmediateIOCommandKind)
1094     return err;
1095     else
1096     return IOCommandIsComplete(commandID, err);
1097     }