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-4/2004
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
= SKEL_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
;
54 // bool display, h, v;
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);
158 // head1_depth(BPP8);
162 // head1_mode(BPP15, 1.0);
163 // head1_depth(BPP15);
167 // head1_mode(BPP16, 1.0);
168 // head1_depth(BPP16);
172 // head1_mode(BPP32, 1.0);
173 // head1_depth(BPP32);
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);
285 LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
287 /* set the colour depth for CRTC1 and the DAC */
288 /* first set the colordepth */
289 // head1_depth(colour_mode);
290 /* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
291 // head1_mode(colour_mode,1.0);
293 /* set the display pitch */
294 // head1_set_display_pitch();
296 /* tell the card what memory to display */
297 // head1_set_display_start(startadd,colour_depth1);
300 // head1_set_timing(target);
302 //fixme: shut-off the videoPLL if it exists...
305 /* update driver's mode store */
308 /* turn screen one on */
309 // head1_dpms(display, h, v);
310 /* turn screen two on if a dualhead mode is active */
311 // if (target.flags & DUALHEAD_BITS) head2_dpms(display,h,v);
313 /* set up acceleration for this mode */
315 /* set up overlay unit for this mode */
318 LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
320 /* enable interrupts using the kernel driver */
321 interrupt_enable(true);
323 /* optimize memory-access if needed */
324 // head1_mem_priority(colour_depth1);
326 /* Tune RAM CAS-latency if needed. Must be done *here*! */
327 eng_set_cas_latency();
333 Set which pixel of the virtual frame buffer will show up in the
334 top left corner of the display device. Used for page-flipping
335 games and virtual desktops.
337 status_t
MOVE_DISPLAY(uint16 h_display_start
, uint16 v_display_start
) {
339 uint32 startadd
,startadd_right
;
341 LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start
, v_display_start
));
343 /* nVidia cards support pixelprecise panning on both heads in all modes:
344 * No stepping granularity needed! */
346 /* determine bits used for the colordepth */
366 /* do not run past end of display */
367 switch (si
->dm
.flags
& DUALHEAD_BITS
)
370 case DUALHEAD_SWITCH
:
371 if (((si
->dm
.timing
.h_display
* 2) + h_display_start
) > si
->dm
.virtual_width
)
375 if ((si
->dm
.timing
.h_display
+ h_display_start
) > si
->dm
.virtual_width
)
379 if ((si
->dm
.timing
.v_display
+ v_display_start
) > si
->dm
.virtual_height
)
382 /* everybody remember where we parked... */
383 si
->dm
.h_display_start
= h_display_start
;
384 si
->dm
.v_display_start
= v_display_start
;
386 /* actually set the registers */
387 //fixme: seperate both heads: we need a secondary si->fbc!
388 startadd
= v_display_start
* si
->fbc
.bytes_per_row
;
389 startadd
+= h_display_start
* (colour_depth
>> 3);
390 startadd
+= (uint8
*)si
->fbc
.frame_buffer
- (uint8
*)si
->framebuffer
;
391 startadd_right
= startadd
+ si
->dm
.timing
.h_display
* (colour_depth
>> 3);
393 interrupt_enable(false);
395 switch (si
->dm
.flags
& DUALHEAD_BITS
)
398 case DUALHEAD_SWITCH
:
399 // head1_set_display_start(startadd,colour_depth);
400 // head2_set_display_start(startadd_right,colour_depth);
403 // head1_set_display_start(startadd,colour_depth);
406 // head1_set_display_start(startadd,colour_depth);
407 // head2_set_display_start(startadd,colour_depth);
411 interrupt_enable(true);
415 /* Set the indexed color palette */
416 void SET_INDEXED_COLORS(uint count
, uint8 first
, uint8
*color_data
, uint32 flags
) {
420 /* Protect gamma correction when not in CMAP8 */
421 if (si
->dm
.space
!= B_CMAP8
) return;
435 // head1_palette(r,g,b);
436 if (si
->dm
.flags
& DUALHEAD_BITS
) head2_palette(r
,g
,b
);
439 /* Put the display into one of the Display Power Management modes. */
440 status_t
SET_DPMS_MODE(uint32 dpms_flags
) {
441 interrupt_enable(false);
443 LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags
));
445 if (si
->dm
.flags
& DUALHEAD_BITS
) /*dualhead*/
449 case B_DPMS_ON
: /* H: on, V: on, display on */
450 // head1_dpms(true, true, true);
451 // if (si->ps.secondary_head) head2_dpms(true, true, true);
453 case B_DPMS_STAND_BY
:
454 // head1_dpms(false, false, true);
455 // if (si->ps.secondary_head) head2_dpms(false, false, true);
458 // head1_dpms(false, true, false);
459 // if (si->ps.secondary_head) head2_dpms(false, true, false);
461 case B_DPMS_OFF
: /* H: off, V: off, display off */
462 // head1_dpms(false, false, false);
463 // if (si->ps.secondary_head) head2_dpms(false, false, false);
466 LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags
));
467 interrupt_enable(true);
471 else /* singlehead */
475 case B_DPMS_ON
: /* H: on, V: on, display on */
476 // head1_dpms(true, true, true);
478 case B_DPMS_STAND_BY
:
479 // head1_dpms(false, false, true);
482 // head1_dpms(false, true, false);
484 case B_DPMS_OFF
: /* H: off, V: off, display off */
485 // head1_dpms(false, false, false);
488 LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags
));
489 interrupt_enable(true);
493 interrupt_enable(true);
497 /* Report device DPMS capabilities */
498 uint32
DPMS_CAPABILITIES(void) {
499 return (B_DPMS_ON
| B_DPMS_STAND_BY
| B_DPMS_SUSPEND
| B_DPMS_OFF
);
502 /* Return the current DPMS mode */
503 uint32
DPMS_MODE(void) {
506 interrupt_enable(false);
507 // head1_dpms_fetch(&display, &h, &v);
508 display
= h
= v
= true;
510 interrupt_enable(true);
512 if (display
&& h
&& v
)
515 return B_DPMS_STAND_BY
;
517 return B_DPMS_SUSPEND
;