xref: /haiku/src/add-ons/accelerants/radeon/multimon.c (revision 2a37e4c1cf59b445e309a3880ceed82d25a0d107)
1 /*
2 	Copyright (c) 2002, Thomas Kurschel
3 
4 
5 	Part of Radeon accelerant
6 
7 	Multi-monitor management
8 */
9 
10 #include "radeon_accelerant.h"
11 #include "generic.h"
12 #include "GlobalData.h"
13 
14 
15 // transform official mode to internal, multi-screen mode enhanced mode
16 void Radeon_DetectMultiMode( virtual_card *vc, display_mode *mode )
17 {
18 	mode->timing.flags &= ~RADEON_MODE_MASK;
19 
20 	switch( vc->wanted_multi_mode ) {
21 	case mm_mirror:
22 		mode->timing.flags |= RADEON_MODE_MIRROR;
23 		break;
24 	case mm_clone:
25 		mode->timing.flags |= RADEON_MODE_CLONE;
26 		break;
27 	case mm_combine:
28 		mode->timing.flags |= RADEON_MODE_COMBINE;
29 		break;
30 	case mm_none:
31 	default:
32 	}
33 
34 	// combine mode is used if virtual area is twice as visible area
35 	// and if scrolling is enabled; if combining is impossible, use
36 	// cloning instead
37 	if( (mode->flags & B_SCROLL) == 0 ) {
38 		if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE ) {
39 			SHOW_FLOW0( 3, "This isn't a combine mode, falling back to clone" );
40 			mode->timing.flags &= ~RADEON_MODE_MASK;
41 			mode->timing.flags |= RADEON_MODE_CLONE;
42 		}
43 		return;
44 	}
45 
46 	SHOW_FLOW0( 3, "possibly combine mode" );
47 
48 	// remove scroll flag - we don't need it anymore
49 	mode->flags &= ~B_SCROLL;
50 
51 	mode->timing.flags &= ~RADEON_MODE_POSITION_MASK;
52 
53 	if( mode->virtual_width == 2 * mode->timing.h_display ) {
54 		SHOW_FLOW0( 3, "horizontal combine mode" );
55 		mode->timing.flags |= RADEON_MODE_POSITION_HORIZONTAL;
56 		mode->timing.flags &= ~RADEON_MODE_MASK;
57 		mode->timing.flags |= RADEON_MODE_COMBINE;
58 	} else if( mode->virtual_height == 2 * mode->timing.v_display ) {
59 		SHOW_FLOW0( 3, "vertical combine mode" );
60 		mode->timing.flags |= RADEON_MODE_POSITION_VERTICAL;
61 		mode->timing.flags &= ~RADEON_MODE_MASK;
62 		mode->timing.flags |= RADEON_MODE_COMBINE;
63 	} else {
64 		// ups, this isn't really a combine mode - restore flags
65 		SHOW_FLOW0( 3, "wasn't really a combine mode" );
66 		mode->timing.flags &= ~RADEON_MODE_MASK;
67 		mode->timing.flags |= RADEON_MODE_CLONE;
68 		mode->flags |= B_SCROLL;
69 	}
70 }
71 
72 // make sure selected multi-screen mode is valid; adapt it if needed
73 void Radeon_VerifyMultiMode( virtual_card *vc, shared_info *si, display_mode *mode )
74 {
75 	// if there is no second port or no second monitor connected,
76 	// fall back to standard mode
77 	if( vc->num_heads == 1 ||
78 		(si->heads[vc->heads[0].physical_head].chosen_displays == dd_none ||
79 		 si->heads[vc->heads[1].physical_head].chosen_displays == dd_none) )
80 	{
81 		SHOW_FLOW0( 3, "only one monitor - disabling any multi-mon mode" );
82 		// restore flags if combine mode is selected
83 		if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
84 			mode->flags |= B_SCROLL;
85 
86 		mode->timing.flags &= ~RADEON_MODE_MASK;
87 		mode->timing.flags |= RADEON_MODE_STANDARD;
88 	}
89 }
90 
91 // transform internal, multi-screen enabled display mode
92 // to official mode
93 void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode )
94 {
95 	(void) vc;
96 
97 	// restore flags for combine mode
98 	if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE )
99 		mode->flags |= B_SCROLL;
100 }
101 
102 
103 // initialize multi-screen mode dependant variables
104 void Radeon_InitMultiModeVars( virtual_card *vc, display_mode *mode )
105 {
106 	uint32 x, y;
107 
108 	// setup single-screen mode
109 	vc->eff_width = mode->timing.h_display;
110 	vc->eff_height = mode->timing.v_display;
111 
112 	vc->heads[0].rel_x = 0;
113 	vc->heads[0].rel_y = 0;
114 
115 	switch( mode->timing.flags & RADEON_MODE_MASK ) {
116 	case RADEON_MODE_CLONE:
117 		// in clone mode, ports are independant but show the same
118 		vc->heads[1].rel_x = 0;
119 		vc->heads[1].rel_y = 0;
120 		break;
121 
122 	case RADEON_MODE_COMBINE:
123 		// detect where second screen must be located and
124 		// adapt total visible area accordingly
125 		if( (mode->timing.flags & RADEON_MODE_POSITION_MASK) == RADEON_MODE_POSITION_HORIZONTAL ) {
126 			vc->eff_width = 2 * mode->timing.h_display;
127 			x = mode->timing.h_display;
128 			y = 0;
129 		} else {
130 			vc->eff_height = 2 * mode->timing.v_display;
131 			x = 0;
132 			y = mode->timing.v_display;
133 		}
134 
135 		SHOW_FLOW( 3, "relative position of second screen: %d, %d", x, y );
136 
137 		vc->heads[1].rel_x = 0;
138 		vc->heads[1].rel_y = 0;
139 
140 		// set relative offset
141 		if( !vc->swap_displays ) {
142 			vc->heads[1].rel_x = x;
143 			vc->heads[1].rel_y = y;
144 		} else {
145 			vc->heads[0].rel_x = x;
146 			vc->heads[0].rel_y = y;
147 		}
148 		break;
149 
150 	case RADEON_MODE_STANDARD:
151 	case RADEON_MODE_MIRROR:
152 		break;
153 	}
154 }
155 
156 
157 // check and execute tunnel settings command
158 status_t Radeon_CheckMultiMonTunnel( virtual_card *vc, display_mode *mode,
159 	const display_mode *low, const display_mode *high, bool *isTunneled )
160 {
161 	if( (mode->timing.flags & RADEON_MODE_MULTIMON_REQUEST) != 0 &&
162 		(mode->timing.flags & RADEON_MODE_MULTIMON_REPLY) == 0 )
163 	{
164 		mode->timing.flags &= ~RADEON_MODE_MULTIMON_REQUEST;
165 		mode->timing.flags |= RADEON_MODE_MULTIMON_REPLY;
166 
167 		// still process request, just in case someone set this flag
168 		// combination by mistake
169 
170 		// TBD: disabled to shorten syslog
171 		*isTunneled = true;
172 		return B_OK;
173 	}
174 
175 	// check magic params
176 	if( mode->space != 0 || low->space != 0 || high->space != 0
177 		|| low->virtual_width != 0xffff || low->virtual_height != 0xffff
178 		|| high->virtual_width != 0 || high->virtual_height != 0
179 		|| mode->timing.pixel_clock != 0
180 		|| low->timing.pixel_clock != 'TKTK' || high->timing.pixel_clock != 'KTKT' )
181 	{
182 		*isTunneled = false;
183 		return B_OK;
184 	}
185 
186 	*isTunneled = true;
187 
188 	switch( mode->h_display_start ) {
189 	case ms_swap:
190 		if( mode->v_display_start != 0 )
191 			vc->swap_displays = mode->timing.flags != 0;
192 		else
193 			mode->timing.flags = vc->swap_displays;
194 
195 		// write settings instantly
196 		Radeon_WriteSettings( vc );
197 		return B_OK;
198 
199 /*	case ms_overlay_port:
200 		if( mode->v_display_start != 0 )
201 			vc->whished_overlay_port = mode->timing.flags;
202 		else
203 			mode->timing.flags = vc->whished_overlay_port;
204 
205 		Radeon_WriteSettings( vc );
206 		return B_OK;*/
207 
208 	default:
209 		return B_BAD_INDEX;
210 	}
211 }
212 
213 
214 // return true if both ports must be programmed
215 bool Radeon_NeedsSecondPort( display_mode *mode )
216 {
217 	switch( mode->timing.flags & RADEON_MODE_MASK ) {
218 	case RADEON_MODE_COMBINE:
219 	case RADEON_MODE_CLONE:
220 		return true;
221 	default:
222 		return false;
223 	}
224 }
225 
226 // return number of ports showing differents parts of frame buffer
227 bool Radeon_DifferentPorts( display_mode *mode )
228 {
229 	switch( mode->timing.flags & RADEON_MODE_MASK ) {
230 	case RADEON_MODE_COMBINE:
231 		return 2;
232 	default:
233 		return 1;
234 	}
235 }
236