1 |
/* |
2 |
* video.cpp - Video/graphics emulation |
3 |
* |
4 |
* SheepShaver (C) 1997-2004 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 |
* - window mode "hardware" cursor hotspot |
25 |
*/ |
26 |
|
27 |
#include <stdio.h> |
28 |
#include <string.h> |
29 |
|
30 |
#include "sysdeps.h" |
31 |
#include "video.h" |
32 |
#include "video_defs.h" |
33 |
#include "main.h" |
34 |
#include "adb.h" |
35 |
#include "macos_util.h" |
36 |
#include "user_strings.h" |
37 |
#include "version.h" |
38 |
#include "thunks.h" |
39 |
|
40 |
#define DEBUG 0 |
41 |
#include "debug.h" |
42 |
|
43 |
|
44 |
// Global variables |
45 |
bool video_activated = false; // Flag: video display activated, mouse and keyboard data valid |
46 |
uint32 screen_base = 0; // Frame buffer base address |
47 |
int cur_mode; // Number of current video mode (index in VModes array) |
48 |
int display_type = DIS_INVALID; // Current display type |
49 |
rgb_color mac_pal[256]; |
50 |
uint8 remap_mac_be[256]; |
51 |
uint8 MacCursor[68] = {16, 1}; // Mac cursor image |
52 |
|
53 |
|
54 |
bool keyfile_valid; // Flag: Keyfile is valid, enable full-screen modes |
55 |
|
56 |
|
57 |
/* |
58 |
* Video mode information (constructed by VideoInit()) |
59 |
*/ |
60 |
|
61 |
struct VideoInfo VModes[64]; |
62 |
|
63 |
|
64 |
/* |
65 |
* Driver local variables |
66 |
*/ |
67 |
|
68 |
VidLocals *private_data = NULL; // Pointer to driver local variables (there is only one display, so this is ok) |
69 |
|
70 |
static long save_conf_id = APPLE_W_640x480; |
71 |
static long save_conf_mode = APPLE_8_BIT; |
72 |
|
73 |
|
74 |
// Function pointers of imported functions |
75 |
typedef int16 (*iocic_ptr)(void *, int16); |
76 |
static uint32 iocic_tvect = 0; |
77 |
static inline int16 IOCommandIsComplete(uintptr arg1, int16 arg2) |
78 |
{ |
79 |
return (int16)CallMacOS2(iocic_ptr, iocic_tvect, (void *)arg1, arg2); |
80 |
} |
81 |
typedef int16 (*vslnewis_ptr)(void *, uint32, uint32 *); |
82 |
static uint32 vslnewis_tvect = 0; |
83 |
static inline int16 VSLNewInterruptService(uintptr arg1, uint32 arg2, uintptr arg3) |
84 |
{ |
85 |
return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, (void *)arg1, arg2, (uint32 *)arg3); |
86 |
} |
87 |
typedef int16 (*vsldisposeis_ptr)(uint32); |
88 |
static uint32 vsldisposeis_tvect = 0; |
89 |
static inline int16 VSLDisposeInterruptService(uint32 arg1) |
90 |
{ |
91 |
return (int16)CallMacOS1(vsldisposeis_ptr, vsldisposeis_tvect, arg1); |
92 |
} |
93 |
typedef int16 (*vsldois_ptr)(uint32); |
94 |
static uint32 vsldois_tvect = 0; |
95 |
int16 VSLDoInterruptService(uint32 arg1) |
96 |
{ |
97 |
return (int16)CallMacOS1(vsldois_ptr, vsldois_tvect, arg1); |
98 |
} |
99 |
typedef void (*nqdmisc_ptr)(uint32, void *); |
100 |
static uint32 nqdmisc_tvect = 0; |
101 |
void NQDMisc(uint32 arg1, uintptr arg2) |
102 |
{ |
103 |
CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, (void *)arg2); |
104 |
} |
105 |
|
106 |
|
107 |
// Prototypes |
108 |
static int16 set_gamma(VidLocals *csSave, uint32 gamma); |
109 |
|
110 |
|
111 |
/* |
112 |
* Tell whether window/screen is activated or not (for mouse/keyboard polling) |
113 |
*/ |
114 |
|
115 |
bool VideoActivated(void) |
116 |
{ |
117 |
return video_activated; |
118 |
} |
119 |
|
120 |
|
121 |
/* |
122 |
* Create RGB snapshot of current screen |
123 |
*/ |
124 |
|
125 |
bool VideoSnapshot(int xsize, int ysize, uint8 *p) |
126 |
{ |
127 |
if (display_type == DIS_WINDOW) { |
128 |
uint8 *screen = (uint8 *)private_data->saveBaseAddr; |
129 |
uint32 row_bytes = VModes[cur_mode].viRowBytes; |
130 |
uint32 y2size = VModes[cur_mode].viYsize; |
131 |
uint32 x2size = VModes[cur_mode].viXsize; |
132 |
for (int j=0;j<ysize;j++) { |
133 |
for (int i=0;i<xsize;i++) { |
134 |
*p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].red; |
135 |
*p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].green; |
136 |
*p++ = mac_pal[screen[uint32(float(j)*float(y2size)/float(ysize))*row_bytes+uint32(float(i)*float(x2size)/float(xsize))]].blue; |
137 |
} |
138 |
} |
139 |
return true; |
140 |
} |
141 |
return false; |
142 |
} |
143 |
|
144 |
|
145 |
/* |
146 |
* Video driver open routine |
147 |
*/ |
148 |
|
149 |
static int16 VideoOpen(uint32 pb, VidLocals *csSave) |
150 |
{ |
151 |
D(bug("Video Open\n")); |
152 |
|
153 |
// Set up VidLocals |
154 |
csSave->saveBaseAddr = screen_base; |
155 |
csSave->saveData = VModes[cur_mode].viAppleID;// First mode ... |
156 |
csSave->saveMode = VModes[cur_mode].viAppleMode; |
157 |
csSave->savePage = 0; |
158 |
csSave->saveVidParms = 0; // Add the right table |
159 |
csSave->gammaTable = NULL; // No gamma table yet |
160 |
csSave->maxGammaTableSize = 0; |
161 |
csSave->luminanceMapping = false; |
162 |
csSave->cursorX = 0; |
163 |
csSave->cursorY = 0; |
164 |
csSave->cursorVisible = 0; |
165 |
csSave->cursorSet = 0; |
166 |
|
167 |
// Activate default gamma table |
168 |
set_gamma(csSave, 0); |
169 |
|
170 |
// Install and activate interrupt service |
171 |
SheepVar32 theServiceID = 0; |
172 |
VSLNewInterruptService(Host2MacAddr((uint8 *)csSave->regEntryID), FOURCC('v','b','l',' '), theServiceID.addr()); |
173 |
csSave->vslServiceID = theServiceID.value(); |
174 |
D(bug(" Interrupt ServiceID %08lx\n", csSave->vslServiceID)); |
175 |
csSave->interruptsEnabled = true; |
176 |
|
177 |
return noErr; |
178 |
} |
179 |
|
180 |
|
181 |
/* |
182 |
* Video driver control routine |
183 |
*/ |
184 |
|
185 |
static int16 set_gamma(VidLocals *csSave, uint32 gamma) |
186 |
{ |
187 |
#warning "FIXME: this code is not little endian aware" |
188 |
GammaTbl *clientGamma = (GammaTbl *)gamma; |
189 |
GammaTbl *gammaTable = csSave->gammaTable; |
190 |
|
191 |
if (clientGamma == NULL) { |
192 |
|
193 |
// No gamma table supplied, build linear ramp |
194 |
uint32 linearRampSize = sizeof(GammaTbl) + 256 - 2; |
195 |
uint8 *correctionData; |
196 |
|
197 |
// Allocate new gamma table if existing gamma table is smaller than required. |
198 |
if (linearRampSize > csSave->maxGammaTableSize) { |
199 |
delete[] csSave->gammaTable; |
200 |
csSave->gammaTable = (GammaTbl *)new uint8[linearRampSize]; |
201 |
csSave->maxGammaTableSize = linearRampSize; |
202 |
gammaTable = csSave->gammaTable; |
203 |
} |
204 |
|
205 |
gammaTable->gVersion = 0; // A version 0 style of the GammaTbl structure |
206 |
gammaTable->gType = 0; // Frame buffer hardware invariant |
207 |
gammaTable->gFormulaSize = 0; // No formula data, just correction data |
208 |
gammaTable->gChanCnt = 1; // Apply same correction to Red, Green, & Blue |
209 |
gammaTable->gDataCnt = 256; // gDataCnt == 2^^gDataWidth |
210 |
gammaTable->gDataWidth = 8; // 8 bits of significant data per entry |
211 |
|
212 |
// Find the starting address of the correction data. This can be computed by starting at |
213 |
// the address of gFormula[0] and adding the gFormulaSize. |
214 |
correctionData = (uint8 *)((uint32)&gammaTable->gFormulaData[0] + gammaTable->gFormulaSize); |
215 |
|
216 |
// Build the linear ramp |
217 |
for (int i=0; i<gammaTable->gDataCnt; i++) |
218 |
*correctionData++ = i; |
219 |
|
220 |
} else { |
221 |
|
222 |
// User supplied a gamma table, so make sure it is a valid one |
223 |
if (clientGamma->gVersion != 0) |
224 |
return paramErr; |
225 |
if (clientGamma->gType != 0) |
226 |
return paramErr; |
227 |
if ((clientGamma->gChanCnt != 1) && (clientGamma->gChanCnt != 3)) |
228 |
return paramErr; |
229 |
if (clientGamma->gDataWidth > 8) |
230 |
return paramErr; |
231 |
if (clientGamma->gDataCnt != (1 << clientGamma->gDataWidth)) |
232 |
return paramErr; |
233 |
|
234 |
uint32 tableSize = sizeof(GammaTbl) // fixed size header |
235 |
+ clientGamma->gFormulaSize // add formula size |
236 |
+ clientGamma->gChanCnt * clientGamma->gDataCnt // assume 1 byte/entry |
237 |
- 2; // correct gFormulaData[0] counted twice |
238 |
|
239 |
// Allocate new gamma table if existing gamma table is smaller than required. |
240 |
if (tableSize > csSave->maxGammaTableSize) { |
241 |
delete[] csSave->gammaTable; |
242 |
csSave->gammaTable = (GammaTbl *)new uint8[tableSize]; |
243 |
csSave->maxGammaTableSize = tableSize; |
244 |
gammaTable = csSave->gammaTable; |
245 |
} |
246 |
|
247 |
// Copy gamma table header |
248 |
*gammaTable = *clientGamma; |
249 |
|
250 |
// Copy the formula data (if any) |
251 |
uint8 *newData = (uint8 *)&gammaTable->gFormulaData[0]; // Point to newGamma's formula data |
252 |
uint8 *clientData = (uint8 *)&clientGamma->gFormulaData[0]; // Point to clientGamma's formula data |
253 |
for (int i=0; i<gammaTable->gFormulaSize; i++) |
254 |
*newData++ = *clientData++; |
255 |
|
256 |
// Copy the correction data. Convientiently, after copying the formula data, the 'newData' |
257 |
// pointer and the 'clientData' pointer are pointing to the their respective starting points |
258 |
// of their correction data. |
259 |
for (int i=0; i<gammaTable->gChanCnt; i++) |
260 |
for (int j=0; j<gammaTable->gDataCnt; j++) |
261 |
*newData++ = *clientData++; |
262 |
} |
263 |
return noErr; |
264 |
} |
265 |
|
266 |
static int16 VideoControl(uint32 pb, VidLocals *csSave) |
267 |
{ |
268 |
int16 code = ReadMacInt16(pb + csCode); |
269 |
D(bug("VideoControl %d: ", code)); |
270 |
uint32 param = ReadMacInt32(pb + csParam); |
271 |
switch (code) { |
272 |
|
273 |
case cscReset: // VidReset |
274 |
D(bug("VidReset\n")); |
275 |
return controlErr; |
276 |
|
277 |
case cscKillIO: // VidKillIO |
278 |
D(bug("VidKillIO\n")); |
279 |
return controlErr; |
280 |
|
281 |
case cscSetMode: // SetVidMode |
282 |
D(bug("SetVidMode\n")); |
283 |
D(bug("mode:%04x page:%04x \n", ReadMacInt16(param + csMode), |
284 |
ReadMacInt16(param + csPage))); |
285 |
WriteMacInt32(param + csData, csSave->saveData); |
286 |
return video_mode_change(csSave, param); |
287 |
|
288 |
case cscSetEntries: { // SetEntries |
289 |
D(bug("SetEntries\n")); |
290 |
if (VModes[cur_mode].viAppleMode > APPLE_8_BIT) return controlErr; |
291 |
uint32 s_pal = ReadMacInt32(param + csTable); |
292 |
uint16 start = ReadMacInt16(param + csStart); |
293 |
uint16 count = ReadMacInt16(param + csCount); |
294 |
if (s_pal == 0 || count > 256) return controlErr; |
295 |
|
296 |
// Preparations for gamma correction |
297 |
bool do_gamma = false; |
298 |
uint8 *red_gamma = NULL; |
299 |
uint8 *green_gamma = NULL; |
300 |
uint8 *blue_gamma = NULL; |
301 |
int gamma_data_width = 0; |
302 |
if (display_type == DIS_SCREEN && csSave->gammaTable != NULL) { // Windows are gamma-corrected by BeOS |
303 |
do_gamma = true; |
304 |
GammaTbl *gamma = csSave->gammaTable; |
305 |
gamma_data_width = gamma->gDataWidth; |
306 |
red_gamma = (uint8 *)&gamma->gFormulaData + gamma->gFormulaSize; |
307 |
if (gamma->gChanCnt == 1) { |
308 |
green_gamma = blue_gamma = red_gamma; |
309 |
} else { |
310 |
green_gamma = red_gamma + gamma->gDataCnt; |
311 |
blue_gamma = red_gamma + 2 * gamma->gDataCnt; |
312 |
} |
313 |
} |
314 |
|
315 |
// Set palette |
316 |
rgb_color *d_pal; |
317 |
if (start == 0xffff) { // Indexed |
318 |
for (int i=0; i<=count; i++) { |
319 |
d_pal = mac_pal + (ReadMacInt16(s_pal + csValue) & 0xff); |
320 |
uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8; |
321 |
uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8; |
322 |
uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8; |
323 |
if (csSave->luminanceMapping) |
324 |
red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; |
325 |
if (do_gamma) { |
326 |
red = red_gamma[red >> (8 - gamma_data_width)]; |
327 |
green = green_gamma[green >> (8 - gamma_data_width)]; |
328 |
blue = blue_gamma[blue >> (8 - gamma_data_width)]; |
329 |
} |
330 |
(*d_pal).red = red; |
331 |
(*d_pal).green = green; |
332 |
(*d_pal).blue = blue; |
333 |
s_pal += 8; |
334 |
} |
335 |
} else { // Sequential |
336 |
d_pal = mac_pal + start; |
337 |
for (int i=0; i<=count; i++) { |
338 |
uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8; |
339 |
uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8; |
340 |
uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8; |
341 |
if (csSave->luminanceMapping) |
342 |
red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; |
343 |
if (do_gamma) { |
344 |
red = red_gamma[red >> (8 - gamma_data_width)]; |
345 |
green = green_gamma[green >> (8 - gamma_data_width)]; |
346 |
blue = blue_gamma[blue >> (8 - gamma_data_width)]; |
347 |
} |
348 |
(*d_pal).red = red; |
349 |
(*d_pal).green = green; |
350 |
(*d_pal).blue = blue; |
351 |
d_pal++; |
352 |
s_pal += 8; |
353 |
} |
354 |
} |
355 |
video_set_palette(); |
356 |
return noErr; |
357 |
} |
358 |
|
359 |
case cscSetGamma: // SetGamma |
360 |
D(bug("SetGamma\n")); |
361 |
return set_gamma(csSave, ReadMacInt32(param)); |
362 |
|
363 |
case cscGrayPage: { // GrayPage |
364 |
D(bug("GrayPage %d\n", ReadMacInt16(param + csPage))); |
365 |
if (ReadMacInt16(param + csPage)) |
366 |
return paramErr; |
367 |
|
368 |
uint32 pattern[6] = { |
369 |
0xaaaaaaaa, // 1 bpp |
370 |
0xcccccccc, // 2 bpp |
371 |
0xf0f0f0f0, // 4 bpp |
372 |
0xff00ff00, // 8 bpp |
373 |
0xffff0000, // 16 bpp |
374 |
0xffffffff // 32 bpp |
375 |
}; |
376 |
uint32 p = csSave->saveBaseAddr; |
377 |
uint32 pat = pattern[VModes[cur_mode].viAppleMode - APPLE_1_BIT]; |
378 |
bool invert = (VModes[cur_mode].viAppleMode == APPLE_32_BIT); |
379 |
for (uint32 y=0; y<VModes[cur_mode].viYsize; y++) { |
380 |
for (uint32 x=0; x<VModes[cur_mode].viRowBytes; x+=4) { |
381 |
WriteMacInt32(p + x, pat); |
382 |
if (invert) |
383 |
pat = ~pat; |
384 |
} |
385 |
p += VModes[cur_mode].viRowBytes; |
386 |
pat = ~pat; |
387 |
} |
388 |
return noErr; |
389 |
} |
390 |
|
391 |
case cscSetGray: // SetGray |
392 |
D(bug("SetGray %02x\n", ReadMacInt8(param))); |
393 |
csSave->luminanceMapping = ReadMacInt8(param); |
394 |
return noErr; |
395 |
|
396 |
case cscSetInterrupt: // SetInterrupt |
397 |
D(bug("SetInterrupt\n")); |
398 |
csSave->interruptsEnabled = !ReadMacInt8(param); |
399 |
return noErr; |
400 |
|
401 |
case cscDirectSetEntries: // DirectSetEntries |
402 |
D(bug("DirectSetEntries\n")); |
403 |
return controlErr; |
404 |
|
405 |
case cscSetDefaultMode: // SetDefaultMode |
406 |
D(bug("SetDefaultMode\n")); |
407 |
return controlErr; |
408 |
|
409 |
case cscSwitchMode: |
410 |
D(bug("cscSwitchMode (Display Manager support) \nMode:%02x ID:%04x Page:%d\n", |
411 |
ReadMacInt16(param + csMode), ReadMacInt32(param + csData), ReadMacInt16(param + csPage))); |
412 |
return video_mode_change(csSave, param); |
413 |
|
414 |
case cscSavePreferredConfiguration: |
415 |
D(bug("SavePreferredConfiguration\n")); |
416 |
save_conf_id = ReadMacInt32(param + csData); |
417 |
save_conf_mode = ReadMacInt16(param + csMode); |
418 |
return noErr; |
419 |
|
420 |
case cscSetHardwareCursor: { |
421 |
// D(bug("SetHardwareCursor\n")); |
422 |
csSave->cursorSet = false; |
423 |
bool changed = false; |
424 |
|
425 |
// Get cursor data even on a screen, to set the right cursor image when switching back to a window |
426 |
// Image |
427 |
uint32 cursor = ReadMacInt32(param); // Pointer to CursorImage |
428 |
uint32 pmhandle = ReadMacInt32(cursor + ciCursorPixMap); |
429 |
if (pmhandle == 0 || ReadMacInt32(pmhandle) == 0) |
430 |
return controlErr; |
431 |
uint32 pixmap = ReadMacInt32(pmhandle); |
432 |
if (memcmp(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32)) { |
433 |
memcpy(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32); |
434 |
changed = true; |
435 |
} |
436 |
|
437 |
// Mask |
438 |
uint32 bmhandle = ReadMacInt32(cursor + ciCursorBitMask); |
439 |
if (bmhandle == 0 || ReadMacInt32(bmhandle) == 0) |
440 |
return controlErr; |
441 |
uint32 bitmap = ReadMacInt32(bmhandle); |
442 |
if (memcmp(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32)) { |
443 |
memcpy(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32); |
444 |
changed = true; |
445 |
} |
446 |
|
447 |
// Hotspot (!! this doesn't work) |
448 |
MacCursor[2] = ReadMacInt8(0x885); |
449 |
MacCursor[3] = ReadMacInt8(0x887); |
450 |
|
451 |
// Set new cursor image |
452 |
if (!video_can_change_cursor()) |
453 |
return controlErr; |
454 |
if (changed) |
455 |
video_set_cursor(); |
456 |
|
457 |
csSave->cursorSet = true; |
458 |
return noErr; |
459 |
} |
460 |
|
461 |
case cscDrawHardwareCursor: |
462 |
// D(bug("DrawHardwareCursor\n")); |
463 |
csSave->cursorX = ReadMacInt32(param + csCursorX); |
464 |
csSave->cursorY = ReadMacInt32(param + csCursorY); |
465 |
csSave->cursorVisible = ReadMacInt32(param + csCursorVisible); |
466 |
return noErr; |
467 |
|
468 |
case 43: { // Driver Gestalt |
469 |
uint32 sel = ReadMacInt32(pb + csParam); |
470 |
D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16, sel >> 8, sel)); |
471 |
switch (sel) { |
472 |
case FOURCC('v','e','r','s'): |
473 |
WriteMacInt32(pb + csParam + 4, 0x01008000); |
474 |
break; |
475 |
case FOURCC('i','n','t','f'): |
476 |
WriteMacInt32(pb + csParam + 4, FOURCC('c','a','r','d')); |
477 |
break; |
478 |
case FOURCC('s','y','n','c'): |
479 |
WriteMacInt32(pb + csParam + 4, 0x01000000); |
480 |
break; |
481 |
default: |
482 |
return statusErr; |
483 |
}; |
484 |
return noErr; |
485 |
} |
486 |
|
487 |
default: |
488 |
D(bug(" unknown control code %d\n", code)); |
489 |
return controlErr; |
490 |
} |
491 |
} |
492 |
|
493 |
|
494 |
/* |
495 |
* Video driver status routine |
496 |
*/ |
497 |
|
498 |
// Search for given AppleID in mode table |
499 |
static bool has_mode(uint32 id) |
500 |
{ |
501 |
VideoInfo *p = VModes; |
502 |
while (p->viType != DIS_INVALID) { |
503 |
if (p->viAppleID == id) |
504 |
return true; |
505 |
p++; |
506 |
} |
507 |
return false; |
508 |
} |
509 |
|
510 |
// Find maximum depth for given AppleID |
511 |
static uint32 max_depth(uint32 id) |
512 |
{ |
513 |
uint32 max = APPLE_1_BIT; |
514 |
VideoInfo *p = VModes; |
515 |
while (p->viType != DIS_INVALID) { |
516 |
if (p->viAppleID == id && p->viAppleMode > max) |
517 |
max = p->viAppleMode; |
518 |
p++; |
519 |
} |
520 |
return max; |
521 |
} |
522 |
|
523 |
static int16 VideoStatus(uint32 pb, VidLocals *csSave) |
524 |
{ |
525 |
int16 code = ReadMacInt16(pb + csCode); |
526 |
D(bug("VideoStatus %d: ", code)); |
527 |
uint32 param = ReadMacInt32(pb + csParam); |
528 |
switch (code) { |
529 |
|
530 |
case cscGetMode: // GetMode |
531 |
D(bug("GetMode\n")); |
532 |
WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr); |
533 |
WriteMacInt16(param + csMode, csSave->saveMode); |
534 |
WriteMacInt16(param + csPage, csSave->savePage); |
535 |
D(bug("return: mode:%04x page:%04x ", ReadMacInt16(param + csMode), |
536 |
ReadMacInt16(param + csPage))); |
537 |
D(bug("base adress %08lx\n", ReadMacInt32(param + csBaseAddr))); |
538 |
return noErr; |
539 |
|
540 |
case cscGetEntries: { // GetEntries |
541 |
D(bug("GetEntries\n")); |
542 |
uint32 d_pal = ReadMacInt32(param + csTable); |
543 |
uint16 start = ReadMacInt16(param + csStart); |
544 |
uint16 count = ReadMacInt16(param + csCount); |
545 |
rgb_color *s_pal; |
546 |
if ((VModes[cur_mode].viAppleMode == APPLE_32_BIT)|| |
547 |
(VModes[cur_mode].viAppleMode == APPLE_16_BIT)) { |
548 |
D(bug("ERROR: GetEntries in direct mode \n")); |
549 |
return statusErr; |
550 |
} |
551 |
|
552 |
if (start == 0xffff) { // Indexed |
553 |
for (uint16 i=0;i<count;i++) { |
554 |
s_pal = mac_pal + (ReadMacInt16(d_pal + csValue) & 0xff); |
555 |
uint8 red = (*s_pal).red; |
556 |
uint8 green = (*s_pal).green; |
557 |
uint8 blue = (*s_pal).blue; |
558 |
WriteMacInt16(d_pal + csRed, red * 0x0101); |
559 |
WriteMacInt16(d_pal + csGreen, green * 0x0101); |
560 |
WriteMacInt16(d_pal + csBlue, blue * 0x0101); |
561 |
d_pal += 8; |
562 |
} |
563 |
} else { // Sequential |
564 |
if (start + count > 255) |
565 |
return paramErr; |
566 |
s_pal = mac_pal + start; |
567 |
for (uint16 i=0;i<count;i++) { |
568 |
uint8 red = (*s_pal).red; |
569 |
uint8 green = (*s_pal).green; |
570 |
uint8 blue = (*s_pal).blue; |
571 |
s_pal++; |
572 |
WriteMacInt16(d_pal + csRed, red * 0x0101); |
573 |
WriteMacInt16(d_pal + csGreen, green * 0x0101); |
574 |
WriteMacInt16(d_pal + csBlue, blue * 0x0101); |
575 |
d_pal += 8; |
576 |
} |
577 |
}; |
578 |
return noErr; |
579 |
} |
580 |
|
581 |
case cscGetPageCnt: // GetPage |
582 |
D(bug("GetPage\n")); |
583 |
WriteMacInt16(param + csPage, 1); |
584 |
return noErr; |
585 |
|
586 |
case cscGetPageBase: // GetPageBase |
587 |
D(bug("GetPageBase\n")); |
588 |
WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr); |
589 |
return noErr; |
590 |
|
591 |
case cscGetGray: // GetGray |
592 |
D(bug("GetGray\n")); |
593 |
WriteMacInt8(param, csSave->luminanceMapping ? 1 : 0); |
594 |
return noErr; |
595 |
|
596 |
case cscGetInterrupt: // GetInterrupt |
597 |
D(bug("GetInterrupt\n")); |
598 |
WriteMacInt8(param, csSave->interruptsEnabled ? 0 : 1); |
599 |
return noErr; |
600 |
|
601 |
case cscGetGamma: // GetGamma |
602 |
D(bug("GetGamma\n")); |
603 |
WriteMacInt32(param, (uint32)csSave->gammaTable); |
604 |
return statusErr; |
605 |
|
606 |
case cscGetDefaultMode: // GetDefaultMode |
607 |
D(bug("GetDefaultMode\n")); |
608 |
return statusErr; |
609 |
|
610 |
case cscGetCurMode: // GetCurMode |
611 |
D(bug("GetCurMode\n")); |
612 |
WriteMacInt16(param + csMode, csSave->saveMode); |
613 |
WriteMacInt32(param + csData, csSave->saveData); |
614 |
WriteMacInt16(param + csPage, csSave->savePage); |
615 |
WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr); |
616 |
|
617 |
D(bug("return: mode:%04x ID:%08lx page:%04x ", ReadMacInt16(param + csMode), |
618 |
ReadMacInt32(param + csData), ReadMacInt16(param + csPage))); |
619 |
D(bug("base adress %08lx\n", ReadMacInt32(param + csBaseAddr))); |
620 |
return noErr; |
621 |
|
622 |
case cscGetConnection: // GetConnection |
623 |
D(bug("GetConnection\n")); |
624 |
WriteMacInt16(param + csDisplayType, kMultiModeCRT3Connect); |
625 |
WriteMacInt8(param + csConnectTaggedType, 6); |
626 |
WriteMacInt8(param + csConnectTaggedData, 0x23); |
627 |
WriteMacInt32(param + csConnectFlags, (1<<kAllModesValid)|(1<<kAllModesSafe)); |
628 |
WriteMacInt32(param + csDisplayComponent, 0); |
629 |
return noErr; |
630 |
|
631 |
case cscGetModeBaseAddress: |
632 |
D(bug("GetModeBaseAddress (obsolete !) \n")); |
633 |
return statusErr; |
634 |
|
635 |
case cscGetPreferredConfiguration: |
636 |
D(bug("GetPreferredConfiguration \n")); |
637 |
WriteMacInt16(param + csMode, save_conf_mode); |
638 |
WriteMacInt32(param + csData, save_conf_id); |
639 |
return noErr; |
640 |
|
641 |
case cscGetNextResolution: { |
642 |
D(bug("GetNextResolution \n")); |
643 |
int work_id = ReadMacInt32(param + csPreviousDisplayModeID); |
644 |
switch (work_id) { |
645 |
case kDisplayModeIDCurrent: |
646 |
work_id = csSave->saveData; |
647 |
break; |
648 |
case kDisplayModeIDFindFirstResolution: |
649 |
work_id = APPLE_ID_MIN; |
650 |
while (!has_mode(work_id)) |
651 |
work_id ++; |
652 |
break; |
653 |
default: |
654 |
if (!has_mode(work_id)) |
655 |
return paramErr; |
656 |
work_id++; |
657 |
while (!has_mode(work_id)) { |
658 |
work_id++; |
659 |
if (work_id > APPLE_ID_MAX) { |
660 |
WriteMacInt32(param + csRIDisplayModeID, kDisplayModeIDNoMoreResolutions); |
661 |
return noErr; |
662 |
} |
663 |
} |
664 |
break; |
665 |
} |
666 |
WriteMacInt32(param + csRIDisplayModeID, work_id); |
667 |
WriteMacInt16(param + csMaxDepthMode, max_depth(work_id)); |
668 |
switch (work_id) { |
669 |
case APPLE_640x480: |
670 |
WriteMacInt32(param + csHorizontalPixels, 640); |
671 |
WriteMacInt32(param + csVerticalLines, 480); |
672 |
WriteMacInt32(param + csRefreshRate, 75<<16); |
673 |
break; |
674 |
case APPLE_W_640x480: |
675 |
WriteMacInt32(param + csHorizontalPixels, 640); |
676 |
WriteMacInt32(param + csVerticalLines, 480); |
677 |
WriteMacInt32(param + csRefreshRate, 60<<16); |
678 |
break; |
679 |
case APPLE_800x600: |
680 |
WriteMacInt32(param + csHorizontalPixels, 800); |
681 |
WriteMacInt32(param + csVerticalLines, 600); |
682 |
WriteMacInt32(param + csRefreshRate, 75<<16); |
683 |
break; |
684 |
case APPLE_W_800x600: |
685 |
WriteMacInt32(param + csHorizontalPixels, 800); |
686 |
WriteMacInt32(param + csVerticalLines, 600); |
687 |
WriteMacInt32(param + csRefreshRate, 60<<16); |
688 |
break; |
689 |
case APPLE_1024x768: |
690 |
WriteMacInt32(param + csHorizontalPixels, 1024); |
691 |
WriteMacInt32(param + csVerticalLines, 768); |
692 |
WriteMacInt32(param + csRefreshRate, 75<<16); |
693 |
break; |
694 |
case APPLE_1152x768: |
695 |
WriteMacInt32(param + csHorizontalPixels, 1152); |
696 |
WriteMacInt32(param + csVerticalLines, 768); |
697 |
WriteMacInt32(param + csRefreshRate, 75<<16); |
698 |
break; |
699 |
case APPLE_1152x900: |
700 |
WriteMacInt32(param + csHorizontalPixels, 1152); |
701 |
WriteMacInt32(param + csVerticalLines, 900); |
702 |
WriteMacInt32(param + csRefreshRate, 75<<16); |
703 |
break; |
704 |
case APPLE_1280x1024: |
705 |
WriteMacInt32(param + csHorizontalPixels, 1280); |
706 |
WriteMacInt32(param + csVerticalLines, 1024); |
707 |
WriteMacInt32(param + csRefreshRate, 75<<16); |
708 |
break; |
709 |
case APPLE_1600x1200: |
710 |
WriteMacInt32(param + csHorizontalPixels, 1600); |
711 |
WriteMacInt32(param + csVerticalLines, 1200); |
712 |
WriteMacInt32(param + csRefreshRate, 75<<16); |
713 |
break; |
714 |
} |
715 |
return noErr; |
716 |
} |
717 |
|
718 |
case cscGetVideoParameters: // GetVideoParameters |
719 |
D(bug("GetVideoParameters ID:%08lx Depth:%04x\n", |
720 |
ReadMacInt32(param + csDisplayModeID), |
721 |
ReadMacInt16(param + csDepthMode))); |
722 |
|
723 |
// find right video mode |
724 |
for (int i=0; VModes[i].viType!=DIS_INVALID; i++) { |
725 |
if ((ReadMacInt16(param + csDepthMode) == VModes[i].viAppleMode) && |
726 |
(ReadMacInt32(param + csDisplayModeID) == VModes[i].viAppleID)) { |
727 |
uint32 vpb = ReadMacInt32(param + csVPBlockPtr); |
728 |
WriteMacInt32(vpb + vpBaseOffset, 0); |
729 |
WriteMacInt16(vpb + vpRowBytes, VModes[i].viRowBytes); |
730 |
WriteMacInt16(vpb + vpBounds, 0); |
731 |
WriteMacInt16(vpb + vpBounds + 2, 0); |
732 |
WriteMacInt16(vpb + vpBounds + 4, VModes[i].viYsize); |
733 |
WriteMacInt16(vpb + vpBounds + 6, VModes[i].viXsize); |
734 |
WriteMacInt16(vpb + vpVersion, 0); // Pixel Map version number |
735 |
WriteMacInt16(vpb + vpPackType, 0); |
736 |
WriteMacInt32(vpb + vpPackSize, 0); |
737 |
WriteMacInt32(vpb + vpHRes, 0x00480000); // horiz res of the device (ppi) |
738 |
WriteMacInt32(vpb + vpVRes, 0x00480000); // vert res of the device (ppi) |
739 |
switch (VModes[i].viAppleMode) { |
740 |
case APPLE_1_BIT: |
741 |
WriteMacInt16(vpb + vpPixelType, 0); |
742 |
WriteMacInt16(vpb + vpPixelSize, 1); |
743 |
WriteMacInt16(vpb + vpCmpCount, 1); |
744 |
WriteMacInt16(vpb + vpCmpSize, 1); |
745 |
WriteMacInt32(param + csDeviceType, 0); // CLUT |
746 |
break; |
747 |
case APPLE_2_BIT: |
748 |
WriteMacInt16(vpb + vpPixelType, 0); |
749 |
WriteMacInt16(vpb + vpPixelSize, 2); |
750 |
WriteMacInt16(vpb + vpCmpCount, 1); |
751 |
WriteMacInt16(vpb + vpCmpSize, 2); |
752 |
WriteMacInt32(param + csDeviceType, 0); // CLUT |
753 |
break; |
754 |
case APPLE_4_BIT: |
755 |
WriteMacInt16(vpb + vpPixelType, 0); |
756 |
WriteMacInt16(vpb + vpPixelSize, 4); |
757 |
WriteMacInt16(vpb + vpCmpCount, 1); |
758 |
WriteMacInt16(vpb + vpCmpSize, 4); |
759 |
WriteMacInt32(param + csDeviceType, 0); // CLUT |
760 |
break; |
761 |
case APPLE_8_BIT: |
762 |
WriteMacInt16(vpb + vpPixelType, 0); |
763 |
WriteMacInt16(vpb + vpPixelSize, 8); |
764 |
WriteMacInt16(vpb + vpCmpCount, 1); |
765 |
WriteMacInt16(vpb + vpCmpSize, 8); |
766 |
WriteMacInt32(param + csDeviceType, 0); // CLUT |
767 |
break; |
768 |
case APPLE_16_BIT: |
769 |
WriteMacInt16(vpb + vpPixelType, 0x10); |
770 |
WriteMacInt16(vpb + vpPixelSize, 16); |
771 |
WriteMacInt16(vpb + vpCmpCount, 3); |
772 |
WriteMacInt16(vpb + vpCmpSize, 5); |
773 |
WriteMacInt32(param + csDeviceType, 2); // DIRECT |
774 |
break; |
775 |
case APPLE_32_BIT: |
776 |
WriteMacInt16(vpb + vpPixelType, 0x10); |
777 |
WriteMacInt16(vpb + vpPixelSize, 32); |
778 |
WriteMacInt16(vpb + vpCmpCount, 3); |
779 |
WriteMacInt16(vpb + vpCmpSize, 8); |
780 |
WriteMacInt32(param + csDeviceType, 2); // DIRECT |
781 |
break; |
782 |
} |
783 |
WriteMacInt32(param + csPageCount, 1); |
784 |
return noErr; |
785 |
} |
786 |
} |
787 |
return paramErr; |
788 |
|
789 |
case cscGetModeTiming: |
790 |
D(bug("GetModeTiming mode %08lx\n", ReadMacInt32(param + csTimingMode))); |
791 |
WriteMacInt32(param + csTimingFormat, kDeclROMtables); |
792 |
WriteMacInt32(param + csTimingFlags, (1<<kModeValid)|(1<<kModeSafe)|(1<<kShowModeNow)); // Mode valid, safe, default and shown in Monitors panel |
793 |
for (int i=0; VModes[i].viType!=DIS_INVALID; i++) { |
794 |
if (ReadMacInt32(param + csTimingMode) == VModes[i].viAppleID) { |
795 |
uint32 timing = timingUnknown; |
796 |
uint32 flags = (1<<kModeValid) | (1<<kShowModeNow); |
797 |
switch (VModes[i].viAppleID) { |
798 |
case APPLE_640x480: |
799 |
timing = timingVESA_640x480_75hz; |
800 |
flags |= (1<<kModeSafe); |
801 |
break; |
802 |
case APPLE_W_640x480: |
803 |
timing = timingVESA_640x480_60hz; |
804 |
flags |= (1<<kModeSafe); |
805 |
break; |
806 |
case APPLE_800x600: |
807 |
timing = timingVESA_800x600_75hz; |
808 |
flags |= (1<<kModeSafe); |
809 |
break; |
810 |
case APPLE_W_800x600: |
811 |
timing = timingVESA_800x600_60hz; |
812 |
flags |= (1<<kModeSafe); |
813 |
break; |
814 |
case APPLE_1024x768: |
815 |
timing = timingVESA_1024x768_75hz; |
816 |
break; |
817 |
case APPLE_1152x768: |
818 |
timing = timingApple_1152x870_75hz; // FIXME |
819 |
break; |
820 |
case APPLE_1152x900: |
821 |
timing = timingApple_1152x870_75hz; |
822 |
break; |
823 |
case APPLE_1280x1024: |
824 |
timing = timingVESA_1280x960_75hz; |
825 |
break; |
826 |
case APPLE_1600x1200: |
827 |
timing = timingVESA_1600x1200_75hz; |
828 |
break; |
829 |
default: |
830 |
timing = timingUnknown; |
831 |
break; |
832 |
} |
833 |
WriteMacInt32(param + csTimingData, timing); |
834 |
WriteMacInt32(param + csTimingFlags, flags); |
835 |
return noErr; |
836 |
} |
837 |
} |
838 |
return paramErr; |
839 |
|
840 |
case cscSupportsHardwareCursor: |
841 |
D(bug("SupportsHardwareCursor\n")); |
842 |
WriteMacInt32(param, 1); |
843 |
return noErr; |
844 |
|
845 |
case cscGetHardwareCursorDrawState: |
846 |
D(bug("GetHardwareCursorDrawState\n")); |
847 |
WriteMacInt32(param + csCursorX, csSave->cursorX); |
848 |
WriteMacInt32(param + csCursorY, csSave->cursorY); |
849 |
WriteMacInt32(param + csCursorVisible, csSave->cursorVisible); |
850 |
WriteMacInt32(param + csCursorSet, csSave->cursorSet); |
851 |
return noErr; |
852 |
|
853 |
default: |
854 |
D(bug(" unknown status code %d\n", code)); |
855 |
return statusErr; |
856 |
} |
857 |
} |
858 |
|
859 |
|
860 |
/* |
861 |
* Video driver close routine |
862 |
*/ |
863 |
|
864 |
static int16 VideoClose(uint32 pb, VidLocals *csSave) |
865 |
{ |
866 |
D(bug("VideoClose\n")); |
867 |
|
868 |
// Delete interrupt service |
869 |
csSave->interruptsEnabled = false; |
870 |
VSLDisposeInterruptService(csSave->vslServiceID); |
871 |
|
872 |
return noErr; |
873 |
} |
874 |
|
875 |
|
876 |
/* |
877 |
* Native (PCI) driver entry |
878 |
*/ |
879 |
|
880 |
int16 VideoDoDriverIO(uint32 spaceID, uint32 commandID, uint32 commandContents, uint32 commandCode, uint32 commandKind) |
881 |
{ |
882 |
// D(bug("VideoDoDriverIO space %08x, command %08x, contents %08x, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind)); |
883 |
int16 err = noErr; |
884 |
|
885 |
switch (commandCode) { |
886 |
case kInitializeCommand: |
887 |
case kReplaceCommand: |
888 |
if (private_data != NULL) // Might be left over from a reboot |
889 |
delete private_data->gammaTable; |
890 |
delete private_data; |
891 |
|
892 |
iocic_tvect = (uint32)FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete"); |
893 |
D(bug("IOCommandIsComplete TVECT at %08lx\n", iocic_tvect)); |
894 |
if (iocic_tvect == 0) { |
895 |
printf("FATAL: VideoDoDriverIO(): Can't find IOCommandIsComplete()\n"); |
896 |
err = -1; |
897 |
break; |
898 |
} |
899 |
vslnewis_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService"); |
900 |
D(bug("VSLNewInterruptService TVECT at %08lx\n", vslnewis_tvect)); |
901 |
if (vslnewis_tvect == 0) { |
902 |
printf("FATAL: VideoDoDriverIO(): Can't find VSLNewInterruptService()\n"); |
903 |
err = -1; |
904 |
break; |
905 |
} |
906 |
vsldisposeis_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService"); |
907 |
D(bug("VSLDisposeInterruptService TVECT at %08lx\n", vsldisposeis_tvect)); |
908 |
if (vsldisposeis_tvect == 0) { |
909 |
printf("FATAL: VideoDoDriverIO(): Can't find VSLDisposeInterruptService()\n"); |
910 |
err = -1; |
911 |
break; |
912 |
} |
913 |
vsldois_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService"); |
914 |
D(bug("VSLDoInterruptService TVECT at %08lx\n", vsldois_tvect)); |
915 |
if (vsldois_tvect == 0) { |
916 |
printf("FATAL: VideoDoDriverIO(): Can't find VSLDoInterruptService()\n"); |
917 |
err = -1; |
918 |
break; |
919 |
} |
920 |
nqdmisc_tvect = (uint32)FindLibSymbol("\014InterfaceLib", "\007NQDMisc"); |
921 |
D(bug("NQDMisc TVECT at %08lx\n", nqdmisc_tvect)); |
922 |
if (nqdmisc_tvect == 0) { |
923 |
printf("FATAL: VideoDoDriverIO(): Can't find NQDMisc()\n"); |
924 |
err = -1; |
925 |
break; |
926 |
} |
927 |
|
928 |
private_data = new VidLocals; |
929 |
private_data->gammaTable = NULL; |
930 |
Mac2Host_memcpy(&private_data->regEntryID, commandContents + 2, 16); // DriverInitInfo.deviceEntry |
931 |
private_data->interruptsEnabled = false; // Disable interrupts |
932 |
break; |
933 |
|
934 |
case kFinalizeCommand: |
935 |
case kSupersededCommand: |
936 |
if (private_data != NULL) |
937 |
delete private_data->gammaTable; |
938 |
delete private_data; |
939 |
private_data = NULL; |
940 |
break; |
941 |
|
942 |
case kOpenCommand: |
943 |
err = VideoOpen(commandContents, private_data); |
944 |
break; |
945 |
|
946 |
case kCloseCommand: |
947 |
err = VideoClose(commandContents, private_data); |
948 |
break; |
949 |
|
950 |
case kControlCommand: |
951 |
err = VideoControl(commandContents, private_data); |
952 |
break; |
953 |
|
954 |
case kStatusCommand: |
955 |
err = VideoStatus(commandContents, private_data); |
956 |
break; |
957 |
|
958 |
case kReadCommand: |
959 |
case kWriteCommand: |
960 |
break; |
961 |
|
962 |
case kKillIOCommand: |
963 |
err = abortErr; |
964 |
break; |
965 |
|
966 |
default: |
967 |
err = paramErr; |
968 |
break; |
969 |
} |
970 |
|
971 |
if (commandKind == kImmediateIOCommandKind) |
972 |
return err; |
973 |
else |
974 |
return IOCommandIsComplete(commandID, err); |
975 |
} |