ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/video.cpp
Revision: 1.25
Committed: 2002-04-25T11:00:30Z (22 years ago) by cebix
Branch: MAIN
Changes since 1.24: +261 -229 lines
Log Message:
- added infrastructure for multi-monitor support; only video_x.cpp is
  converted for the new scheme; not actually tested with a mult-monitor
  setup yet but at least single-monitor display doesn't seem to be broken
  (UAE banked addressing would definitely require some extensions to handle
  multiple frame buffers)
- struct video_mode has an extra field that is free for use by platform-
  specific code

File Contents

# Content
1 /*
2 * video.cpp - Video/graphics emulation
3 *
4 * Basilisk II (C) 1997-2002 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 gdev = ReadMacInt32(gdev);
420 uint32 pmap = ReadMacInt32(gdev + 0x16); // gdPMap
421 pmap = ReadMacInt32(pmap);
422 WriteMacInt32(pmap, mac_frame_base); // baseAddr
423 }
424 }
425
426
427 /*
428 * Driver Open() routine
429 */
430
431 int16 monitor_desc::driver_open(void)
432 {
433 // This shouldn't happen unless the platform-specific video code is broken
434 if (modes.empty())
435 fprintf(stderr, "No valid video modes found (broken video driver?)\n");
436
437 // Init local variables
438 luminance_mapping = false;
439 interrupts_enabled = false;
440 current_apple_mode = preferred_apple_mode = depth_to_apple_mode(current_mode->depth);
441 current_id = preferred_id = current_mode->resolution_id;
442 dm_present = false;
443
444 // Allocate Slot Manager parameter block in Mac RAM
445 M68kRegisters r;
446 r.d[0] = SIZEOF_SPBlock;
447 Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
448 if (r.a[0] == 0)
449 return memFullErr;
450 slot_param = r.a[0];
451 D(bug("SPBlock at %08x\n", slot_param));
452
453 // Find and set default gamma table
454 gamma_table = 0;
455 alloc_gamma_table_size = 0;
456 set_gamma_table(0);
457
458 // Init color palette (solid gray)
459 set_gray_palette();
460 return noErr;
461 }
462
463 int16 VideoDriverOpen(uint32 pb, uint32 dce)
464 {
465 uint8 slot_id = ReadMacInt8(dce + dCtlSlotId);
466 D(bug("VideoDriverOpen slot %02x\n", slot_id));
467
468 monitor_desc *m = find_monitor(slot_id);
469 if (m)
470 return m->driver_open();
471 else
472 return nsDrvErr;
473 }
474
475
476 /*
477 * Driver Control() routine
478 */
479
480 int16 monitor_desc::driver_control(uint16 code, uint32 param, uint32 dce)
481 {
482 switch (code) {
483
484 case cscSetMode: { // Set color depth
485 uint16 mode = ReadMacInt16(param + csMode);
486 D(bug(" SetMode %04x\n", mode));
487
488 // Set old base address in case the switch fails
489 WriteMacInt32(param + csBaseAddr, mac_frame_base);
490
491 if (ReadMacInt16(param + csPage))
492 return paramErr;
493
494 if (mode != current_apple_mode) {
495 vector<video_mode>::const_iterator i = find_mode(mode, current_id);
496 if (i == invalid_mode())
497 return paramErr;
498 switch_mode(i, param, dce);
499 }
500 D(bug(" base %08x\n", mac_frame_base));
501 return noErr;
502 }
503
504 case cscSetEntries: // Set palette
505 case cscDirectSetEntries: {
506 D(bug(" (Direct)SetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart)));
507 bool is_direct = IsDirectMode(*current_mode);
508 if (code == cscSetEntries && is_direct)
509 return controlErr;
510 if (code == cscDirectSetEntries && !is_direct)
511 return controlErr;
512
513 uint32 s_pal = ReadMacInt32(param + csTable); // Source palette
514 uint8 *d_pal; // Destination palette
515 uint16 start = ReadMacInt16(param + csStart);
516 uint16 count = ReadMacInt16(param + csCount);
517 if (s_pal == 0 || count > 255)
518 return paramErr;
519
520 // Find tables for gamma correction
521 uint8 *red_gamma = NULL, *green_gamma = NULL, *blue_gamma = NULL;
522 bool have_gamma = false;
523 int data_width = 0;
524 if (gamma_table) {
525 red_gamma = Mac2HostAddr(gamma_table + gFormulaData + ReadMacInt16(gamma_table + gFormulaSize));
526 int chan_cnt = ReadMacInt16(gamma_table + gChanCnt);
527 if (chan_cnt == 1)
528 green_gamma = blue_gamma = red_gamma;
529 else {
530 int ofs = ReadMacInt16(gamma_table + gDataCnt);
531 green_gamma = red_gamma + ofs;
532 blue_gamma = green_gamma + ofs;
533 }
534 data_width = ReadMacInt16(gamma_table + gDataWidth);
535 have_gamma = true;
536 }
537
538 // Convert palette
539 if (start == 0xffff) { // Indexed
540 for (uint32 i=0; i<=count; i++) {
541 d_pal = palette + (ReadMacInt16(s_pal) & 0xff) * 3;
542 uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8;
543 uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8;
544 uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8;
545 if (luminance_mapping && !is_direct)
546 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
547 if (have_gamma) {
548 red = red_gamma[red >> (8 - data_width)];
549 green = green_gamma[green >> (8 - data_width)];
550 blue = blue_gamma[blue >> (8 - data_width)];
551 }
552 *d_pal++ = red;
553 *d_pal++ = green;
554 *d_pal++ = blue;
555 s_pal += 8;
556 }
557 } else { // Sequential
558 if (start + count > 255)
559 return paramErr;
560 d_pal = palette + start * 3;
561 for (uint32 i=0; i<=count; i++) {
562 uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8;
563 uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8;
564 uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8;
565 if (luminance_mapping && !is_direct)
566 red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16;
567 if (have_gamma) {
568 red = red_gamma[red >> (8 - data_width)];
569 green = green_gamma[green >> (8 - data_width)];
570 blue = blue_gamma[blue >> (8 - data_width)];
571 }
572 *d_pal++ = red;
573 *d_pal++ = green;
574 *d_pal++ = blue;
575 s_pal += 8;
576 }
577 }
578 set_palette(palette, palette_size(current_mode->depth));
579 return noErr;
580 }
581
582 case cscSetGamma: { // Set gamma table
583 uint32 user_table = ReadMacInt32(param + csGTable);
584 D(bug(" SetGamma %08x\n", user_table));
585 return set_gamma_table(user_table) ? noErr : memFullErr;
586 }
587
588 case cscGrayPage: { // Fill page with dithered gray pattern
589 D(bug(" GrayPage %d\n", ReadMacInt16(param + csPage)));
590 if (ReadMacInt16(param + csPage))
591 return paramErr;
592
593 uint32 pattern[6] = {
594 0xaaaaaaaa, // 1 bpp
595 0xcccccccc, // 2 bpp
596 0xf0f0f0f0, // 4 bpp
597 0xff00ff00, // 8 bpp
598 0xffff0000, // 16 bpp
599 0xffffffff // 32 bpp
600 };
601 uint32 p = mac_frame_base;
602 uint32 pat = pattern[current_mode->depth];
603 bool invert = (current_mode->depth == VDEPTH_32BIT);
604 for (uint32 y=0; y<current_mode->y; y++) {
605 for (uint32 x=0; x<current_mode->bytes_per_row; x+=4) {
606 WriteMacInt32(p + x, pat);
607 if (invert)
608 pat = ~pat;
609 }
610 p += current_mode->bytes_per_row;
611 pat = ~pat;
612 }
613
614 if (IsDirectMode(*current_mode))
615 load_ramp_palette();
616
617 return noErr;
618 }
619
620 case cscSetGray: // Enable/disable luminance mapping
621 D(bug(" SetGray %02x\n", ReadMacInt8(param + csMode)));
622 luminance_mapping = ReadMacInt8(param + csMode);
623 return noErr;
624
625 case cscSetInterrupt: // Enable/disable VBL
626 D(bug(" SetInterrupt %02x\n", ReadMacInt8(param + csMode)));
627 interrupts_enabled = (ReadMacInt8(param + csMode) == 0);
628 return noErr;
629
630 case cscSetDefaultMode: { // Set default color depth
631 uint16 mode = ReadMacInt8(param + csMode);
632 D(bug(" SetDefaultMode %02x\n", mode));
633 preferred_apple_mode = mode;
634 return noErr;
635 }
636
637 case cscSwitchMode: { // Switch video mode (depth and resolution)
638 uint16 mode = ReadMacInt16(param + csMode);
639 uint32 id = ReadMacInt32(param + csData);
640 D(bug(" SwitchMode %04x, %08x\n", mode, id));
641
642 // Set old base address in case the switch fails
643 WriteMacInt32(param + csBaseAddr, mac_frame_base);
644
645 if (ReadMacInt16(param + csPage))
646 return paramErr;
647
648 if (mode != current_apple_mode || id != current_id) {
649 vector<video_mode>::const_iterator i = find_mode(mode, id);
650 if (i == invalid_mode())
651 return paramErr;
652 switch_mode(i, param, dce);
653 }
654 D(bug(" base %08x\n", mac_frame_base));
655 return noErr;
656 }
657
658 case cscSavePreferredConfiguration: {
659 uint16 mode = ReadMacInt16(param + csMode);
660 uint32 id = ReadMacInt32(param + csData);
661 D(bug(" SavePreferredConfiguration %04x, %08x\n", mode, id));
662 preferred_apple_mode = mode;
663 preferred_id = id;
664 return noErr;
665 }
666
667 default:
668 printf("WARNING: Unknown VideoDriverControl(%d)\n", code);
669 return controlErr;
670 }
671 }
672
673 int16 VideoDriverControl(uint32 pb, uint32 dce)
674 {
675 uint8 slot_id = ReadMacInt8(dce + dCtlSlotId);
676 uint16 code = ReadMacInt16(pb + csCode);
677 uint32 param = ReadMacInt32(pb + csParam);
678 D(bug("VideoDriverControl slot %02x, code %d\n", slot_id, code));
679
680 monitor_desc *m = find_monitor(slot_id);
681 if (m)
682 return m->driver_control(code, param, dce);
683 else
684 return nsDrvErr;
685 }
686
687
688 /*
689 * Driver Status() routine
690 */
691
692 int16 monitor_desc::driver_status(uint16 code, uint32 param)
693 {
694 switch (code) {
695
696 case cscGetMode: // Get current color depth
697 D(bug(" GetMode -> %04x, base %08x\n", current_apple_mode, mac_frame_base));
698 WriteMacInt16(param + csMode, current_apple_mode);
699 WriteMacInt16(param + csPage, 0);
700 WriteMacInt32(param + csBaseAddr, mac_frame_base);
701 return noErr;
702
703 case cscGetEntries: { // Read palette
704 D(bug(" GetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart)));
705
706 uint8 *s_pal; // Source palette
707 uint32 d_pal = ReadMacInt32(param + csTable); // Destination palette
708 uint16 start = ReadMacInt16(param + csStart);
709 uint16 count = ReadMacInt16(param + csCount);
710 if (d_pal == 0 || count > 255)
711 return paramErr;
712
713 if (start == 0xffff) { // Indexed
714 for (uint32 i=0; i<=count; i++) {
715 s_pal = palette + (ReadMacInt16(d_pal) & 0xff) * 3;
716 uint8 red = *s_pal++;
717 uint8 green = *s_pal++;
718 uint8 blue = *s_pal++;
719 WriteMacInt16(d_pal + 2, red * 0x0101);
720 WriteMacInt16(d_pal + 4, green * 0x0101);
721 WriteMacInt16(d_pal + 6, blue * 0x0101);
722 d_pal += 8;
723 }
724 } else { // Sequential
725 if (start + count > 255)
726 return paramErr;
727 s_pal = palette + start * 3;
728 for (uint32 i=0; i<=count; i++) {
729 uint8 red = *s_pal++;
730 uint8 green = *s_pal++;
731 uint8 blue = *s_pal++;
732 WriteMacInt16(d_pal + 2, red * 0x0101);
733 WriteMacInt16(d_pal + 4, green * 0x0101);
734 WriteMacInt16(d_pal + 6, blue * 0x0101);
735 d_pal += 8;
736 }
737 }
738 return noErr;
739 }
740
741 case cscGetPages: // Get number of pages
742 D(bug(" GetPages -> 1\n"));
743 WriteMacInt16(param + csPage, 1);
744 return noErr;
745
746 case cscGetBaseAddress: // Get page base address
747 D(bug(" GetBaseAddress -> %08x\n", mac_frame_base));
748 WriteMacInt32(param + csBaseAddr, mac_frame_base);
749 if (ReadMacInt16(param + csPage))
750 return paramErr;
751 else
752 return noErr;
753
754 case cscGetGray: // Get luminance mapping flag
755 D(bug(" GetGray -> %d\n", luminance_mapping));
756 WriteMacInt8(param, luminance_mapping ? 1 : 0);
757 return noErr;
758
759 case cscGetInterrupt: // Get interrupt disable flag
760 D(bug(" GetInterrupt -> %d\n", interrupts_enabled));
761 WriteMacInt8(param, interrupts_enabled ? 0 : 1);
762 return noErr;
763
764 case cscGetGamma:
765 D(bug(" GetGamma -> %08x\n", gamma_table));
766 WriteMacInt32(param + csGTable, gamma_table);
767 return noErr;
768
769 case cscGetDefaultMode: // Get default color depth
770 D(bug(" GetDefaultMode -> %02x\n", preferred_apple_mode));
771 WriteMacInt8(param + csMode, preferred_apple_mode);
772 return noErr;
773
774 case cscGetCurrentMode: // Get current video mode (depth and resolution)
775 D(bug(" GetCurMode -> %04x/%08x, base %08x\n", current_apple_mode, current_id, mac_frame_base));
776 WriteMacInt16(param + csMode, current_apple_mode);
777 WriteMacInt32(param + csData, current_id);
778 WriteMacInt16(param + csPage, 0);
779 WriteMacInt32(param + csBaseAddr, mac_frame_base);
780 return noErr;
781
782 case cscGetConnection: // Get monitor information
783 D(bug(" GetConnection\n"));
784 WriteMacInt16(param + csDisplayType, 8); // Modeless connection
785 WriteMacInt8(param + csConnectTaggedType, 0);
786 WriteMacInt8(param + csConnectTaggedData, 0);
787 WriteMacInt32(param + csConnectFlags, 0x43); // All modes valid and safe, non-standard tagging
788 WriteMacInt32(param + csDisplayComponent, 0);
789 return noErr;
790
791 case cscGetModeTiming: { // Get video timing for specified resolution
792 uint32 id = ReadMacInt32(param + csTimingMode);
793 D(bug(" GetModeTiming %08x\n", id));
794 if (!has_resolution(id))
795 return paramErr;
796
797 WriteMacInt32(param + csTimingFormat, FOURCC('d', 'e', 'c', 'l'));
798 WriteMacInt32(param + csTimingData, 0); // unknown
799 uint32 flags = 0xb; // mode valid, safe and shown in Monitors panel
800 if (id == preferred_id)
801 flags |= 4; // default mode
802 WriteMacInt32(param + csTimingFlags, flags);
803 return noErr;
804 }
805
806 case cscGetModeBaseAddress: // Get frame buffer base address
807 D(bug(" GetModeBaseAddress -> base %08x\n", mac_frame_base));
808 WriteMacInt32(param + csBaseAddr, mac_frame_base);
809 return noErr;
810
811 case cscGetPreferredConfiguration: // Get default video mode (depth and resolution)
812 D(bug(" GetPreferredConfiguration -> %04x/%08x\n", preferred_apple_mode, preferred_id));
813 WriteMacInt16(param + csMode, preferred_apple_mode);
814 WriteMacInt32(param + csData, preferred_id);
815 return noErr;
816
817 case cscGetNextResolution: { // Called iteratively to obtain a list of all supported resolutions
818 uint32 id = ReadMacInt32(param + csPreviousDisplayModeID);
819 D(bug(" GetNextResolution %08x\n", id));
820
821 switch (id) {
822 case 0:
823 // Return current resolution
824 id = current_id;
825 break;
826
827 case 0xfffffffe:
828 // Return first supported resolution
829 id = 0x80;
830 while (!has_resolution(id))
831 id++;
832 break;
833
834 default:
835 // Get next resolution
836 if (!has_resolution(id))
837 return paramErr;
838 id++;
839 while (!has_resolution(id) && id < 0x100)
840 id++;
841 if (id == 0x100) { // No more resolutions
842 WriteMacInt32(param + csRIDisplayModeID, 0xfffffffd);
843 return noErr;
844 }
845 break;
846 }
847
848 WriteMacInt32(param + csRIDisplayModeID, id);
849 uint32 x, y;
850 get_size_of_resolution(id, x, y);
851 WriteMacInt32(param + csHorizontalPixels, x);
852 WriteMacInt32(param + csVerticalLines, y);
853 WriteMacInt32(param + csRefreshRate, 75 << 16);
854 WriteMacInt16(param + csMaxDepthMode, depth_to_apple_mode(max_depth_of_resolution(id)));
855 WriteMacInt32(param + csResolutionFlags, 0);
856 return noErr;
857 }
858
859 case cscGetVideoParameters: { // Get information about specified resolution/depth
860 uint32 id = ReadMacInt32(param + csDisplayModeID);
861 uint16 mode = ReadMacInt16(param + csDepthMode);
862 D(bug(" GetVideoParameters %04x/%08x\n", mode, id));
863 dm_present = true; // Display Manager seems to be present
864 D(bug(" Display Manager detected\n"));
865
866 vector<video_mode>::const_iterator i, end = modes.end();
867 for (i = modes.begin(); i != end; ++i) {
868 if (depth_to_apple_mode(i->depth) == mode && i->resolution_id == id) {
869 uint32 vp = ReadMacInt32(param + csVPBlockPtr);
870 WriteMacInt32(vp + vpBaseOffset, 0);
871 WriteMacInt16(vp + vpRowBytes, i->bytes_per_row);
872 WriteMacInt16(vp + vpBounds, 0);
873 WriteMacInt16(vp + vpBounds + 2, 0);
874 WriteMacInt16(vp + vpBounds + 4, i->y);
875 WriteMacInt16(vp + vpBounds + 6, i->x);
876 WriteMacInt16(vp + vpVersion, 0);
877 WriteMacInt16(vp + vpPackType, 0);
878 WriteMacInt32(vp + vpPackSize, 0);
879 WriteMacInt32(vp + vpHRes, 0x00480000); // 72 dpi
880 WriteMacInt32(vp + vpVRes, 0x00480000);
881 uint32 pix_type, pix_size, cmp_count, cmp_size, dev_type;
882 switch (i->depth) {
883 case VDEPTH_16BIT:
884 pix_type = 0x10; pix_size = 16;
885 cmp_count = 3; cmp_size = 5;
886 dev_type = 2; // direct
887 break;
888 case VDEPTH_32BIT:
889 pix_type = 0x10; pix_size = 32;
890 cmp_count = 3; cmp_size = 8;
891 dev_type = 2; // direct
892 break;
893 default:
894 pix_type = 0; pix_size = 1 << i->depth;
895 cmp_count = 1; cmp_size = 1 << i->depth;
896 dev_type = 0; // CLUT
897 break;
898 }
899 WriteMacInt16(vp + vpPixelType, pix_type);
900 WriteMacInt16(vp + vpPixelSize, pix_size);
901 WriteMacInt16(vp + vpCmpCount, cmp_count);
902 WriteMacInt16(vp + vpCmpSize, cmp_size);
903 WriteMacInt32(param + csPageCount, 1);
904 WriteMacInt32(param + csDeviceType, dev_type);
905 return noErr;
906 }
907 }
908 return paramErr; // specified resolution/depth not supported
909 }
910
911 case cscGetMultiConnect: {
912 uint32 conn = ReadMacInt32(param + csDisplayCountOrNumber);
913 D(bug(" GetMultiConnect %08x\n", conn));
914 if (conn == 0xffffffff) { // Get number of connections
915 WriteMacInt32(param + csDisplayCountOrNumber, 1); // Single-headed
916 return noErr;
917 } else if (conn == 1) { // Get information about first connection
918 WriteMacInt16(param + csConnectInfo + csDisplayType, 8); // Modeless connection
919 WriteMacInt8(param + csConnectInfo + csConnectTaggedType, 0);
920 WriteMacInt8(param + csConnectInfo + csConnectTaggedData, 0);
921 WriteMacInt32(param + csConnectInfo + csConnectFlags, 0x43); // All modes valid and safe, non-standard tagging
922 WriteMacInt32(param + csConnectInfo + csDisplayComponent, 0);
923 return noErr;
924 } else
925 return paramErr;
926 }
927
928 default:
929 printf("WARNING: Unknown VideoDriverStatus(%d)\n", code);
930 return statusErr;
931 }
932 }
933
934 int16 VideoDriverStatus(uint32 pb, uint32 dce)
935 {
936 uint8 slot_id = ReadMacInt8(dce + dCtlSlotId);
937 uint16 code = ReadMacInt16(pb + csCode);
938 uint32 param = ReadMacInt32(pb + csParam);
939 D(bug("VideoDriverStatus slot %02x, code %d\n", slot_id, code));
940
941 monitor_desc *m = find_monitor(slot_id);
942 if (m)
943 return m->driver_status(code, param);
944 else
945 return nsDrvErr;
946 }