BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / accelerants / skeleton / SetDisplayMode.c
blobc2e7b06a4e0de866c966775705e7976d8205146e
2 /*
3 Copyright 1999, Be Incorporated. All Rights Reserved.
4 This file may be used under the terms of the Be Sample Code License.
6 Other authors:
7 Mark Watson,
8 Apsed,
9 Rudolf Cornelissen 11/2002-4/2004
12 #define MODULE_BIT 0x00200000
14 #include "acc_std.h"
17 Enable/Disable interrupts. Just a wrapper around the
18 ioctl() to the kernel driver.
20 static void interrupt_enable(bool flag) {
21 status_t result;
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;
26 sbs.do_it = flag;
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)
34 /* BOUNDS WARNING:
35 * It's impossible to deviate whatever small amount in a display_mode if the lower
36 * and upper limits are the same!
37 * Besides:
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
41 * deviations for:
42 * display_mode.virtual_width;
43 * display_mode.virtual_height;
44 * display_mode.timing.h_display;
45 * display_mode.timing.v_display;
46 * So:
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;
52 // status_t result;
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))
106 // {
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"));
110 // }
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' */
118 // if (crt1)
119 // {
120 /* connector1 is used as primary output */
121 // cross = false;
122 // }
123 // else
124 // {
125 // if (crt2)
126 /* connector2 is used as primary output */
127 // cross = true;
128 // else
129 /* no CRT detected: assume connector1 is used as primary output */
130 // cross = false;
131 // }
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);
136 // else
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))
146 // {
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"));
150 // }
152 /*set the colour depth for CRTC1 and the DAC */
153 switch(target.space)
155 case B_CMAP8:
156 colour_depth1 = 8;
157 // head1_mode(BPP8, 1.0);
158 // head1_depth(BPP8);
159 break;
160 case B_RGB15_LITTLE:
161 colour_depth1 = 16;
162 // head1_mode(BPP15, 1.0);
163 // head1_depth(BPP15);
164 break;
165 case B_RGB16_LITTLE:
166 colour_depth1 = 16;
167 // head1_mode(BPP16, 1.0);
168 // head1_depth(BPP16);
169 break;
170 case B_RGB32_LITTLE:
171 colour_depth1 = 32;
172 // head1_mode(BPP32, 1.0);
173 // head1_depth(BPP32);
174 break;
176 /*set the colour depth for CRTC2 and DAC2 */
177 switch(target2.space)
179 case B_CMAP8:
180 colour_depth2 = 8;
181 // head2_mode(BPP8, 1.0);
182 // head2_depth(BPP8);
183 break;
184 case B_RGB15_LITTLE:
185 colour_depth2 = 16;
186 // head2_mode(BPP15, 1.0);
187 // head2_depth(BPP15);
188 break;
189 case B_RGB16_LITTLE:
190 colour_depth2 = 16;
191 // head2_mode(BPP16, 1.0);
192 // head2_depth(BPP16);
193 break;
194 case B_RGB32_LITTLE:
195 colour_depth2 = 32;
196 // head2_mode(BPP32, 1.0);
197 // head2_depth(BPP32);
198 break;
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)
218 case DUALHEAD_ON:
219 case DUALHEAD_SWITCH:
220 // head1_set_display_start(startadd,colour_depth1);
221 // head2_set_display_start(startadd_right,colour_depth2);
222 break;
223 case DUALHEAD_CLONE:
224 // head1_set_display_start(startadd,colour_depth1);
225 // head2_set_display_start(startadd,colour_depth2);
226 break;
229 /* set the timing */
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 */
239 status_t status;
240 int colour_mode = BPP32;
242 /* connect output */
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' */
251 // if (crt1)
252 // {
253 /* connector1 is used as primary output */
254 // cross = false;
255 // }
256 // else
257 // {
258 // if (crt2)
259 /* connector2 is used as primary output */
260 // cross = true;
261 // else
262 /* no CRT detected: assume connector1 is used as primary output */
263 // cross = false;
264 // }
265 /* set output connectors assignment if possible */
266 eng_general_head_select(false);
269 switch(target.space)
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;
275 default:
276 LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
277 return B_ERROR;
280 /* set the pixel clock PLL */
281 // status = head1_set_pix_pll(target);
282 status = B_OK;
284 if (status==B_ERROR)
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);
299 /* set the timing */
300 // head1_set_timing(target);
302 //fixme: shut-off the videoPLL if it exists...
305 /* update driver's mode store */
306 si->dm = target;
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 */
314 // eng_acc_init();
315 /* set up overlay unit for this mode */
316 // eng_bes_init();
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();
329 return B_OK;
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) {
338 uint8 colour_depth;
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 */
347 switch(si->dm.space)
349 case B_CMAP8:
350 colour_depth=8;
351 break;
352 case B_RGB15_LITTLE:
353 case B_RGB16_LITTLE:
354 colour_depth=16;
355 break;
356 case B_RGB24_LITTLE:
357 colour_depth=24;
358 break;
359 case B_RGB32_LITTLE:
360 colour_depth=32;
361 break;
362 default:
363 return B_ERROR;
366 /* do not run past end of display */
367 switch (si->dm.flags & DUALHEAD_BITS)
369 case DUALHEAD_ON:
370 case DUALHEAD_SWITCH:
371 if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
372 return B_ERROR;
373 break;
374 default:
375 if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
376 return B_ERROR;
377 break;
379 if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
380 return B_ERROR;
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)
397 case DUALHEAD_ON:
398 case DUALHEAD_SWITCH:
399 // head1_set_display_start(startadd,colour_depth);
400 // head2_set_display_start(startadd_right,colour_depth);
401 break;
402 case DUALHEAD_OFF:
403 // head1_set_display_start(startadd,colour_depth);
404 break;
405 case DUALHEAD_CLONE:
406 // head1_set_display_start(startadd,colour_depth);
407 // head2_set_display_start(startadd,colour_depth);
408 break;
411 interrupt_enable(true);
412 return B_OK;
415 /* Set the indexed color palette */
416 void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
417 int i;
418 uint8 *r,*g,*b;
420 /* Protect gamma correction when not in CMAP8 */
421 if (si->dm.space != B_CMAP8) return;
423 r=si->color_data;
424 g=r+256;
425 b=g+256;
427 i=first;
428 while (count--)
430 r[i]=*color_data++;
431 g[i]=*color_data++;
432 b[i]=*color_data++;
433 i++;
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*/
447 switch(dpms_flags)
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);
452 break;
453 case B_DPMS_STAND_BY:
454 // head1_dpms(false, false, true);
455 // if (si->ps.secondary_head) head2_dpms(false, false, true);
456 break;
457 case B_DPMS_SUSPEND:
458 // head1_dpms(false, true, false);
459 // if (si->ps.secondary_head) head2_dpms(false, true, false);
460 break;
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);
464 break;
465 default:
466 LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
467 interrupt_enable(true);
468 return B_ERROR;
471 else /* singlehead */
473 switch(dpms_flags)
475 case B_DPMS_ON: /* H: on, V: on, display on */
476 // head1_dpms(true, true, true);
477 break;
478 case B_DPMS_STAND_BY:
479 // head1_dpms(false, false, true);
480 break;
481 case B_DPMS_SUSPEND:
482 // head1_dpms(false, true, false);
483 break;
484 case B_DPMS_OFF: /* H: off, V: off, display off */
485 // head1_dpms(false, false, false);
486 break;
487 default:
488 LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
489 interrupt_enable(true);
490 return B_ERROR;
493 interrupt_enable(true);
494 return B_OK;
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) {
504 bool display, h, v;
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)
513 return B_DPMS_ON;
514 else if(v)
515 return B_DPMS_STAND_BY;
516 else if(h)
517 return B_DPMS_SUSPEND;
518 else
519 return B_DPMS_OFF;