1706f2543Smrg/* 2706f2543Smrg * Copyright © 2006 Keith Packard 3706f2543Smrg * 4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its 5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that 6706f2543Smrg * the above copyright notice appear in all copies and that both that copyright 7706f2543Smrg * notice and this permission notice appear in supporting documentation, and 8706f2543Smrg * that the name of the copyright holders not be used in advertising or 9706f2543Smrg * publicity pertaining to distribution of the software without specific, 10706f2543Smrg * written prior permission. The copyright holders make no representations 11706f2543Smrg * about the suitability of this software for any purpose. It is provided "as 12706f2543Smrg * is" without express or implied warranty. 13706f2543Smrg * 14706f2543Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16706f2543Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20706f2543Smrg * OF THIS SOFTWARE. 21706f2543Smrg */ 22706f2543Smrg 23706f2543Smrg#include "randrstr.h" 24706f2543Smrg 25706f2543SmrgRESTYPE RRModeType; 26706f2543Smrg 27706f2543Smrgstatic Bool 28706f2543SmrgRRModeEqual (xRRModeInfo *a, xRRModeInfo *b) 29706f2543Smrg{ 30706f2543Smrg if (a->width != b->width) return FALSE; 31706f2543Smrg if (a->height != b->height) return FALSE; 32706f2543Smrg if (a->dotClock != b->dotClock) return FALSE; 33706f2543Smrg if (a->hSyncStart != b->hSyncStart) return FALSE; 34706f2543Smrg if (a->hSyncEnd != b->hSyncEnd) return FALSE; 35706f2543Smrg if (a->hTotal != b->hTotal) return FALSE; 36706f2543Smrg if (a->hSkew != b->hSkew) return FALSE; 37706f2543Smrg if (a->vSyncStart != b->vSyncStart) return FALSE; 38706f2543Smrg if (a->vSyncEnd != b->vSyncEnd) return FALSE; 39706f2543Smrg if (a->vTotal != b->vTotal) return FALSE; 40706f2543Smrg if (a->nameLength != b->nameLength) return FALSE; 41706f2543Smrg if (a->modeFlags != b->modeFlags) return FALSE; 42706f2543Smrg return TRUE; 43706f2543Smrg} 44706f2543Smrg 45706f2543Smrg/* 46706f2543Smrg * Keep a list so it's easy to find modes in the resource database. 47706f2543Smrg */ 48706f2543Smrgstatic int num_modes; 49706f2543Smrgstatic RRModePtr *modes; 50706f2543Smrg 51706f2543Smrgstatic RRModePtr 52706f2543SmrgRRModeCreate (xRRModeInfo *modeInfo, 53706f2543Smrg const char *name, 54706f2543Smrg ScreenPtr userScreen) 55706f2543Smrg{ 56706f2543Smrg RRModePtr mode, *newModes; 57706f2543Smrg 58706f2543Smrg if (!RRInit ()) 59706f2543Smrg return NULL; 60706f2543Smrg 61706f2543Smrg mode = malloc(sizeof (RRModeRec) + modeInfo->nameLength + 1); 62706f2543Smrg if (!mode) 63706f2543Smrg return NULL; 64706f2543Smrg mode->refcnt = 1; 65706f2543Smrg mode->mode = *modeInfo; 66706f2543Smrg mode->name = (char *) (mode + 1); 67706f2543Smrg memcpy (mode->name, name, modeInfo->nameLength); 68706f2543Smrg mode->name[modeInfo->nameLength] = '\0'; 69706f2543Smrg mode->userScreen = userScreen; 70706f2543Smrg 71706f2543Smrg if (num_modes) 72706f2543Smrg newModes = realloc(modes, (num_modes + 1) * sizeof (RRModePtr)); 73706f2543Smrg else 74706f2543Smrg newModes = malloc(sizeof (RRModePtr)); 75706f2543Smrg 76706f2543Smrg if (!newModes) 77706f2543Smrg { 78706f2543Smrg free(mode); 79706f2543Smrg return NULL; 80706f2543Smrg } 81706f2543Smrg 82706f2543Smrg mode->mode.id = FakeClientID(0); 83706f2543Smrg if (!AddResource (mode->mode.id, RRModeType, (pointer) mode)) 84706f2543Smrg return NULL; 85706f2543Smrg modes = newModes; 86706f2543Smrg modes[num_modes++] = mode; 87706f2543Smrg 88706f2543Smrg /* 89706f2543Smrg * give the caller a reference to this mode 90706f2543Smrg */ 91706f2543Smrg ++mode->refcnt; 92706f2543Smrg return mode; 93706f2543Smrg} 94706f2543Smrg 95706f2543Smrgstatic RRModePtr 96706f2543SmrgRRModeFindByName (const char *name, 97706f2543Smrg CARD16 nameLength) 98706f2543Smrg{ 99706f2543Smrg int i; 100706f2543Smrg RRModePtr mode; 101706f2543Smrg 102706f2543Smrg for (i = 0; i < num_modes; i++) 103706f2543Smrg { 104706f2543Smrg mode = modes[i]; 105706f2543Smrg if (mode->mode.nameLength == nameLength && 106706f2543Smrg !memcmp (name, mode->name, nameLength)) 107706f2543Smrg { 108706f2543Smrg return mode; 109706f2543Smrg } 110706f2543Smrg } 111706f2543Smrg return NULL; 112706f2543Smrg} 113706f2543Smrg 114706f2543SmrgRRModePtr 115706f2543SmrgRRModeGet (xRRModeInfo *modeInfo, 116706f2543Smrg const char *name) 117706f2543Smrg{ 118706f2543Smrg int i; 119706f2543Smrg 120706f2543Smrg for (i = 0; i < num_modes; i++) 121706f2543Smrg { 122706f2543Smrg RRModePtr mode = modes[i]; 123706f2543Smrg if (RRModeEqual (&mode->mode, modeInfo) && 124706f2543Smrg !memcmp (name, mode->name, modeInfo->nameLength)) 125706f2543Smrg { 126706f2543Smrg ++mode->refcnt; 127706f2543Smrg return mode; 128706f2543Smrg } 129706f2543Smrg } 130706f2543Smrg 131706f2543Smrg return RRModeCreate (modeInfo, name, NULL); 132706f2543Smrg} 133706f2543Smrg 134706f2543Smrgstatic RRModePtr 135706f2543SmrgRRModeCreateUser (ScreenPtr pScreen, 136706f2543Smrg xRRModeInfo *modeInfo, 137706f2543Smrg const char *name, 138706f2543Smrg int *error) 139706f2543Smrg{ 140706f2543Smrg RRModePtr mode; 141706f2543Smrg 142706f2543Smrg mode = RRModeFindByName (name, modeInfo->nameLength); 143706f2543Smrg if (mode) 144706f2543Smrg { 145706f2543Smrg *error = BadName; 146706f2543Smrg return NULL; 147706f2543Smrg } 148706f2543Smrg 149706f2543Smrg mode = RRModeCreate (modeInfo, name, pScreen); 150706f2543Smrg if (!mode) 151706f2543Smrg { 152706f2543Smrg *error = BadAlloc; 153706f2543Smrg return NULL; 154706f2543Smrg } 155706f2543Smrg *error = Success; 156706f2543Smrg return mode; 157706f2543Smrg} 158706f2543Smrg 159706f2543SmrgRRModePtr * 160706f2543SmrgRRModesForScreen (ScreenPtr pScreen, int *num_ret) 161706f2543Smrg{ 162706f2543Smrg rrScrPriv(pScreen); 163706f2543Smrg int o, c, m; 164706f2543Smrg RRModePtr *screen_modes; 165706f2543Smrg int num_screen_modes = 0; 166706f2543Smrg 167706f2543Smrg screen_modes = malloc((num_modes ? num_modes : 1) * sizeof (RRModePtr)); 168706f2543Smrg if (!screen_modes) 169706f2543Smrg return NULL; 170706f2543Smrg 171706f2543Smrg /* 172706f2543Smrg * Add modes from all outputs 173706f2543Smrg */ 174706f2543Smrg for (o = 0; o < pScrPriv->numOutputs; o++) 175706f2543Smrg { 176706f2543Smrg RROutputPtr output = pScrPriv->outputs[o]; 177706f2543Smrg int m, n; 178706f2543Smrg 179706f2543Smrg for (m = 0; m < output->numModes + output->numUserModes; m++) 180706f2543Smrg { 181706f2543Smrg RRModePtr mode = (m < output->numModes ? 182706f2543Smrg output->modes[m] : 183706f2543Smrg output->userModes[m-output->numModes]); 184706f2543Smrg for (n = 0; n < num_screen_modes; n++) 185706f2543Smrg if (screen_modes[n] == mode) 186706f2543Smrg break; 187706f2543Smrg if (n == num_screen_modes) 188706f2543Smrg screen_modes[num_screen_modes++] = mode; 189706f2543Smrg } 190706f2543Smrg } 191706f2543Smrg /* 192706f2543Smrg * Add modes from all crtcs. The goal is to 193706f2543Smrg * make sure all available and active modes 194706f2543Smrg * are visible to the client 195706f2543Smrg */ 196706f2543Smrg for (c = 0; c < pScrPriv->numCrtcs; c++) 197706f2543Smrg { 198706f2543Smrg RRCrtcPtr crtc = pScrPriv->crtcs[c]; 199706f2543Smrg RRModePtr mode = crtc->mode; 200706f2543Smrg int n; 201706f2543Smrg 202706f2543Smrg if (!mode) continue; 203706f2543Smrg for (n = 0; n < num_screen_modes; n++) 204706f2543Smrg if (screen_modes[n] == mode) 205706f2543Smrg break; 206706f2543Smrg if (n == num_screen_modes) 207706f2543Smrg screen_modes[num_screen_modes++] = mode; 208706f2543Smrg } 209706f2543Smrg /* 210706f2543Smrg * Add all user modes for this screen 211706f2543Smrg */ 212706f2543Smrg for (m = 0; m < num_modes; m++) 213706f2543Smrg { 214706f2543Smrg RRModePtr mode = modes[m]; 215706f2543Smrg int n; 216706f2543Smrg 217706f2543Smrg if (mode->userScreen != pScreen) 218706f2543Smrg continue; 219706f2543Smrg for (n = 0; n < num_screen_modes; n++) 220706f2543Smrg if (screen_modes[n] == mode) 221706f2543Smrg break; 222706f2543Smrg if (n == num_screen_modes) 223706f2543Smrg screen_modes[num_screen_modes++] = mode; 224706f2543Smrg } 225706f2543Smrg 226706f2543Smrg *num_ret = num_screen_modes; 227706f2543Smrg return screen_modes; 228706f2543Smrg} 229706f2543Smrg 230706f2543Smrgvoid 231706f2543SmrgRRModeDestroy (RRModePtr mode) 232706f2543Smrg{ 233706f2543Smrg int m; 234706f2543Smrg 235706f2543Smrg if (--mode->refcnt > 0) 236706f2543Smrg return; 237706f2543Smrg for (m = 0; m < num_modes; m++) 238706f2543Smrg { 239706f2543Smrg if (modes[m] == mode) 240706f2543Smrg { 241706f2543Smrg memmove (modes + m, modes + m + 1, 242706f2543Smrg (num_modes - m - 1) * sizeof (RRModePtr)); 243706f2543Smrg num_modes--; 244706f2543Smrg if (!num_modes) 245706f2543Smrg { 246706f2543Smrg free(modes); 247706f2543Smrg modes = NULL; 248706f2543Smrg } 249706f2543Smrg break; 250706f2543Smrg } 251706f2543Smrg } 252706f2543Smrg 253706f2543Smrg free(mode); 254706f2543Smrg} 255706f2543Smrg 256706f2543Smrgstatic int 257706f2543SmrgRRModeDestroyResource (pointer value, XID pid) 258706f2543Smrg{ 259706f2543Smrg RRModeDestroy ((RRModePtr) value); 260706f2543Smrg return 1; 261706f2543Smrg} 262706f2543Smrg 263706f2543Smrg/* 264706f2543Smrg * Initialize mode type 265706f2543Smrg */ 266706f2543SmrgBool 267706f2543SmrgRRModeInit (void) 268706f2543Smrg{ 269706f2543Smrg assert (num_modes == 0); 270706f2543Smrg assert (modes == NULL); 271706f2543Smrg RRModeType = CreateNewResourceType (RRModeDestroyResource, "MODE"); 272706f2543Smrg if (!RRModeType) 273706f2543Smrg return FALSE; 274706f2543Smrg 275706f2543Smrg return TRUE; 276706f2543Smrg} 277706f2543Smrg 278706f2543Smrg/* 279706f2543Smrg * Initialize mode type error value 280706f2543Smrg */ 281706f2543Smrgvoid 282706f2543SmrgRRModeInitErrorValue(void) 283706f2543Smrg{ 284706f2543Smrg SetResourceTypeErrorValue(RRModeType, RRErrorBase + BadRRMode); 285706f2543Smrg} 286706f2543Smrg 287706f2543Smrgint 288706f2543SmrgProcRRCreateMode (ClientPtr client) 289706f2543Smrg{ 290706f2543Smrg REQUEST(xRRCreateModeReq); 291706f2543Smrg xRRCreateModeReply rep = {0}; 292706f2543Smrg WindowPtr pWin; 293706f2543Smrg ScreenPtr pScreen; 294706f2543Smrg rrScrPrivPtr pScrPriv; 295706f2543Smrg xRRModeInfo *modeInfo; 296706f2543Smrg long units_after; 297706f2543Smrg char *name; 298706f2543Smrg int error, rc; 299706f2543Smrg RRModePtr mode; 300706f2543Smrg 301706f2543Smrg REQUEST_AT_LEAST_SIZE (xRRCreateModeReq); 302706f2543Smrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 303706f2543Smrg if (rc != Success) 304706f2543Smrg return rc; 305706f2543Smrg 306706f2543Smrg pScreen = pWin->drawable.pScreen; 307706f2543Smrg pScrPriv = rrGetScrPriv(pScreen); 308706f2543Smrg 309706f2543Smrg modeInfo = &stuff->modeInfo; 310706f2543Smrg name = (char *) (stuff + 1); 311706f2543Smrg units_after = (stuff->length - bytes_to_int32(sizeof (xRRCreateModeReq))); 312706f2543Smrg 313706f2543Smrg /* check to make sure requested name fits within the data provided */ 314706f2543Smrg if (bytes_to_int32(modeInfo->nameLength) > units_after) 315706f2543Smrg return BadLength; 316706f2543Smrg 317706f2543Smrg mode = RRModeCreateUser (pScreen, modeInfo, name, &error); 318706f2543Smrg if (!mode) 319706f2543Smrg return error; 320706f2543Smrg 321706f2543Smrg rep.type = X_Reply; 322706f2543Smrg rep.pad0 = 0; 323706f2543Smrg rep.sequenceNumber = client->sequence; 324706f2543Smrg rep.length = 0; 325706f2543Smrg rep.mode = mode->mode.id; 326706f2543Smrg if (client->swapped) 327706f2543Smrg { 328706f2543Smrg int n; 329706f2543Smrg swaps(&rep.sequenceNumber, n); 330706f2543Smrg swapl(&rep.length, n); 331706f2543Smrg swapl(&rep.mode, n); 332706f2543Smrg } 333706f2543Smrg WriteToClient(client, sizeof(xRRCreateModeReply), (char *)&rep); 334706f2543Smrg /* Drop out reference to this mode */ 335706f2543Smrg RRModeDestroy (mode); 336706f2543Smrg return Success; 337706f2543Smrg} 338706f2543Smrg 339706f2543Smrgint 340706f2543SmrgProcRRDestroyMode (ClientPtr client) 341706f2543Smrg{ 342706f2543Smrg REQUEST(xRRDestroyModeReq); 343706f2543Smrg RRModePtr mode; 344706f2543Smrg 345706f2543Smrg REQUEST_SIZE_MATCH(xRRDestroyModeReq); 346706f2543Smrg VERIFY_RR_MODE(stuff->mode, mode, DixDestroyAccess); 347706f2543Smrg 348706f2543Smrg if (!mode->userScreen) 349706f2543Smrg return BadMatch; 350706f2543Smrg if (mode->refcnt > 1) 351706f2543Smrg return BadAccess; 352706f2543Smrg FreeResource (stuff->mode, 0); 353706f2543Smrg return Success; 354706f2543Smrg} 355706f2543Smrg 356706f2543Smrgint 357706f2543SmrgProcRRAddOutputMode (ClientPtr client) 358706f2543Smrg{ 359706f2543Smrg REQUEST(xRRAddOutputModeReq); 360706f2543Smrg RRModePtr mode; 361706f2543Smrg RROutputPtr output; 362706f2543Smrg 363706f2543Smrg REQUEST_SIZE_MATCH(xRRAddOutputModeReq); 364706f2543Smrg VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); 365706f2543Smrg VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); 366706f2543Smrg 367706f2543Smrg return RROutputAddUserMode (output, mode); 368706f2543Smrg} 369706f2543Smrg 370706f2543Smrgint 371706f2543SmrgProcRRDeleteOutputMode (ClientPtr client) 372706f2543Smrg{ 373706f2543Smrg REQUEST(xRRDeleteOutputModeReq); 374706f2543Smrg RRModePtr mode; 375706f2543Smrg RROutputPtr output; 376706f2543Smrg 377706f2543Smrg REQUEST_SIZE_MATCH(xRRDeleteOutputModeReq); 378706f2543Smrg VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); 379706f2543Smrg VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); 380706f2543Smrg 381706f2543Smrg return RROutputDeleteUserMode (output, mode); 382706f2543Smrg} 383