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 2535c4bbdfSmrgRESTYPE RRModeType; 2605b261ecSmrg 2705b261ecSmrgstatic Bool 2835c4bbdfSmrgRRModeEqual(xRRModeInfo * a, xRRModeInfo * b) 2905b261ecSmrg{ 3035c4bbdfSmrg if (a->width != b->width) 3135c4bbdfSmrg return FALSE; 3235c4bbdfSmrg if (a->height != b->height) 3335c4bbdfSmrg return FALSE; 3435c4bbdfSmrg if (a->dotClock != b->dotClock) 3535c4bbdfSmrg return FALSE; 3635c4bbdfSmrg if (a->hSyncStart != b->hSyncStart) 3735c4bbdfSmrg return FALSE; 3835c4bbdfSmrg if (a->hSyncEnd != b->hSyncEnd) 3935c4bbdfSmrg return FALSE; 4035c4bbdfSmrg if (a->hTotal != b->hTotal) 4135c4bbdfSmrg return FALSE; 4235c4bbdfSmrg if (a->hSkew != b->hSkew) 4335c4bbdfSmrg return FALSE; 4435c4bbdfSmrg if (a->vSyncStart != b->vSyncStart) 4535c4bbdfSmrg return FALSE; 4635c4bbdfSmrg if (a->vSyncEnd != b->vSyncEnd) 4735c4bbdfSmrg return FALSE; 4835c4bbdfSmrg if (a->vTotal != b->vTotal) 4935c4bbdfSmrg return FALSE; 5035c4bbdfSmrg if (a->nameLength != b->nameLength) 5135c4bbdfSmrg return FALSE; 5235c4bbdfSmrg if (a->modeFlags != b->modeFlags) 5335c4bbdfSmrg return FALSE; 5405b261ecSmrg return TRUE; 5505b261ecSmrg} 5605b261ecSmrg 5705b261ecSmrg/* 5805b261ecSmrg * Keep a list so it's easy to find modes in the resource database. 5905b261ecSmrg */ 6035c4bbdfSmrgstatic int num_modes; 6135c4bbdfSmrgstatic RRModePtr *modes; 6205b261ecSmrg 6305b261ecSmrgstatic RRModePtr 6435c4bbdfSmrgRRModeCreate(xRRModeInfo * modeInfo, const char *name, ScreenPtr userScreen) 6505b261ecSmrg{ 6635c4bbdfSmrg RRModePtr mode, *newModes; 6705b261ecSmrg 6835c4bbdfSmrg if (!RRInit()) 6935c4bbdfSmrg return NULL; 7035c4bbdfSmrg 7135c4bbdfSmrg mode = malloc(sizeof(RRModeRec) + modeInfo->nameLength + 1); 7205b261ecSmrg if (!mode) 7335c4bbdfSmrg return NULL; 7405b261ecSmrg mode->refcnt = 1; 7505b261ecSmrg mode->mode = *modeInfo; 7605b261ecSmrg mode->name = (char *) (mode + 1); 7735c4bbdfSmrg memcpy(mode->name, name, modeInfo->nameLength); 7805b261ecSmrg mode->name[modeInfo->nameLength] = '\0'; 7905b261ecSmrg mode->userScreen = userScreen; 8005b261ecSmrg 8105b261ecSmrg if (num_modes) 8235c4bbdfSmrg newModes = reallocarray(modes, num_modes + 1, sizeof(RRModePtr)); 8305b261ecSmrg else 8435c4bbdfSmrg newModes = malloc(sizeof(RRModePtr)); 8505b261ecSmrg 8635c4bbdfSmrg if (!newModes) { 8735c4bbdfSmrg free(mode); 8835c4bbdfSmrg return NULL; 8905b261ecSmrg } 9005b261ecSmrg 9105b261ecSmrg mode->mode.id = FakeClientID(0); 9235c4bbdfSmrg if (!AddResource(mode->mode.id, RRModeType, (void *) mode)) { 9335c4bbdfSmrg free(newModes); 9435c4bbdfSmrg return NULL; 9535c4bbdfSmrg } 9605b261ecSmrg modes = newModes; 9705b261ecSmrg modes[num_modes++] = mode; 9835c4bbdfSmrg 9905b261ecSmrg /* 10005b261ecSmrg * give the caller a reference to this mode 10105b261ecSmrg */ 10205b261ecSmrg ++mode->refcnt; 10305b261ecSmrg return mode; 10405b261ecSmrg} 10505b261ecSmrg 10605b261ecSmrgstatic RRModePtr 10735c4bbdfSmrgRRModeFindByName(const char *name, CARD16 nameLength) 10805b261ecSmrg{ 10935c4bbdfSmrg int i; 11035c4bbdfSmrg RRModePtr mode; 11135c4bbdfSmrg 11235c4bbdfSmrg for (i = 0; i < num_modes; i++) { 11335c4bbdfSmrg mode = modes[i]; 11435c4bbdfSmrg if (mode->mode.nameLength == nameLength && 11535c4bbdfSmrg !memcmp(name, mode->name, nameLength)) { 11635c4bbdfSmrg return mode; 11735c4bbdfSmrg } 11805b261ecSmrg } 11905b261ecSmrg return NULL; 12005b261ecSmrg} 12105b261ecSmrg 12205b261ecSmrgRRModePtr 12335c4bbdfSmrgRRModeGet(xRRModeInfo * modeInfo, const char *name) 12405b261ecSmrg{ 12535c4bbdfSmrg int i; 12635c4bbdfSmrg 12735c4bbdfSmrg for (i = 0; i < num_modes; i++) { 12835c4bbdfSmrg RRModePtr mode = modes[i]; 12935c4bbdfSmrg 13035c4bbdfSmrg if (RRModeEqual(&mode->mode, modeInfo) && 13135c4bbdfSmrg !memcmp(name, mode->name, modeInfo->nameLength)) { 13235c4bbdfSmrg ++mode->refcnt; 13335c4bbdfSmrg return mode; 13435c4bbdfSmrg } 13505b261ecSmrg } 13605b261ecSmrg 13735c4bbdfSmrg return RRModeCreate(modeInfo, name, NULL); 13805b261ecSmrg} 13905b261ecSmrg 14005b261ecSmrgstatic RRModePtr 14135c4bbdfSmrgRRModeCreateUser(ScreenPtr pScreen, 14235c4bbdfSmrg xRRModeInfo * modeInfo, const char *name, int *error) 14305b261ecSmrg{ 14435c4bbdfSmrg RRModePtr mode; 14505b261ecSmrg 14635c4bbdfSmrg mode = RRModeFindByName(name, modeInfo->nameLength); 14735c4bbdfSmrg if (mode) { 14835c4bbdfSmrg *error = BadName; 14935c4bbdfSmrg return NULL; 15005b261ecSmrg } 15135c4bbdfSmrg 15235c4bbdfSmrg mode = RRModeCreate(modeInfo, name, pScreen); 15335c4bbdfSmrg if (!mode) { 15435c4bbdfSmrg *error = BadAlloc; 15535c4bbdfSmrg return NULL; 15605b261ecSmrg } 15705b261ecSmrg *error = Success; 15805b261ecSmrg return mode; 15905b261ecSmrg} 16005b261ecSmrg 16105b261ecSmrgRRModePtr * 16235c4bbdfSmrgRRModesForScreen(ScreenPtr pScreen, int *num_ret) 16305b261ecSmrg{ 16405b261ecSmrg rrScrPriv(pScreen); 16535c4bbdfSmrg int o, c, m; 16635c4bbdfSmrg RRModePtr *screen_modes; 16735c4bbdfSmrg int num_screen_modes = 0; 16805b261ecSmrg 16935c4bbdfSmrg screen_modes = xallocarray((num_modes ? num_modes : 1), sizeof(RRModePtr)); 1704642e01fSmrg if (!screen_modes) 17135c4bbdfSmrg return NULL; 17235c4bbdfSmrg 17305b261ecSmrg /* 17405b261ecSmrg * Add modes from all outputs 17505b261ecSmrg */ 17635c4bbdfSmrg for (o = 0; o < pScrPriv->numOutputs; o++) { 17735c4bbdfSmrg RROutputPtr output = pScrPriv->outputs[o]; 17835c4bbdfSmrg int n; 17935c4bbdfSmrg 18035c4bbdfSmrg for (m = 0; m < output->numModes + output->numUserModes; m++) { 18135c4bbdfSmrg RRModePtr mode = (m < output->numModes ? 18235c4bbdfSmrg output->modes[m] : 18335c4bbdfSmrg output->userModes[m - output->numModes]); 18435c4bbdfSmrg for (n = 0; n < num_screen_modes; n++) 18535c4bbdfSmrg if (screen_modes[n] == mode) 18635c4bbdfSmrg break; 18735c4bbdfSmrg if (n == num_screen_modes) 18835c4bbdfSmrg screen_modes[num_screen_modes++] = mode; 18935c4bbdfSmrg } 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 */ 19635c4bbdfSmrg for (c = 0; c < pScrPriv->numCrtcs; c++) { 19735c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[c]; 19835c4bbdfSmrg RRModePtr mode = crtc->mode; 19935c4bbdfSmrg int n; 20035c4bbdfSmrg 20135c4bbdfSmrg if (!mode) 20235c4bbdfSmrg continue; 20335c4bbdfSmrg for (n = 0; n < num_screen_modes; n++) 20435c4bbdfSmrg if (screen_modes[n] == mode) 20535c4bbdfSmrg break; 20635c4bbdfSmrg if (n == num_screen_modes) 20735c4bbdfSmrg screen_modes[num_screen_modes++] = mode; 20805b261ecSmrg } 20905b261ecSmrg /* 21005b261ecSmrg * Add all user modes for this screen 21105b261ecSmrg */ 21235c4bbdfSmrg for (m = 0; m < num_modes; m++) { 21335c4bbdfSmrg RRModePtr mode = modes[m]; 21435c4bbdfSmrg int n; 21535c4bbdfSmrg 21635c4bbdfSmrg if (mode->userScreen != pScreen) 21735c4bbdfSmrg continue; 21835c4bbdfSmrg for (n = 0; n < num_screen_modes; n++) 21935c4bbdfSmrg if (screen_modes[n] == mode) 22035c4bbdfSmrg break; 22135c4bbdfSmrg if (n == num_screen_modes) 22235c4bbdfSmrg screen_modes[num_screen_modes++] = mode; 22305b261ecSmrg } 22435c4bbdfSmrg 22505b261ecSmrg *num_ret = num_screen_modes; 22605b261ecSmrg return screen_modes; 22705b261ecSmrg} 22805b261ecSmrg 22905b261ecSmrgvoid 23035c4bbdfSmrgRRModeDestroy(RRModePtr mode) 23105b261ecSmrg{ 23235c4bbdfSmrg int m; 23335c4bbdfSmrg 23405b261ecSmrg if (--mode->refcnt > 0) 23535c4bbdfSmrg return; 23635c4bbdfSmrg for (m = 0; m < num_modes; m++) { 23735c4bbdfSmrg if (modes[m] == mode) { 23835c4bbdfSmrg memmove(modes + m, modes + m + 1, 23935c4bbdfSmrg (num_modes - m - 1) * sizeof(RRModePtr)); 24035c4bbdfSmrg num_modes--; 24135c4bbdfSmrg if (!num_modes) { 24235c4bbdfSmrg free(modes); 24335c4bbdfSmrg modes = NULL; 24435c4bbdfSmrg } 24535c4bbdfSmrg break; 24635c4bbdfSmrg } 24705b261ecSmrg } 24835c4bbdfSmrg 2496747b715Smrg free(mode); 25005b261ecSmrg} 25105b261ecSmrg 25205b261ecSmrgstatic int 25335c4bbdfSmrgRRModeDestroyResource(void *value, XID pid) 25405b261ecSmrg{ 25535c4bbdfSmrg RRModeDestroy((RRModePtr) value); 25605b261ecSmrg return 1; 25705b261ecSmrg} 25805b261ecSmrg 2596747b715Smrg/* 2606747b715Smrg * Initialize mode type 2616747b715Smrg */ 26205b261ecSmrgBool 26335c4bbdfSmrgRRModeInit(void) 26405b261ecSmrg{ 26535c4bbdfSmrg assert(num_modes == 0); 26635c4bbdfSmrg assert(modes == NULL); 26735c4bbdfSmrg RRModeType = CreateNewResourceType(RRModeDestroyResource, "MODE"); 26805b261ecSmrg if (!RRModeType) 26935c4bbdfSmrg return FALSE; 27035c4bbdfSmrg 27105b261ecSmrg return TRUE; 27205b261ecSmrg} 27305b261ecSmrg 2746747b715Smrg/* 2756747b715Smrg * Initialize mode type error value 2766747b715Smrg */ 2776747b715Smrgvoid 2786747b715SmrgRRModeInitErrorValue(void) 2796747b715Smrg{ 2806747b715Smrg SetResourceTypeErrorValue(RRModeType, RRErrorBase + BadRRMode); 2816747b715Smrg} 2826747b715Smrg 28305b261ecSmrgint 28435c4bbdfSmrgProcRRCreateMode(ClientPtr client) 28505b261ecSmrg{ 28605b261ecSmrg REQUEST(xRRCreateModeReq); 28735c4bbdfSmrg xRRCreateModeReply rep; 28835c4bbdfSmrg WindowPtr pWin; 28935c4bbdfSmrg ScreenPtr pScreen; 29035c4bbdfSmrg xRRModeInfo *modeInfo; 29135c4bbdfSmrg long units_after; 29235c4bbdfSmrg char *name; 29335c4bbdfSmrg int error, rc; 29435c4bbdfSmrg RRModePtr mode; 29535c4bbdfSmrg 29635c4bbdfSmrg REQUEST_AT_LEAST_SIZE(xRRCreateModeReq); 2976747b715Smrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 29805b261ecSmrg if (rc != Success) 29935c4bbdfSmrg return rc; 30005b261ecSmrg 30105b261ecSmrg pScreen = pWin->drawable.pScreen; 30235c4bbdfSmrg 30305b261ecSmrg modeInfo = &stuff->modeInfo; 30405b261ecSmrg name = (char *) (stuff + 1); 30535c4bbdfSmrg units_after = (stuff->length - bytes_to_int32(sizeof(xRRCreateModeReq))); 30605b261ecSmrg 30705b261ecSmrg /* check to make sure requested name fits within the data provided */ 3086747b715Smrg if (bytes_to_int32(modeInfo->nameLength) > units_after) 30935c4bbdfSmrg return BadLength; 31005b261ecSmrg 31135c4bbdfSmrg mode = RRModeCreateUser(pScreen, modeInfo, name, &error); 31205b261ecSmrg if (!mode) 31335c4bbdfSmrg return error; 31435c4bbdfSmrg 31535c4bbdfSmrg rep = (xRRCreateModeReply) { 31635c4bbdfSmrg .type = X_Reply, 31735c4bbdfSmrg .sequenceNumber = client->sequence, 31835c4bbdfSmrg .length = 0, 31935c4bbdfSmrg .mode = mode->mode.id 32035c4bbdfSmrg }; 32135c4bbdfSmrg if (client->swapped) { 32235c4bbdfSmrg swaps(&rep.sequenceNumber); 32335c4bbdfSmrg swapl(&rep.length); 32435c4bbdfSmrg swapl(&rep.mode); 32505b261ecSmrg } 32635c4bbdfSmrg WriteToClient(client, sizeof(xRRCreateModeReply), &rep); 3274642e01fSmrg /* Drop out reference to this mode */ 32835c4bbdfSmrg RRModeDestroy(mode); 3296747b715Smrg return Success; 33005b261ecSmrg} 33105b261ecSmrg 33205b261ecSmrgint 33335c4bbdfSmrgProcRRDestroyMode(ClientPtr client) 33405b261ecSmrg{ 33505b261ecSmrg REQUEST(xRRDestroyModeReq); 33635c4bbdfSmrg RRModePtr mode; 33735c4bbdfSmrg 33805b261ecSmrg REQUEST_SIZE_MATCH(xRRDestroyModeReq); 3396747b715Smrg VERIFY_RR_MODE(stuff->mode, mode, DixDestroyAccess); 3406747b715Smrg 34105b261ecSmrg if (!mode->userScreen) 34235c4bbdfSmrg return BadMatch; 34305b261ecSmrg if (mode->refcnt > 1) 34435c4bbdfSmrg return BadAccess; 34535c4bbdfSmrg FreeResource(stuff->mode, 0); 34605b261ecSmrg return Success; 34705b261ecSmrg} 34805b261ecSmrg 34905b261ecSmrgint 35035c4bbdfSmrgProcRRAddOutputMode(ClientPtr client) 35105b261ecSmrg{ 35205b261ecSmrg REQUEST(xRRAddOutputModeReq); 35335c4bbdfSmrg RRModePtr mode; 35435c4bbdfSmrg RROutputPtr output; 35535c4bbdfSmrg 35605b261ecSmrg REQUEST_SIZE_MATCH(xRRAddOutputModeReq); 3576747b715Smrg VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); 3586747b715Smrg VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); 35935c4bbdfSmrg 3601b5d61b8Smrg if (RROutputIsLeased(output)) 3611b5d61b8Smrg return BadAccess; 3621b5d61b8Smrg 36335c4bbdfSmrg return RROutputAddUserMode(output, mode); 36405b261ecSmrg} 36505b261ecSmrg 36605b261ecSmrgint 36735c4bbdfSmrgProcRRDeleteOutputMode(ClientPtr client) 36805b261ecSmrg{ 36905b261ecSmrg REQUEST(xRRDeleteOutputModeReq); 37035c4bbdfSmrg RRModePtr mode; 37135c4bbdfSmrg RROutputPtr output; 37235c4bbdfSmrg 37305b261ecSmrg REQUEST_SIZE_MATCH(xRRDeleteOutputModeReq); 3746747b715Smrg VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); 3756747b715Smrg VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess); 37635c4bbdfSmrg 3771b5d61b8Smrg if (RROutputIsLeased(output)) 3781b5d61b8Smrg return BadAccess; 3791b5d61b8Smrg 38035c4bbdfSmrg return RROutputDeleteUserMode(output, mode); 38105b261ecSmrg} 382