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