3 Copyright 1999, Be Incorporated. All Rights Reserved.
4 This file may be used under the terms of the Be Sample Code License.
9 Rudolf Cornelissen 11/2002-9/2005
12 #define MODULE_BIT 0x00200000
17 Enable/Disable interrupts. Just a wrapper around the
18 ioctl() to the kernel driver.
20 static void interrupt_enable(bool flag
) {
22 eng_set_bool_state sbs
;
24 /* set the magic number so the driver knows we're for real */
25 sbs
.magic
= VIA_PRIVATE_DATA_MAGIC
;
27 /* contact driver and get a pointer to the registers and shared data */
28 result
= ioctl(fd
, ENG_RUN_INTERRUPTS
, &sbs
, sizeof(sbs
));
31 /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
32 status_t
SET_DISPLAY_MODE(display_mode
*mode_to_set
)
35 * It's impossible to deviate whatever small amount in a display_mode if the lower
36 * and upper limits are the same!
38 * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
39 * returns B_BAD_VALUE!
40 * Which means PROPOSEMODE should not return that on anything except on
42 * display_mode.virtual_width;
43 * display_mode.virtual_height;
44 * display_mode.timing.h_display;
45 * display_mode.timing.v_display;
47 * We don't use bounds here by making sure bounds and target are the same struct!
48 * (See the call to PROPOSE_DISPLAY_MODE below) */
49 display_mode
/*bounds,*/ target
;
51 uint8 colour_depth1
= 32;
53 uint32 startadd
,startadd_right
;
55 // bool crt1, crt2, cross;
57 /* Adjust mode to valid one and fail if invalid */
58 target
/*= bounds*/ = *mode_to_set
;
59 /* show the mode bits */
60 LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target
.flags
));
61 LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target
.timing
.pixel_clock
));
62 LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
63 target
.virtual_width
, target
.virtual_height
));
65 /* See BOUNDS WARNING above... */
66 if (PROPOSE_DISPLAY_MODE(&target
, &target
, &target
) == B_ERROR
) return B_ERROR
;
68 /* if not dualhead capable card clear dualhead flags */
69 if (!(target
.flags
& DUALHEAD_CAPABLE
))
71 target
.flags
&= ~DUALHEAD_BITS
;
73 /* if not TVout capable card clear TVout flags */
74 if (!(target
.flags
& TV_CAPABLE
))
76 target
.flags
&= ~TV_BITS
;
78 LOG(1, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target
.flags
));
80 /* disable interrupts using the kernel driver */
81 interrupt_enable(false);
83 /* find current DPMS state, then turn off screen(s) */
84 head1_dpms_fetch(&display
, &h
, &v
);
85 head1_dpms(false, false, false);
86 // if (si->ps.secondary_head) head2_dpms(false, false, false);
88 /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
89 startadd
= (uint8
*)si
->fbc
.frame_buffer
- (uint8
*)si
->framebuffer
;
91 /* calculate and set new mode bytes_per_row */
92 eng_general_validate_pic_size (&target
, &si
->fbc
.bytes_per_row
, &si
->acc_mode
);
94 /*Perform the very long mode switch!*/
95 if (target
.flags
& DUALHEAD_BITS
) /*if some dualhead mode*/
97 uint8 colour_depth2
= colour_depth1
;
99 /* init display mode for secondary head */
100 display_mode target2
= target
;
102 LOG(1,("SETMODE: setting DUALHEAD mode\n"));
104 /* validate flags for secondary TVout */
105 // if ((i2c_sec_tv_adapter() != B_OK) && (target2.flags & TV_BITS))
107 // target.flags &= ~TV_BITS;//still needed for some routines...
108 // target2.flags &= ~TV_BITS;
109 // LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n"));
112 /* detect which connectors have a CRT connected */
113 //fixme: 'hot-plugging' for analog monitors removed: remove code as well;
114 //or make it work with digital panels connected as well.
115 // crt1 = eng_dac_crt_connected();
116 // crt2 = eng_dac2_crt_connected();
117 /* connect outputs 'straight-through' */
120 /* connector1 is used as primary output */
126 /* connector2 is used as primary output */
129 /* no CRT detected: assume connector1 is used as primary output */
132 /* set output connectors assignment if possible */
133 // if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH)
134 /* invert output assignment in switch mode */
135 // eng_general_head_select(true);
137 // eng_general_head_select(false);
139 /* set the pixel clock PLL(s) */
140 LOG(8,("SETMODE: target clock %dkHz\n",target
.timing
.pixel_clock
));
141 if (head1_set_pix_pll(target
) == B_ERROR
)
142 LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
144 /* we do not need to set the pixelclock here for a head that's in TVout mode */
145 // if (!(target2.flags & TV_BITS))
147 // LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
148 // if (head2_set_pix_pll(target2) == B_ERROR)
149 // LOG(8,("SETMODE: error setting pixel clock (DAC2)\n"));
152 /*set the colour depth for CRTC1 and the DAC */
157 head1_mode(BPP8
, 1.0);
162 head1_mode(BPP15
, 1.0);
167 head1_mode(BPP16
, 1.0);
172 head1_mode(BPP32
, 1.0);
176 /*set the colour depth for CRTC2 and DAC2 */
177 switch(target2
.space
)
181 // head2_mode(BPP8, 1.0);
182 // head2_depth(BPP8);
186 // head2_mode(BPP15, 1.0);
187 // head2_depth(BPP15);
191 // head2_mode(BPP16, 1.0);
192 // head2_depth(BPP16);
196 // head2_mode(BPP32, 1.0);
197 // head2_depth(BPP32);
201 /* check if we are doing interlaced TVout mode */
202 si
->interlaced_tv_mode
= false;
203 /* if ((target2.flags & TV_BITS) && (si->ps.card_type >= G450))
204 si->interlaced_tv_mode = true;
206 /*set the display(s) pitches*/
207 head1_set_display_pitch ();
208 //fixme: seperate for real dualhead modes:
209 //we need a secondary si->fbc!
210 // head2_set_display_pitch ();
212 /*work out where the "right" screen starts*/
213 startadd_right
= startadd
+ (target
.timing
.h_display
* (colour_depth1
>> 3));
215 /* Tell card what memory to display */
216 switch (target
.flags
& DUALHEAD_BITS
)
219 case DUALHEAD_SWITCH
:
220 head1_set_display_start(startadd
,colour_depth1
);
221 // head2_set_display_start(startadd_right,colour_depth2);
224 head1_set_display_start(startadd
,colour_depth1
);
225 // head2_set_display_start(startadd,colour_depth2);
230 head1_set_timing(target
);
231 /* we do not need to setup CRTC2 here for a head that's in TVout mode */
232 // if (!(target2.flags & TV_BITS)) result = head2_set_timing(target2);
234 /* TVout support: setup CRTC2 and it's pixelclock */
235 // if (si->ps.tvout && (target2.flags & TV_BITS)) maventv_init(target2);
237 else /* single head mode */
240 int colour_mode
= BPP32
;
243 if (si
->ps
.secondary_head
)
245 /* detect which connectors have a CRT connected */
246 //fixme: 'hot-plugging' for analog monitors removed: remove code as well;
247 //or make it work with digital panels connected as well.
248 // crt1 = eng_dac_crt_connected();
249 // crt2 = eng_dac2_crt_connected();
250 /* connect outputs 'straight-through' */
253 /* connector1 is used as primary output */
259 /* connector2 is used as primary output */
262 /* no CRT detected: assume connector1 is used as primary output */
265 /* set output connectors assignment if possible */
266 eng_general_head_select(false);
271 case B_CMAP8
: colour_depth1
= 8; colour_mode
= BPP8
; break;
272 case B_RGB15_LITTLE
: colour_depth1
= 16; colour_mode
= BPP15
; break;
273 case B_RGB16_LITTLE
: colour_depth1
= 16; colour_mode
= BPP16
; break;
274 case B_RGB32_LITTLE
: colour_depth1
= 32; colour_mode
= BPP32
; break;
276 LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target
.space
));
280 /* set the pixel clock PLL */
281 status
= head1_set_pix_pll(target
);
284 LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
286 /* set the colour depth for CRTC1 and the DAC */
287 /* first set the colordepth */
288 head1_depth(colour_mode
);
289 /* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
290 head1_mode(colour_mode
,1.0);
292 /* set the display pitch */
293 head1_set_display_pitch();
295 /* tell the card what memory to display */
296 head1_set_display_start(startadd
,colour_depth1
);
299 head1_set_timing(target
);
301 //fixme: shut-off the videoPLL if it exists...
304 /* update driver's mode store */
307 /* turn screen one on */
308 head1_dpms(display
, h
, v
);
309 /* turn screen two on if a dualhead mode is active */
310 // if (target.flags & DUALHEAD_BITS) head2_dpms(display,h,v);
312 /* set up acceleration for this mode */
314 /* set up overlay unit for this mode */
317 LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
319 /* enable interrupts using the kernel driver */
320 interrupt_enable(true);
322 /* optimize memory-access if needed */
323 // head1_mem_priority(colour_depth1);
325 /* Tune RAM CAS-latency if needed. Must be done *here*! */
326 eng_set_cas_latency();
332 Set which pixel of the virtual frame buffer will show up in the
333 top left corner of the display device. Used for page-flipping
334 games and virtual desktops.
336 status_t
MOVE_DISPLAY(uint16 h_display_start
, uint16 v_display_start
) {
338 uint32 startadd
,startadd_right
;
340 LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start
, v_display_start
));
342 /* VIA CRTC1 handles multiples of 8 for 8bit, 4 for 16bit, 2 for 32 bit
343 VIA CRTC2 is yet unknown...
346 /* reset lower bits, don't return an error! */
347 if (si
->dm
.flags
& DUALHEAD_BITS
)
354 h_display_start
&= ~0x1f;
358 h_display_start
&= ~0x0f;
361 LOG(8,("SET:Invalid DH colour depth 0x%08x, should never happen\n", si
->dm
.space
));
371 h_display_start
&= ~0x07;
373 case B_RGB15_LITTLE
: case B_RGB16_LITTLE
:
375 h_display_start
&= ~0x03;
379 h_display_start
&= ~0x01;
386 /* do not run past end of display */
387 switch (si
->dm
.flags
& DUALHEAD_BITS
)
390 case DUALHEAD_SWITCH
:
391 if (((si
->dm
.timing
.h_display
* 2) + h_display_start
) > si
->dm
.virtual_width
)
395 if ((si
->dm
.timing
.h_display
+ h_display_start
) > si
->dm
.virtual_width
)
399 if ((si
->dm
.timing
.v_display
+ v_display_start
) > si
->dm
.virtual_height
)
402 /* everybody remember where we parked... */
403 si
->dm
.h_display_start
= h_display_start
;
404 si
->dm
.v_display_start
= v_display_start
;
406 /* actually set the registers */
407 //fixme: seperate both heads: we need a secondary si->fbc!
408 startadd
= v_display_start
* si
->fbc
.bytes_per_row
;
409 startadd
+= h_display_start
* (colour_depth
>> 3);
410 startadd
+= (uint8
*)si
->fbc
.frame_buffer
- (uint8
*)si
->framebuffer
;
411 startadd_right
= startadd
+ si
->dm
.timing
.h_display
* (colour_depth
>> 3);
413 interrupt_enable(false);
415 switch (si
->dm
.flags
& DUALHEAD_BITS
)
418 case DUALHEAD_SWITCH
:
419 head1_set_display_start(startadd
,colour_depth
);
420 // head2_set_display_start(startadd_right,colour_depth);
423 head1_set_display_start(startadd
,colour_depth
);
426 head1_set_display_start(startadd
,colour_depth
);
427 // head2_set_display_start(startadd,colour_depth);
431 interrupt_enable(true);
435 /* Set the indexed color palette */
436 void SET_INDEXED_COLORS(uint count
, uint8 first
, uint8
*color_data
, uint32 flags
) {
440 /* Protect gamma correction when not in CMAP8 */
441 if (si
->dm
.space
!= B_CMAP8
) return;
455 head1_palette(r
,g
,b
);
456 // if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b);
459 /* Put the display into one of the Display Power Management modes. */
460 status_t
SET_DPMS_MODE(uint32 dpms_flags
) {
461 interrupt_enable(false);
463 LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags
));
465 if (si
->dm
.flags
& DUALHEAD_BITS
) /*dualhead*/
469 case B_DPMS_ON
: /* H: on, V: on, display on */
470 head1_dpms(true, true, true);
471 // if (si->ps.secondary_head) head2_dpms(true, true, true);
473 case B_DPMS_STAND_BY
:
474 head1_dpms(false, false, true);
475 // if (si->ps.secondary_head) head2_dpms(false, false, true);
478 head1_dpms(false, true, false);
479 // if (si->ps.secondary_head) head2_dpms(false, true, false);
481 case B_DPMS_OFF
: /* H: off, V: off, display off */
482 head1_dpms(false, false, false);
483 // if (si->ps.secondary_head) head2_dpms(false, false, false);
486 LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags
));
487 interrupt_enable(true);
491 else /* singlehead */
495 case B_DPMS_ON
: /* H: on, V: on, display on */
496 head1_dpms(true, true, true);
498 case B_DPMS_STAND_BY
:
499 head1_dpms(false, false, true);
502 head1_dpms(false, true, false);
504 case B_DPMS_OFF
: /* H: off, V: off, display off */
505 head1_dpms(false, false, false);
508 LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags
));
509 interrupt_enable(true);
513 interrupt_enable(true);
517 /* Report device DPMS capabilities */
518 uint32
DPMS_CAPABILITIES(void) {
519 return (B_DPMS_ON
| B_DPMS_STAND_BY
| B_DPMS_SUSPEND
| B_DPMS_OFF
);
522 /* Return the current DPMS mode */
523 uint32
DPMS_MODE(void) {
526 interrupt_enable(false);
527 head1_dpms_fetch(&display
, &h
, &v
);
529 interrupt_enable(true);
531 if (display
&& h
&& v
)
534 return B_DPMS_STAND_BY
;
536 return B_DPMS_SUSPEND
;