ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/video.cpp
Revision: 1.29
Committed: 2008-01-01T09:40:31Z (16 years, 4 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.28: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * video.cpp - Video/graphics emulation
3 *
4 * Basilisk II (C) 1997-2008 Christian Bauer
5 * Portions written by Marc Hellwig
6 *
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 * Designing PCI Cards and Drivers for Power Macintosh Computers
27 * Display Device Driver Guide
28 */
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 #include "slot_rom.h"
37 #include "video.h"
38 #include "video_defs.h"
39
40 #define DEBUG 0
41 #include "debug.h"
42
43
44 // Next available NuBus slot ID
45 uint8 monitor_desc::next_slot_id = 0x80;
46
47 // Vector of pointers to available monitor descriptions, filled by VideoInit()
48 vector<monitor_desc *> VideoMonitors;
49
50
51 /*
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
68
69 /*
70 * Find pointer to monitor_desc for given slot ID (or NULL if not found)
71 */
72
73 static monitor_desc *find_monitor(uint8 id)
74 {
75 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 uint16 mode = 0x80;
95 for (int depth = VDEPTH_1BIT; depth <= VDEPTH_32BIT; depth++) {
96 if (has_depth(video_depth(depth)))
97 apple_mode_for_depth[depth] = mode++;
98 else
99 apple_mode_for_depth[depth] = 0;
100 }
101
102 // Set default mode
103 current_mode = find_mode(depth_to_apple_mode(default_depth), default_id);
104 }
105
106
107 /*
108 * Get bytes-per-row value for specified resolution/depth
109 * (if the mode isn't supported, make a good guess)
110 */
111
112 uint32 monitor_desc::get_bytes_per_row(video_depth depth, uint32 id) const
113 {
114 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 while (i != end) {
133 if (i->depth == depth)
134 return true;
135 ++i;
136 }
137 return false;
138 }
139
140
141 /*
142 * Check whether the specified resolution ID is one of the supported resolutions
143 */
144
145 bool monitor_desc::has_resolution(uint32 id) const
146 {
147 vector<video_mode>::const_iterator i, end = modes.end();
148 for (i = modes.begin(); i != end; ++i) {
149 if (i->resolution_id == id)
150 return true;
151 }
152 return false;
153 }
154
155
156 /*
157 * Find specified mode (depth/resolution) (or invalid_mode() if not found)
158 */
159
160 vector<video_mode>::const_iterator monitor_desc::find_mode(uint16 apple_mode, uint32 id) const
161 {
162 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 return i;
166 }
167 return i;
168 }
169
170
171 /*
172 * Find maximum supported depth for given resolution ID
173 */
174
175 video_depth monitor_desc::max_depth_of_resolution(uint32 id) const
176 {
177 video_depth m = VDEPTH_1BIT;
178 vector<video_mode>::const_iterator i, end = modes.end();
179 for (i = modes.begin(); i != end; ++i) {
180 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 void monitor_desc::get_size_of_resolution(uint32 id, uint32 &x, uint32 &y) const
192 {
193 vector<video_mode>::const_iterator i, end = modes.end();
194 for (i = modes.begin(); i != end; ++i) {
195 if (i->resolution_id == id) {
196 x = i->x;
197 y = i->y;
198 return;
199 }
200 }
201 x = y = 0;
202 }
203
204
205 /*
206 * Set palette to 50% gray
207 */
208
209 void monitor_desc::set_gray_palette(void)
210 {
211 for (int i=0; i<256; i++) {
212 palette[i * 3 + 0] = 127;
213 palette[i * 3 + 1] = 127;
214 palette[i * 3 + 2] = 127;
215 }
216 set_palette(palette, 256);
217 }
218
219
220 /*
221 * Load gamma-corrected black-to-white ramp to palette for direct-color mode
222 */
223
224 void monitor_desc::load_ramp_palette(void)
225 {
226 // Find tables for gamma correction
227 uint8 *red_gamma = NULL, *green_gamma = NULL, *blue_gamma = NULL;
228 bool have_gamma = false;
229 int data_width = 0;
230 if (gamma_table) {
231 uint32 table = gamma_table;
232 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 int num = (current_mode->depth == VDEPTH_16BIT ? 32 : 256);
246 uint8 *p = palette;
247 for (int i=0; i<num; i++) {
248 uint8 red = (i * 256 / num), green = red, blue = red;
249 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 set_palette(palette, num);
260 }
261
262
263 /*
264 * Allocate gamma table of specified size
265 */
266
267 bool monitor_desc::allocate_gamma_table(int size)
268 {
269 M68kRegisters r;
270
271 if (size > alloc_gamma_table_size) {
272 if (gamma_table) {
273 r.a[0] = gamma_table;
274 Execute68kTrap(0xa01f, &r); // DisposePtr()
275 gamma_table = 0;
276 alloc_gamma_table_size = 0;
277 }
278 r.d[0] = size;
279 Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
280 if (r.a[0] == 0)
281 return false;
282 gamma_table = r.a[0];
283 alloc_gamma_table_size = size;
284 }
285 return true;
286 }
287
288
289 /*
290 * Set gamma table (0 = build linear ramp)
291 */
292
293 bool monitor_desc::set_gamma_table(uint32 user_table)
294 {
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 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
309 // Build ramp
310 uint32 p = gamma_table + gFormulaData;
311 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 Mac2Mac_memcpy(gamma_table, user_table, size);
338 }
339
340 if (IsDirectMode(*current_mode))
341 load_ramp_palette();
342
343 return true;
344 }
345
346
347 /*
348 * Switch video mode
349 */
350
351 void monitor_desc::switch_mode(vector<video_mode>::const_iterator it, uint32 param, uint32 dce)
352 {
353 const video_mode &mode = *it;
354
355 // Switch mode
356 set_gray_palette();
357 current_mode = it;
358 switch_to_current_mode();
359
360 // Update variables
361 current_apple_mode = depth_to_apple_mode(mode.depth);
362 current_id = mode.resolution_id;
363
364 M68kRegisters r;
365 r.a[0] = slot_param;
366
367 // Find functional sResource for this display
368 WriteMacInt8(slot_param + spSlot, ReadMacInt8(dce + dCtlSlot));
369 WriteMacInt8(slot_param + spID, ReadMacInt8(dce + dCtlSlotId));
370 WriteMacInt8(slot_param + spExtDev, 0);
371 r.d[0] = 0x0016;
372 Execute68kTrap(0xa06e, &r); // SRsrcInfo()
373 uint32 rsrc = ReadMacInt32(slot_param + spPointer);
374
375 // Patch minorBase (otherwise rebooting won't work)
376 WriteMacInt8(slot_param + spID, 0x0a); // minorBase
377 r.d[0] = 0x0006;
378 Execute68kTrap(0xa06e, &r); // SFindStruct()
379 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
385 // Patch video mode parameter table
386 WriteMacInt32(slot_param + spPointer, rsrc);
387 WriteMacInt8(slot_param + spID, depth_to_apple_mode(mode.depth));
388 r.d[0] = 0x0006;
389 Execute68kTrap(0xa06e, &r); // SFindStruct()
390 WriteMacInt8(slot_param + spID, 0x01);
391 r.d[0] = 0x0006;
392 Execute68kTrap(0xa06e, &r); // SFindStruct()
393 uint32 p = ReadMacInt32(slot_param + spPointer) - ROMBaseMac;
394 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 WriteMacInt8(slot_param + spID, ReadMacInt8(dce + dCtlSlotId));
406 r.d[0] = 0x002b;
407 Execute68kTrap(0xa06e, &r); // SUpdateSRT()
408
409 // Update frame buffer base in DCE and param block
410 WriteMacInt32(dce + dCtlDevBase, mac_frame_base);
411 WriteMacInt32(param + csBaseAddr, mac_frame_base);
412
413 // Patch frame buffer base address for MacOS versions <7.6
414 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 uint32 gdev = ReadMacInt32(0x8a4); // MainDevice
419 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 }
432 }
433
434
435 /*
436 * Driver Open() routine
437 */
438
439 int16 monitor_desc::driver_open(void)
440 {
441 // This shouldn't happen unless the platform-specific video code is broken
442 if (modes.empty())
443 fprintf(stderr, "No valid video modes found (broken video driver?)\n");
444
445 // Init local variables
446 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
452 // 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 slot_param = r.a[0];
459 D(bug("SPBlock at %08x\n", slot_param));
460
461 // Find and set default gamma table
462 gamma_table = 0;
463 alloc_gamma_table_size = 0;
464 set_gamma_table(0);
465
466 // Init color palette (solid gray)
467 set_gray_palette();
468 return noErr;
469 }
470
471 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
484 /*
485 * Driver Control() routine
486 */
487
488 int16 monitor_desc::driver_control(uint16 code, uint32 param, uint32 dce)
489 {
490 switch (code) {
491
492 case cscSetMode: { // Set color depth
493 uint16 mode = ReadMacInt16(param + csMode);
494 D(bug(" SetMode %04x\n", mode));
495
496 // Set old base address in case the switch fails
497 WriteMacInt32(param + csBaseAddr, mac_frame_base);
498
499 if (ReadMacInt16(param + csPage))
500 return paramErr;
501
502 if (mode != current_apple_mode) {
503 vector<video_mode>::const_iterator i = find_mode(mode, current_id);
504 if (i == invalid_mode())
505 return paramErr;
506 switch_mode(i, param, dce);
507 }
508 D(bug(" base %08x\n", mac_frame_base));
509 return noErr;
510 }
511
512 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 bool is_direct = IsDirectMode(*current_mode);
516 if (code == cscSetEntries && is_direct)
517 return controlErr;
518 if (code == cscDirectSetEntries && !is_direct)
519 return controlErr;
520
521 uint32 s_pal = ReadMacInt32(param + csTable); // Source palette
522 uint8 *d_pal; // Destination palette
523 uint16 start = ReadMacInt16(param + csStart);
524 uint16 count = ReadMacInt16(param + csCount);
525 if (s_pal == 0 || count > 255)
526 return paramErr;
527
528 // Find tables for gamma correction
529 uint8 *red_gamma = NULL, *green_gamma = NULL, *blue_gamma = NULL;
530 bool have_gamma = false;
531 int data_width = 0;
532 if (gamma_table) {
533 red_gamma = Mac2HostAddr(gamma_table + gFormulaData + ReadMacInt16(gamma_table + gFormulaSize));
534 int chan_cnt = ReadMacInt16(gamma_table + gChanCnt);
535 if (chan_cnt == 1)
536 green_gamma = blue_gamma = red_gamma;
537 else {
538 int ofs = ReadMacInt16(gamma_table + gDataCnt);
539 green_gamma = red_gamma + ofs;
540 blue_gamma = green_gamma + ofs;
541 }
542 data_width = ReadMacInt16(gamma_table + gDataWidth);
543 have_gamma = true;
544 }
545
546 // Convert palette
547 if (start == 0xffff) { // Indexed
548 for (uint32 i=0; i<=count; i++) {
549 d_pal = palette + (ReadMacInt16(s_pal) & 0xff) * 3;
550 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 if (luminance_mapping && !is_direct)
554 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
555 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 *d_pal++ = red;
561 *d_pal++ = green;
562 *d_pal++ = blue;
563 s_pal += 8;
564 }
565 } else { // Sequential
566 if (start + count > 255)
567 return paramErr;
568 d_pal = palette + start * 3;
569 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 if (luminance_mapping && !is_direct)
574 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
575 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 *d_pal++ = red;
581 *d_pal++ = green;
582 *d_pal++ = blue;
583 s_pal += 8;
584 }
585 }
586 set_palette(palette, palette_size(current_mode->depth));
587 return noErr;
588 }
589
590 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
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 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 if (invert)
616 pat = ~pat;
617 }
618 p += current_mode->bytes_per_row;
619 pat = ~pat;
620 }
621
622 if (IsDirectMode(*current_mode))
623 load_ramp_palette();
624
625 return noErr;
626 }
627
628 case cscSetGray: // Enable/disable luminance mapping
629 D(bug(" SetGray %02x\n", ReadMacInt8(param + csMode)));
630 luminance_mapping = ReadMacInt8(param + csMode);
631 return noErr;
632
633 case cscSetInterrupt: // Enable/disable VBL
634 D(bug(" SetInterrupt %02x\n", ReadMacInt8(param + csMode)));
635 interrupts_enabled = (ReadMacInt8(param + csMode) == 0);
636 return noErr;
637
638 case cscSetDefaultMode: { // Set default color depth
639 uint16 mode = ReadMacInt8(param + csMode);
640 D(bug(" SetDefaultMode %02x\n", mode));
641 preferred_apple_mode = mode;
642 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
650 // Set old base address in case the switch fails
651 WriteMacInt32(param + csBaseAddr, mac_frame_base);
652
653 if (ReadMacInt16(param + csPage))
654 return paramErr;
655
656 if (mode != current_apple_mode || id != current_id) {
657 vector<video_mode>::const_iterator i = find_mode(mode, id);
658 if (i == invalid_mode())
659 return paramErr;
660 switch_mode(i, param, dce);
661 }
662 D(bug(" base %08x\n", mac_frame_base));
663 return noErr;
664 }
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 preferred_apple_mode = mode;
671 preferred_id = id;
672 return noErr;
673 }
674
675 default:
676 printf("WARNING: Unknown VideoDriverControl(%d)\n", code);
677 return controlErr;
678 }
679 }
680
681 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
696 /*
697 * Driver Status() routine
698 */
699
700 int16 monitor_desc::driver_status(uint16 code, uint32 param)
701 {
702 switch (code) {
703
704 case cscGetMode: // Get current color depth
705 D(bug(" GetMode -> %04x, base %08x\n", current_apple_mode, mac_frame_base));
706 WriteMacInt16(param + csMode, current_apple_mode);
707 WriteMacInt16(param + csPage, 0);
708 WriteMacInt32(param + csBaseAddr, mac_frame_base);
709 return noErr;
710
711 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
714 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 s_pal = palette + (ReadMacInt16(d_pal) & 0xff) * 3;
724 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 s_pal = palette + start * 3;
736 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 WriteMacInt16(param + csPage, 1);
752 return noErr;
753
754 case cscGetBaseAddress: // Get page base address
755 D(bug(" GetBaseAddress -> %08x\n", mac_frame_base));
756 WriteMacInt32(param + csBaseAddr, mac_frame_base);
757 if (ReadMacInt16(param + csPage))
758 return paramErr;
759 else
760 return noErr;
761
762 case cscGetGray: // Get luminance mapping flag
763 D(bug(" GetGray -> %d\n", luminance_mapping));
764 WriteMacInt8(param, luminance_mapping ? 1 : 0);
765 return noErr;
766
767 case cscGetInterrupt: // Get interrupt disable flag
768 D(bug(" GetInterrupt -> %d\n", interrupts_enabled));
769 WriteMacInt8(param, interrupts_enabled ? 0 : 1);
770 return noErr;
771
772 case cscGetGamma:
773 D(bug(" GetGamma -> %08x\n", gamma_table));
774 WriteMacInt32(param + csGTable, gamma_table);
775 return noErr;
776
777 case cscGetDefaultMode: // Get default color depth
778 D(bug(" GetDefaultMode -> %02x\n", preferred_apple_mode));
779 WriteMacInt8(param + csMode, preferred_apple_mode);
780 return noErr;
781
782 case cscGetCurrentMode: // Get current video mode (depth and resolution)
783 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 WriteMacInt16(param + csPage, 0);
787 WriteMacInt32(param + csBaseAddr, mac_frame_base);
788 return noErr;
789
790 case cscGetConnection: // Get monitor information
791 D(bug(" GetConnection\n"));
792 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 WriteMacInt32(param + csDisplayComponent, 0);
797 return noErr;
798
799 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 if (id == preferred_id)
809 flags |= 4; // default mode
810 WriteMacInt32(param + csTimingFlags, flags);
811 return noErr;
812 }
813
814 case cscGetModeBaseAddress: // Get frame buffer base address
815 D(bug(" GetModeBaseAddress -> base %08x\n", mac_frame_base));
816 WriteMacInt32(param + csBaseAddr, mac_frame_base);
817 return noErr;
818
819 case cscGetPreferredConfiguration: // Get default video mode (depth and resolution)
820 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 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 id = current_id;
833 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 WriteMacInt16(param + csMaxDepthMode, depth_to_apple_mode(max_depth_of_resolution(id)));
863 WriteMacInt32(param + csResolutionFlags, 0);
864 return noErr;
865 }
866
867 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 dm_present = true; // Display Manager seems to be present
872 D(bug(" Display Manager detected\n"));
873
874 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 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 WriteMacInt32(vp + vpHRes, 0x00480000); // 72 dpi
888 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 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 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 }
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 }
935
936 default:
937 printf("WARNING: Unknown VideoDriverStatus(%d)\n", code);
938 return statusErr;
939 }
940 }
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 }