1/* 2 * Copyright © 2013 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Chris Wilson <chris@chris-wilson.co.uk> 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include "sna.h" 33 34static bool add_fake_output(struct sna *sna, bool late); 35 36static void 37sna_crtc_dpms(xf86CrtcPtr crtc, int mode) 38{ 39} 40 41static char *outputs_for_crtc(xf86CrtcPtr crtc, char *outputs, int max) 42{ 43 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 44 int len, i; 45 46 for (i = len = 0; i < config->num_output; i++) { 47 xf86OutputPtr output = config->output[i]; 48 49 if (output->crtc != crtc) 50 continue; 51 52 len += snprintf(outputs+len, max-len, "%s, ", output->name); 53 } 54 assert(len >= 2); 55 outputs[len-2] = '\0'; 56 57 return outputs; 58} 59 60static const char *rotation_to_str(Rotation rotation) 61{ 62 switch (rotation & RR_Rotate_All) { 63 case 0: 64 case RR_Rotate_0: return "normal"; 65 case RR_Rotate_90: return "left"; 66 case RR_Rotate_180: return "inverted"; 67 case RR_Rotate_270: return "right"; 68 default: return "unknown"; 69 } 70} 71 72static const char *reflection_to_str(Rotation rotation) 73{ 74 switch (rotation & RR_Reflect_All) { 75 case 0: return "none"; 76 case RR_Reflect_X: return "X axis"; 77 case RR_Reflect_Y: return "Y axis"; 78 case RR_Reflect_X | RR_Reflect_Y: return "X and Y axes"; 79 default: return "invalid"; 80 } 81} 82 83static Bool 84sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 85 Rotation rotation, int x, int y) 86{ 87 char outputs[256]; 88 89 xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO, 90 "switch to mode %dx%d on %s, position (%d, %d), rotation %s, reflection %s\n", 91 mode->HDisplay, mode->VDisplay, 92 outputs_for_crtc(crtc, outputs, sizeof(outputs)), 93 x, y, rotation_to_str(rotation), reflection_to_str(rotation)); 94 95 return TRUE; 96} 97 98static void 99sna_crtc_gamma_set(xf86CrtcPtr crtc, 100 CARD16 *red, CARD16 *green, CARD16 *blue, int size) 101{ 102} 103 104static void 105sna_crtc_destroy(xf86CrtcPtr crtc) 106{ 107} 108 109static const xf86CrtcFuncsRec sna_crtc_funcs = { 110 .dpms = sna_crtc_dpms, 111 .set_mode_major = sna_crtc_set_mode_major, 112 .gamma_set = sna_crtc_gamma_set, 113 .destroy = sna_crtc_destroy, 114}; 115 116static void 117sna_output_create_resources(xf86OutputPtr output) 118{ 119} 120 121static Bool 122sna_output_set_property(xf86OutputPtr output, Atom property, 123 RRPropertyValuePtr value) 124{ 125 return TRUE; 126} 127 128static Bool 129sna_output_get_property(xf86OutputPtr output, Atom property) 130{ 131 return FALSE; 132} 133 134static void 135sna_output_dpms(xf86OutputPtr output, int dpms) 136{ 137} 138 139static xf86OutputStatus 140sna_output_detect(xf86OutputPtr output) 141{ 142 DBG(("%s(%s) has user modes? %d\n", 143 __FUNCTION__, output->name, 144 output->randr_output && output->randr_output->numUserModes)); 145 146 if (output->randr_output && output->randr_output->numUserModes) { 147 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(output->scrn); 148 149 if (xf86_config->output[xf86_config->num_output-1] == output) 150 add_fake_output(to_sna(output->scrn), true); 151 152 return XF86OutputStatusConnected; 153 } 154 155 return XF86OutputStatusDisconnected; 156} 157 158static Bool 159sna_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode) 160{ 161 if (mode->type & M_T_DEFAULT) 162 return MODE_BAD; 163 164 return MODE_OK; 165} 166 167static DisplayModePtr 168sna_output_get_modes(xf86OutputPtr output) 169{ 170 return NULL; 171} 172 173static void 174sna_output_destroy(xf86OutputPtr output) 175{ 176} 177 178static const xf86OutputFuncsRec sna_output_funcs = { 179 .create_resources = sna_output_create_resources, 180#ifdef RANDR_12_INTERFACE 181 .set_property = sna_output_set_property, 182 .get_property = sna_output_get_property, 183#endif 184 .dpms = sna_output_dpms, 185 .detect = sna_output_detect, 186 .mode_valid = sna_output_mode_valid, 187 188 .get_modes = sna_output_get_modes, 189 .destroy = sna_output_destroy 190}; 191 192static Bool 193sna_mode_resize(ScrnInfoPtr scrn, int width, int height) 194{ 195 ScreenPtr screen = scrn->pScreen; 196 PixmapPtr new_front; 197 198 DBG(("%s (%d, %d) -> (%d, %d)\n", __FUNCTION__, 199 scrn->virtualX, scrn->virtualY, 200 width, height)); 201 202 if (scrn->virtualX == width && scrn->virtualY == height) 203 return TRUE; 204 205 assert(to_sna_from_screen(screen)->front); 206 assert(screen->GetScreenPixmap(screen) == to_sna_from_screen(screen)->front); 207 208 DBG(("%s: creating new framebuffer %dx%d\n", 209 __FUNCTION__, width, height)); 210 211 new_front = screen->CreatePixmap(screen, 212 width, height, scrn->depth, 213 0); 214 if (!new_front) 215 return FALSE; 216 217 scrn->virtualX = width; 218 scrn->virtualY = height; 219 scrn->displayWidth = width; 220 221 screen->SetScreenPixmap(new_front); 222 assert(screen->GetScreenPixmap(screen) == new_front); 223 assert(to_sna_from_screen(screen)->front == new_front); 224 225 screen->DestroyPixmap(new_front); 226 227 return TRUE; 228} 229 230static const xf86CrtcConfigFuncsRec sna_mode_funcs = { 231 sna_mode_resize 232}; 233 234static bool add_fake_output(struct sna *sna, bool late) 235{ 236 ScrnInfoPtr scrn = sna->scrn; 237 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 238 xf86OutputPtr output; 239 xf86CrtcPtr crtc; 240 RROutputPtr clones[32]; 241 RRCrtcPtr crtcs[32]; 242 char buf[80]; 243 int i, len; 244 245 if (sna->mode.num_fake >= 32) 246 return false; 247 248 DBG(("%s(late=%d, num_fake=%d)\n", __FUNCTION__, late, sna->mode.num_fake+1)); 249 250 crtc = xf86CrtcCreate(scrn, &sna_crtc_funcs); 251 if (crtc == NULL) 252 return false; 253 254 len = sprintf(buf, "VIRTUAL%d", sna->mode.num_fake+1); 255 output = xf86OutputCreate(scrn, &sna_output_funcs, buf); 256 if (!output) { 257 xf86CrtcDestroy(crtc); 258 return false; 259 } 260 261 output->mm_width = 0; 262 output->mm_height = 0; 263 output->interlaceAllowed = FALSE; 264 output->subpixel_order = SubPixelNone; 265 266 output->possible_crtcs = ~((1 << sna->mode.num_real_crtc) - 1); 267 output->possible_clones = ~((1 << sna->mode.num_real_output) - 1); 268 269 if (late) { 270 ScreenPtr screen = xf86ScrnToScreen(scrn); 271 272 crtc->randr_crtc = RRCrtcCreate(screen, crtc); 273 output->randr_output = RROutputCreate(screen, buf, len, output); 274 if (crtc->randr_crtc == NULL || output->randr_output == NULL) { 275 xf86OutputDestroy(output); 276 xf86CrtcDestroy(crtc); 277 return false; 278 } 279 280 RRPostPendingProperties(output->randr_output); 281 282 for (i = sna->mode.num_real_output; i < xf86_config->num_output; i++) 283 clones[i - sna->mode.num_real_output] = xf86_config->output[i]->randr_output; 284 assert(i - sna->mode.num_real_output == sna->mode.num_fake + 1); 285 286 for (i = sna->mode.num_real_crtc; i < xf86_config->num_crtc; i++) 287 crtcs[i - sna->mode.num_real_crtc] = xf86_config->crtc[i]->randr_crtc; 288 assert(i - sna->mode.num_real_crtc == sna->mode.num_fake + 1); 289 290 for (i = sna->mode.num_real_output; i < xf86_config->num_output; i++) { 291 RROutputPtr rr_output = xf86_config->output[i]->randr_output; 292 293 if (!RROutputSetCrtcs(rr_output, crtcs, sna->mode.num_fake + 1) || 294 !RROutputSetClones(rr_output, clones, sna->mode.num_fake + 1)) 295 goto err; 296 } 297 298 RRCrtcSetRotations(crtc->randr_crtc, 299 RR_Rotate_All | RR_Reflect_All); 300 } 301 302 sna->mode.num_fake++; 303 xf86DrvMsg(scrn->scrnIndex, X_INFO, 304 "Enabled output %s\n", 305 output->name); 306 return true; 307 308err: 309 for (i = 0; i < xf86_config->num_output; i++) { 310 output = xf86_config->output[i]; 311 if (output->driver_private) 312 continue; 313 314 xf86OutputDestroy(output); 315 } 316 317 for (i = 0; i < xf86_config->num_crtc; i++) { 318 crtc = xf86_config->crtc[i]; 319 if (crtc->driver_private) 320 continue; 321 xf86CrtcDestroy(crtc); 322 } 323 sna->mode.num_fake = -1; 324 return false; 325} 326 327bool sna_mode_fake_init(struct sna *sna, int num_fake) 328{ 329 bool ret; 330 331 if (num_fake == 0) 332 return true; 333 334 if (sna->mode.num_real_crtc == 0) { 335 xf86CrtcConfigInit(sna->scrn, &sna_mode_funcs); 336 xf86CrtcSetSizeRange(sna->scrn, 1, 1, INT16_MAX, INT16_MAX); 337 } 338 339 ret = true; 340 while (ret && num_fake--) 341 ret = add_fake_output(sna, false); 342 return ret; 343} 344