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

# Content
1 /*
2 * video.cpp - Video/graphics emulation
3 *
4 * SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer
5 *
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 #include "thunks.h"
38
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 static inline int16 IOCommandIsComplete(uintptr arg1, int16 arg2)
77 {
78 return (int16)CallMacOS2(iocic_ptr, iocic_tvect, (void *)arg1, arg2);
79 }
80 typedef int16 (*vslnewis_ptr)(void *, uint32, uint32 *);
81 static uint32 vslnewis_tvect = 0;
82 static inline int16 VSLNewInterruptService(uintptr arg1, uint32 arg2, uintptr arg3)
83 {
84 return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, (void *)arg1, arg2, (uint32 *)arg3);
85 }
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 void NQDMisc(uint32 arg1, uintptr arg2)
101 {
102 CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, (void *)arg2);
103 }
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 * 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 * 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 csSave->cursorHardware = UseHardwareCursor();
171 csSave->cursorX = 0;
172 csSave->cursorY = 0;
173 csSave->cursorVisible = 0;
174 csSave->cursorSet = 0;
175 csSave->cursorHotFlag = false;
176 csSave->cursorHotX = 0;
177 csSave->cursorHotY = 0;
178
179 // Find and set default gamma table
180 csSave->gammaTable = 0;
181 csSave->maxGammaTableSize = 0;
182 set_gamma(csSave, 0);
183
184 // Install and activate interrupt service
185 SheepVar32 theServiceID = 0;
186 VSLNewInterruptService(csSave->regEntryID, FOURCC('v','b','l',' '), theServiceID.addr());
187 csSave->vslServiceID = theServiceID.value();
188 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 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 static int16 set_gamma(VidLocals *csSave, uint32 gamma)
215 {
216 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
230 // Build the linear ramp
231 uint32 p = csSave->gammaTable + gFormulaData;
232 for (int i=0; i<256; i++)
233 WriteMacInt8(p + i, i);
234
235 } else { // User-supplied gamma table
236
237 // Validate header
238 if (ReadMacInt16(gamma + gVersion) != 0)
239 return paramErr;
240 if (ReadMacInt16(gamma + gType) != 0)
241 return paramErr;
242 int chan_cnt = ReadMacInt16(gamma + gChanCnt);
243 if (chan_cnt != 1 && chan_cnt != 3)
244 return paramErr;
245 int data_width = ReadMacInt16(gamma + gDataWidth);
246 if (data_width > 8)
247 return paramErr;
248 int data_cnt = ReadMacInt16(gamma + gDataCnt);
249 if (data_cnt != (1 << data_width))
250 return paramErr;
251
252 // 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
257 // Copy table
258 Mac2Mac_memcpy(csSave->gammaTable, gamma, size);
259 }
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 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
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 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 }
320 }
321
322 // Set palette
323 rgb_color *d_pal;
324 if (start == 0xffff) { // Indexed
325 for (int i=0; i<=count; i++) {
326 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 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 s_pal += 8;
341 }
342 } else { // Sequential
343 d_pal = mac_pal + start;
344 for (int i=0; i<=count; i++) {
345 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 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 d_pal++;
359 s_pal += 8;
360 }
361 }
362 video_set_palette();
363 return noErr;
364 }
365
366 case cscSetGamma: { // SetGamma
367 uint32 user_table = ReadMacInt32(param + csGTable);
368 D(bug("SetGamma %08x\n", user_table));
369 return set_gamma(csSave, user_table);
370 }
371
372 case cscGrayPage: { // GrayPage
373 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 }
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
432 if (!csSave->cursorHardware)
433 return controlErr;
434
435 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
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
450 // Mask
451 uint32 bmhandle = ReadMacInt32(cursor + ciCursorBitMask);
452 if (bmhandle == 0 || ReadMacInt32(bmhandle) == 0)
453 return controlErr;
454 uint32 bitmap = ReadMacInt32(bmhandle);
455
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 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 if (!video_can_change_cursor())
471 return controlErr;
472 if (changed)
473 video_set_cursor();
474
475 csSave->cursorSet = true;
476 csSave->cursorHotFlag = true;
477 return noErr;
478 }
479
480 case cscDrawHardwareCursor: {
481 // D(bug("DrawHardwareCursor\n"));
482
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 csSave->cursorX = ReadMacInt32(param + csCursorX);
491 csSave->cursorY = ReadMacInt32(param + csCursorY);
492 csSave->cursorVisible = ReadMacInt32(param + csCursorVisible);
493 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 return noErr;
547 }
548
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 // 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 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 uint32 d_pal = ReadMacInt32(param + csTable);
639 uint16 start = ReadMacInt16(param + csStart);
640 uint16 count = ReadMacInt16(param + csCount);
641 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
648 if (start == 0xffff) { // Indexed
649 for (uint16 i=0;i<count;i++) {
650 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 }
659 } else { // Sequential
660 if (start + count > 255)
661 return paramErr;
662 s_pal = mac_pal + start;
663 for (uint16 i=0;i<count;i++) {
664 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 }
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 return noErr;
701
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 case APPLE_1152x768:
791 WriteMacInt32(param + csHorizontalPixels, 1152);
792 WriteMacInt32(param + csVerticalLines, 768);
793 WriteMacInt32(param + csRefreshRate, 75<<16);
794 break;
795 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 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 }
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 break;
921 case APPLE_1152x768:
922 timing = timingApple_1152x870_75hz; // FIXME
923 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 WriteMacInt32(param, csSave->cursorHardware);
947 return noErr;
948
949 case cscGetHardwareCursorDrawState:
950 D(bug("GetHardwareCursorDrawState\n"));
951
952 if (!csSave->cursorHardware)
953 return statusErr;
954
955 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 int16 VideoDoDriverIO(uint32 spaceID, uint32 commandID, uint32 commandContents, uint32 commandCode, uint32 commandKind)
989 {
990 // D(bug("VideoDoDriverIO space %08x, command %08x, contents %08x, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind));
991 int16 err = noErr;
992
993 switch (commandCode) {
994 case kInitializeCommand:
995 case kReplaceCommand:
996 if (private_data != NULL) { // Might be left over from a reboot
997 if (private_data->gammaTable)
998 Mac_sysfree(private_data->gammaTable);
999 if (private_data->regEntryID)
1000 Mac_sysfree(private_data->regEntryID);
1001 }
1002 delete private_data;
1003
1004 iocic_tvect = FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete");
1005 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 vslnewis_tvect = FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService");
1012 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 vsldisposeis_tvect = FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService");
1019 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 vsldois_tvect = FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService");
1026 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 nqdmisc_tvect = FindLibSymbol("\014InterfaceLib", "\007NQDMisc");
1033 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 private_data->gammaTable = 0;
1042 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 private_data->interruptsEnabled = false; // Disable interrupts
1050 break;
1051
1052 case kFinalizeCommand:
1053 case kSupersededCommand:
1054 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 delete private_data;
1061 private_data = NULL;
1062 break;
1063
1064 case kOpenCommand:
1065 err = VideoOpen(commandContents, private_data);
1066 break;
1067
1068 case kCloseCommand:
1069 err = VideoClose(commandContents, private_data);
1070 break;
1071
1072 case kControlCommand:
1073 err = VideoControl(commandContents, private_data);
1074 break;
1075
1076 case kStatusCommand:
1077 err = VideoStatus(commandContents, private_data);
1078 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 }