ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/video.cpp
Revision: 1.26
Committed: 2002-04-25T13:14:11Z (22 years, 7 months ago) by cebix
Branch: MAIN
CVS Tags: nigel-build-12, nigel-build-13
Changes since 1.25: +12 -4 lines
Log Message:
added some safety checks

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * video.cpp - Video/graphics emulation
3     *
4 cebix 1.24 * Basilisk II (C) 1997-2002 Christian Bauer
5     * Portions written by Marc Hellwig
6 cebix 1.1 *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21    
22     /*
23     * SEE ALSO
24     * Inside Macintosh: Devices, chapter 1 "Device Manager"
25     * Designing Cards and Drivers for the Macintosh Family, Second Edition
26 cebix 1.22 * Designing PCI Cards and Drivers for Power Macintosh Computers
27     * Display Device Driver Guide
28 cebix 1.1 */
29    
30     #include <stdio.h>
31    
32     #include "sysdeps.h"
33     #include "cpu_emulation.h"
34     #include "main.h"
35     #include "macos_util.h"
36 cebix 1.13 #include "slot_rom.h"
37 cebix 1.1 #include "video.h"
38     #include "video_defs.h"
39    
40 cebix 1.11 #define DEBUG 0
41 cebix 1.1 #include "debug.h"
42    
43    
44 cebix 1.25 // Next available NuBus slot ID
45     uint8 monitor_desc::next_slot_id = 0x80;
46 cebix 1.9
47 cebix 1.25 // Vector of pointers to available monitor descriptions, filled by VideoInit()
48     vector<monitor_desc *> VideoMonitors;
49 cebix 1.1
50 cebix 1.20
51 cebix 1.25 /*
52     * Find palette size for given color depth
53     */
54    
55     static int palette_size(video_depth depth)
56     {
57     switch (depth) {
58     case VDEPTH_1BIT: return 2;
59     case VDEPTH_2BIT: return 4;
60     case VDEPTH_4BIT: return 16;
61     case VDEPTH_8BIT: return 256;
62     case VDEPTH_16BIT: return 32;
63     case VDEPTH_32BIT: return 256;
64     default: return 0;
65     }
66     }
67 cebix 1.1
68    
69     /*
70 cebix 1.25 * Find pointer to monitor_desc for given slot ID (or NULL if not found)
71 cebix 1.20 */
72    
73 cebix 1.25 static monitor_desc *find_monitor(uint8 id)
74 cebix 1.20 {
75 cebix 1.25 vector<monitor_desc *>::const_iterator i, end = VideoMonitors.end();
76     for (i = VideoMonitors.begin(); i != end; ++i) {
77     if ((*i)->get_slot_id() == id)
78     return *i;
79     }
80     return NULL;
81     }
82    
83    
84     /*
85     * monitor_desc constructor
86     */
87    
88     monitor_desc::monitor_desc(const vector<video_mode> &available_modes, video_depth default_depth, uint32 default_id) : modes(available_modes)
89     {
90     // Assign the next slot ID on construction
91     slot_id = next_slot_id++;
92    
93     // Initialize Apple mode list
94 cebix 1.20 uint16 mode = 0x80;
95     for (int depth = VDEPTH_1BIT; depth <= VDEPTH_32BIT; depth++) {
96 cebix 1.25 if (has_depth(video_depth(depth)))
97 cebix 1.20 apple_mode_for_depth[depth] = mode++;
98     else
99     apple_mode_for_depth[depth] = 0;
100     }
101 cebix 1.25
102     // Set default mode
103     current_mode = find_mode(depth_to_apple_mode(default_depth), default_id);
104 cebix 1.20 }
105    
106    
107     /*
108 cebix 1.25 * Get bytes-per-row value for specified resolution/depth
109     * (if the mode isn't supported, make a good guess)
110 cebix 1.20 */
111    
112 cebix 1.25 uint32 monitor_desc::get_bytes_per_row(video_depth depth, uint32 id) const
113 cebix 1.20 {
114 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
115     for (i = modes.begin(); i != end; ++i) {
116     if (i->depth == depth && i->resolution_id == id)
117     return i->bytes_per_row;
118     }
119     uint32 x, y;
120     get_size_of_resolution(id, x, y);
121     return TrivialBytesPerRow(x, depth);
122     }
123    
124    
125     /*
126     * Check whether a mode with the specified depth exists on this display
127     */
128    
129     bool monitor_desc::has_depth(video_depth depth) const
130     {
131     vector<video_mode>::const_iterator i = modes.begin(), end = modes.end();
132 cebix 1.20 while (i != end) {
133     if (i->depth == depth)
134     return true;
135     ++i;
136     }
137     return false;
138     }
139    
140    
141     /*
142 cebix 1.25 * Check whether the specified resolution ID is one of the supported resolutions
143 cebix 1.9 */
144    
145 cebix 1.25 bool monitor_desc::has_resolution(uint32 id) const
146 cebix 1.9 {
147 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
148     for (i = modes.begin(); i != end; ++i) {
149 cebix 1.9 if (i->resolution_id == id)
150     return true;
151     }
152     return false;
153     }
154    
155    
156     /*
157 cebix 1.25 * Find specified mode (depth/resolution) (or invalid_mode() if not found)
158 cebix 1.10 */
159    
160 cebix 1.25 vector<video_mode>::const_iterator monitor_desc::find_mode(uint16 apple_mode, uint32 id) const
161 cebix 1.10 {
162 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
163     for (i = modes.begin(); i != end; ++i) {
164     if (i->resolution_id == id && depth_to_apple_mode(i->depth) == apple_mode)
165 cebix 1.10 return i;
166     }
167     return i;
168     }
169    
170    
171     /*
172 cebix 1.9 * Find maximum supported depth for given resolution ID
173     */
174    
175 cebix 1.25 video_depth monitor_desc::max_depth_of_resolution(uint32 id) const
176 cebix 1.9 {
177     video_depth m = VDEPTH_1BIT;
178 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
179     for (i = modes.begin(); i != end; ++i) {
180 cebix 1.9 if (i->depth > m)
181     m = i->depth;
182     }
183     return m;
184     }
185    
186    
187     /*
188     * Get X/Y size of specified resolution
189     */
190    
191 cebix 1.25 void monitor_desc::get_size_of_resolution(uint32 id, uint32 &x, uint32 &y) const
192 cebix 1.9 {
193 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
194     for (i = modes.begin(); i != end; ++i) {
195 cebix 1.9 if (i->resolution_id == id) {
196     x = i->x;
197     y = i->y;
198     return;
199     }
200     }
201 cebix 1.20 x = y = 0;
202     }
203    
204    
205     /*
206 cebix 1.11 * Set palette to 50% gray
207     */
208    
209 cebix 1.25 void monitor_desc::set_gray_palette(void)
210 cebix 1.11 {
211 cebix 1.14 for (int i=0; i<256; i++) {
212 cebix 1.25 palette[i * 3 + 0] = 127;
213     palette[i * 3 + 1] = 127;
214     palette[i * 3 + 2] = 127;
215 cebix 1.14 }
216 cebix 1.25 set_palette(palette, 256);
217 cebix 1.14 }
218    
219    
220     /*
221     * Load gamma-corrected black-to-white ramp to palette for direct-color mode
222     */
223    
224 cebix 1.25 void monitor_desc::load_ramp_palette(void)
225 cebix 1.14 {
226     // Find tables for gamma correction
227 cebix 1.23 uint8 *red_gamma = NULL, *green_gamma = NULL, *blue_gamma = NULL;
228 cebix 1.14 bool have_gamma = false;
229     int data_width = 0;
230 cebix 1.25 if (gamma_table) {
231     uint32 table = gamma_table;
232 cebix 1.14 red_gamma = Mac2HostAddr(table + gFormulaData + ReadMacInt16(table + gFormulaSize));
233     int chan_cnt = ReadMacInt16(table + gChanCnt);
234     if (chan_cnt == 1)
235     green_gamma = blue_gamma = red_gamma;
236     else {
237     int ofs = ReadMacInt16(table + gDataCnt);
238     green_gamma = red_gamma + ofs;
239     blue_gamma = green_gamma + ofs;
240     }
241     data_width = ReadMacInt16(table + gDataWidth);
242     have_gamma = true;
243     }
244    
245 cebix 1.25 int num = (current_mode->depth == VDEPTH_16BIT ? 32 : 256);
246     uint8 *p = palette;
247 cebix 1.14 for (int i=0; i<num; i++) {
248 cebix 1.15 uint8 red = (i * 256 / num), green = red, blue = red;
249 cebix 1.14 if (have_gamma) {
250     red = red_gamma[red >> (8 - data_width)];
251     green = green_gamma[green >> (8 - data_width)];
252     blue = blue_gamma[blue >> (8 - data_width)];
253     }
254     *p++ = red;
255     *p++ = green;
256     *p++ = blue;
257     }
258    
259 cebix 1.25 set_palette(palette, num);
260 cebix 1.14 }
261    
262    
263     /*
264     * Allocate gamma table of specified size
265     */
266    
267 cebix 1.25 bool monitor_desc::allocate_gamma_table(int size)
268 cebix 1.14 {
269     M68kRegisters r;
270    
271 cebix 1.25 if (size > alloc_gamma_table_size) {
272     if (gamma_table) {
273     r.a[0] = gamma_table;
274 cebix 1.14 Execute68kTrap(0xa01f, &r); // DisposePtr()
275 cebix 1.25 gamma_table = 0;
276     alloc_gamma_table_size = 0;
277 cebix 1.11 }
278 cebix 1.14 r.d[0] = size;
279     Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
280     if (r.a[0] == 0)
281     return false;
282 cebix 1.25 gamma_table = r.a[0];
283     alloc_gamma_table_size = size;
284 cebix 1.11 }
285 cebix 1.14 return true;
286     }
287    
288    
289     /*
290     * Set gamma table (0 = build linear ramp)
291     */
292    
293 cebix 1.25 bool monitor_desc::set_gamma_table(uint32 user_table)
294 cebix 1.14 {
295     if (user_table == 0) { // Build linear ramp, 256 entries
296    
297     // Allocate new table, if necessary
298     if (!allocate_gamma_table(SIZEOF_GammaTbl + 256))
299     return memFullErr;
300    
301     // Initialize header
302 cebix 1.25 WriteMacInt16(gamma_table + gVersion, 0);
303     WriteMacInt16(gamma_table + gType, 0);
304     WriteMacInt16(gamma_table + gFormulaSize, 0);
305     WriteMacInt16(gamma_table + gChanCnt, 1);
306     WriteMacInt16(gamma_table + gDataCnt, 256);
307     WriteMacInt16(gamma_table + gDataWidth, 8);
308 cebix 1.14
309     // Build ramp
310 cebix 1.25 uint32 p = gamma_table + gFormulaData;
311 cebix 1.14 for (int i=0; i<256; i++)
312     WriteMacInt8(p + i, i);
313    
314     } else { // User-supplied gamma table
315    
316     // Validate header
317     if (ReadMacInt16(user_table + gVersion))
318     return paramErr;
319     if (ReadMacInt16(user_table + gType))
320     return paramErr;
321     int chan_cnt = ReadMacInt16(user_table + gChanCnt);
322     if (chan_cnt != 1 && chan_cnt != 3)
323     return paramErr;
324     int data_width = ReadMacInt16(user_table + gDataWidth);
325     if (data_width > 8)
326     return paramErr;
327     int data_cnt = ReadMacInt16(user_table + gDataCnt);
328     if (data_cnt != (1 << data_width))
329     return paramErr;
330    
331     // Allocate new table, if necessary
332     int size = SIZEOF_GammaTbl + ReadMacInt16(user_table + gFormulaSize) + chan_cnt * data_cnt;
333     if (!allocate_gamma_table(size))
334     return memFullErr;
335    
336     // Copy table
337 cebix 1.25 Mac2Mac_memcpy(gamma_table, user_table, size);
338 cebix 1.14 }
339    
340 cebix 1.25 if (IsDirectMode(*current_mode))
341 cebix 1.14 load_ramp_palette();
342    
343     return true;
344 cebix 1.11 }
345    
346    
347     /*
348 cebix 1.18 * Switch video mode
349     */
350    
351 cebix 1.25 void monitor_desc::switch_mode(vector<video_mode>::const_iterator it, uint32 param, uint32 dce)
352 cebix 1.18 {
353 cebix 1.25 const video_mode &mode = *it;
354    
355 cebix 1.18 // Switch mode
356     set_gray_palette();
357 cebix 1.25 current_mode = it;
358     switch_to_current_mode();
359 cebix 1.18
360 cebix 1.25 // Update variables
361     current_apple_mode = depth_to_apple_mode(mode.depth);
362     current_id = mode.resolution_id;
363 cebix 1.18
364     M68kRegisters r;
365 cebix 1.25 r.a[0] = slot_param;
366 cebix 1.18
367     // Find functional sResource for this display
368 cebix 1.25 WriteMacInt8(slot_param + spSlot, ReadMacInt8(dce + dCtlSlot));
369     WriteMacInt8(slot_param + spID, ReadMacInt8(dce + dCtlSlotId));
370     WriteMacInt8(slot_param + spExtDev, 0);
371 cebix 1.18 r.d[0] = 0x0016;
372     Execute68kTrap(0xa06e, &r); // SRsrcInfo()
373 cebix 1.25 uint32 rsrc = ReadMacInt32(slot_param + spPointer);
374 cebix 1.18
375     // Patch minorBase (otherwise rebooting won't work)
376 cebix 1.25 WriteMacInt8(slot_param + spID, 0x0a); // minorBase
377 cebix 1.18 r.d[0] = 0x0006;
378     Execute68kTrap(0xa06e, &r); // SFindStruct()
379 cebix 1.25 uint32 minor_base = ReadMacInt32(slot_param + spPointer) - ROMBaseMac;
380     ROMBaseHost[minor_base + 0] = mac_frame_base >> 24;
381     ROMBaseHost[minor_base + 1] = mac_frame_base >> 16;
382     ROMBaseHost[minor_base + 2] = mac_frame_base >> 8;
383     ROMBaseHost[minor_base + 3] = mac_frame_base;
384 cebix 1.18
385     // Patch video mode parameter table
386 cebix 1.25 WriteMacInt32(slot_param + spPointer, rsrc);
387     WriteMacInt8(slot_param + spID, depth_to_apple_mode(mode.depth));
388 cebix 1.18 r.d[0] = 0x0006;
389     Execute68kTrap(0xa06e, &r); // SFindStruct()
390 cebix 1.25 WriteMacInt8(slot_param + spID, 0x01);
391 cebix 1.18 r.d[0] = 0x0006;
392     Execute68kTrap(0xa06e, &r); // SFindStruct()
393 cebix 1.25 uint32 p = ReadMacInt32(slot_param + spPointer) - ROMBaseMac;
394 cebix 1.18 ROMBaseHost[p + 8] = mode.bytes_per_row >> 8;
395     ROMBaseHost[p + 9] = mode.bytes_per_row;
396     ROMBaseHost[p + 14] = mode.y >> 8;
397     ROMBaseHost[p + 15] = mode.y;
398     ROMBaseHost[p + 16] = mode.x >> 8;
399     ROMBaseHost[p + 17] = mode.x;
400    
401     // Recalculate slot ROM checksum
402     ChecksumSlotROM();
403    
404     // Update sResource
405 cebix 1.25 WriteMacInt8(slot_param + spID, ReadMacInt8(dce + dCtlSlotId));
406 cebix 1.18 r.d[0] = 0x002b;
407     Execute68kTrap(0xa06e, &r); // SUpdateSRT()
408    
409     // Update frame buffer base in DCE and param block
410 cebix 1.25 WriteMacInt32(dce + dCtlDevBase, mac_frame_base);
411     WriteMacInt32(param + csBaseAddr, mac_frame_base);
412 cebix 1.20
413     // Patch frame buffer base address for MacOS versions <7.6
414 cebix 1.25 if (!dm_present) { // Only do this when no Display Manager seems to be present; otherwise, the screen will not get redrawn
415     D(bug("No Display Manager, patching frame buffer base\n"));
416     WriteMacInt32(0x824, mac_frame_base); // ScrnBase
417     WriteMacInt32(0x898, mac_frame_base); // CrsrBase
418 cebix 1.20 uint32 gdev = ReadMacInt32(0x8a4); // MainDevice
419 cebix 1.26 D(bug("MainDevice handle at %08lx\n", gdev));
420     if (gdev != 0 && gdev != 0xffffffff) {
421     gdev = ReadMacInt32(gdev);
422     D(bug(" pointer at %08lx\n", gdev));
423     uint32 pmap = ReadMacInt32(gdev + 0x16); // gdPMap
424     D(bug(" PixMap handle at %08lx\n", pmap));
425     pmap = ReadMacInt32(pmap);
426     D(bug(" pointer at %08lx\n", pmap));
427     WriteMacInt32(pmap, mac_frame_base); // baseAddr
428     }
429     gdev = ReadMacInt32(0xcc8); // TheGDevice
430     D(bug("TheGDevice handle at %08lx\n", gdev));
431 cebix 1.20 }
432 cebix 1.18 }
433    
434    
435     /*
436 cebix 1.1 * Driver Open() routine
437     */
438    
439 cebix 1.25 int16 monitor_desc::driver_open(void)
440 cebix 1.1 {
441 cebix 1.9 // This shouldn't happen unless the platform-specific video code is broken
442 cebix 1.25 if (modes.empty())
443 cebix 1.9 fprintf(stderr, "No valid video modes found (broken video driver?)\n");
444    
445 cebix 1.1 // Init local variables
446 cebix 1.25 luminance_mapping = false;
447     interrupts_enabled = false;
448     current_apple_mode = preferred_apple_mode = depth_to_apple_mode(current_mode->depth);
449     current_id = preferred_id = current_mode->resolution_id;
450     dm_present = false;
451 cebix 1.1
452 cebix 1.11 // Allocate Slot Manager parameter block in Mac RAM
453     M68kRegisters r;
454     r.d[0] = SIZEOF_SPBlock;
455     Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
456     if (r.a[0] == 0)
457     return memFullErr;
458 cebix 1.25 slot_param = r.a[0];
459     D(bug("SPBlock at %08x\n", slot_param));
460 cebix 1.11
461     // Find and set default gamma table
462 cebix 1.25 gamma_table = 0;
463     alloc_gamma_table_size = 0;
464 cebix 1.14 set_gamma_table(0);
465 cebix 1.11
466 cebix 1.1 // Init color palette (solid gray)
467 cebix 1.11 set_gray_palette();
468 cebix 1.1 return noErr;
469     }
470    
471 cebix 1.25 int16 VideoDriverOpen(uint32 pb, uint32 dce)
472     {
473     uint8 slot_id = ReadMacInt8(dce + dCtlSlotId);
474     D(bug("VideoDriverOpen slot %02x\n", slot_id));
475    
476     monitor_desc *m = find_monitor(slot_id);
477     if (m)
478     return m->driver_open();
479     else
480     return nsDrvErr;
481     }
482    
483 cebix 1.1
484     /*
485     * Driver Control() routine
486     */
487    
488 cebix 1.25 int16 monitor_desc::driver_control(uint16 code, uint32 param, uint32 dce)
489 cebix 1.1 {
490     switch (code) {
491    
492 cebix 1.9 case cscSetMode: { // Set color depth
493     uint16 mode = ReadMacInt16(param + csMode);
494     D(bug(" SetMode %04x\n", mode));
495 cebix 1.10
496 cebix 1.11 // Set old base address in case the switch fails
497 cebix 1.25 WriteMacInt32(param + csBaseAddr, mac_frame_base);
498 cebix 1.11
499     if (ReadMacInt16(param + csPage))
500     return paramErr;
501    
502 cebix 1.25 if (mode != current_apple_mode) {
503     vector<video_mode>::const_iterator i = find_mode(mode, current_id);
504     if (i == invalid_mode())
505 cebix 1.10 return paramErr;
506 cebix 1.25 switch_mode(i, param, dce);
507 cebix 1.10 }
508 cebix 1.25 D(bug(" base %08x\n", mac_frame_base));
509 cebix 1.10 return noErr;
510 cebix 1.9 }
511 cebix 1.1
512 cebix 1.14 case cscSetEntries: // Set palette
513     case cscDirectSetEntries: {
514     D(bug(" (Direct)SetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart)));
515 cebix 1.25 bool is_direct = IsDirectMode(*current_mode);
516 cebix 1.14 if (code == cscSetEntries && is_direct)
517     return controlErr;
518     if (code == cscDirectSetEntries && !is_direct)
519 cebix 1.1 return controlErr;
520    
521     uint32 s_pal = ReadMacInt32(param + csTable); // Source palette
522     uint8 *d_pal; // Destination palette
523 cebix 1.11 uint16 start = ReadMacInt16(param + csStart);
524 cebix 1.1 uint16 count = ReadMacInt16(param + csCount);
525 cebix 1.11 if (s_pal == 0 || count > 255)
526 cebix 1.1 return paramErr;
527    
528 cebix 1.14 // Find tables for gamma correction
529 cebix 1.23 uint8 *red_gamma = NULL, *green_gamma = NULL, *blue_gamma = NULL;
530 cebix 1.14 bool have_gamma = false;
531     int data_width = 0;
532 cebix 1.25 if (gamma_table) {
533     red_gamma = Mac2HostAddr(gamma_table + gFormulaData + ReadMacInt16(gamma_table + gFormulaSize));
534     int chan_cnt = ReadMacInt16(gamma_table + gChanCnt);
535 cebix 1.14 if (chan_cnt == 1)
536     green_gamma = blue_gamma = red_gamma;
537     else {
538 cebix 1.25 int ofs = ReadMacInt16(gamma_table + gDataCnt);
539 cebix 1.14 green_gamma = red_gamma + ofs;
540     blue_gamma = green_gamma + ofs;
541     }
542 cebix 1.25 data_width = ReadMacInt16(gamma_table + gDataWidth);
543 cebix 1.14 have_gamma = true;
544     }
545    
546     // Convert palette
547 cebix 1.11 if (start == 0xffff) { // Indexed
548 cebix 1.1 for (uint32 i=0; i<=count; i++) {
549 cebix 1.25 d_pal = palette + (ReadMacInt16(s_pal) & 0xff) * 3;
550 cebix 1.1 uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8;
551     uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8;
552     uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8;
553 cebix 1.25 if (luminance_mapping && !is_direct)
554 cebix 1.1 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
555 cebix 1.14 if (have_gamma) {
556     red = red_gamma[red >> (8 - data_width)];
557     green = green_gamma[green >> (8 - data_width)];
558     blue = blue_gamma[blue >> (8 - data_width)];
559     }
560 cebix 1.1 *d_pal++ = red;
561     *d_pal++ = green;
562     *d_pal++ = blue;
563     s_pal += 8;
564     }
565 cebix 1.11 } else { // Sequential
566     if (start + count > 255)
567     return paramErr;
568 cebix 1.25 d_pal = palette + start * 3;
569 cebix 1.1 for (uint32 i=0; i<=count; i++) {
570     uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8;
571     uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8;
572     uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8;
573 cebix 1.25 if (luminance_mapping && !is_direct)
574 cebix 1.1 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
575 cebix 1.14 if (have_gamma) {
576     red = red_gamma[red >> (8 - data_width)];
577     green = green_gamma[green >> (8 - data_width)];
578     blue = blue_gamma[blue >> (8 - data_width)];
579     }
580 cebix 1.1 *d_pal++ = red;
581     *d_pal++ = green;
582     *d_pal++ = blue;
583     s_pal += 8;
584     }
585     }
586 cebix 1.25 set_palette(palette, palette_size(current_mode->depth));
587 cebix 1.1 return noErr;
588     }
589    
590 cebix 1.14 case cscSetGamma: { // Set gamma table
591     uint32 user_table = ReadMacInt32(param + csGTable);
592     D(bug(" SetGamma %08x\n", user_table));
593     return set_gamma_table(user_table) ? noErr : memFullErr;
594     }
595 cebix 1.1
596     case cscGrayPage: { // Fill page with dithered gray pattern
597     D(bug(" GrayPage %d\n", ReadMacInt16(param + csPage)));
598     if (ReadMacInt16(param + csPage))
599     return paramErr;
600    
601     uint32 pattern[6] = {
602     0xaaaaaaaa, // 1 bpp
603     0xcccccccc, // 2 bpp
604     0xf0f0f0f0, // 4 bpp
605     0xff00ff00, // 8 bpp
606     0xffff0000, // 16 bpp
607     0xffffffff // 32 bpp
608     };
609 cebix 1.25 uint32 p = mac_frame_base;
610     uint32 pat = pattern[current_mode->depth];
611     bool invert = (current_mode->depth == VDEPTH_32BIT);
612     for (uint32 y=0; y<current_mode->y; y++) {
613     for (uint32 x=0; x<current_mode->bytes_per_row; x+=4) {
614     WriteMacInt32(p + x, pat);
615 cebix 1.11 if (invert)
616 cebix 1.1 pat = ~pat;
617     }
618 cebix 1.25 p += current_mode->bytes_per_row;
619 cebix 1.1 pat = ~pat;
620     }
621 cebix 1.14
622 cebix 1.25 if (IsDirectMode(*current_mode))
623 cebix 1.14 load_ramp_palette();
624    
625 cebix 1.1 return noErr;
626     }
627    
628     case cscSetGray: // Enable/disable luminance mapping
629     D(bug(" SetGray %02x\n", ReadMacInt8(param + csMode)));
630 cebix 1.25 luminance_mapping = ReadMacInt8(param + csMode);
631 cebix 1.1 return noErr;
632    
633     case cscSetInterrupt: // Enable/disable VBL
634     D(bug(" SetInterrupt %02x\n", ReadMacInt8(param + csMode)));
635 cebix 1.25 interrupts_enabled = (ReadMacInt8(param + csMode) == 0);
636 cebix 1.1 return noErr;
637    
638 cebix 1.9 case cscSetDefaultMode: { // Set default color depth
639 cebix 1.21 uint16 mode = ReadMacInt8(param + csMode);
640     D(bug(" SetDefaultMode %02x\n", mode));
641 cebix 1.25 preferred_apple_mode = mode;
642 cebix 1.9 return noErr;
643     }
644    
645     case cscSwitchMode: { // Switch video mode (depth and resolution)
646     uint16 mode = ReadMacInt16(param + csMode);
647     uint32 id = ReadMacInt32(param + csData);
648     D(bug(" SwitchMode %04x, %08x\n", mode, id));
649 cebix 1.10
650 cebix 1.11 // Set old base address in case the switch fails
651 cebix 1.25 WriteMacInt32(param + csBaseAddr, mac_frame_base);
652 cebix 1.11
653     if (ReadMacInt16(param + csPage))
654     return paramErr;
655    
656 cebix 1.25 if (mode != current_apple_mode || id != current_id) {
657 cebix 1.17 vector<video_mode>::const_iterator i = find_mode(mode, id);
658 cebix 1.25 if (i == invalid_mode())
659 cebix 1.10 return paramErr;
660 cebix 1.25 switch_mode(i, param, dce);
661 cebix 1.10 }
662 cebix 1.25 D(bug(" base %08x\n", mac_frame_base));
663 cebix 1.10 return noErr;
664 cebix 1.9 }
665    
666     case cscSavePreferredConfiguration: {
667     uint16 mode = ReadMacInt16(param + csMode);
668     uint32 id = ReadMacInt32(param + csData);
669     D(bug(" SavePreferredConfiguration %04x, %08x\n", mode, id));
670 cebix 1.25 preferred_apple_mode = mode;
671     preferred_id = id;
672 cebix 1.9 return noErr;
673     }
674    
675 cebix 1.1 default:
676 cebix 1.2 printf("WARNING: Unknown VideoDriverControl(%d)\n", code);
677 cebix 1.1 return controlErr;
678     }
679     }
680    
681 cebix 1.25 int16 VideoDriverControl(uint32 pb, uint32 dce)
682     {
683     uint8 slot_id = ReadMacInt8(dce + dCtlSlotId);
684     uint16 code = ReadMacInt16(pb + csCode);
685     uint32 param = ReadMacInt32(pb + csParam);
686     D(bug("VideoDriverControl slot %02x, code %d\n", slot_id, code));
687    
688     monitor_desc *m = find_monitor(slot_id);
689     if (m)
690     return m->driver_control(code, param, dce);
691     else
692     return nsDrvErr;
693     }
694    
695 cebix 1.1
696     /*
697     * Driver Status() routine
698     */
699    
700 cebix 1.25 int16 monitor_desc::driver_status(uint16 code, uint32 param)
701 cebix 1.1 {
702     switch (code) {
703    
704 cebix 1.9 case cscGetMode: // Get current color depth
705 cebix 1.25 D(bug(" GetMode -> %04x, base %08x\n", current_apple_mode, mac_frame_base));
706     WriteMacInt16(param + csMode, current_apple_mode);
707 cebix 1.9 WriteMacInt16(param + csPage, 0);
708 cebix 1.25 WriteMacInt32(param + csBaseAddr, mac_frame_base);
709 cebix 1.9 return noErr;
710    
711 cebix 1.11 case cscGetEntries: { // Read palette
712     D(bug(" GetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart)));
713 cebix 1.9
714 cebix 1.11 uint8 *s_pal; // Source palette
715     uint32 d_pal = ReadMacInt32(param + csTable); // Destination palette
716     uint16 start = ReadMacInt16(param + csStart);
717     uint16 count = ReadMacInt16(param + csCount);
718     if (d_pal == 0 || count > 255)
719     return paramErr;
720    
721     if (start == 0xffff) { // Indexed
722     for (uint32 i=0; i<=count; i++) {
723 cebix 1.25 s_pal = palette + (ReadMacInt16(d_pal) & 0xff) * 3;
724 cebix 1.11 uint8 red = *s_pal++;
725     uint8 green = *s_pal++;
726     uint8 blue = *s_pal++;
727     WriteMacInt16(d_pal + 2, red * 0x0101);
728     WriteMacInt16(d_pal + 4, green * 0x0101);
729     WriteMacInt16(d_pal + 6, blue * 0x0101);
730     d_pal += 8;
731     }
732     } else { // Sequential
733     if (start + count > 255)
734     return paramErr;
735 cebix 1.25 s_pal = palette + start * 3;
736 cebix 1.11 for (uint32 i=0; i<=count; i++) {
737     uint8 red = *s_pal++;
738     uint8 green = *s_pal++;
739     uint8 blue = *s_pal++;
740     WriteMacInt16(d_pal + 2, red * 0x0101);
741     WriteMacInt16(d_pal + 4, green * 0x0101);
742     WriteMacInt16(d_pal + 6, blue * 0x0101);
743     d_pal += 8;
744     }
745     }
746     return noErr;
747     }
748    
749     case cscGetPages: // Get number of pages
750     D(bug(" GetPages -> 1\n"));
751 cebix 1.1 WriteMacInt16(param + csPage, 1);
752     return noErr;
753    
754 cebix 1.11 case cscGetBaseAddress: // Get page base address
755 cebix 1.25 D(bug(" GetBaseAddress -> %08x\n", mac_frame_base));
756     WriteMacInt32(param + csBaseAddr, mac_frame_base);
757 cebix 1.11 if (ReadMacInt16(param + csPage))
758     return paramErr;
759     else
760     return noErr;
761 cebix 1.1
762     case cscGetGray: // Get luminance mapping flag
763 cebix 1.25 D(bug(" GetGray -> %d\n", luminance_mapping));
764     WriteMacInt8(param, luminance_mapping ? 1 : 0);
765 cebix 1.1 return noErr;
766    
767     case cscGetInterrupt: // Get interrupt disable flag
768 cebix 1.25 D(bug(" GetInterrupt -> %d\n", interrupts_enabled));
769     WriteMacInt8(param, interrupts_enabled ? 0 : 1);
770 cebix 1.1 return noErr;
771    
772 cebix 1.11 case cscGetGamma:
773 cebix 1.25 D(bug(" GetGamma -> %08x\n", gamma_table));
774     WriteMacInt32(param + csGTable, gamma_table);
775 cebix 1.14 return noErr;
776 cebix 1.9
777     case cscGetDefaultMode: // Get default color depth
778 cebix 1.25 D(bug(" GetDefaultMode -> %02x\n", preferred_apple_mode));
779     WriteMacInt8(param + csMode, preferred_apple_mode);
780 cebix 1.1 return noErr;
781    
782 cebix 1.11 case cscGetCurrentMode: // Get current video mode (depth and resolution)
783 cebix 1.25 D(bug(" GetCurMode -> %04x/%08x, base %08x\n", current_apple_mode, current_id, mac_frame_base));
784     WriteMacInt16(param + csMode, current_apple_mode);
785     WriteMacInt32(param + csData, current_id);
786 cebix 1.1 WriteMacInt16(param + csPage, 0);
787 cebix 1.25 WriteMacInt32(param + csBaseAddr, mac_frame_base);
788 cebix 1.1 return noErr;
789    
790     case cscGetConnection: // Get monitor information
791     D(bug(" GetConnection\n"));
792 cebix 1.11 WriteMacInt16(param + csDisplayType, 8); // Modeless connection
793     WriteMacInt8(param + csConnectTaggedType, 0);
794     WriteMacInt8(param + csConnectTaggedData, 0);
795     WriteMacInt32(param + csConnectFlags, 0x43); // All modes valid and safe, non-standard tagging
796 cebix 1.1 WriteMacInt32(param + csDisplayComponent, 0);
797     return noErr;
798    
799 cebix 1.11 case cscGetModeTiming: { // Get video timing for specified resolution
800     uint32 id = ReadMacInt32(param + csTimingMode);
801     D(bug(" GetModeTiming %08x\n", id));
802     if (!has_resolution(id))
803     return paramErr;
804    
805     WriteMacInt32(param + csTimingFormat, FOURCC('d', 'e', 'c', 'l'));
806     WriteMacInt32(param + csTimingData, 0); // unknown
807     uint32 flags = 0xb; // mode valid, safe and shown in Monitors panel
808 cebix 1.25 if (id == preferred_id)
809 cebix 1.11 flags |= 4; // default mode
810     WriteMacInt32(param + csTimingFlags, flags);
811     return noErr;
812     }
813    
814 cebix 1.9 case cscGetModeBaseAddress: // Get frame buffer base address
815 cebix 1.25 D(bug(" GetModeBaseAddress -> base %08x\n", mac_frame_base));
816     WriteMacInt32(param + csBaseAddr, mac_frame_base);
817 cebix 1.1 return noErr;
818    
819 cebix 1.9 case cscGetPreferredConfiguration: // Get default video mode (depth and resolution)
820 cebix 1.25 D(bug(" GetPreferredConfiguration -> %04x/%08x\n", preferred_apple_mode, preferred_id));
821     WriteMacInt16(param + csMode, preferred_apple_mode);
822     WriteMacInt32(param + csData, preferred_id);
823 cebix 1.9 return noErr;
824    
825     case cscGetNextResolution: { // Called iteratively to obtain a list of all supported resolutions
826     uint32 id = ReadMacInt32(param + csPreviousDisplayModeID);
827     D(bug(" GetNextResolution %08x\n", id));
828    
829     switch (id) {
830     case 0:
831     // Return current resolution
832 cebix 1.25 id = current_id;
833 cebix 1.9 break;
834    
835     case 0xfffffffe:
836     // Return first supported resolution
837     id = 0x80;
838     while (!has_resolution(id))
839     id++;
840     break;
841    
842     default:
843     // Get next resolution
844     if (!has_resolution(id))
845     return paramErr;
846     id++;
847     while (!has_resolution(id) && id < 0x100)
848     id++;
849     if (id == 0x100) { // No more resolutions
850     WriteMacInt32(param + csRIDisplayModeID, 0xfffffffd);
851     return noErr;
852     }
853     break;
854     }
855    
856     WriteMacInt32(param + csRIDisplayModeID, id);
857     uint32 x, y;
858     get_size_of_resolution(id, x, y);
859     WriteMacInt32(param + csHorizontalPixels, x);
860     WriteMacInt32(param + csVerticalLines, y);
861     WriteMacInt32(param + csRefreshRate, 75 << 16);
862 cebix 1.25 WriteMacInt16(param + csMaxDepthMode, depth_to_apple_mode(max_depth_of_resolution(id)));
863 cebix 1.21 WriteMacInt32(param + csResolutionFlags, 0);
864 jlachmann 1.5 return noErr;
865 cebix 1.9 }
866 jlachmann 1.5
867 cebix 1.9 case cscGetVideoParameters: { // Get information about specified resolution/depth
868     uint32 id = ReadMacInt32(param + csDisplayModeID);
869     uint16 mode = ReadMacInt16(param + csDepthMode);
870     D(bug(" GetVideoParameters %04x/%08x\n", mode, id));
871 cebix 1.25 dm_present = true; // Display Manager seems to be present
872     D(bug(" Display Manager detected\n"));
873 cebix 1.9
874 cebix 1.25 vector<video_mode>::const_iterator i, end = modes.end();
875     for (i = modes.begin(); i != end; ++i) {
876     if (depth_to_apple_mode(i->depth) == mode && i->resolution_id == id) {
877 cebix 1.9 uint32 vp = ReadMacInt32(param + csVPBlockPtr);
878     WriteMacInt32(vp + vpBaseOffset, 0);
879     WriteMacInt16(vp + vpRowBytes, i->bytes_per_row);
880     WriteMacInt16(vp + vpBounds, 0);
881     WriteMacInt16(vp + vpBounds + 2, 0);
882     WriteMacInt16(vp + vpBounds + 4, i->y);
883     WriteMacInt16(vp + vpBounds + 6, i->x);
884     WriteMacInt16(vp + vpVersion, 0);
885     WriteMacInt16(vp + vpPackType, 0);
886     WriteMacInt32(vp + vpPackSize, 0);
887 cebix 1.11 WriteMacInt32(vp + vpHRes, 0x00480000); // 72 dpi
888 cebix 1.9 WriteMacInt32(vp + vpVRes, 0x00480000);
889     uint32 pix_type, pix_size, cmp_count, cmp_size, dev_type;
890     switch (i->depth) {
891     case VDEPTH_16BIT:
892     pix_type = 0x10; pix_size = 16;
893     cmp_count = 3; cmp_size = 5;
894     dev_type = 2; // direct
895     break;
896     case VDEPTH_32BIT:
897     pix_type = 0x10; pix_size = 32;
898     cmp_count = 3; cmp_size = 8;
899     dev_type = 2; // direct
900 cebix 1.23 break;
901     default:
902     pix_type = 0; pix_size = 1 << i->depth;
903     cmp_count = 1; cmp_size = 1 << i->depth;
904     dev_type = 0; // CLUT
905 cebix 1.9 break;
906     }
907     WriteMacInt16(vp + vpPixelType, pix_type);
908     WriteMacInt16(vp + vpPixelSize, pix_size);
909     WriteMacInt16(vp + vpCmpCount, cmp_count);
910     WriteMacInt16(vp + vpCmpSize, cmp_size);
911     WriteMacInt32(param + csPageCount, 1);
912     WriteMacInt32(param + csDeviceType, dev_type);
913     return noErr;
914     }
915     }
916     return paramErr; // specified resolution/depth not supported
917 cebix 1.21 }
918    
919     case cscGetMultiConnect: {
920     uint32 conn = ReadMacInt32(param + csDisplayCountOrNumber);
921     D(bug(" GetMultiConnect %08x\n", conn));
922     if (conn == 0xffffffff) { // Get number of connections
923     WriteMacInt32(param + csDisplayCountOrNumber, 1); // Single-headed
924     return noErr;
925     } else if (conn == 1) { // Get information about first connection
926     WriteMacInt16(param + csConnectInfo + csDisplayType, 8); // Modeless connection
927     WriteMacInt8(param + csConnectInfo + csConnectTaggedType, 0);
928     WriteMacInt8(param + csConnectInfo + csConnectTaggedData, 0);
929     WriteMacInt32(param + csConnectInfo + csConnectFlags, 0x43); // All modes valid and safe, non-standard tagging
930     WriteMacInt32(param + csConnectInfo + csDisplayComponent, 0);
931     return noErr;
932     } else
933     return paramErr;
934 cebix 1.9 }
935 cebix 1.1
936     default:
937 cebix 1.2 printf("WARNING: Unknown VideoDriverStatus(%d)\n", code);
938 cebix 1.1 return statusErr;
939     }
940 cebix 1.25 }
941    
942     int16 VideoDriverStatus(uint32 pb, uint32 dce)
943     {
944     uint8 slot_id = ReadMacInt8(dce + dCtlSlotId);
945     uint16 code = ReadMacInt16(pb + csCode);
946     uint32 param = ReadMacInt32(pb + csParam);
947     D(bug("VideoDriverStatus slot %02x, code %d\n", slot_id, code));
948    
949     monitor_desc *m = find_monitor(slot_id);
950     if (m)
951     return m->driver_status(code, param);
952     else
953     return nsDrvErr;
954 cebix 1.1 }