1 /* 2 Copyright (c) 2002-2004, 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 (void)vc; 19 20 mode->timing.flags &= ~RADEON_MODE_MASK; 21 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; 27 28 SHOW_FLOW0( 3, "possibly combine mode" ); 29 30 // remove scroll flag - we don't need it anymore 31 mode->flags &= ~B_SCROLL; 32 33 mode->timing.flags &= ~RADEON_MODE_POSITION_MASK; 34 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; 50 } 51 } 52 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 ) 55 { 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; 59 60 if( si->num_crtc > 1 ) 61 num_usable_crtcs += vc->assigned_crtc[1] && si->crtc[1].chosen_displays != dd_none; 62 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; 68 69 mode->timing.flags &= ~RADEON_MODE_MASK; 70 mode->timing.flags |= RADEON_MODE_STANDARD; 71 } 72 } 73 74 // transform internal, multi-screen enabled display mode 75 // to official mode 76 void Radeon_HideMultiMode( virtual_card *vc, display_mode *mode ) 77 { 78 (void) vc; 79 80 // restore flags for combine mode 81 if( (mode->timing.flags & RADEON_MODE_MASK) == RADEON_MODE_COMBINE ) 82 mode->flags |= B_SCROLL; 83 } 84 85 86 // initialize multi-screen mode dependant variables 87 void Radeon_InitMultiModeVars( 88 accelerator_info *ai, display_mode *mode ) 89 { 90 virtual_card *vc = ai->vc; 91 shared_info *si = ai->si; 92 uint32 x, y; 93 94 // setup single-screen mode 95 vc->eff_width = mode->timing.h_display; 96 vc->eff_height = mode->timing.v_display; 97 98 if( vc->used_crtc[0] ) { 99 si->crtc[0].rel_x = 0; 100 si->crtc[0].rel_y = 0; 101 } 102 103 if( vc->used_crtc[1] ) { 104 si->crtc[1].rel_x = 0; 105 si->crtc[1].rel_y = 0; 106 } 107 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; 120 } 121 122 SHOW_FLOW( 3, "relative position of second screen: %d, %d", x, y ); 123 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; 131 } 132 break; 133 134 default: 135 // else, ports are independant but show the same 136 break; 137 } 138 } 139 140 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 }; 144 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 ) 148 { 149 if( (mode->timing.flags & RADEON_MODE_MULTIMON_REQUEST) != 0 && 150 (mode->timing.flags & RADEON_MODE_MULTIMON_REPLY) == 0 ) 151 { 152 mode->timing.flags &= ~RADEON_MODE_MULTIMON_REQUEST; 153 mode->timing.flags |= RADEON_MODE_MULTIMON_REPLY; 154 155 // still process request, just in case someone set this flag 156 // combination by mistake 157 158 // TBD: disabled to shorten syslog 159 *isTunneled = true; 160 return B_OK; 161 } 162 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' ) 169 { 170 *isTunneled = false; 171 return B_OK; 172 } 173 174 *isTunneled = true; 175 176 /*SHOW_FLOW( 1, "tunnel access code=%d, command=%d", 177 mode->h_display_start, mode->v_display_start );*/ 178 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; 185 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; 192 } 193 break; 194 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; 200 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; 206 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; 213 } 214 break; 215 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; 223 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; 236 } 237 238 SHOW_FLOW( 1, "set tv_standard (internal %d, public %d)", 239 vc->tv_standard, mode->timing.flags ); 240 241 vc->enforce_mode_change = true; 242 Radeon_WriteSettings( vc ); 243 return B_OK; 244 245 case 2: { 246 uint32 idx = mode->timing.flags; 247 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; 256 } 257 } 258 } 259 260 return B_ERROR; 261 } 262 263 264 // return true if both ports must be programmed 265 bool Radeon_NeedsSecondPort( display_mode *mode ) 266 { 267 switch( mode->timing.flags & RADEON_MODE_MASK ) { 268 case RADEON_MODE_COMBINE: 269 return true; 270 default: 271 return false; 272 } 273 } 274 275 276 // return number of ports showing differents parts of frame buffer 277 bool Radeon_DifferentPorts( display_mode *mode ) 278 { 279 switch( mode->timing.flags & RADEON_MODE_MASK ) { 280 case RADEON_MODE_COMBINE: 281 return 2; 282 default: 283 return 1; 284 } 285 } 286