vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / radeon / multimon.c
blob31ef5b4a6c981965d9571d59e0f7b5a5178e8fde
1 /*
2 Copyright (c) 2002-2004, Thomas Kurschel
5 Part of Radeon accelerant
7 Multi-monitor management
8 */
10 #include "radeon_accelerant.h"
11 #include "generic.h"
12 #include "GlobalData.h"
15 // transform official mode to internal, multi-screen mode enhanced mode
16 void Radeon_DetectMultiMode( virtual_card *vc, display_mode *mode )
18 (void)vc;
20 mode->timing.flags &= ~RADEON_MODE_MASK;
22 // combine mode is used if virtual area is twice as visible area
23 // and if scrolling is enabled; if combining is impossible, use
24 // cloning instead
25 if( (mode->flags & B_SCROLL) == 0 )
26 return;
28 SHOW_FLOW0( 3, "possibly combine mode" );
30 // remove scroll flag - we don't need it anymore
31 mode->flags &= ~B_SCROLL;
33 mode->timing.flags &= ~RADEON_MODE_POSITION_MASK;
35 if( mode->virtual_width == 2 * mode->timing.h_display ) {
36 SHOW_FLOW0( 2, "horizontal combine mode" );
37 mode->timing.flags |= RADEON_MODE_POSITION_HORIZONTAL;
38 mode->timing.flags &= ~RADEON_MODE_MASK;
39 mode->timing.flags |= RADEON_MODE_COMBINE;
40 } else if( mode->virtual_height == 2 * mode->timing.v_display ) {
41 SHOW_FLOW0( 2, "vertical combine mode" );
42 mode->timing.flags |= RADEON_MODE_POSITION_VERTICAL;
43 mode->timing.flags &= ~RADEON_MODE_MASK;
44 mode->timing.flags |= RADEON_MODE_COMBINE;
45 } else {
46 // ups, this isn't really a combine mode - restore flags
47 SHOW_FLOW0( 2, "wasn't really a combine mode" );
48 mode->timing.flags &= ~RADEON_MODE_MASK;
49 mode->flags |= B_SCROLL;
53 // make sure selected multi-screen mode is valid; adapt it if needed
54 void Radeon_VerifyMultiMode( virtual_card *vc, shared_info *si, display_mode *mode )
56 // if there is no second port or no second monitor connected,
57 // fall back to standard mode
58 int num_usable_crtcs = vc->assigned_crtc[0] && si->crtc[0].chosen_displays != dd_none;
60 if( si->num_crtc > 1 )
61 num_usable_crtcs += vc->assigned_crtc[1] && si->crtc[1].chosen_displays != dd_none;
63 if( num_usable_crtcs < 2 ) {
64 SHOW_FLOW0( 2, "only one monitor - disabling any multi-mon mode" );
65 // restore flags if combine mode is selected
66 if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
67 mode->flags |= B_SCROLL;
69 mode->timing.flags &= ~RADEON_MODE_MASK;
70 mode->timing.flags |= RADEON_MODE_STANDARD;
74 // transform internal, multi-screen enabled display mode
75 // to official mode
76 void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode )
78 (void) vc;
80 // restore flags for combine mode
81 if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
82 mode->flags |= B_SCROLL;
86 // initialize multi-screen mode dependant variables
87 void Radeon_InitMultiModeVars(
88 accelerator_info *ai, display_mode *mode )
90 virtual_card *vc = ai->vc;
91 shared_info *si = ai->si;
92 uint32 x, y;
94 // setup single-screen mode
95 vc->eff_width = mode->timing.h_display;
96 vc->eff_height = mode->timing.v_display;
98 if( vc->used_crtc[0] ) {
99 si->crtc[0].rel_x = 0;
100 si->crtc[0].rel_y = 0;
103 if( vc->used_crtc[1] ) {
104 si->crtc[1].rel_x = 0;
105 si->crtc[1].rel_y = 0;
108 switch( mode->timing.flags & RADEON_MODE_MASK ) {
109 case RADEON_MODE_COMBINE:
110 // detect where second screen must be located and
111 // adapt total visible area accordingly
112 if( (mode->timing.flags & RADEON_MODE_POSITION_MASK) == RADEON_MODE_POSITION_HORIZONTAL ) {
113 vc->eff_width = 2 * mode->timing.h_display;
114 x = mode->timing.h_display;
115 y = 0;
116 } else {
117 vc->eff_height = 2 * mode->timing.v_display;
118 x = 0;
119 y = mode->timing.v_display;
122 SHOW_FLOW( 3, "relative position of second screen: %d, %d", x, y );
124 // set relative offset
125 if( !vc->swap_displays ) {
126 si->crtc[1].rel_x = x;
127 si->crtc[1].rel_y = y;
128 } else {
129 si->crtc[0].rel_x = x;
130 si->crtc[0].rel_y = y;
132 break;
134 default:
135 // else, ports are independant but show the same
136 break;
141 // mapping of internal TV standard code to public TV standard code
142 static const uint32 private2be[] = {
143 0, 1, 3, 4, 103, 3/* PAL SCART - no public id, so I use PAL BDGHI */, 102 };
145 // check and execute tunnel settings command
146 status_t Radeon_CheckMultiMonTunnel( virtual_card *vc, display_mode *mode,
147 const display_mode *low, const display_mode *high, bool *isTunneled )
149 if( (mode->timing.flags & RADEON_MODE_MULTIMON_REQUEST) != 0 &&
150 (mode->timing.flags & RADEON_MODE_MULTIMON_REPLY) == 0 )
152 mode->timing.flags &= ~RADEON_MODE_MULTIMON_REQUEST;
153 mode->timing.flags |= RADEON_MODE_MULTIMON_REPLY;
155 // still process request, just in case someone set this flag
156 // combination by mistake
158 // TBD: disabled to shorten syslog
159 *isTunneled = true;
160 return B_OK;
163 // check magic params
164 if( mode->space != 0 || low->space != 0 || high->space != 0
165 || low->virtual_width != 0xffff || low->virtual_height != 0xffff
166 || high->virtual_width != 0 || high->virtual_height != 0
167 || mode->timing.pixel_clock != 0
168 || low->timing.pixel_clock != 'TKTK' || high->timing.pixel_clock != 'KTKT' )
170 *isTunneled = false;
171 return B_OK;
174 *isTunneled = true;
176 /*SHOW_FLOW( 1, "tunnel access code=%d, command=%d",
177 mode->h_display_start, mode->v_display_start );*/
179 switch( mode->h_display_start ) {
180 case ms_swap:
181 switch( mode->v_display_start ) {
182 case 0:
183 mode->timing.flags = vc->swap_displays;
184 return B_OK;
186 case 1:
187 vc->swap_displays = mode->timing.flags != 0;
188 vc->enforce_mode_change = true;
189 // write settings instantly
190 Radeon_WriteSettings( vc );
191 return B_OK;
193 break;
195 case ms_use_laptop_panel:
196 // we must refuse this setting if there is no laptop panel;
197 // else, the preferences dialog would show this (useless) option
198 if( (vc->connected_displays & dd_lvds) == 0 )
199 return B_ERROR;
201 switch( mode->v_display_start ) {
202 case 0:
203 mode->timing.flags = vc->use_laptop_panel;
204 //SHOW_FLOW( 1, "get use_laptop_panel settings (%d)", mode->timing.flags );
205 return B_OK;
207 case 1:
208 vc->use_laptop_panel = mode->timing.flags != 0;
209 //SHOW_FLOW( 1, "set use_laptop_panel settings (%d)", vc->use_laptop_panel );
210 vc->enforce_mode_change = true;
211 Radeon_WriteSettings( vc );
212 return B_OK;
214 break;
216 case ms_tv_standard:
217 switch( mode->v_display_start ) {
218 case 0:
219 mode->timing.flags = private2be[vc->tv_standard];
220 /*SHOW_FLOW( 1, "read tv_standard (internal %d, public %d)",
221 vc->tv_standard, mode->timing.flags );*/
222 return B_OK;
224 case 1:
225 switch( mode->timing.flags ) {
226 case 0: vc->tv_standard = ts_off; break;
227 case 1: vc->tv_standard = ts_ntsc; break;
228 case 2: break; // ntsc j
229 case 3: vc->tv_standard = ts_pal_bdghi; break;
230 case 4: vc->tv_standard = ts_pal_m; break;
231 case 5: break; // pal n
232 case 6: break; // secam - I reckon not supported by hardware
233 case 101: break; // ntsc 443
234 case 102: vc->tv_standard = ts_pal_60; break;
235 case 103: vc->tv_standard = ts_pal_nc; break;
238 SHOW_FLOW( 1, "set tv_standard (internal %d, public %d)",
239 vc->tv_standard, mode->timing.flags );
241 vc->enforce_mode_change = true;
242 Radeon_WriteSettings( vc );
243 return B_OK;
245 case 2: {
246 uint32 idx = mode->timing.flags;
248 // we limit it explicetely to NTSC and PAL as all other
249 // modes are not fully implemented
250 if( idx < sizeof( private2be ) / sizeof( private2be[0] ) &&
251 idx < 3 ) {
252 mode->timing.flags = private2be[idx];
253 return B_OK;
254 } else
255 return B_ERROR;
260 return B_ERROR;
264 // return true if both ports must be programmed
265 bool Radeon_NeedsSecondPort( display_mode *mode )
267 switch( mode->timing.flags & RADEON_MODE_MASK ) {
268 case RADEON_MODE_COMBINE:
269 return true;
270 default:
271 return false;
276 // return number of ports showing differents parts of frame buffer
277 bool Radeon_DifferentPorts( display_mode *mode )
279 switch( mode->timing.flags & RADEON_MODE_MASK ) {
280 case RADEON_MODE_COMBINE:
281 return 2;
282 default:
283 return 1;