vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / via / ProposeDisplayMode.c
blob6637c847f673684b4d9d2721066d83d1766998bb
1 /*
2 Copyright 1999, Be Incorporated. All Rights Reserved.
3 This file may be used under the terms of the Be Sample Code License.
5 Other authors for NV driver:
6 Mark Watson,
7 Rudolf Cornelissen 9/2002-11/2005
8 */
10 #define MODULE_BIT 0x00400000
12 #include "acc_std.h"
14 #include <string.h>
16 #define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
17 /* mode flags will be setup as status info by PROPOSEMODE! */
18 #define MODE_FLAGS 0
19 #define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
21 /*some monitors only handle a fixed set of modes*/
22 #include "valid_mode_list"
24 /* Standard VESA modes,
25 * plus panel specific resolution modes which are internally modified during run-time depending on the requirements of the actual
26 * panel connected. The modes as listed here, should timing-wise be as compatible with analog (CRT) monitors as can be... */
27 static const display_mode mode_list[] = {
28 /* 4:3 modes; 307.2k pixels */
29 { { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
30 { { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */
31 { { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */
32 { { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
33 { { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
34 { { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
35 /* 4:3 modes; 480k pixels */
36 { { 36000, 800, 824, 896, 1024, 600, 601, 603, 625, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@56Hz_(800X600) from Be, Inc. driver + XFree86 */
37 { { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
38 { { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) + XFree86 */
39 { { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) + XFree86 */
40 { { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) + XFree86 */
41 { { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) + XFree86 */
42 /* 4:3 modes; 786.432k pixels */
43 { { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) + XFree86 */
44 { { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) + XFree86 */
45 { { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) + XFree86 */
46 { { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) + XFree86 */
47 /* 4:3 modes; 995.328k pixels */
48 { { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
49 { { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
50 { { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) + XFree86 */
51 { { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
52 /* 5:4 modes; 1.311M pixels */
53 { { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024) from Be, Inc. driver + XFree86 */
54 { { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) + XFree86 */
55 { { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) + XFree86 */
56 /* 4:3 panel mode; 1.47M pixels */
57 { { 122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1400X1050) */
58 /* 4:3 modes; 1.92M pixels */
59 { { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) + XFree86 */
60 /* identical lines to above one, apart from refreshrate.. */
61 { { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) + XFree86 */
62 { { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) + XFree86 */
63 { { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) + XFree86 */
64 { { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */
65 { { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) + XFree86 */
66 /* end identical lines. */
67 /* 4:3 modes; 2.408M pixels */
68 { { 204750, 1792, 1920, 2120, 2448, 1344, 1345, 1348, 1394, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1792X1344) from Be, Inc. driver + XFree86 */
69 { { 261000, 1792, 1888, 2104, 2456, 1344, 1345, 1348, 1417, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1792X1344) from Be, Inc. driver + XFree86 */
70 /* 4:3 modes; 2.584M pixels */
71 { { 218250, 1856, 1952, 2176, 2528, 1392, 1393, 1396, 1439, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1856X1392) from Be, Inc. driver + XFree86 */
72 { { 288000, 1856, 1984, 2208, 2560, 1392, 1393, 1396, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1856X1392) from Be, Inc. driver + XFree86 */
73 /* 4:3 modes; 2.765M pixels */
74 { { 234000, 1920, 2048, 2256, 2600, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1440) from Be, Inc. driver + XFree86 */
75 { { 297000, 1920, 2064, 2288, 2640, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1920X1440) from Be, Inc. driver + XFree86 */
76 /* 4:3 modes; 3.146M pixels */
77 { { 266950, 2048, 2200, 2424, 2800, 1536, 1537, 1540, 1589, B_POSITIVE_VSYNC}, B_CMAP8, 2048, 1536, 0, 0, MODE_FLAGS}, /* From XFree86 posting @60Hz + XFree86 */
78 /* 16:10 panel mode; 400k pixels */
79 { { 31300, 800, 848, 928, 1008, 500, 501, 504, 518, T_POSITIVE_SYNC}, B_CMAP8, 800, 500, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X500) */
80 /* 16:10 panel mode; 655.36k pixels */
81 { { 52800, 1024, 1072, 1176, 1328, 640, 641, 644, 663, T_POSITIVE_SYNC}, B_CMAP8, 1024, 640, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X640) */
82 /* 16:10 panel-TV mode; 983.04k pixels */
83 { { 80135, 1280, 1344, 1480, 1680, 768, 769, 772, 795, T_POSITIVE_SYNC}, B_CMAP8, 1280, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X768) */
84 /* 16:10 panel mode; 1.024M pixels */
85 { { 83500, 1280, 1344, 1480, 1680, 800, 801, 804, 828, T_POSITIVE_SYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X800) */
86 /* 16:10 panel mode; 1.296M pixels */
87 { { 106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, T_POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1440X900) */
88 /* 16:10 panel mode; 1.764M pixels */
89 { { 147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1680X1050) */
90 /* 16:10 panel mode; 2.304M pixels */
91 { { 193200, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, T_POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */
95 Check mode is between low and high limits
96 returns:
97 B_OK - found one
98 B_BAD_VALUE - mode can be made, but outside limits
99 B_ERROR - not possible
101 /* BOUNDS WARNING:
102 * BeOS (tested R5.0.3PE) is failing BWindowScreen.SetFrameBuffer() if PROPOSEMODE
103 * returns B_BAD_VALUE. It's called by the OS with target, low and high set to
104 * have the same settings for BWindowScreen!
105 * Which means we should not return B_BAD_VALUE on anything except for deviations on:
106 * display_mode.virtual_width;
107 * display_mode.virtual_height;
108 * display_mode.timing.h_display;
109 * display_mode.timing.v_display;
111 /* Note:
112 * The target mode should be modified to correspond to the mode as it can be made. */
113 status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high)
115 status_t status = B_OK;
116 float pix_clock_found, target_aspect;
117 uint8 m,n,p, bpp;
118 status_t result;
119 uint32 max_vclk, row_bytes, pointer_reservation;
120 bool acc_mode;
121 double target_refresh = ((double)target->timing.pixel_clock * 1000.0) /
123 (double)target->timing.h_total *
124 (double)target->timing.v_total
126 bool
127 want_same_width = target->timing.h_display == target->virtual_width,
128 want_same_height = target->timing.v_display == target->virtual_height;
130 LOG(1, ("PROPOSEMODE: (ENTER) requested virtual_width %d, virtual_height %d\n",
131 target->virtual_width, target->virtual_height));
133 /*check valid list:
134 if (VALID_REQUIRED is set)
136 if (find modes with same size)
138 pick one with nearest pixel clock
140 else
142 pick next largest with nearest pixel clock and modify visible portion as far as possible
146 #ifdef VALID_MODE_REQUIRED
148 int i;
149 int closest_mode_ptr;
150 uint32 closest_mode_clock;
152 LOG(1, ("PROPOSEMODE: valid mode required!\n"));
154 closest_mode_ptr = 0xbad;
155 closest_mode_clock = 0;
156 for (i=0;i<VALID_MODES;i++)
158 /*check size is ok and clock is better than any found before*/
160 target->timing.h_display==valid_mode_list[i].h_display &&
161 target->timing.v_display==valid_mode_list[i].v_display
164 if (
165 abs(valid_mode_list[i].pixel_clock-target->timing.pixel_clock)<
166 abs(closest_mode_clock-target->timing.pixel_clock)
169 closest_mode_clock=valid_mode_list[i].pixel_clock;
170 closest_mode_ptr=i;
175 if (closest_mode_ptr==0xbad)/*if no modes of correct size*/
177 LOG(4, ("PROPOSEMODE: no valid mode found, aborted.\n"));
178 return B_ERROR;
180 else
182 target->timing=valid_mode_list[closest_mode_ptr];
183 target_refresh = ((double)target->timing.pixel_clock * 1000.0) / /*I require this refresh*/
184 ((double)target->timing.h_total * (double)target->timing.v_total);
187 #endif
189 /*find a nearby valid timing from that given*/
190 result = head1_validate_timing
192 &target->timing.h_display, &target->timing.h_sync_start, &target->timing.h_sync_end, &target->timing.h_total,
193 &target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total
195 if (result == B_ERROR)
197 LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n"));
198 return result;
201 /* check if all connected output devices can display the requested mode's aspect: */
202 /* calculate display mode aspect */
203 target_aspect = (target->timing.h_display / ((float)target->timing.v_display));
204 /* NOTE:
205 * allow 0.10 difference so 5:4 aspect panels will be able to use 4:3 aspect modes! */
206 switch (si->ps.monitors)
208 case 0x01: /* digital panel on head 1, nothing on head 2 */
209 if (si->ps.panel1_aspect < (target_aspect - 0.10))
211 LOG(4, ("PROPOSEMODE: connected panel1 is not widescreen type, aborted.\n"));
212 return B_ERROR;
214 break;
215 case 0x10: /* nothing on head 1, digital panel on head 2 */
216 if (si->ps.panel2_aspect < (target_aspect - 0.10))
218 LOG(4, ("PROPOSEMODE: connected panel2 is not widescreen type, aborted.\n"));
219 return B_ERROR;
221 break;
222 case 0x11: /* digital panels on both heads */
223 if ((si->ps.panel1_aspect < (target_aspect - 0.10)) ||
224 (si->ps.panel2_aspect < (target_aspect - 0.10)))
226 LOG(4, ("PROPOSEMODE: not all connected panels are widescreen type, aborted.\n"));
227 return B_ERROR;
229 break;
230 default: /* at least one analog monitor is connected, or nothing detected at all */
231 if (target_aspect > 1.34)
233 LOG(4, ("PROPOSEMODE: not all output devices can display widescreen modes, aborted.\n"));
234 return B_ERROR;
236 break;
239 /* only export widescreen panel-TV modes when an exact resolution match exists,
240 * to prevent the modelist from becoming too crowded */
241 if (target_aspect > 1.61)
243 status_t panel_TV_stat = B_ERROR;
245 if (si->ps.tmds1_active)
247 if ((target->timing.h_display == si->ps.p1_timing.h_display) &&
248 (target->timing.v_display == si->ps.p1_timing.v_display))
250 panel_TV_stat = B_OK;
253 if (si->ps.tmds2_active)
255 if ((target->timing.h_display == si->ps.p2_timing.h_display) &&
256 (target->timing.v_display == si->ps.p2_timing.v_display))
258 panel_TV_stat = B_OK;
261 if (panel_TV_stat != B_OK)
263 LOG(4, ("PROPOSEMODE: WS panel_TV mode requested but no such TV here, aborted.\n"));
264 return B_ERROR;
268 /* check if panel(s) can display the requested resolution (if connected) */
269 if (si->ps.tmds1_active)
271 if ((target->timing.h_display > si->ps.p1_timing.h_display) ||
272 (target->timing.v_display > si->ps.p1_timing.v_display))
274 LOG(4, ("PROPOSEMODE: panel1 can't display requested resolution, aborted.\n"));
275 return B_ERROR;
278 if (si->ps.tmds2_active)
280 if ((target->timing.h_display > si->ps.p2_timing.h_display) ||
281 (target->timing.v_display > si->ps.p2_timing.v_display))
283 LOG(4, ("PROPOSEMODE: panel2 can't display requested resolution, aborted.\n"));
284 return B_ERROR;
288 /* validate display vs. virtual */
289 if ((target->timing.h_display > target->virtual_width) || want_same_width)
290 target->virtual_width = target->timing.h_display;
291 if ((target->timing.v_display > target->virtual_height) || want_same_height)
292 target->virtual_height = target->timing.v_display;
294 /* nail virtual size and 'subsequently' calculate rowbytes */
295 result = eng_general_validate_pic_size (target, &row_bytes, &acc_mode);
296 if (result == B_ERROR)
298 LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n"));
299 return result;
302 /*check if virtual_width is still within the requested limits*/
303 if ((target->virtual_width < low->virtual_width) ||
304 (target->virtual_width > high->virtual_width))
306 status = B_BAD_VALUE;
307 LOG(4, ("PROPOSEMODE: WARNING: virtual_width deviates too much\n"));
310 /*check if timing found is within the requested horizontal limits*/
311 if ((target->timing.h_display < low->timing.h_display) ||
312 (target->timing.h_display > high->timing.h_display) ||
313 (target->timing.h_sync_start < low->timing.h_sync_start) ||
314 (target->timing.h_sync_start > high->timing.h_sync_start) ||
315 (target->timing.h_sync_end < low->timing.h_sync_end) ||
316 (target->timing.h_sync_end > high->timing.h_sync_end) ||
317 (target->timing.h_total < low->timing.h_total) ||
318 (target->timing.h_total > high->timing.h_total))
320 /* BWindowScreen workaround: we accept everything except h_display deviations */
321 if ((target->timing.h_display < low->timing.h_display) ||
322 (target->timing.h_display > high->timing.h_display))
324 status = B_BAD_VALUE;
326 LOG(4, ("PROPOSEMODE: WARNING: horizontal timing deviates too much\n"));
329 /*check if timing found is within the requested vertical limits*/
330 if (
331 (target->timing.v_display < low->timing.v_display) ||
332 (target->timing.v_display > high->timing.v_display) ||
333 (target->timing.v_sync_start < low->timing.v_sync_start) ||
334 (target->timing.v_sync_start > high->timing.v_sync_start) ||
335 (target->timing.v_sync_end < low->timing.v_sync_end) ||
336 (target->timing.v_sync_end > high->timing.v_sync_end) ||
337 (target->timing.v_total < low->timing.v_total) ||
338 (target->timing.v_total > high->timing.v_total)
341 /* BWindowScreen workaround: we accept everything except v_display deviations */
342 if ((target->timing.v_display < low->timing.v_display) ||
343 (target->timing.v_display > high->timing.v_display))
345 status = B_BAD_VALUE;
347 LOG(4, ("PROPOSEMODE: WARNING: vertical timing deviates too much\n"));
350 /* adjust pixelclock for possible timing modifications done above */
351 target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0;
353 /* Now find the nearest valid pixelclock we actually can setup for the target mode,
354 * this also makes sure we don't generate more pixel bandwidth than the device can handle */
355 /* calculate settings, but do not actually test anything (that costs too much time!) */
356 result = head1_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0);
357 /* update the target mode */
358 target->timing.pixel_clock = (pix_clock_found * 1000);
360 /* note if we fell outside the limits */
361 if ((target->timing.pixel_clock < low->timing.pixel_clock) ||
362 (target->timing.pixel_clock > high->timing.pixel_clock)
365 /* BWindowScreen workaround: we accept deviations <= 1Mhz */
366 if ((target->timing.pixel_clock < (low->timing.pixel_clock - 1000)) ||
367 (target->timing.pixel_clock > (high->timing.pixel_clock + 1000)))
369 status = B_BAD_VALUE;
371 LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n"));
374 /* checkout space needed for hardcursor (if any) */
375 pointer_reservation = 0;
376 if (si->settings.hardcursor) pointer_reservation = 2048;
377 /* memory requirement for frame buffer */
378 if ((row_bytes * target->virtual_height) >
379 (si->ps.memory_size - pointer_reservation))
381 target->virtual_height =
382 (si->ps.memory_size - pointer_reservation) / row_bytes;
384 if (target->virtual_height < target->timing.v_display)
386 LOG(4,("PROPOSEMODE: not enough memory for current mode, aborted.\n"));
387 return B_ERROR;
389 LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n",
390 target->virtual_width, target->virtual_height));
392 if ((target->virtual_height < low->virtual_height) ||
393 (target->virtual_height > high->virtual_height))
395 status = B_BAD_VALUE;
396 LOG(4, ("PROPOSEMODE: WARNING: virtual_height deviates too much\n"));
399 /* setup status flags */
400 LOG(1, ("PROPOSEMODE: initial modeflags: $%08x\n", target->flags));
401 /* preset to singlehead card without TVout, no overlay support and no hardcursor.
402 * also advice system that app_server and acc engine may touch the framebuffer
403 * simultaneously (fixed). */
404 target->flags &=
405 ~(DUALHEAD_CAPABLE | TV_CAPABLE | B_SUPPORTS_OVERLAYS | B_HARDWARE_CURSOR | B_IO_FB_NA);
406 /* we always allow parallel access (fixed), the DAC is always in 'enhanced'
407 * mode (fixed), and all modes support DPMS (fixed);
408 * We support scrolling and panning in every mode, so we 'send a signal' to
409 * BWindowScreen.CanControlFrameBuffer() by setting B_SCROLL. */
410 /* BTW: B_PARALLEL_ACCESS in combination with a hardcursor enables
411 * BDirectWindow windowed modes. */
412 target->flags |= (B_PARALLEL_ACCESS | B_8_BIT_DAC | B_DPMS | B_SCROLL);
414 /* determine the 'would be' max. pixelclock for the second DAC for the current videomode if dualhead were activated */
415 switch (target->space)
417 case B_CMAP8:
418 max_vclk = si->ps.max_dac2_clock_8;
419 bpp = 1;
420 break;
421 case B_RGB15_LITTLE:
422 case B_RGB16_LITTLE:
423 max_vclk = si->ps.max_dac2_clock_16;
424 bpp = 2;
425 break;
426 case B_RGB24_LITTLE:
427 max_vclk = si->ps.max_dac2_clock_24;
428 bpp = 3;
429 break;
430 case B_RGB32_LITTLE:
431 max_vclk = si->ps.max_dac2_clock_32dh;
432 bpp = 4;
433 break;
434 default:
435 /* use fail-safe value */
436 max_vclk = si->ps.max_dac2_clock_32dh;
437 bpp = 4;
438 break;
441 /* set DUALHEAD_CAPABLE if suitable */
442 //fixme: update for independant secondary head use! (reserve fixed memory then)
443 if (si->ps.secondary_head && (target->timing.pixel_clock <= (max_vclk * 1000)))
445 switch (target->flags & DUALHEAD_BITS)
447 case DUALHEAD_ON:
448 case DUALHEAD_SWITCH:
449 if (((si->ps.memory_size - pointer_reservation) >=
450 (row_bytes * target->virtual_height)) &&
451 ((uint16)(row_bytes / bpp) >= (target->timing.h_display * 2)))
453 target->flags |= DUALHEAD_CAPABLE;
455 break;
456 case DUALHEAD_CLONE:
457 if ((si->ps.memory_size - pointer_reservation) >=
458 (row_bytes * target->virtual_height))
460 target->flags |= DUALHEAD_CAPABLE;
462 break;
463 case DUALHEAD_OFF:
464 if ((si->ps.memory_size - pointer_reservation) >=
465 (row_bytes * target->virtual_height * 2))
467 target->flags |= DUALHEAD_CAPABLE;
469 break;
473 /* set TV_CAPABLE if suitable: pixelclock is not important (defined by TVstandard) */
474 //fixme: modify for G100 and G200 TVout later on...
475 if (target->flags & DUALHEAD_CAPABLE)
477 if (si->ps.tvout &&
478 (target->timing.h_display <= 1024) &&
479 (target->timing.v_display <= 768))
481 target->flags |= TV_CAPABLE;
485 /* set HARDWARE_CURSOR mode if suitable */
486 if (si->settings.hardcursor)
487 target->flags |= B_HARDWARE_CURSOR;
489 /* set SUPPORTS_OVERLAYS */
490 target->flags |= B_SUPPORTS_OVERLAYS;
492 LOG(1, ("PROPOSEMODE: validated status modeflags: $%08x\n", target->flags));
494 /* overrule timing command flags to be (fixed) blank_pedestal = 0.0IRE,
495 * progressive scan (fixed), and sync_on_green not avaible. */
496 target->timing.flags &= ~(B_BLANK_PEDESTAL | B_TIMING_INTERLACED | B_SYNC_ON_GREEN);
497 /* The HSYNC and VSYNC command flags are actually executed by the driver. */
499 if (status == B_OK) LOG(4, ("PROPOSEMODE: completed successfully.\n"));
500 else LOG(4, ("PROPOSEMODE: mode can be made, but outside given limits.\n"));
501 return status;
504 /* Return the number of modes this device will return from GET_MODE_LIST().
505 This is precalculated in create_mode_list (called from InitAccelerant stuff)
507 uint32 ACCELERANT_MODE_COUNT(void)
509 LOG(1, ("ACCELERANT_MODE_COUNT: the modelist contains %d modes\n",si->mode_count));
511 return si->mode_count;
514 /* Copy the list of guaranteed supported video modes to the location provided.*/
515 status_t GET_MODE_LIST(display_mode *dm)
517 LOG(1, ("GET_MODE_LIST: exporting the modelist created before.\n"));
519 memcpy(dm, my_mode_list, si->mode_count * sizeof(display_mode));
520 return B_OK;
523 /* Create a list of display_modes to pass back to the caller.*/
524 status_t create_mode_list(void)
526 size_t max_size;
527 uint32
528 i, j,
529 pix_clk_range;
530 const display_mode
531 *src;
532 display_mode
533 *dst,
534 low,
535 high;
537 color_space spaces[4] = {B_RGB32_LITTLE,B_RGB16_LITTLE,B_RGB15_LITTLE,B_CMAP8};
539 /* figure out how big the list could be, and adjust up to nearest multiple of B_PAGE_SIZE */
540 max_size = (((MODE_COUNT * 4) * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
541 /* create an area to hold the info */
542 si->mode_area = my_mode_list_area =
543 create_area("NV accelerant mode info", (void **)&my_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
544 if (my_mode_list_area < B_OK) return my_mode_list_area;
546 /* walk through our predefined list and see which modes fit this device */
547 src = mode_list;
548 dst = my_mode_list;
549 si->mode_count = 0;
550 for (i = 0; i < MODE_COUNT; i++)
552 /* set ranges for acceptable values */
553 low = high = *src;
554 /* range is 6.25% of default clock: arbitrarily picked */
555 pix_clk_range = low.timing.pixel_clock >> 5;
556 low.timing.pixel_clock -= pix_clk_range;
557 high.timing.pixel_clock += pix_clk_range;
558 /* 'some cards need wider virtual widths for certain modes':
559 * Not true. They might need a wider pitch, but this is _not_ reflected in
560 * virtual_width, but in fbc.bytes_per_row. */
561 //So disable next line:
562 //high.virtual_width = 4096;
563 /* do it once for each depth we want to support */
564 for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++)
566 /* set target values */
567 *dst = *src;
568 /* poke the specific space */
569 dst->space = low.space = high.space = spaces[j];
570 /* ask for a compatible mode */
571 /* We have to check for B_OK, because otherwise the pix_clk_range
572 * won't be taken into account!! */
573 //So don't do this:
574 //if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) {
575 //Instead, do this:
576 if (PROPOSE_DISPLAY_MODE(dst, &low, &high) == B_OK) {
577 /* count it, and move on to next mode */
578 dst++;
579 si->mode_count++;
582 /* advance to next mode */
583 src++;
586 return B_OK;