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