rrmode.c revision 6747b715
105b261ecSmrg/* 205b261ecSmrg * Copyright © 2006 Keith Packard 305b261ecSmrg * 405b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its 505b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that 605b261ecSmrg * the above copyright notice appear in all copies and that both that copyright 705b261ecSmrg * notice and this permission notice appear in supporting documentation, and 805b261ecSmrg * that the name of the copyright holders not be used in advertising or 905b261ecSmrg * publicity pertaining to distribution of the software without specific, 1005b261ecSmrg * written prior permission. The copyright holders make no representations 1105b261ecSmrg * about the suitability of this software for any purpose. It is provided "as 1205b261ecSmrg * is" without express or implied warranty. 1305b261ecSmrg * 1405b261ecSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1505b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1605b261ecSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1705b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1805b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1905b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2005b261ecSmrg * OF THIS SOFTWARE. 2105b261ecSmrg */ 2205b261ecSmrg 2305b261ecSmrg#include "randrstr.h" 2405b261ecSmrg 2505b261ecSmrgRESTYPE RRModeType; 2605b261ecSmrg 2705b261ecSmrgstatic Bool 2805b261ecSmrgRRModeEqual (xRRModeInfo *a, xRRModeInfo *b) 2905b261ecSmrg{ 3005b261ecSmrg if (a->width != b->width) return FALSE; 3105b261ecSmrg if (a->height != b->height) return FALSE; 3205b261ecSmrg if (a->dotClock != b->dotClock) return FALSE; 3305b261ecSmrg if (a->hSyncStart != b->hSyncStart) return FALSE; 3405b261ecSmrg if (a->hSyncEnd != b->hSyncEnd) return FALSE; 3505b261ecSmrg if (a->hTotal != b->hTotal) return FALSE; 3605b261ecSmrg if (a->hSkew != b->hSkew) return FALSE; 3705b261ecSmrg if (a->vSyncStart != b->vSyncStart) return FALSE; 3805b261ecSmrg if (a->vSyncEnd != b->vSyncEnd) return FALSE; 3905b261ecSmrg if (a->vTotal != b->vTotal) return FALSE; 4005b261ecSmrg if (a->nameLength != b->nameLength) return FALSE; 4105b261ecSmrg if (a->modeFlags != b->modeFlags) return FALSE; 4205b261ecSmrg return TRUE; 4305b261ecSmrg} 4405b261ecSmrg 4505b261ecSmrg/* 4605b261ecSmrg * Keep a list so it's easy to find modes in the resource database. 4705b261ecSmrg */ 4805b261ecSmrgstatic int num_modes; 4905b261ecSmrgstatic RRModePtr *modes; 5005b261ecSmrg 5105b261ecSmrgstatic RRModePtr 5205b261ecSmrgRRModeCreate (xRRModeInfo *modeInfo, 5305b261ecSmrg const char *name, 5405b261ecSmrg ScreenPtr userScreen) 5505b261ecSmrg{ 5605b261ecSmrg RRModePtr mode, *newModes; 5705b261ecSmrg 5805b261ecSmrg if (!RRInit ()) 5905b261ecSmrg return NULL; 6005b261ecSmrg 616747b715Smrg mode = malloc(sizeof (RRModeRec) + modeInfo->nameLength + 1); 6205b261ecSmrg if (!mode) 6305b261ecSmrg return NULL; 6405b261ecSmrg mode->refcnt = 1; 6505b261ecSmrg mode->mode = *modeInfo; 6605b261ecSmrg mode->name = (char *) (mode + 1); 6705b261ecSmrg memcpy (mode->name, name, modeInfo->nameLength); 6805b261ecSmrg mode->name[modeInfo->nameLength] = '\0'; 6905b261ecSmrg mode->userScreen = userScreen; 7005b261ecSmrg 7105b261ecSmrg if (num_modes) 726747b715Smrg newModes = realloc(modes, (num_modes + 1) * sizeof (RRModePtr)); 7305b261ecSmrg else 746747b715Smrg newModes = malloc(sizeof (RRModePtr)); 7505b261ecSmrg 7605b261ecSmrg if (!newModes) 7705b261ecSmrg { 786747b715Smrg free(mode); 7905b261ecSmrg return NULL; 8005b261ecSmrg } 8105b261ecSmrg 8205b261ecSmrg mode->mode.id = FakeClientID(0); 8305b261ecSmrg if (!AddResource (mode->mode.id, RRModeType, (pointer) mode)) 8405b261ecSmrg return NULL; 8505b261ecSmrg modes = newModes; 8605b261ecSmrg modes[num_modes++] = mode; 8705b261ecSmrg 8805b261ecSmrg /* 8905b261ecSmrg * give the caller a reference to this mode 9005b261ecSmrg */ 9105b261ecSmrg ++mode->refcnt; 9205b261ecSmrg return mode; 9305b261ecSmrg} 9405b261ecSmrg 9505b261ecSmrgstatic RRModePtr 9605b261ecSmrgRRModeFindByName (const char *name, 9705b261ecSmrg CARD16 nameLength) 9805b261ecSmrg{ 9905b261ecSmrg int i; 10005b261ecSmrg RRModePtr mode; 10105b261ecSmrg 10205b261ecSmrg for (i = 0; i < num_modes; i++) 10305b261ecSmrg { 10405b261ecSmrg mode = modes[i]; 10505b261ecSmrg if (mode->mode.nameLength == nameLength && 10605b261ecSmrg !memcmp (name, mode->name, nameLength)) 10705b261ecSmrg { 10805b261ecSmrg return mode; 10905b261ecSmrg } 11005b261ecSmrg } 11105b261ecSmrg return NULL; 11205b261ecSmrg} 11305b261ecSmrg 11405b261ecSmrgRRModePtr 11505b261ecSmrgRRModeGet (xRRModeInfo *modeInfo, 11605b261ecSmrg const char *name) 11705b261ecSmrg{ 11805b261ecSmrg int i; 11905b261ecSmrg 12005b261ecSmrg for (i = 0; i < num_modes; i++) 12105b261ecSmrg { 12205b261ecSmrg RRModePtr mode = modes[i]; 12305b261ecSmrg if (RRModeEqual (&mode->mode, modeInfo) && 12405b261ecSmrg !memcmp (name, mode->name, modeInfo->nameLength)) 12505b261ecSmrg { 12605b261ecSmrg ++mode->refcnt; 12705b261ecSmrg return mode; 12805b261ecSmrg } 12905b261ecSmrg } 13005b261ecSmrg 13105b261ecSmrg return RRModeCreate (modeInfo, name, NULL); 13205b261ecSmrg} 13305b261ecSmrg 13405b261ecSmrgstatic RRModePtr 13505b261ecSmrgRRModeCreateUser (ScreenPtr pScreen, 13605b261ecSmrg xRRModeInfo *modeInfo, 13705b261ecSmrg const char *name, 13805b261ecSmrg int *error) 13905b261ecSmrg{ 14005b261ecSmrg RRModePtr mode; 14105b261ecSmrg 14205b261ecSmrg mode = RRModeFindByName (name, modeInfo->nameLength); 14305b261ecSmrg if (mode) 14405b261ecSmrg { 14505b261ecSmrg *error = BadName; 14605b261ecSmrg return NULL; 14705b261ecSmrg } 14805b261ecSmrg 14905b261ecSmrg mode = RRModeCreate (modeInfo, name, pScreen); 15005b261ecSmrg if (!mode) 15105b261ecSmrg { 15205b261ecSmrg *error = BadAlloc; 15305b261ecSmrg return NULL; 15405b261ecSmrg } 15505b261ecSmrg *error = Success; 15605b261ecSmrg return mode; 15705b261ecSmrg} 15805b261ecSmrg 15905b261ecSmrgRRModePtr * 16005b261ecSmrgRRModesForScreen (ScreenPtr pScreen, int *num_ret) 16105b261ecSmrg{ 16205b261ecSmrg rrScrPriv(pScreen); 16305b261ecSmrg int o, c, m; 16405b261ecSmrg RRModePtr *screen_modes; 16505b261ecSmrg int num_screen_modes = 0; 16605b261ecSmrg 1676747b715Smrg screen_modes = malloc((num_modes ? num_modes : 1) * sizeof (RRModePtr)); 1684642e01fSmrg if (!screen_modes) 1694642e01fSmrg return NULL; 17005b261ecSmrg 17105b261ecSmrg /* 17205b261ecSmrg * Add modes from all outputs 17305b261ecSmrg */ 17405b261ecSmrg for (o = 0; o < pScrPriv->numOutputs; o++) 17505b261ecSmrg { 17605b261ecSmrg RROutputPtr output = pScrPriv->outputs[o]; 17705b261ecSmrg int m, n; 17805b261ecSmrg 17905b261ecSmrg for (m = 0; m < output->numModes + output->numUserModes; m++) 18005b261ecSmrg { 18105b261ecSmrg RRModePtr mode = (m < output->numModes ? 18205b261ecSmrg output->modes[m] : 18305b261ecSmrg output->userModes[m-output->numModes]); 18405b261ecSmrg for (n = 0; n < num_screen_modes; n++) 18505b261ecSmrg if (screen_modes[n] == mode) 18605b261ecSmrg break; 18705b261ecSmrg if (n == num_screen_modes) 18805b261ecSmrg screen_modes[num_screen_modes++] = mode; 18905b261ecSmrg } 19005b261ecSmrg } 19105b261ecSmrg /* 19205b261ecSmrg * Add modes from all crtcs. The goal is to 19305b261ecSmrg * make sure all available and active modes 19405b261ecSmrg * are visible to the client 19505b261ecSmrg */ 19605b261ecSmrg for (c = 0; c < pScrPriv->numCrtcs; c++) 19705b261ecSmrg { 19805b261ecSmrg RRCrtcPtr crtc = pScrPriv->crtcs[c]; 19905b261ecSmrg RRModePtr mode = crtc->mode; 20005b261ecSmrg int n; 20105b261ecSmrg 20205b261ecSmrg if (!mode) continue; 20305b261ecSmrg for (n = 0; n < num_screen_modes; n++) 20405b261ecSmrg if (screen_modes[n] == mode) 20505b261ecSmrg break; 20605b261ecSmrg if (n == num_screen_modes) 20705b261ecSmrg screen_modes[num_screen_modes++] = mode; 20805b261ecSmrg } 20905b261ecSmrg /* 21005b261ecSmrg * Add all user modes for this screen 21105b261ecSmrg */ 21205b261ecSmrg for (m = 0; m < num_modes; m++) 21305b261ecSmrg { 21405b261ecSmrg RRModePtr mode = modes[m]; 21505b261ecSmrg int n; 21605b261ecSmrg 21705b261ecSmrg if (mode->userScreen != pScreen) 21805b261ecSmrg continue; 21905b261ecSmrg for (n = 0; n < num_screen_modes; n++) 22005b261ecSmrg if (screen_modes[n] == mode) 22105b261ecSmrg break; 22205b261ecSmrg if (n == num_screen_modes) 22305b261ecSmrg screen_modes[num_screen_modes++] = mode; 22405b261ecSmrg } 22505b261ecSmrg 22605b261ecSmrg *num_ret = num_screen_modes; 22705b261ecSmrg return screen_modes; 22805b261ecSmrg} 22905b261ecSmrg 23005b261ecSmrgvoid 23105b261ecSmrgRRModeDestroy (RRModePtr mode) 23205b261ecSmrg{ 23305b261ecSmrg int m; 23405b261ecSmrg 23505b261ecSmrg if (--mode->refcnt > 0) 23605b261ecSmrg return; 23705b261ecSmrg for (m = 0; m < num_modes; m++) 23805b261ecSmrg { 23905b261ecSmrg if (modes[m] == mode) 24005b261ecSmrg { 24105b261ecSmrg memmove (modes + m, modes + m + 1, 24205b261ecSmrg (num_modes - m - 1) * sizeof (RRModePtr)); 24305b261ecSmrg num_modes--; 24405b261ecSmrg if (!num_modes) 24505b261ecSmrg { 2466747b715Smrg free(modes); 24705b261ecSmrg modes = NULL; 24805b261ecSmrg } 24905b261ecSmrg break; 25005b261ecSmrg } 25105b261ecSmrg } 25205b261ecSmrg 2536747b715Smrg free(mode); 25405b261ecSmrg} 25505b261ecSmrg 25605b261ecSmrgstatic int 25705b261ecSmrgRRModeDestroyResource (pointer value, XID pid) 25805b261ecSmrg{ 25905b261ecSmrg RRModeDestroy ((RRModePtr) value); 26005b261ecSmrg return 1; 26105b261ecSmrg} 26205b261ecSmrg 2636747b715Smrg/* 2646747b715Smrg * Initialize mode type 2656747b715Smrg */ 26605b261ecSmrgBool 26705b261ecSmrgRRModeInit (void) 26805b261ecSmrg{ 26905b261ecSmrg assert (num_modes == 0); 27005b261ecSmrg assert (modes == NULL); 2716747b715Smrg RRModeType = CreateNewResourceType (RRModeDestroyResource, "MODE"); 27205b261ecSmrg if (!RRModeType) 27305b261ecSmrg return FALSE; 2746747b715Smrg 27505b261ecSmrg return TRUE; 27605b261ecSmrg} 27705b261ecSmrg 2786747b715Smrg/* 2796747b715Smrg * Initialize mode type error value 2806747b715Smrg */ 2816747b715Smrgvoid 2826747b715SmrgRRModeInitErrorValue(void) 2836747b715Smrg{ 2846747b715Smrg SetResourceTypeErrorValue(RRModeType, RRErrorBase + BadRRMode); 2856747b715Smrg} 2866747b715Smrg 28705b261ecSmrgint 28805b261ecSmrgProcRRCreateMode (ClientPtr client) 28905b261ecSmrg{ 29005b261ecSmrg REQUEST(xRRCreateModeReq); 29105b261ecSmrg xRRCreateModeReply rep; 29205b261ecSmrg WindowPtr pWin; 29305b261ecSmrg ScreenPtr pScreen; 29405b261ecSmrg rrScrPrivPtr pScrPriv; 29505b261ecSmrg xRRModeInfo *modeInfo; 29605b261ecSmrg long units_after; 29705b261ecSmrg char *name; 29805b261ecSmrg int error, rc; 29905b261ecSmrg RRModePtr mode; 30005b261ecSmrg 30105b261ecSmrg REQUEST_AT_LEAST_SIZE (xRRCreateModeReq); 3026747b715Smrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 30305b261ecSmrg if (rc != Success) 30405b261ecSmrg return rc; 30505b261ecSmrg 30605b261ecSmrg pScreen = pWin->drawable.pScreen; 30705b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 30805b261ecSmrg 30905b261ecSmrg modeInfo = &stuff->modeInfo; 31005b261ecSmrg name = (char *) (stuff + 1); 3116747b715Smrg units_after = (stuff->length - bytes_to_int32(sizeof (xRRCreateModeReq))); 31205b261ecSmrg 31305b261ecSmrg /* check to make sure requested name fits within the data provided */ 3146747b715Smrg if (bytes_to_int32(modeInfo->nameLength) > units_after) 31505b261ecSmrg return BadLength; 31605b261ecSmrg 31705b261ecSmrg mode = RRModeCreateUser (pScreen, modeInfo, name, &error); 31805b261ecSmrg if (!mode) 31905b261ecSmrg return error; 32005b261ecSmrg 32105b261ecSmrg rep.type = X_Reply; 32205b261ecSmrg rep.pad0 = 0; 32305b261ecSmrg rep.sequenceNumber = client->sequence; 32405b261ecSmrg rep.length = 0; 32505b261ecSmrg rep.mode = mode->mode.id; 32605b261ecSmrg if (client->swapped) 32705b261ecSmrg { 32805b261ecSmrg int n; 32905b261ecSmrg swaps(&rep.sequenceNumber, n); 33005b261ecSmrg swapl(&rep.length, n); 33105b261ecSmrg swapl(&rep.mode, n); 33205b261ecSmrg } 33305b261ecSmrg WriteToClient(client, sizeof(xRRCreateModeReply), (char *)&rep); 3344642e01fSmrg /* Drop out reference to this mode */ 3354642e01fSmrg RRModeDestroy (mode); 3366747b715Smrg return Success; 33705b261ecSmrg} 33805b261ecSmrg 33905b261ecSmrgint 34005b261ecSmrgProcRRDestroyMode (ClientPtr client) 34105b261ecSmrg{ 34205b261ecSmrg REQUEST(xRRDestroyModeReq); 34305b261ecSmrg RRModePtr mode; 34405b261ecSmrg 34505b261ecSmrg REQUEST_SIZE_MATCH(xRRDestroyModeReq); 3466747b715Smrg VERIFY_RR_MODE(stuff->mode, mode, DixDestroyAccess); 3476747b715Smrg 34805b261ecSmrg if (!mode->userScreen) 34905b261ecSmrg return BadMatch; 35005b261ecSmrg if (mode->refcnt > 1) 35105b261ecSmrg return BadAccess; 35205b261ecSmrg FreeResource (stuff->mode, 0); 35305b261ecSmrg return Success; 35405b261ecSmrg} 35505b261ecSmrg 35605b261ecSmrgint 35705b261ecSmrgProcRRAddOutputMode (ClientPtr client) 35805b261ecSmrg{ 35905b261ecSmrg REQUEST(xRRAddOutputModeReq); 36005b261ecSmrg RRModePtr mode; 36105b261ecSmrg RROutputPtr output; 36205b261ecSmrg 36305b261ecSmrg REQUEST_SIZE_MATCH(xRRAddOutputModeReq); 3646747b715Smrg VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); 3656747b715Smrg VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); 36605b261ecSmrg 36705b261ecSmrg return RROutputAddUserMode (output, mode); 36805b261ecSmrg} 36905b261ecSmrg 37005b261ecSmrgint 37105b261ecSmrgProcRRDeleteOutputMode (ClientPtr client) 37205b261ecSmrg{ 37305b261ecSmrg REQUEST(xRRDeleteOutputModeReq); 37405b261ecSmrg RRModePtr mode; 37505b261ecSmrg RROutputPtr output; 37605b261ecSmrg 37705b261ecSmrg REQUEST_SIZE_MATCH(xRRDeleteOutputModeReq); 3786747b715Smrg VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); 3796747b715Smrg VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); 38005b261ecSmrg 38105b261ecSmrg return RROutputDeleteUserMode (output, mode); 38205b261ecSmrg} 383