aboutsummaryrefslogtreecommitdiff
path: root/xorg-server
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2010-12-20 09:39:54 +0000
committermarha <marha@users.sourceforge.net>2010-12-20 09:39:54 +0000
commitfe2ccbf887ddf31f99d6f630830e3180ff259e40 (patch)
treed075f4fb9dfc80e5f6fb927ad2115b57c22bdf3b /xorg-server
parentb24af6c6af003368ebb5c3e042db0ab7a295d89e (diff)
downloadvcxsrv-fe2ccbf887ddf31f99d6f630830e3180ff259e40.tar.gz
vcxsrv-fe2ccbf887ddf31f99d6f630830e3180ff259e40.tar.bz2
vcxsrv-fe2ccbf887ddf31f99d6f630830e3180ff259e40.zip
xserver libXext git update 20-12-2010
Diffstat (limited to 'xorg-server')
-rw-r--r--xorg-server/Xext/sync.c5760
-rw-r--r--xorg-server/hw/xfree86/loader/sdksyms.sh844
-rw-r--r--xorg-server/hw/xfree86/modes/xf86EdidModes.c2427
-rw-r--r--xorg-server/hw/xfree86/parser/Makefile.am102
-rw-r--r--xorg-server/os/xprintf.c452
-rw-r--r--xorg-server/randr/rrscreen.c2062
6 files changed, 5849 insertions, 5798 deletions
diff --git a/xorg-server/Xext/sync.c b/xorg-server/Xext/sync.c
index 097900058..d495116dc 100644
--- a/xorg-server/Xext/sync.c
+++ b/xorg-server/Xext/sync.c
@@ -1,2865 +1,2895 @@
-/*
-
-Copyright 1991, 1993, 1998 The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation.
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
-OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall
-not be used in advertising or otherwise to promote the sale, use or
-other dealings in this Software without prior written authorization
-from The Open Group.
-
-
-Copyright 1991, 1993 by Digital Equipment Corporation, Maynard, Massachusetts,
-and Olivetti Research Limited, Cambridge, England.
-
- All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the names of Digital or Olivetti
-not be used in advertising or publicity pertaining to distribution of the
-software without specific, written prior permission. Digital and Olivetti
-make no representations about the suitability of this software
-for any purpose. It is provided "as is" without express or implied warranty.
-
-DIGITAL AND OLIVETTI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
-SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS, IN NO EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
-CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
-USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
-
-*/
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <string.h>
-
-#include <X11/X.h>
-#include <X11/Xproto.h>
-#include <X11/Xmd.h>
-#include "scrnintstr.h"
-#include "os.h"
-#include "extnsionst.h"
-#include "dixstruct.h"
-#include "pixmapstr.h"
-#include "resource.h"
-#include "opaque.h"
-#include <X11/extensions/syncproto.h>
-#include "syncsrv.h"
-#include "syncsdk.h"
-#include "protocol-versions.h"
-
-#include <stdio.h>
-#if !defined(WIN32)
-#include <sys/time.h>
-#endif
-
-#include "modinit.h"
-
-/*
- * Local Global Variables
- */
-static int SyncEventBase;
-static int SyncErrorBase;
-static RESTYPE RTCounter = 0;
-static RESTYPE RTAwait;
-static RESTYPE RTAlarm;
-static RESTYPE RTAlarmClient;
-static RESTYPE RTFence;
-static int SyncNumSystemCounters = 0;
-static SyncCounter **SysCounterList = NULL;
-
-#define IsSystemCounter(pCounter) \
- (pCounter && (pCounter->sync.client == NULL))
-
-/* these are all the alarm attributes that pertain to the alarm's trigger */
-#define XSyncCAAllTrigger \
- (XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType)
-
-static void SyncComputeBracketValues(SyncCounter *);
-
-static void SyncInitServerTime(void);
-
-static void SyncInitIdleTime(void);
-
-
-/* Each counter maintains a simple linked list of triggers that are
- * interested in the counter. The two functions below are used to
- * delete and add triggers on this list.
- */
-static void
-SyncDeleteTriggerFromSyncObject(SyncTrigger *pTrigger)
-{
- SyncTriggerList *pCur;
- SyncTriggerList *pPrev;
- SyncCounter *pCounter;
-
- /* pSync needs to be stored in pTrigger before calling here. */
-
- if (!pTrigger->pSync)
- return;
-
- pPrev = NULL;
- pCur = pTrigger->pSync->pTriglist;
-
- while (pCur)
- {
- if (pCur->pTrigger == pTrigger)
- {
- if (pPrev)
- pPrev->next = pCur->next;
- else
- pTrigger->pSync->pTriglist = pCur->next;
-
- free(pCur);
- break;
- }
-
- pPrev = pCur;
- pCur = pCur->next;
- }
-
- if (SYNC_COUNTER == pTrigger->pSync->type)
- {
- pCounter = (SyncCounter *)pTrigger->pSync;
-
- if (IsSystemCounter(pCounter))
- SyncComputeBracketValues(pCounter);
- } else if (SYNC_FENCE == pTrigger->pSync->type) {
- SyncFence* pFence = (SyncFence*) pTrigger->pSync;
- pFence->funcs.DeleteTrigger(pTrigger);
- }
-}
-
-
-static int
-SyncAddTriggerToSyncObject(SyncTrigger *pTrigger)
-{
- SyncTriggerList *pCur;
- SyncCounter *pCounter;
-
- if (!pTrigger->pSync)
- return Success;
-
- /* don't do anything if it's already there */
- for (pCur = pTrigger->pSync->pTriglist; pCur; pCur = pCur->next)
- {
- if (pCur->pTrigger == pTrigger)
- return Success;
- }
-
- if (!(pCur = malloc(sizeof(SyncTriggerList))))
- return BadAlloc;
-
- pCur->pTrigger = pTrigger;
- pCur->next = pTrigger->pSync->pTriglist;
- pTrigger->pSync->pTriglist = pCur;
-
- if (SYNC_COUNTER == pTrigger->pSync->type)
- {
- pCounter = (SyncCounter *)pTrigger->pSync;
-
- if (IsSystemCounter(pCounter))
- SyncComputeBracketValues(pCounter);
- } else if (SYNC_FENCE == pTrigger->pSync->type) {
- SyncFence* pFence = (SyncFence*) pTrigger->pSync;
- pFence->funcs.AddTrigger(pTrigger);
- }
-
- return Success;
-}
-
-
-/* Below are five possible functions that can be plugged into
- * pTrigger->CheckTrigger for counter sync objects, corresponding to
- * the four possible test-types, and the one possible function that
- * can be plugged into pTrigger->CheckTrigger for fence sync objects.
- * These functions are called after the sync object's state changes
- * but are also passed the old state so they can inspect both the old
- * and new values. (PositiveTransition and NegativeTransition need to
- * see both pieces of information.) These functions return the truth
- * value of the trigger.
- *
- * All of them include the condition pTrigger->pSync == NULL.
- * This is because the spec says that a trigger with a sync value
- * of None is always TRUE.
- */
-
-static Bool
-SyncCheckTriggerPositiveComparison(SyncTrigger *pTrigger, CARD64 oldval)
-{
- SyncCounter *pCounter;
-
- assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
- pCounter = (SyncCounter *)pTrigger->pSync;
-
- return (pCounter == NULL ||
- XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value));
-}
-
-static Bool
-SyncCheckTriggerNegativeComparison(SyncTrigger *pTrigger, CARD64 oldval)
-{
- SyncCounter *pCounter;
-
- assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
- pCounter = (SyncCounter *)pTrigger->pSync;
-
- return (pCounter == NULL ||
- XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value));
-}
-
-static Bool
-SyncCheckTriggerPositiveTransition(SyncTrigger *pTrigger, CARD64 oldval)
-{
- SyncCounter *pCounter;
-
- assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
- pCounter = (SyncCounter *)pTrigger->pSync;
-
- return (pCounter == NULL ||
- (XSyncValueLessThan(oldval, pTrigger->test_value) &&
- XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value)));
-}
-
-static Bool
-SyncCheckTriggerNegativeTransition(SyncTrigger *pTrigger, CARD64 oldval)
-{
- SyncCounter *pCounter;
-
- assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
- pCounter = (SyncCounter *)pTrigger->pSync;
-
- return (pCounter == NULL ||
- (XSyncValueGreaterThan(oldval, pTrigger->test_value) &&
- XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value)));
-}
-
-static Bool
-SyncCheckTriggerFence(SyncTrigger *pTrigger, CARD64 unused)
-{
- SyncFence* pFence = (SyncFence*) pTrigger->pSync;
- (void)unused;
-
- return (pFence == NULL ||
- pFence->funcs.CheckTriggered(pFence));
-}
-
-static int
-SyncInitTrigger(ClientPtr client, SyncTrigger *pTrigger, XID syncObject,
- RESTYPE resType, Mask changes)
-{
- SyncObject *pSync = pTrigger->pSync;
- SyncCounter *pCounter = NULL;
- int rc;
- Bool newSyncObject = FALSE;
-
- if (changes & XSyncCACounter)
- {
- if (syncObject == None)
- pSync = NULL;
- else if (Success != (rc = dixLookupResourceByType ((pointer *)&pSync,
- syncObject, resType, client, DixReadAccess)))
- {
- client->errorValue = syncObject;
- return rc;
- }
- if (pSync != pTrigger->pSync)
- { /* new counter for trigger */
- SyncDeleteTriggerFromSyncObject(pTrigger);
- pTrigger->pSync = pSync;
- newSyncObject = TRUE;
- }
- }
-
- /* if system counter, ask it what the current value is */
-
- if (pSync && SYNC_COUNTER == pSync->type)
- {
- pCounter = (SyncCounter *)pSync;
-
- if (IsSystemCounter(pCounter))
- {
- (*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
- &pCounter->value);
- }
- }
-
- if (changes & XSyncCAValueType)
- {
- if (pTrigger->value_type != XSyncRelative &&
- pTrigger->value_type != XSyncAbsolute)
- {
- client->errorValue = pTrigger->value_type;
- return BadValue;
- }
- }
-
- if (changes & XSyncCATestType)
- {
-
- if (pSync && SYNC_FENCE == pSync->type)
- {
- pTrigger->CheckTrigger = SyncCheckTriggerFence;
- }
- else
- {
- if (pTrigger->test_type != XSyncPositiveTransition &&
- pTrigger->test_type != XSyncNegativeTransition &&
- pTrigger->test_type != XSyncPositiveComparison &&
- pTrigger->test_type != XSyncNegativeComparison)
- {
- client->errorValue = pTrigger->test_type;
- return BadValue;
- }
- /* select appropriate CheckTrigger function */
-
- switch (pTrigger->test_type)
- {
- case XSyncPositiveTransition:
- pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition;
- break;
- case XSyncNegativeTransition:
- pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition;
- break;
- case XSyncPositiveComparison:
- pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison;
- break;
- case XSyncNegativeComparison:
- pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison;
- break;
- }
- }
- }
-
- if (changes & (XSyncCAValueType | XSyncCAValue))
- {
- if (pTrigger->value_type == XSyncAbsolute)
- pTrigger->test_value = pTrigger->wait_value;
- else /* relative */
- {
- Bool overflow;
- if (pCounter == NULL)
- return BadMatch;
-
- XSyncValueAdd(&pTrigger->test_value, pCounter->value,
- pTrigger->wait_value, &overflow);
- if (overflow)
- {
- client->errorValue = XSyncValueHigh32(pTrigger->wait_value);
- return BadValue;
- }
- }
- }
-
- /* we wait until we're sure there are no errors before registering
- * a new counter on a trigger
- */
- if (newSyncObject)
- {
- if ((rc = SyncAddTriggerToSyncObject(pTrigger)) != Success)
- return rc;
- }
- else if (pCounter && IsSystemCounter(pCounter))
- {
- SyncComputeBracketValues(pCounter);
- }
-
- return Success;
-}
-
-/* AlarmNotify events happen in response to actions taken on an Alarm or
- * the counter used by the alarm. AlarmNotify may be sent to multiple
- * clients. The alarm maintains a list of clients interested in events.
- */
-static void
-SyncSendAlarmNotifyEvents(SyncAlarm *pAlarm)
-{
- SyncAlarmClientList *pcl;
- xSyncAlarmNotifyEvent ane;
- SyncTrigger *pTrigger = &pAlarm->trigger;
- SyncCounter *pCounter;
-
- assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
-
- pCounter = (SyncCounter *)pTrigger->pSync;
-
- UpdateCurrentTime();
-
- ane.type = SyncEventBase + XSyncAlarmNotify;
- ane.kind = XSyncAlarmNotify;
- ane.alarm = pAlarm->alarm_id;
- if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type)
- {
- ane.counter_value_hi = XSyncValueHigh32(pCounter->value);
- ane.counter_value_lo = XSyncValueLow32(pCounter->value);
- }
- else
- { /* XXX what else can we do if there's no counter? */
- ane.counter_value_hi = ane.counter_value_lo = 0;
- }
-
- ane.alarm_value_hi = XSyncValueHigh32(pTrigger->test_value);
- ane.alarm_value_lo = XSyncValueLow32(pTrigger->test_value);
- ane.time = currentTime.milliseconds;
- ane.state = pAlarm->state;
-
- /* send to owner */
- if (pAlarm->events)
- WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane);
-
- /* send to other interested clients */
- for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next)
- WriteEventsToClient(pcl->client, 1, (xEvent *) &ane);
-}
-
-
-/* CounterNotify events only occur in response to an Await. The events
- * go only to the Awaiting client.
- */
-static void
-SyncSendCounterNotifyEvents(ClientPtr client, SyncAwait **ppAwait,
- int num_events)
-{
- xSyncCounterNotifyEvent *pEvents, *pev;
- int i;
-
- if (client->clientGone)
- return;
- pev = pEvents = malloc(num_events * sizeof(xSyncCounterNotifyEvent));
- if (!pEvents)
- return;
- UpdateCurrentTime();
- for (i = 0; i < num_events; i++, ppAwait++, pev++)
- {
- SyncTrigger *pTrigger = &(*ppAwait)->trigger;
- pev->type = SyncEventBase + XSyncCounterNotify;
- pev->kind = XSyncCounterNotify;
- pev->counter = pTrigger->pSync->id;
- pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value);
- pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
- if (SYNC_COUNTER == pTrigger->pSync->type)
- {
- SyncCounter *pCounter = (SyncCounter *)pTrigger->pSync;
-
- pev->counter_value_lo = XSyncValueLow32(pCounter->value);
- pev->counter_value_hi = XSyncValueHigh32(pCounter->value);
- }
- else
- {
- pev->counter_value_lo = 0;
- pev->counter_value_hi = 0;
- }
-
- pev->time = currentTime.milliseconds;
- pev->count = num_events - i - 1; /* events remaining */
- pev->destroyed = pTrigger->pSync->beingDestroyed;
- }
- /* swapping will be taken care of by this */
- WriteEventsToClient(client, num_events, (xEvent *)pEvents);
- free(pEvents);
-}
-
-
-/* This function is called when an alarm's counter is destroyed.
- * It is plugged into pTrigger->CounterDestroyed (for alarm triggers).
- */
-static void
-SyncAlarmCounterDestroyed(SyncTrigger *pTrigger)
-{
- SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
-
- pAlarm->state = XSyncAlarmInactive;
- SyncSendAlarmNotifyEvents(pAlarm);
- pTrigger->pSync = NULL;
-}
-
-
-/* This function is called when an alarm "goes off."
- * It is plugged into pTrigger->TriggerFired (for alarm triggers).
- */
-static void
-SyncAlarmTriggerFired(SyncTrigger *pTrigger)
-{
- SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
- SyncCounter *pCounter;
- CARD64 new_test_value;
-
- assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
- pCounter = (SyncCounter *)pTrigger->pSync;
-
- /* no need to check alarm unless it's active */
- if (pAlarm->state != XSyncAlarmActive)
- return;
-
- /* " if the counter value is None, or if the delta is 0 and
- * the test-type is PositiveComparison or NegativeComparison,
- * no change is made to value (test-value) and the alarm
- * state is changed to Inactive before the event is generated."
- */
- if (pCounter == NULL
- || (XSyncValueIsZero(pAlarm->delta)
- && (pAlarm->trigger.test_type == XSyncPositiveComparison
- || pAlarm->trigger.test_type == XSyncNegativeComparison)))
- pAlarm->state = XSyncAlarmInactive;
-
- new_test_value = pAlarm->trigger.test_value;
-
- if (pAlarm->state == XSyncAlarmActive)
- {
- Bool overflow;
- CARD64 oldvalue;
- SyncTrigger *paTrigger = &pAlarm->trigger;
- SyncCounter *paCounter;
-
- assert(!paTrigger->pSync || (SYNC_COUNTER == paTrigger->pSync->type));
- paCounter = (SyncCounter *)pTrigger->pSync;
-
- /* "The alarm is updated by repeatedly adding delta to the
- * value of the trigger and re-initializing it until it
- * becomes FALSE."
- */
- oldvalue = paTrigger->test_value;
-
- /* XXX really should do something smarter here */
-
- do
- {
- XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value,
- pAlarm->delta, &overflow);
- } while (!overflow &&
- (*paTrigger->CheckTrigger)(paTrigger,
- paCounter->value));
-
- new_test_value = paTrigger->test_value;
- paTrigger->test_value = oldvalue;
-
- /* "If this update would cause value to fall outside the range
- * for an INT64...no change is made to value (test-value) and
- * the alarm state is changed to Inactive before the event is
- * generated."
- */
- if (overflow)
- {
- new_test_value = oldvalue;
- pAlarm->state = XSyncAlarmInactive;
- }
- }
- /* The AlarmNotify event has to have the "new state of the alarm"
- * which we can't be sure of until this point. However, it has
- * to have the "old" trigger test value. That's the reason for
- * all the newvalue/oldvalue shuffling above. After we send the
- * events, give the trigger its new test value.
- */
- SyncSendAlarmNotifyEvents(pAlarm);
- pTrigger->test_value = new_test_value;
-}
-
-
-/* This function is called when an Await unblocks, either as a result
- * of the trigger firing OR the counter being destroyed.
- * It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed
- * (for Await triggers).
- */
-static void
-SyncAwaitTriggerFired(SyncTrigger *pTrigger)
-{
- SyncAwait *pAwait = (SyncAwait *)pTrigger;
- int numwaits;
- SyncAwaitUnion *pAwaitUnion;
- SyncAwait **ppAwait;
- int num_events = 0;
-
- pAwaitUnion = (SyncAwaitUnion *)pAwait->pHeader;
- numwaits = pAwaitUnion->header.num_waitconditions;
- ppAwait = malloc(numwaits * sizeof(SyncAwait *));
- if (!ppAwait)
- goto bail;
-
- pAwait = &(pAwaitUnion+1)->await;
-
- /* "When a client is unblocked, all the CounterNotify events for
- * the Await request are generated contiguously. If count is 0
- * there are no more events to follow for this request. If
- * count is n, there are at least n more events to follow."
- *
- * Thus, it is best to find all the counters for which events
- * need to be sent first, so that an accurate count field can
- * be stored in the events.
- */
- for ( ; numwaits; numwaits--, pAwait++)
- {
- CARD64 diff;
- Bool overflow, diffgreater, diffequal;
-
- /* "A CounterNotify event with the destroyed flag set to TRUE is
- * always generated if the counter for one of the triggers is
- * destroyed."
- */
- if (pAwait->trigger.pSync->beingDestroyed)
- {
- ppAwait[num_events++] = pAwait;
- continue;
- }
-
- if (SYNC_COUNTER == pAwait->trigger.pSync->type)
- {
- SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync;
-
- /* "The difference between the counter and the test value is
- * calculated by subtracting the test value from the value of
- * the counter."
- */
- XSyncValueSubtract(&diff, pCounter->value,
- pAwait->trigger.test_value, &overflow);
-
- /* "If the difference lies outside the range for an INT64, an
- * event is not generated."
- */
- if (overflow)
- continue;
- diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold);
- diffequal = XSyncValueEqual(diff, pAwait->event_threshold);
-
- /* "If the test-type is PositiveTransition or
- * PositiveComparison, a CounterNotify event is generated if
- * the difference is at least event-threshold. If the test-type
- * is NegativeTransition or NegativeComparison, a CounterNotify
- * event is generated if the difference is at most
- * event-threshold."
- */
-
- if ( ((pAwait->trigger.test_type == XSyncPositiveComparison ||
- pAwait->trigger.test_type == XSyncPositiveTransition)
- && (diffgreater || diffequal))
- ||
- ((pAwait->trigger.test_type == XSyncNegativeComparison ||
- pAwait->trigger.test_type == XSyncNegativeTransition)
- && (!diffgreater) /* less or equal */
- )
- )
- {
- ppAwait[num_events++] = pAwait;
- }
- }
- }
- if (num_events)
- SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait,
- num_events);
- free(ppAwait);
-
-bail:
- /* unblock the client */
- AttendClient(pAwaitUnion->header.client);
- /* delete the await */
- FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
-}
-
-
-/* This function should always be used to change a counter's value so that
- * any triggers depending on the counter will be checked.
- */
-void
-SyncChangeCounter(SyncCounter *pCounter, CARD64 newval)
-{
- SyncTriggerList *ptl, *pnext;
- CARD64 oldval;
-
- oldval = pCounter->value;
- pCounter->value = newval;
-
- /* run through triggers to see if any become true */
- for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext)
- {
- pnext = ptl->next;
- if ((*ptl->pTrigger->CheckTrigger)(ptl->pTrigger, oldval))
- (*ptl->pTrigger->TriggerFired)(ptl->pTrigger);
- }
-
- if (IsSystemCounter(pCounter))
- {
- SyncComputeBracketValues(pCounter);
- }
-}
-
-
-/* loosely based on dix/events.c/EventSelectForWindow */
-static Bool
-SyncEventSelectForAlarm(SyncAlarm *pAlarm, ClientPtr client, Bool wantevents)
-{
- SyncAlarmClientList *pClients;
-
- if (client == pAlarm->client) /* alarm owner */
- {
- pAlarm->events = wantevents;
- return Success;
- }
-
- /* see if the client is already on the list (has events selected) */
-
- for (pClients = pAlarm->pEventClients; pClients;
- pClients = pClients->next)
- {
- if (pClients->client == client)
- {
- /* client's presence on the list indicates desire for
- * events. If the client doesn't want events, remove it
- * from the list. If the client does want events, do
- * nothing, since it's already got them.
- */
- if (!wantevents)
- {
- FreeResource(pClients->delete_id, RT_NONE);
- }
- return Success;
- }
- }
-
- /* if we get here, this client does not currently have
- * events selected on the alarm
- */
-
- if (!wantevents)
- /* client doesn't want events, and we just discovered that it
- * doesn't have them, so there's nothing to do.
- */
- return Success;
-
- /* add new client to pAlarm->pEventClients */
-
- pClients = malloc(sizeof(SyncAlarmClientList));
- if (!pClients)
- return BadAlloc;
-
- /* register it as a resource so it will be cleaned up
- * if the client dies
- */
-
- pClients->delete_id = FakeClientID(client->index);
- if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
- {
- free(pClients);
- return BadAlloc;
- }
-
- /* link it into list after we know all the allocations succeed */
-
- pClients->next = pAlarm->pEventClients;
- pAlarm->pEventClients = pClients;
- pClients->client = client;
- return Success;
-}
-
-/*
- * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm
- */
-static int
-SyncChangeAlarmAttributes(ClientPtr client, SyncAlarm *pAlarm, Mask mask,
- CARD32 *values)
-{
- int status;
- XSyncCounter counter;
- Mask origmask = mask;
-
- counter =
- pAlarm->trigger.pSync ? pAlarm->trigger.pSync->id : None;
-
- while (mask)
- {
- int index2 = lowbit(mask);
- mask &= ~index2;
- switch (index2)
- {
- case XSyncCACounter:
- mask &= ~XSyncCACounter;
- /* sanity check in SyncInitTrigger */
- counter = *values++;
- break;
-
- case XSyncCAValueType:
- mask &= ~XSyncCAValueType;
- /* sanity check in SyncInitTrigger */
- pAlarm->trigger.value_type = *values++;
- break;
-
- case XSyncCAValue:
- mask &= ~XSyncCAValue;
- XSyncIntsToValue(&pAlarm->trigger.wait_value, values[1], values[0]);
- values += 2;
- break;
-
- case XSyncCATestType:
- mask &= ~XSyncCATestType;
- /* sanity check in SyncInitTrigger */
- pAlarm->trigger.test_type = *values++;
- break;
-
- case XSyncCADelta:
- mask &= ~XSyncCADelta;
- XSyncIntsToValue(&pAlarm->delta, values[1], values[0]);
- values += 2;
- break;
-
- case XSyncCAEvents:
- mask &= ~XSyncCAEvents;
- if ((*values != xTrue) && (*values != xFalse))
- {
- client->errorValue = *values;
- return BadValue;
- }
- status = SyncEventSelectForAlarm(pAlarm, client,
- (Bool)(*values++));
- if (status != Success)
- return status;
- break;
-
- default:
- client->errorValue = mask;
- return BadValue;
- }
- }
-
- /* "If the test-type is PositiveComparison or PositiveTransition
- * and delta is less than zero, or if the test-type is
- * NegativeComparison or NegativeTransition and delta is
- * greater than zero, a Match error is generated."
- */
- if (origmask & (XSyncCADelta|XSyncCATestType))
- {
- CARD64 zero;
- XSyncIntToValue(&zero, 0);
- if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) ||
- (pAlarm->trigger.test_type == XSyncPositiveTransition))
- && XSyncValueLessThan(pAlarm->delta, zero))
- ||
- (((pAlarm->trigger.test_type == XSyncNegativeComparison) ||
- (pAlarm->trigger.test_type == XSyncNegativeTransition))
- && XSyncValueGreaterThan(pAlarm->delta, zero))
- )
- {
- return BadMatch;
- }
- }
-
- /* postpone this until now, when we're sure nothing else can go wrong */
- if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter,
- origmask & XSyncCAAllTrigger)) != Success)
- return status;
-
- /* XXX spec does not really say to do this - needs clarification */
- pAlarm->state = XSyncAlarmActive;
- return Success;
-}
-
-static SyncObject *
-SyncCreate(ClientPtr client, XID id, unsigned char type)
-{
- SyncObject *pSync;
- RESTYPE resType;
-
- switch (type) {
- case SYNC_COUNTER:
- resType = RTCounter;
- pSync = malloc(sizeof(SyncCounter));
- break;
- case SYNC_FENCE:
- resType = RTFence;
- pSync = dixAllocateObjectWithPrivates(SyncFence,
- PRIVATE_SYNC_FENCE);
- break;
- default:
- return NULL;
- }
-
- if (!pSync)
- return NULL;
-
- if (!AddResource(id, resType, (pointer) pSync))
- {
- switch (type) {
- case SYNC_FENCE:
- dixFreeObjectWithPrivates((SyncFence *)pSync, PRIVATE_SYNC_FENCE);
- break;
- default:
- free(pSync);
- }
-
- return NULL;
- }
-
- pSync->client = client;
- pSync->id = id;
- pSync->pTriglist = NULL;
- pSync->beingDestroyed = FALSE;
- pSync->type = type;
-
- return pSync;
-}
-
-
-static SyncCounter *
-SyncCreateCounter(ClientPtr client, XSyncCounter id, CARD64 initialvalue)
-{
- SyncCounter *pCounter;
-
- if (!(pCounter = (SyncCounter *)SyncCreate(client,
- id,
- SYNC_COUNTER)))
- return NULL;
-
- pCounter->value = initialvalue;
- pCounter->pSysCounterInfo = NULL;
- return pCounter;
-}
-
-static int FreeCounter(void *, XID);
-
-/*
- * ***** System Counter utilities
- */
-
-pointer
-SyncCreateSystemCounter(
- char *name,
- CARD64 initial,
- CARD64 resolution,
- SyncCounterType counterType,
- void (*QueryValue)(pointer /* pCounter */,
- CARD64 * /* pValue_return */),
- void (*BracketValues)(pointer /* pCounter */,
- CARD64 * /* pbracket_less */,
- CARD64 * /* pbracket_greater */)
- )
-{
- SyncCounter *pCounter;
-
- SysCounterList = realloc(SysCounterList,
- (SyncNumSystemCounters+1)*sizeof(SyncCounter *));
- if (!SysCounterList)
- return NULL;
-
- /* this function may be called before SYNC has been initialized, so we
- * have to make sure RTCounter is created.
- */
- if (RTCounter == 0)
- {
- RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
- if (RTCounter == 0)
- {
- return NULL;
- }
- }
-
- pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial);
-
- if (pCounter)
- {
- SysCounterInfo *psci;
-
- psci = malloc(sizeof(SysCounterInfo));
- if (!psci)
- {
- FreeResource(pCounter->sync.id, RT_NONE);
- return pCounter;
- }
- pCounter->pSysCounterInfo = psci;
- psci->name = name;
- psci->resolution = resolution;
- psci->counterType = counterType;
- psci->QueryValue = QueryValue;
- psci->BracketValues = BracketValues;
- XSyncMaxValue(&psci->bracket_greater);
- XSyncMinValue(&psci->bracket_less);
- SysCounterList[SyncNumSystemCounters++] = pCounter;
- }
- return pCounter;
-}
-
-void
-SyncDestroySystemCounter(pointer pSysCounter)
-{
- SyncCounter *pCounter = (SyncCounter *)pSysCounter;
- FreeResource(pCounter->sync.id, RT_NONE);
-}
-
-static void
-SyncComputeBracketValues(SyncCounter *pCounter)
-{
- SyncTriggerList *pCur;
- SyncTrigger *pTrigger;
- SysCounterInfo *psci;
- CARD64 *pnewgtval = NULL;
- CARD64 *pnewltval = NULL;
- SyncCounterType ct;
-
- if (!pCounter)
- return;
-
- psci = pCounter->pSysCounterInfo;
- ct = pCounter->pSysCounterInfo->counterType;
- if (ct == XSyncCounterNeverChanges)
- return;
-
- XSyncMaxValue(&psci->bracket_greater);
- XSyncMinValue(&psci->bracket_less);
-
- for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next)
- {
- pTrigger = pCur->pTrigger;
-
- if (pTrigger->test_type == XSyncPositiveComparison &&
- ct != XSyncCounterNeverIncreases)
- {
- if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
- XSyncValueLessThan(pTrigger->test_value,
- psci->bracket_greater))
- {
- psci->bracket_greater = pTrigger->test_value;
- pnewgtval = &psci->bracket_greater;
- }
- }
- else if (pTrigger->test_type == XSyncNegativeComparison &&
- ct != XSyncCounterNeverDecreases)
- {
- if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
- XSyncValueGreaterThan(pTrigger->test_value,
- psci->bracket_less))
- {
- psci->bracket_less = pTrigger->test_value;
- pnewltval = &psci->bracket_less;
- }
- }
- else if (pTrigger->test_type == XSyncNegativeTransition &&
- ct != XSyncCounterNeverIncreases)
- {
- if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
- XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less))
- {
- psci->bracket_less = pTrigger->test_value;
- pnewltval = &psci->bracket_less;
- }
- }
- else if (pTrigger->test_type == XSyncPositiveTransition &&
- ct != XSyncCounterNeverDecreases)
- {
- if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
- XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater))
- {
- psci->bracket_greater = pTrigger->test_value;
- pnewgtval = &psci->bracket_greater;
- }
- }
- } /* end for each trigger */
-
- if (pnewgtval || pnewltval)
- {
- (*psci->BracketValues)((pointer)pCounter, pnewltval, pnewgtval);
- }
-}
-
-/*
- * ***** Resource delete functions
- */
-
-/* ARGSUSED */
-static int
-FreeAlarm(void *addr, XID id)
-{
- SyncAlarm *pAlarm = (SyncAlarm *) addr;
-
- pAlarm->state = XSyncAlarmDestroyed;
-
- SyncSendAlarmNotifyEvents(pAlarm);
-
- /* delete event selections */
-
- while (pAlarm->pEventClients)
- FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
-
- SyncDeleteTriggerFromSyncObject(&pAlarm->trigger);
-
- free(pAlarm);
- return Success;
-}
-
-
-/*
- * ** Cleanup after the destruction of a Counter
- */
-/* ARGSUSED */
-static int
-FreeCounter(void *env, XID id)
-{
- SyncCounter *pCounter = (SyncCounter *) env;
- SyncTriggerList *ptl, *pnext;
-
- pCounter->sync.beingDestroyed = TRUE;
- /* tell all the counter's triggers that the counter has been destroyed */
- for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext)
- {
- (*ptl->pTrigger->CounterDestroyed)(ptl->pTrigger);
- pnext = ptl->next;
- free(ptl); /* destroy the trigger list as we go */
- }
- if (IsSystemCounter(pCounter))
- {
- int i, found = 0;
-
- free(pCounter->pSysCounterInfo);
-
- /* find the counter in the list of system counters and remove it */
-
- if (SysCounterList)
- {
- for (i = 0; i < SyncNumSystemCounters; i++)
- {
- if (SysCounterList[i] == pCounter)
- {
- found = i;
- break;
- }
- }
- if (found < (SyncNumSystemCounters-1))
- {
- for (i = found; i < SyncNumSystemCounters-1; i++)
- {
- SysCounterList[i] = SysCounterList[i+1];
- }
- }
- }
- SyncNumSystemCounters--;
- }
- free(pCounter);
- return Success;
-}
-
-/*
- * ** Cleanup after Await
- */
-/* ARGSUSED */
-static int
-FreeAwait(void *addr, XID id)
-{
- SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
- SyncAwait *pAwait;
- int numwaits;
-
- pAwait = &(pAwaitUnion+1)->await; /* first await on list */
-
- /* remove triggers from counters */
-
- for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
- numwaits--, pAwait++)
- {
- /* If the counter is being destroyed, FreeCounter will delete
- * the trigger list itself, so don't do it here.
- */
- SyncObject *pSync = pAwait->trigger.pSync;
- if (pSync && !pSync->beingDestroyed)
- SyncDeleteTriggerFromSyncObject(&pAwait->trigger);
- }
- free(pAwaitUnion);
- return Success;
-}
-
-/* loosely based on dix/events.c/OtherClientGone */
-static int
-FreeAlarmClient(void *value, XID id)
-{
- SyncAlarm *pAlarm = (SyncAlarm *)value;
- SyncAlarmClientList *pCur, *pPrev;
-
- for (pPrev = NULL, pCur = pAlarm->pEventClients;
- pCur;
- pPrev = pCur, pCur = pCur->next)
- {
- if (pCur->delete_id == id)
- {
- if (pPrev)
- pPrev->next = pCur->next;
- else
- pAlarm->pEventClients = pCur->next;
- free(pCur);
- return Success;
- }
- }
- FatalError("alarm client not on event list");
- /*NOTREACHED*/
-}
-
-
-/*
- * ***** Proc functions
- */
-
-
-/*
- * ** Initialize the extension
- */
-static int
-ProcSyncInitialize(ClientPtr client)
-{
- xSyncInitializeReply rep;
- int n;
-
- REQUEST_SIZE_MATCH(xSyncInitializeReq);
-
- memset(&rep, 0, sizeof(xSyncInitializeReply));
- rep.type = X_Reply;
- rep.sequenceNumber = client->sequence;
- rep.majorVersion = SERVER_SYNC_MAJOR_VERSION;
- rep.minorVersion = SERVER_SYNC_MINOR_VERSION;
- rep.length = 0;
-
- if (client->swapped)
- {
- swaps(&rep.sequenceNumber, n);
- }
- WriteToClient(client, sizeof(rep), (char *) &rep);
- return Success;
-}
-
-/*
- * ** Get list of system counters available through the extension
- */
-static int
-ProcSyncListSystemCounters(ClientPtr client)
-{
- xSyncListSystemCountersReply rep;
- int i, len;
- xSyncSystemCounter *list = NULL, *walklist = NULL;
-
- REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
-
- rep.type = X_Reply;
- rep.sequenceNumber = client->sequence;
- rep.nCounters = SyncNumSystemCounters;
-
- for (i = len = 0; i < SyncNumSystemCounters; i++)
- {
- char *name = SysCounterList[i]->pSysCounterInfo->name;
- /* pad to 4 byte boundary */
- len += pad_to_int32(sz_xSyncSystemCounter + strlen(name));
- }
-
- if (len)
- {
- walklist = list = malloc(len);
- if (!list)
- return BadAlloc;
- }
-
- rep.length = bytes_to_int32(len);
-
- if (client->swapped)
- {
- char n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swapl(&rep.nCounters, n);
- }
-
- for (i = 0; i < SyncNumSystemCounters; i++)
- {
- int namelen;
- char *pname_in_reply;
- SysCounterInfo *psci = SysCounterList[i]->pSysCounterInfo;
-
- walklist->counter = SysCounterList[i]->sync.id;
- walklist->resolution_hi = XSyncValueHigh32(psci->resolution);
- walklist->resolution_lo = XSyncValueLow32(psci->resolution);
- namelen = strlen(psci->name);
- walklist->name_length = namelen;
-
- if (client->swapped)
- {
- char n;
- swapl(&walklist->counter, n);
- swapl(&walklist->resolution_hi, n);
- swapl(&walklist->resolution_lo, n);
- swaps(&walklist->name_length, n);
- }
-
- pname_in_reply = ((char *)walklist) + sz_xSyncSystemCounter;
- strncpy(pname_in_reply, psci->name, namelen);
- walklist = (xSyncSystemCounter *) (((char *)walklist) +
- pad_to_int32(sz_xSyncSystemCounter + namelen));
- }
-
- WriteToClient(client, sizeof(rep), (char *) &rep);
- if (len)
- {
- WriteToClient(client, len, (char *) list);
- free(list);
- }
-
- return Success;
-}
-
-/*
- * ** Set client Priority
- */
-static int
-ProcSyncSetPriority(ClientPtr client)
-{
- REQUEST(xSyncSetPriorityReq);
- ClientPtr priorityclient;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
-
- if (stuff->id == None)
- priorityclient = client;
- else {
- rc = dixLookupClient(&priorityclient, stuff->id, client,
- DixSetAttrAccess);
- if (rc != Success)
- return rc;
- }
-
- if (priorityclient->priority != stuff->priority)
- {
- priorityclient->priority = stuff->priority;
-
- /* The following will force the server back into WaitForSomething
- * so that the change in this client's priority is immediately
- * reflected.
- */
- isItTimeToYield = TRUE;
- dispatchException |= DE_PRIORITYCHANGE;
- }
- return Success;
-}
-
-/*
- * ** Get client Priority
- */
-static int
-ProcSyncGetPriority(ClientPtr client)
-{
- REQUEST(xSyncGetPriorityReq);
- xSyncGetPriorityReply rep;
- ClientPtr priorityclient;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
-
- if (stuff->id == None)
- priorityclient = client;
- else {
- rc = dixLookupClient(&priorityclient, stuff->id, client,
- DixGetAttrAccess);
- if (rc != Success)
- return rc;
- }
-
- rep.type = X_Reply;
- rep.length = 0;
- rep.sequenceNumber = client->sequence;
- rep.priority = priorityclient->priority;
-
- if (client->swapped)
- {
- char n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.priority, n);
- }
-
- WriteToClient(client, sizeof(xSyncGetPriorityReply), (char *) &rep);
-
- return Success;
-}
-
-/*
- * ** Create a new counter
- */
-static int
-ProcSyncCreateCounter(ClientPtr client)
-{
- REQUEST(xSyncCreateCounterReq);
- CARD64 initial;
-
- REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
-
- LEGAL_NEW_RESOURCE(stuff->cid, client);
-
- XSyncIntsToValue(&initial, stuff->initial_value_lo, stuff->initial_value_hi);
- if (!SyncCreateCounter(client, stuff->cid, initial))
- return BadAlloc;
-
- return Success;
-}
-
-/*
- * ** Set Counter value
- */
-static int
-ProcSyncSetCounter(ClientPtr client)
-{
- REQUEST(xSyncSetCounterReq);
- SyncCounter *pCounter;
- CARD64 newvalue;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncSetCounterReq);
-
- rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
- client, DixWriteAccess);
- if (rc != Success)
- return rc;
-
- if (IsSystemCounter(pCounter))
- {
- client->errorValue = stuff->cid;
- return BadAccess;
- }
-
- XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
- SyncChangeCounter(pCounter, newvalue);
- return Success;
-}
-
-/*
- * ** Change Counter value
- */
-static int
-ProcSyncChangeCounter(ClientPtr client)
-{
- REQUEST(xSyncChangeCounterReq);
- SyncCounter *pCounter;
- CARD64 newvalue;
- Bool overflow;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
-
- rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
- client, DixWriteAccess);
- if (rc != Success)
- return rc;
-
- if (IsSystemCounter(pCounter))
- {
- client->errorValue = stuff->cid;
- return BadAccess;
- }
-
- XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
- XSyncValueAdd(&newvalue, pCounter->value, newvalue, &overflow);
- if (overflow)
- {
- /* XXX 64 bit value can't fit in 32 bits; do the best we can */
- client->errorValue = stuff->value_hi;
- return BadValue;
- }
- SyncChangeCounter(pCounter, newvalue);
- return Success;
-}
-
-/*
- * ** Destroy a counter
- */
-static int
-ProcSyncDestroyCounter(ClientPtr client)
-{
- REQUEST(xSyncDestroyCounterReq);
- SyncCounter *pCounter;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
-
- rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter, RTCounter,
- client, DixDestroyAccess);
- if (rc != Success)
- return rc;
-
- if (IsSystemCounter(pCounter))
- {
- client->errorValue = stuff->counter;
- return BadAccess;
- }
- FreeResource(pCounter->sync.id, RT_NONE);
- return Success;
-}
-
-static SyncAwaitUnion*
-SyncAwaitPrologue(ClientPtr client, int items)
-{
- SyncAwaitUnion *pAwaitUnion;
-
- /* all the memory for the entire await list is allocated
- * here in one chunk
- */
- pAwaitUnion = malloc((items+1) * sizeof(SyncAwaitUnion));
- if (!pAwaitUnion)
- return NULL;
-
- /* first item is the header, remainder are real wait conditions */
-
- pAwaitUnion->header.delete_id = FakeClientID(client->index);
- if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
- {
- free(pAwaitUnion);
- return NULL;
- }
-
- pAwaitUnion->header.client = client;
- pAwaitUnion->header.num_waitconditions = 0;
-
- return pAwaitUnion;
-}
-
-static void
-SyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion *pAwaitUnion)
-{
- SyncAwait *pAwait;
- int i;
-
- IgnoreClient(client);
-
- /* see if any of the triggers are already true */
-
- pAwait = &(pAwaitUnion+1)->await; /* skip over header */
- for (i = 0; i < items; i++, pAwait++)
- {
- CARD64 value;
-
- /* don't have to worry about NULL counters because the request
- * errors before we get here out if they occur
- */
- switch (pAwait->trigger.pSync->type) {
- case SYNC_COUNTER:
- value = ((SyncCounter *)pAwait->trigger.pSync)->value;
- break;
- default:
- XSyncIntToValue(&value, 0);
- }
-
- if ((*pAwait->trigger.CheckTrigger)(&pAwait->trigger, value))
- {
- (*pAwait->trigger.TriggerFired)(&pAwait->trigger);
- break; /* once is enough */
- }
- }
-}
-
-/*
- * ** Await
- */
-static int
-ProcSyncAwait(ClientPtr client)
-{
- REQUEST(xSyncAwaitReq);
- int len, items;
- int i;
- xSyncWaitCondition *pProtocolWaitConds;
- SyncAwaitUnion *pAwaitUnion;
- SyncAwait *pAwait;
- int status;
-
- REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
-
- len = client->req_len << 2;
- len -= sz_xSyncAwaitReq;
- items = len / sz_xSyncWaitCondition;
-
- if (items * sz_xSyncWaitCondition != len)
- {
- return BadLength;
- }
- if (items == 0)
- {
- client->errorValue = items; /* XXX protocol change */
- return BadValue;
- }
-
- if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
- return BadAlloc;
-
- /* don't need to do any more memory allocation for this request! */
-
- pProtocolWaitConds = (xSyncWaitCondition *) & stuff[1];
-
- pAwait = &(pAwaitUnion+1)->await; /* skip over header */
- for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++)
- {
- if (pProtocolWaitConds->counter == None) /* XXX protocol change */
- {
- /* this should take care of removing any triggers created by
- * this request that have already been registered on sync objects
- */
- FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
- client->errorValue = pProtocolWaitConds->counter;
- return SyncErrorBase + XSyncBadCounter;
- }
-
- /* sanity checks are in SyncInitTrigger */
- pAwait->trigger.pSync = NULL;
- pAwait->trigger.value_type = pProtocolWaitConds->value_type;
- XSyncIntsToValue(&pAwait->trigger.wait_value,
- pProtocolWaitConds->wait_value_lo,
- pProtocolWaitConds->wait_value_hi);
- pAwait->trigger.test_type = pProtocolWaitConds->test_type;
-
- status = SyncInitTrigger(client, &pAwait->trigger,
- pProtocolWaitConds->counter, RTCounter,
- XSyncCAAllTrigger);
- if (status != Success)
- {
- /* this should take care of removing any triggers created by
- * this request that have already been registered on sync objects
- */
- FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
- return status;
- }
- /* this is not a mistake -- same function works for both cases */
- pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
- pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
- XSyncIntsToValue(&pAwait->event_threshold,
- pProtocolWaitConds->event_threshold_lo,
- pProtocolWaitConds->event_threshold_hi);
- pAwait->pHeader = &pAwaitUnion->header;
- pAwaitUnion->header.num_waitconditions++;
- }
-
- SyncAwaitEpilogue(client, items, pAwaitUnion);
-
- return Success;
-}
-
-
-/*
- * ** Query a counter
- */
-static int
-ProcSyncQueryCounter(ClientPtr client)
-{
- REQUEST(xSyncQueryCounterReq);
- xSyncQueryCounterReply rep;
- SyncCounter *pCounter;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
-
- rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter,
- RTCounter, client, DixReadAccess);
- if (rc != Success)
- return rc;
-
- rep.type = X_Reply;
- rep.length = 0;
- rep.sequenceNumber = client->sequence;
-
- /* if system counter, ask it what the current value is */
-
- if (IsSystemCounter(pCounter))
- {
- (*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
- &pCounter->value);
- }
-
- rep.value_hi = XSyncValueHigh32(pCounter->value);
- rep.value_lo = XSyncValueLow32(pCounter->value);
- if (client->swapped)
- {
- char n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swapl(&rep.value_hi, n);
- swapl(&rep.value_lo, n);
- }
- WriteToClient(client, sizeof(xSyncQueryCounterReply), (char *) &rep);
- return Success;
-}
-
-
-/*
- * ** Create Alarm
- */
-static int
-ProcSyncCreateAlarm(ClientPtr client)
-{
- REQUEST(xSyncCreateAlarmReq);
- SyncAlarm *pAlarm;
- int status;
- unsigned long len, vmask;
- SyncTrigger *pTrigger;
-
- REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
-
- LEGAL_NEW_RESOURCE(stuff->id, client);
-
- vmask = stuff->valueMask;
- len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq));
- /* the "extra" call to Ones accounts for the presence of 64 bit values */
- if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
- return BadLength;
-
- if (!(pAlarm = malloc(sizeof(SyncAlarm))))
- {
- return BadAlloc;
- }
-
- /* set up defaults */
-
- pTrigger = &pAlarm->trigger;
- pTrigger->pSync = NULL;
- pTrigger->value_type = XSyncAbsolute;
- XSyncIntToValue(&pTrigger->wait_value, 0L);
- pTrigger->test_type = XSyncPositiveComparison;
- pTrigger->TriggerFired = SyncAlarmTriggerFired;
- pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed;
- status = SyncInitTrigger(client, pTrigger, None, RTCounter,
- XSyncCAAllTrigger);
- if (status != Success)
- {
- free(pAlarm);
- return status;
- }
-
- pAlarm->client = client;
- pAlarm->alarm_id = stuff->id;
- XSyncIntToValue(&pAlarm->delta, 1L);
- pAlarm->events = TRUE;
- pAlarm->state = XSyncAlarmInactive;
- pAlarm->pEventClients = NULL;
- status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
- (CARD32 *)&stuff[1]);
- if (status != Success)
- {
- free(pAlarm);
- return status;
- }
-
- if (!AddResource(stuff->id, RTAlarm, pAlarm))
- {
- free(pAlarm);
- return BadAlloc;
- }
-
- /* see if alarm already triggered. NULL counter will not trigger
- * in CreateAlarm and sets alarm state to Inactive.
- */
-
- if (!pTrigger->pSync)
- {
- pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */
- }
- else
- {
- SyncCounter *pCounter;
-
- assert(SYNC_COUNTER == pTrigger->pSync->type);
- pCounter = (SyncCounter *)pTrigger->pSync;
-
- if ((*pTrigger->CheckTrigger)(pTrigger, pCounter->value))
- (*pTrigger->TriggerFired)(pTrigger);
- }
-
- return Success;
-}
-
-/*
- * ** Change Alarm
- */
-static int
-ProcSyncChangeAlarm(ClientPtr client)
-{
- REQUEST(xSyncChangeAlarmReq);
- SyncAlarm *pAlarm;
- SyncCounter *pCounter = NULL;
- long vmask;
- int len, status;
-
- REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
-
- status = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
- client, DixWriteAccess);
- if (status != Success)
- return status;
-
- vmask = stuff->valueMask;
- len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq));
- /* the "extra" call to Ones accounts for the presence of 64 bit values */
- if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
- return BadLength;
-
- if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
- (CARD32 *)&stuff[1])) != Success)
- return status;
-
- if (pAlarm->trigger.pSync)
- {
- assert(SYNC_COUNTER == pAlarm->trigger.pSync->type);
- pCounter = (SyncCounter *)pAlarm->trigger.pSync;
- }
-
- /* see if alarm already triggered. NULL counter WILL trigger
- * in ChangeAlarm.
- */
-
- if (!pCounter ||
- (*pAlarm->trigger.CheckTrigger)(&pAlarm->trigger, pCounter->value))
- {
- (*pAlarm->trigger.TriggerFired)(&pAlarm->trigger);
- }
- return Success;
-}
-
-static int
-ProcSyncQueryAlarm(ClientPtr client)
-{
- REQUEST(xSyncQueryAlarmReq);
- SyncAlarm *pAlarm;
- xSyncQueryAlarmReply rep;
- SyncTrigger *pTrigger;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
-
- rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
- client, DixReadAccess);
- if (rc != Success)
- return rc;
-
- rep.type = X_Reply;
- rep.length = bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply));
- rep.sequenceNumber = client->sequence;
-
- pTrigger = &pAlarm->trigger;
- rep.counter = (pTrigger->pSync) ? pTrigger->pSync->id : None;
-
-#if 0 /* XXX unclear what to do, depends on whether relative value-types
- * are "consumed" immediately and are considered absolute from then
- * on.
- */
- rep.value_type = pTrigger->value_type;
- rep.wait_value_hi = XSyncValueHigh32(pTrigger->wait_value);
- rep.wait_value_lo = XSyncValueLow32(pTrigger->wait_value);
-#else
- rep.value_type = XSyncAbsolute;
- rep.wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
- rep.wait_value_lo = XSyncValueLow32(pTrigger->test_value);
-#endif
-
- rep.test_type = pTrigger->test_type;
- rep.delta_hi = XSyncValueHigh32(pAlarm->delta);
- rep.delta_lo = XSyncValueLow32(pAlarm->delta);
- rep.events = pAlarm->events;
- rep.state = pAlarm->state;
-
- if (client->swapped)
- {
- char n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swapl(&rep.counter, n);
- swapl(&rep.wait_value_hi, n);
- swapl(&rep.wait_value_lo, n);
- swapl(&rep.test_type, n);
- swapl(&rep.delta_hi, n);
- swapl(&rep.delta_lo, n);
- }
-
- WriteToClient(client, sizeof(xSyncQueryAlarmReply), (char *) &rep);
- return Success;
-}
-
-static int
-ProcSyncDestroyAlarm(ClientPtr client)
-{
- SyncAlarm *pAlarm;
- int rc;
- REQUEST(xSyncDestroyAlarmReq);
-
- REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
-
- rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
- client, DixDestroyAccess);
- if (rc != Success)
- return rc;
-
- FreeResource(stuff->alarm, RT_NONE);
- return Success;
-}
-
-static int
-ProcSyncCreateFence(ClientPtr client)
-{
- REQUEST(xSyncCreateFenceReq);
- DrawablePtr pDraw;
- SyncFence *pFence;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
-
- rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess);
- if (rc != Success)
- return rc;
-
- LEGAL_NEW_RESOURCE(stuff->fid, client);
-
- if (!(pFence = (SyncFence *)SyncCreate(client,
- stuff->fid,
- SYNC_FENCE)))
- return BadAlloc;
-
- miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered);
-
- return client->noClientException;
-}
-
-static int
-FreeFence(void *obj, XID id)
-{
- SyncFence *pFence = (SyncFence *) obj;
-
- miSyncDestroyFence(pFence);
-
- return Success;
-}
-
-int SyncVerifyFence(SyncFence **ppSyncFence, XID fid,
- ClientPtr client, Mask mode)
-{
- int rc = dixLookupResourceByType((pointer *)ppSyncFence, fid, RTFence,
- client, mode);
-
- if (rc != Success)
- client->errorValue = fid;
-
- return rc;
-}
-
-static int
-ProcSyncTriggerFence(ClientPtr client)
-{
- REQUEST(xSyncTriggerFenceReq);
- SyncFence *pFence;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
-
- rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
- client, DixWriteAccess);
- if (rc != Success)
- return rc;
-
- miSyncTriggerFence(pFence);
-
- return client->noClientException;
-}
-
-static int
-ProcSyncResetFence(ClientPtr client)
-{
- REQUEST(xSyncResetFenceReq);
- SyncFence *pFence;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncResetFenceReq);
-
- rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
- client, DixWriteAccess);
- if (rc != Success)
- return rc;
-
- if (pFence->funcs.CheckTriggered(pFence) != TRUE)
- return BadMatch;
-
- pFence->funcs.Reset(pFence);
-
- return client->noClientException;
-}
-
-static int
-ProcSyncDestroyFence(ClientPtr client)
-{
- REQUEST(xSyncDestroyFenceReq);
- SyncFence *pFence;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
-
- rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
- client, DixDestroyAccess);
- if (rc != Success)
- return rc;
-
- FreeResource(stuff->fid, RT_NONE);
- return client->noClientException;
-}
-
-static int
-ProcSyncQueryFence(ClientPtr client)
-{
- REQUEST(xSyncQueryFenceReq);
- xSyncQueryFenceReply rep;
- SyncFence *pFence;
- int rc;
-
- REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
-
- rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid,
- RTFence, client, DixReadAccess);
- if (rc != Success)
- return rc;
-
- rep.type = X_Reply;
- rep.length = 0;
- rep.sequenceNumber = client->sequence;
-
- rep.triggered = pFence->funcs.CheckTriggered(pFence);
-
- if (client->swapped)
- {
- char n;
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- }
-
- WriteToClient(client, sizeof(xSyncQueryFenceReply), (char *) &rep);
- return client->noClientException;
-}
-
-static int
-ProcSyncAwaitFence(ClientPtr client)
-{
- REQUEST(xSyncAwaitFenceReq);
- SyncAwaitUnion *pAwaitUnion;
- SyncAwait *pAwait;
- /* Use CARD32 rather than XSyncFence because XIDs are hard-coded to
- * CARD32 in protocol definitions */
- CARD32 *pProtocolFences;
- int status;
- int len;
- int items;
- int i;
-
- REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
-
- len = client->req_len << 2;
- len -= sz_xSyncAwaitFenceReq;
- items = len / sizeof(CARD32);
-
- if (items * sizeof(CARD32) != len)
- {
- return BadLength;
- }
- if (items == 0)
- {
- client->errorValue = items; /* XXX protocol change */
- return BadValue;
- }
-
- if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
- return BadAlloc;
-
- /* don't need to do any more memory allocation for this request! */
-
- pProtocolFences = (CARD32 *) & stuff[1];
-
- pAwait = &(pAwaitUnion+1)->await; /* skip over header */
- for (i = 0; i < items; i++, pProtocolFences++, pAwait++)
- {
- if (*pProtocolFences == None) /* XXX protocol change */
- {
- /* this should take care of removing any triggers created by
- * this request that have already been registered on sync objects
- */
- FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
- client->errorValue = *pProtocolFences;
- return SyncErrorBase + XSyncBadCounter;
- }
-
- pAwait->trigger.pSync = NULL;
- /* Provide acceptable values for these unused fields to
- * satisfy SyncInitTrigger's validation logic
- */
- pAwait->trigger.value_type = XSyncAbsolute;
- XSyncIntToValue(&pAwait->trigger.wait_value, 0);
- pAwait->trigger.test_type = 0;
-
- status = SyncInitTrigger(client, &pAwait->trigger,
- *pProtocolFences, RTFence,
- XSyncCAAllTrigger);
- if (status != Success)
- {
- /* this should take care of removing any triggers created by
- * this request that have already been registered on sync objects
- */
- FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
- return status;
- }
- /* this is not a mistake -- same function works for both cases */
- pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
- pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
- /* event_threshold is unused for fence syncs */
- XSyncIntToValue(&pAwait->event_threshold, 0);
- pAwait->pHeader = &pAwaitUnion->header;
- pAwaitUnion->header.num_waitconditions++;
- }
-
- SyncAwaitEpilogue(client, items, pAwaitUnion);
-
- return client->noClientException;
-}
-
-/*
- * ** Given an extension request, call the appropriate request procedure
- */
-static int
-ProcSyncDispatch(ClientPtr client)
-{
- REQUEST(xReq);
-
- switch (stuff->data)
- {
- case X_SyncInitialize:
- return ProcSyncInitialize(client);
- case X_SyncListSystemCounters:
- return ProcSyncListSystemCounters(client);
- case X_SyncCreateCounter:
- return ProcSyncCreateCounter(client);
- case X_SyncSetCounter:
- return ProcSyncSetCounter(client);
- case X_SyncChangeCounter:
- return ProcSyncChangeCounter(client);
- case X_SyncQueryCounter:
- return ProcSyncQueryCounter(client);
- case X_SyncDestroyCounter:
- return ProcSyncDestroyCounter(client);
- case X_SyncAwait:
- return ProcSyncAwait(client);
- case X_SyncCreateAlarm:
- return ProcSyncCreateAlarm(client);
- case X_SyncChangeAlarm:
- return ProcSyncChangeAlarm(client);
- case X_SyncQueryAlarm:
- return ProcSyncQueryAlarm(client);
- case X_SyncDestroyAlarm:
- return ProcSyncDestroyAlarm(client);
- case X_SyncSetPriority:
- return ProcSyncSetPriority(client);
- case X_SyncGetPriority:
- return ProcSyncGetPriority(client);
- case X_SyncCreateFence:
- return ProcSyncCreateFence(client);
- case X_SyncTriggerFence:
- return ProcSyncTriggerFence(client);
- case X_SyncResetFence:
- return ProcSyncResetFence(client);
- case X_SyncDestroyFence:
- return ProcSyncDestroyFence(client);
- case X_SyncQueryFence:
- return ProcSyncQueryFence(client);
- case X_SyncAwaitFence:
- return ProcSyncAwaitFence(client);
- default:
- return BadRequest;
- }
-}
-
-/*
- * Boring Swapping stuff ...
- */
-
-static int
-SProcSyncInitialize(ClientPtr client)
-{
- REQUEST(xSyncInitializeReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncInitializeReq);
-
- return ProcSyncInitialize(client);
-}
-
-static int
-SProcSyncListSystemCounters(ClientPtr client)
-{
- REQUEST(xSyncListSystemCountersReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncListSystemCountersReq);
-
- return ProcSyncListSystemCounters(client);
-}
-
-static int
-SProcSyncCreateCounter(ClientPtr client)
-{
- REQUEST(xSyncCreateCounterReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncCreateCounterReq);
- swapl(&stuff->cid, n);
- swapl(&stuff->initial_value_lo, n);
- swapl(&stuff->initial_value_hi, n);
-
- return ProcSyncCreateCounter(client);
-}
-
-static int
-SProcSyncSetCounter(ClientPtr client)
-{
- REQUEST(xSyncSetCounterReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncSetCounterReq);
- swapl(&stuff->cid, n);
- swapl(&stuff->value_lo, n);
- swapl(&stuff->value_hi, n);
-
- return ProcSyncSetCounter(client);
-}
-
-static int
-SProcSyncChangeCounter(ClientPtr client)
-{
- REQUEST(xSyncChangeCounterReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncChangeCounterReq);
- swapl(&stuff->cid, n);
- swapl(&stuff->value_lo, n);
- swapl(&stuff->value_hi, n);
-
- return ProcSyncChangeCounter(client);
-}
-
-static int
-SProcSyncQueryCounter(ClientPtr client)
-{
- REQUEST(xSyncQueryCounterReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncQueryCounterReq);
- swapl(&stuff->counter, n);
-
- return ProcSyncQueryCounter(client);
-}
-
-static int
-SProcSyncDestroyCounter(ClientPtr client)
-{
- REQUEST(xSyncDestroyCounterReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncDestroyCounterReq);
- swapl(&stuff->counter, n);
-
- return ProcSyncDestroyCounter(client);
-}
-
-static int
-SProcSyncAwait(ClientPtr client)
-{
- REQUEST(xSyncAwaitReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
- SwapRestL(stuff);
-
- return ProcSyncAwait(client);
-}
-
-static int
-SProcSyncCreateAlarm(ClientPtr client)
-{
- REQUEST(xSyncCreateAlarmReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
- swapl(&stuff->id, n);
- swapl(&stuff->valueMask, n);
- SwapRestL(stuff);
-
- return ProcSyncCreateAlarm(client);
-}
-
-static int
-SProcSyncChangeAlarm(ClientPtr client)
-{
- REQUEST(xSyncChangeAlarmReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
- swapl(&stuff->alarm, n);
- swapl(&stuff->valueMask, n);
- SwapRestL(stuff);
- return ProcSyncChangeAlarm(client);
-}
-
-static int
-SProcSyncQueryAlarm(ClientPtr client)
-{
- REQUEST(xSyncQueryAlarmReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncQueryAlarmReq);
- swapl(&stuff->alarm, n);
-
- return ProcSyncQueryAlarm(client);
-}
-
-static int
-SProcSyncDestroyAlarm(ClientPtr client)
-{
- REQUEST(xSyncDestroyAlarmReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncDestroyAlarmReq);
- swapl(&stuff->alarm, n);
-
- return ProcSyncDestroyAlarm(client);
-}
-
-static int
-SProcSyncSetPriority(ClientPtr client)
-{
- REQUEST(xSyncSetPriorityReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncSetPriorityReq);
- swapl(&stuff->id, n);
- swapl(&stuff->priority, n);
-
- return ProcSyncSetPriority(client);
-}
-
-static int
-SProcSyncGetPriority(ClientPtr client)
-{
- REQUEST(xSyncGetPriorityReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncGetPriorityReq);
- swapl(&stuff->id, n);
-
- return ProcSyncGetPriority(client);
-}
-
-static int
-SProcSyncCreateFence(ClientPtr client)
-{
- REQUEST(xSyncCreateFenceReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncCreateFenceReq);
- swapl(&stuff->fid, n);
-
- return ProcSyncCreateFence(client);
-}
-
-static int
-SProcSyncTriggerFence(ClientPtr client)
-{
- REQUEST(xSyncTriggerFenceReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncTriggerFenceReq);
- swapl(&stuff->fid, n);
-
- return ProcSyncTriggerFence(client);
-}
-
-static int
-SProcSyncResetFence(ClientPtr client)
-{
- REQUEST(xSyncResetFenceReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncResetFenceReq);
- swapl(&stuff->fid, n);
-
- return ProcSyncResetFence(client);
-}
-
-static int
-SProcSyncDestroyFence(ClientPtr client)
-{
- REQUEST(xSyncDestroyFenceReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncDestroyFenceReq);
- swapl(&stuff->fid, n);
-
- return ProcSyncDestroyFence(client);
-}
-
-static int
-SProcSyncQueryFence(ClientPtr client)
-{
- REQUEST(xSyncQueryFenceReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_SIZE_MATCH (xSyncQueryFenceReq);
- swapl(&stuff->fid, n);
-
- return ProcSyncQueryFence(client);
-}
-
-static int
-SProcSyncAwaitFence(ClientPtr client)
-{
- REQUEST(xSyncAwaitFenceReq);
- char n;
-
- swaps(&stuff->length, n);
- REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
- SwapRestL(stuff);
-
- return ProcSyncAwaitFence(client);
-}
-
-static int
-SProcSyncDispatch(ClientPtr client)
-{
- REQUEST(xReq);
-
- switch (stuff->data)
- {
- case X_SyncInitialize:
- return SProcSyncInitialize(client);
- case X_SyncListSystemCounters:
- return SProcSyncListSystemCounters(client);
- case X_SyncCreateCounter:
- return SProcSyncCreateCounter(client);
- case X_SyncSetCounter:
- return SProcSyncSetCounter(client);
- case X_SyncChangeCounter:
- return SProcSyncChangeCounter(client);
- case X_SyncQueryCounter:
- return SProcSyncQueryCounter(client);
- case X_SyncDestroyCounter:
- return SProcSyncDestroyCounter(client);
- case X_SyncAwait:
- return SProcSyncAwait(client);
- case X_SyncCreateAlarm:
- return SProcSyncCreateAlarm(client);
- case X_SyncChangeAlarm:
- return SProcSyncChangeAlarm(client);
- case X_SyncQueryAlarm:
- return SProcSyncQueryAlarm(client);
- case X_SyncDestroyAlarm:
- return SProcSyncDestroyAlarm(client);
- case X_SyncSetPriority:
- return SProcSyncSetPriority(client);
- case X_SyncGetPriority:
- return SProcSyncGetPriority(client);
- case X_SyncCreateFence:
- return SProcSyncCreateFence(client);
- case X_SyncTriggerFence:
- return SProcSyncTriggerFence(client);
- case X_SyncResetFence:
- return SProcSyncResetFence(client);
- case X_SyncDestroyFence:
- return SProcSyncDestroyFence(client);
- case X_SyncQueryFence:
- return SProcSyncQueryFence(client);
- case X_SyncAwaitFence:
- return SProcSyncAwaitFence(client);
- default:
- return BadRequest;
- }
-}
-
-/*
- * Event Swapping
- */
-
-static void
-SCounterNotifyEvent(xSyncCounterNotifyEvent *from, xSyncCounterNotifyEvent *to)
-{
- to->type = from->type;
- to->kind = from->kind;
- cpswaps(from->sequenceNumber, to->sequenceNumber);
- cpswapl(from->counter, to->counter);
- cpswapl(from->wait_value_lo, to->wait_value_lo);
- cpswapl(from->wait_value_hi, to->wait_value_hi);
- cpswapl(from->counter_value_lo, to->counter_value_lo);
- cpswapl(from->counter_value_hi, to->counter_value_hi);
- cpswapl(from->time, to->time);
- cpswaps(from->count, to->count);
- to->destroyed = from->destroyed;
-}
-
-
-static void
-SAlarmNotifyEvent(xSyncAlarmNotifyEvent *from, xSyncAlarmNotifyEvent *to)
-{
- to->type = from->type;
- to->kind = from->kind;
- cpswaps(from->sequenceNumber, to->sequenceNumber);
- cpswapl(from->alarm, to->alarm);
- cpswapl(from->counter_value_lo, to->counter_value_lo);
- cpswapl(from->counter_value_hi, to->counter_value_hi);
- cpswapl(from->alarm_value_lo, to->alarm_value_lo);
- cpswapl(from->alarm_value_hi, to->alarm_value_hi);
- cpswapl(from->time, to->time);
- to->state = from->state;
-}
-
-/*
- * ** Close everything down. ** This is fairly simple for now.
- */
-/* ARGSUSED */
-static void
-SyncResetProc(ExtensionEntry *extEntry)
-{
- free(SysCounterList);
- SysCounterList = NULL;
- RTCounter = 0;
-}
-
-/*
- * ** Initialise the extension.
- */
-void
-SyncExtensionInit(void)
-{
- ExtensionEntry *extEntry;
- int s;
-
- for (s = 0; s < screenInfo.numScreens; s++)
- miSyncSetup(screenInfo.screens[s]);
-
- if (RTCounter == 0)
- {
- RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
- }
- RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm");
- RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait");
- RTFence = CreateNewResourceType(FreeFence, "SyncFence");
- if (RTAwait)
- RTAwait |= RC_NEVERRETAIN;
- RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient");
- if (RTAlarmClient)
- RTAlarmClient |= RC_NEVERRETAIN;
-
- if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 ||
- RTAlarmClient == 0 ||
- (extEntry = AddExtension(SYNC_NAME,
- XSyncNumberEvents, XSyncNumberErrors,
- ProcSyncDispatch, SProcSyncDispatch,
- SyncResetProc,
- StandardMinorOpcode)) == NULL)
- {
- ErrorF("Sync Extension %d.%d failed to Initialise\n",
- SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
- return;
- }
-
- SyncEventBase = extEntry->eventBase;
- SyncErrorBase = extEntry->errorBase;
- EventSwapVector[SyncEventBase + XSyncCounterNotify] = (EventSwapPtr) SCounterNotifyEvent;
- EventSwapVector[SyncEventBase + XSyncAlarmNotify] = (EventSwapPtr) SAlarmNotifyEvent;
-
- SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter);
- SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm);
- SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence);
-
- /*
- * Although SERVERTIME is implemented by the OS layer, we initialise it
- * here because doing it in OsInit() is too early. The resource database
- * is not initialised when OsInit() is called. This is just about OK
- * because there is always a servertime counter.
- */
- SyncInitServerTime();
- SyncInitIdleTime();
-
-#ifdef DEBUG
- fprintf(stderr, "Sync Extension %d.%d\n",
- SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
-#endif
-}
-
-
-/*
- * ***** SERVERTIME implementation - should go in its own file in OS directory?
- */
-
-
-
-static pointer ServertimeCounter;
-static XSyncValue Now;
-static XSyncValue *pnext_time;
-
-#define GetTime()\
-{\
- unsigned long millis = GetTimeInMillis();\
- unsigned long maxis = XSyncValueHigh32(Now);\
- if (millis < XSyncValueLow32(Now)) maxis++;\
- XSyncIntsToValue(&Now, millis, maxis);\
-}
-
-/*
-*** Server Block Handler
-*** code inspired by multibuffer extension (now deprecated)
- */
-/*ARGSUSED*/
-static void
-ServertimeBlockHandler(void *env, struct timeval **wt, void *LastSelectMask)
-{
- XSyncValue delay;
- unsigned long timeout;
-
- if (pnext_time)
- {
- GetTime();
-
- if (XSyncValueGreaterOrEqual(Now, *pnext_time))
- {
- timeout = 0;
- }
- else
- {
- Bool overflow;
- XSyncValueSubtract(&delay, *pnext_time, Now, &overflow);
- (void)overflow;
- timeout = XSyncValueLow32(delay);
- }
- AdjustWaitForDelay(wt, timeout); /* os/utils.c */
- }
-}
-
-/*
-*** Wakeup Handler
- */
-/*ARGSUSED*/
-static void
-ServertimeWakeupHandler(void *env, int rc, void *LastSelectMask)
-{
- if (pnext_time)
- {
- GetTime();
-
- if (XSyncValueGreaterOrEqual(Now, *pnext_time))
- {
- SyncChangeCounter(ServertimeCounter, Now);
- }
- }
-}
-
-static void
-ServertimeQueryValue(void *pCounter, CARD64 *pValue_return)
-{
- GetTime();
- *pValue_return = Now;
-}
-
-static void
-ServertimeBracketValues(void *pCounter, CARD64 *pbracket_less,
- CARD64 *pbracket_greater)
-{
- if (!pnext_time && pbracket_greater)
- {
- RegisterBlockAndWakeupHandlers(ServertimeBlockHandler,
- ServertimeWakeupHandler,
- NULL);
- }
- else if (pnext_time && !pbracket_greater)
- {
- RemoveBlockAndWakeupHandlers(ServertimeBlockHandler,
- ServertimeWakeupHandler,
- NULL);
- }
- pnext_time = pbracket_greater;
-}
-
-static void
-SyncInitServerTime(void)
-{
- CARD64 resolution;
-
- XSyncIntsToValue(&Now, GetTimeInMillis(), 0);
- XSyncIntToValue(&resolution, 4);
- ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
- XSyncCounterNeverDecreases,
- ServertimeQueryValue, ServertimeBracketValues);
- pnext_time = NULL;
-}
-
-
-
-/*
- * IDLETIME implementation
- */
-
-static SyncCounter *IdleTimeCounter;
-static XSyncValue *pIdleTimeValueLess;
-static XSyncValue *pIdleTimeValueGreater;
-
-static void
-IdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return)
-{
- CARD32 idle = GetTimeInMillis() - lastDeviceEventTime.milliseconds;
- XSyncIntsToValue (pValue_return, idle, 0);
-}
-
-static void
-IdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask)
-{
- XSyncValue idle, old_idle;
- SyncTriggerList *list = IdleTimeCounter->sync.pTriglist;
- SyncTrigger *trig;
-
- if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
- return;
-
- old_idle = IdleTimeCounter->value;
- IdleTimeQueryValue (NULL, &idle);
- IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
-
- if (pIdleTimeValueLess &&
- XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))
- {
- /*
- * We've been idle for less than the threshold value, and someone
- * wants to know about that, but now we need to know whether they
- * want level or edge trigger. Check the trigger list against the
- * current idle time, and if any succeed, bomb out of select()
- * immediately so we can reschedule.
- */
-
- for (list = IdleTimeCounter->sync.pTriglist; list; list = list->next) {
- trig = list->pTrigger;
- if (trig->CheckTrigger(trig, old_idle)) {
- AdjustWaitForDelay(wt, 0);
- break;
- }
- }
- }
- else if (pIdleTimeValueGreater)
- {
- /*
- * There's a threshold in the positive direction. If we've been
- * idle less than it, schedule a wakeup for sometime in the future.
- * If we've been idle more than it, and someone wants to know about
- * that level-triggered, schedule an immediate wakeup.
- */
- unsigned long timeout = -1;
-
- if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) {
- XSyncValue value;
- Bool overflow;
-
- XSyncValueSubtract (&value, *pIdleTimeValueGreater,
- idle, &overflow);
- timeout = min(timeout, XSyncValueLow32 (value));
- } else {
- for (list = IdleTimeCounter->sync.pTriglist; list; list = list->next) {
- trig = list->pTrigger;
- if (trig->CheckTrigger(trig, old_idle)) {
- timeout = min(timeout, 0);
- break;
- }
- }
- }
-
- AdjustWaitForDelay (wt, timeout);
- }
-
- IdleTimeCounter->value = old_idle; /* pop */
-}
-
-static void
-IdleTimeWakeupHandler (pointer env, int rc, pointer LastSelectMask)
-{
- XSyncValue idle;
-
- if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
- return;
-
- IdleTimeQueryValue (NULL, &idle);
-
- if ((pIdleTimeValueGreater &&
- XSyncValueGreaterOrEqual (idle, *pIdleTimeValueGreater)) ||
- (pIdleTimeValueLess &&
- XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)))
- {
- SyncChangeCounter (IdleTimeCounter, idle);
- }
-}
-
-static void
-IdleTimeBracketValues (pointer pCounter, CARD64 *pbracket_less,
- CARD64 *pbracket_greater)
-{
- Bool registered = (pIdleTimeValueLess || pIdleTimeValueGreater);
-
- if (registered && !pbracket_less && !pbracket_greater)
- {
- RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
- IdleTimeWakeupHandler,
- NULL);
- }
- else if (!registered && (pbracket_less || pbracket_greater))
- {
- RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
- IdleTimeWakeupHandler,
- NULL);
- }
-
- pIdleTimeValueGreater = pbracket_greater;
- pIdleTimeValueLess = pbracket_less;
-}
-
-static void
-SyncInitIdleTime (void)
-{
- CARD64 resolution;
- XSyncValue idle;
-
- IdleTimeQueryValue (NULL, &idle);
- XSyncIntToValue (&resolution, 4);
-
- IdleTimeCounter = SyncCreateSystemCounter ("IDLETIME", idle, resolution,
- XSyncCounterUnrestricted,
- IdleTimeQueryValue,
- IdleTimeBracketValues);
-
- pIdleTimeValueLess = pIdleTimeValueGreater = NULL;
-}
+/*
+
+Copyright 1991, 1993, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+
+Copyright 1991, 1993 by Digital Equipment Corporation, Maynard, Massachusetts,
+and Olivetti Research Limited, Cambridge, England.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or Olivetti
+not be used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission. Digital and Olivetti
+make no representations about the suitability of this software
+for any purpose. It is provided "as is" without express or implied warranty.
+
+DIGITAL AND OLIVETTI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <string.h>
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include <X11/Xmd.h>
+#include "scrnintstr.h"
+#include "os.h"
+#include "extnsionst.h"
+#include "dixstruct.h"
+#include "pixmapstr.h"
+#include "resource.h"
+#include "opaque.h"
+#include <X11/extensions/syncproto.h>
+#include "syncsrv.h"
+#include "syncsdk.h"
+#include "protocol-versions.h"
+
+#include <stdio.h>
+#if !defined(WIN32)
+#include <sys/time.h>
+#endif
+
+#include "modinit.h"
+
+/*
+ * Local Global Variables
+ */
+static int SyncEventBase;
+static int SyncErrorBase;
+static RESTYPE RTCounter = 0;
+static RESTYPE RTAwait;
+static RESTYPE RTAlarm;
+static RESTYPE RTAlarmClient;
+static RESTYPE RTFence;
+static int SyncNumSystemCounters = 0;
+static SyncCounter **SysCounterList = NULL;
+
+#define IsSystemCounter(pCounter) \
+ (pCounter && (pCounter->sync.client == NULL))
+
+/* these are all the alarm attributes that pertain to the alarm's trigger */
+#define XSyncCAAllTrigger \
+ (XSyncCACounter | XSyncCAValueType | XSyncCAValue | XSyncCATestType)
+
+static void SyncComputeBracketValues(SyncCounter *);
+
+static void SyncInitServerTime(void);
+
+static void SyncInitIdleTime(void);
+
+
+/* Each counter maintains a simple linked list of triggers that are
+ * interested in the counter. The two functions below are used to
+ * delete and add triggers on this list.
+ */
+static void
+SyncDeleteTriggerFromSyncObject(SyncTrigger *pTrigger)
+{
+ SyncTriggerList *pCur;
+ SyncTriggerList *pPrev;
+ SyncCounter *pCounter;
+
+ /* pSync needs to be stored in pTrigger before calling here. */
+
+ if (!pTrigger->pSync)
+ return;
+
+ pPrev = NULL;
+ pCur = pTrigger->pSync->pTriglist;
+
+ while (pCur)
+ {
+ if (pCur->pTrigger == pTrigger)
+ {
+ if (pPrev)
+ pPrev->next = pCur->next;
+ else
+ pTrigger->pSync->pTriglist = pCur->next;
+
+ free(pCur);
+ break;
+ }
+
+ pPrev = pCur;
+ pCur = pCur->next;
+ }
+
+ if (SYNC_COUNTER == pTrigger->pSync->type)
+ {
+ pCounter = (SyncCounter *)pTrigger->pSync;
+
+ if (IsSystemCounter(pCounter))
+ SyncComputeBracketValues(pCounter);
+ } else if (SYNC_FENCE == pTrigger->pSync->type) {
+ SyncFence* pFence = (SyncFence*) pTrigger->pSync;
+ pFence->funcs.DeleteTrigger(pTrigger);
+ }
+}
+
+
+static int
+SyncAddTriggerToSyncObject(SyncTrigger *pTrigger)
+{
+ SyncTriggerList *pCur;
+ SyncCounter *pCounter;
+
+ if (!pTrigger->pSync)
+ return Success;
+
+ /* don't do anything if it's already there */
+ for (pCur = pTrigger->pSync->pTriglist; pCur; pCur = pCur->next)
+ {
+ if (pCur->pTrigger == pTrigger)
+ return Success;
+ }
+
+ if (!(pCur = malloc(sizeof(SyncTriggerList))))
+ return BadAlloc;
+
+ pCur->pTrigger = pTrigger;
+ pCur->next = pTrigger->pSync->pTriglist;
+ pTrigger->pSync->pTriglist = pCur;
+
+ if (SYNC_COUNTER == pTrigger->pSync->type)
+ {
+ pCounter = (SyncCounter *)pTrigger->pSync;
+
+ if (IsSystemCounter(pCounter))
+ SyncComputeBracketValues(pCounter);
+ } else if (SYNC_FENCE == pTrigger->pSync->type) {
+ SyncFence* pFence = (SyncFence*) pTrigger->pSync;
+ pFence->funcs.AddTrigger(pTrigger);
+ }
+
+ return Success;
+}
+
+
+/* Below are five possible functions that can be plugged into
+ * pTrigger->CheckTrigger for counter sync objects, corresponding to
+ * the four possible test-types, and the one possible function that
+ * can be plugged into pTrigger->CheckTrigger for fence sync objects.
+ * These functions are called after the sync object's state changes
+ * but are also passed the old state so they can inspect both the old
+ * and new values. (PositiveTransition and NegativeTransition need to
+ * see both pieces of information.) These functions return the truth
+ * value of the trigger.
+ *
+ * All of them include the condition pTrigger->pSync == NULL.
+ * This is because the spec says that a trigger with a sync value
+ * of None is always TRUE.
+ */
+
+static Bool
+SyncCheckTriggerPositiveComparison(SyncTrigger *pTrigger, CARD64 oldval)
+{
+ SyncCounter *pCounter;
+
+ assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
+ pCounter = (SyncCounter *)pTrigger->pSync;
+
+ return (pCounter == NULL ||
+ XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value));
+}
+
+static Bool
+SyncCheckTriggerNegativeComparison(SyncTrigger *pTrigger, CARD64 oldval)
+{
+ SyncCounter *pCounter;
+
+ assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
+ pCounter = (SyncCounter *)pTrigger->pSync;
+
+ return (pCounter == NULL ||
+ XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value));
+}
+
+static Bool
+SyncCheckTriggerPositiveTransition(SyncTrigger *pTrigger, CARD64 oldval)
+{
+ SyncCounter *pCounter;
+
+ assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
+ pCounter = (SyncCounter *)pTrigger->pSync;
+
+ return (pCounter == NULL ||
+ (XSyncValueLessThan(oldval, pTrigger->test_value) &&
+ XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value)));
+}
+
+static Bool
+SyncCheckTriggerNegativeTransition(SyncTrigger *pTrigger, CARD64 oldval)
+{
+ SyncCounter *pCounter;
+
+ assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
+ pCounter = (SyncCounter *)pTrigger->pSync;
+
+ return (pCounter == NULL ||
+ (XSyncValueGreaterThan(oldval, pTrigger->test_value) &&
+ XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value)));
+}
+
+static Bool
+SyncCheckTriggerFence(SyncTrigger *pTrigger, CARD64 unused)
+{
+ SyncFence* pFence = (SyncFence*) pTrigger->pSync;
+ (void)unused;
+
+ return (pFence == NULL ||
+ pFence->funcs.CheckTriggered(pFence));
+}
+
+static int
+SyncInitTrigger(ClientPtr client, SyncTrigger *pTrigger, XID syncObject,
+ RESTYPE resType, Mask changes)
+{
+ SyncObject *pSync = pTrigger->pSync;
+ SyncCounter *pCounter = NULL;
+ int rc;
+ Bool newSyncObject = FALSE;
+
+ if (changes & XSyncCACounter)
+ {
+ if (syncObject == None)
+ pSync = NULL;
+ else if (Success != (rc = dixLookupResourceByType ((pointer *)&pSync,
+ syncObject, resType, client, DixReadAccess)))
+ {
+ client->errorValue = syncObject;
+ return rc;
+ }
+ if (pSync != pTrigger->pSync)
+ { /* new counter for trigger */
+ SyncDeleteTriggerFromSyncObject(pTrigger);
+ pTrigger->pSync = pSync;
+ newSyncObject = TRUE;
+ }
+ }
+
+ /* if system counter, ask it what the current value is */
+
+ if (pSync && SYNC_COUNTER == pSync->type)
+ {
+ pCounter = (SyncCounter *)pSync;
+
+ if (IsSystemCounter(pCounter))
+ {
+ (*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
+ &pCounter->value);
+ }
+ }
+
+ if (changes & XSyncCAValueType)
+ {
+ if (pTrigger->value_type != XSyncRelative &&
+ pTrigger->value_type != XSyncAbsolute)
+ {
+ client->errorValue = pTrigger->value_type;
+ return BadValue;
+ }
+ }
+
+ if (changes & XSyncCATestType)
+ {
+
+ if (pSync && SYNC_FENCE == pSync->type)
+ {
+ pTrigger->CheckTrigger = SyncCheckTriggerFence;
+ }
+ else
+ {
+ if (pTrigger->test_type != XSyncPositiveTransition &&
+ pTrigger->test_type != XSyncNegativeTransition &&
+ pTrigger->test_type != XSyncPositiveComparison &&
+ pTrigger->test_type != XSyncNegativeComparison)
+ {
+ client->errorValue = pTrigger->test_type;
+ return BadValue;
+ }
+ /* select appropriate CheckTrigger function */
+
+ switch (pTrigger->test_type)
+ {
+ case XSyncPositiveTransition:
+ pTrigger->CheckTrigger = SyncCheckTriggerPositiveTransition;
+ break;
+ case XSyncNegativeTransition:
+ pTrigger->CheckTrigger = SyncCheckTriggerNegativeTransition;
+ break;
+ case XSyncPositiveComparison:
+ pTrigger->CheckTrigger = SyncCheckTriggerPositiveComparison;
+ break;
+ case XSyncNegativeComparison:
+ pTrigger->CheckTrigger = SyncCheckTriggerNegativeComparison;
+ break;
+ }
+ }
+ }
+
+ if (changes & (XSyncCAValueType | XSyncCAValue))
+ {
+ if (pTrigger->value_type == XSyncAbsolute)
+ pTrigger->test_value = pTrigger->wait_value;
+ else /* relative */
+ {
+ Bool overflow;
+ if (pCounter == NULL)
+ return BadMatch;
+
+ XSyncValueAdd(&pTrigger->test_value, pCounter->value,
+ pTrigger->wait_value, &overflow);
+ if (overflow)
+ {
+ client->errorValue = XSyncValueHigh32(pTrigger->wait_value);
+ return BadValue;
+ }
+ }
+ }
+
+ /* we wait until we're sure there are no errors before registering
+ * a new counter on a trigger
+ */
+ if (newSyncObject)
+ {
+ if ((rc = SyncAddTriggerToSyncObject(pTrigger)) != Success)
+ return rc;
+ }
+ else if (pCounter && IsSystemCounter(pCounter))
+ {
+ SyncComputeBracketValues(pCounter);
+ }
+
+ return Success;
+}
+
+/* AlarmNotify events happen in response to actions taken on an Alarm or
+ * the counter used by the alarm. AlarmNotify may be sent to multiple
+ * clients. The alarm maintains a list of clients interested in events.
+ */
+static void
+SyncSendAlarmNotifyEvents(SyncAlarm *pAlarm)
+{
+ SyncAlarmClientList *pcl;
+ xSyncAlarmNotifyEvent ane;
+ SyncTrigger *pTrigger = &pAlarm->trigger;
+ SyncCounter *pCounter;
+
+ assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
+
+ pCounter = (SyncCounter *)pTrigger->pSync;
+
+ UpdateCurrentTime();
+
+ ane.type = SyncEventBase + XSyncAlarmNotify;
+ ane.kind = XSyncAlarmNotify;
+ ane.alarm = pAlarm->alarm_id;
+ if (pTrigger->pSync && SYNC_COUNTER == pTrigger->pSync->type)
+ {
+ ane.counter_value_hi = XSyncValueHigh32(pCounter->value);
+ ane.counter_value_lo = XSyncValueLow32(pCounter->value);
+ }
+ else
+ { /* XXX what else can we do if there's no counter? */
+ ane.counter_value_hi = ane.counter_value_lo = 0;
+ }
+
+ ane.alarm_value_hi = XSyncValueHigh32(pTrigger->test_value);
+ ane.alarm_value_lo = XSyncValueLow32(pTrigger->test_value);
+ ane.time = currentTime.milliseconds;
+ ane.state = pAlarm->state;
+
+ /* send to owner */
+ if (pAlarm->events)
+ WriteEventsToClient(pAlarm->client, 1, (xEvent *) &ane);
+
+ /* send to other interested clients */
+ for (pcl = pAlarm->pEventClients; pcl; pcl = pcl->next)
+ WriteEventsToClient(pcl->client, 1, (xEvent *) &ane);
+}
+
+
+/* CounterNotify events only occur in response to an Await. The events
+ * go only to the Awaiting client.
+ */
+static void
+SyncSendCounterNotifyEvents(ClientPtr client, SyncAwait **ppAwait,
+ int num_events)
+{
+ xSyncCounterNotifyEvent *pEvents, *pev;
+ int i;
+
+ if (client->clientGone)
+ return;
+ pev = pEvents = malloc(num_events * sizeof(xSyncCounterNotifyEvent));
+ if (!pEvents)
+ return;
+ UpdateCurrentTime();
+ for (i = 0; i < num_events; i++, ppAwait++, pev++)
+ {
+ SyncTrigger *pTrigger = &(*ppAwait)->trigger;
+ pev->type = SyncEventBase + XSyncCounterNotify;
+ pev->kind = XSyncCounterNotify;
+ pev->counter = pTrigger->pSync->id;
+ pev->wait_value_lo = XSyncValueLow32(pTrigger->test_value);
+ pev->wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
+ if (SYNC_COUNTER == pTrigger->pSync->type)
+ {
+ SyncCounter *pCounter = (SyncCounter *)pTrigger->pSync;
+
+ pev->counter_value_lo = XSyncValueLow32(pCounter->value);
+ pev->counter_value_hi = XSyncValueHigh32(pCounter->value);
+ }
+ else
+ {
+ pev->counter_value_lo = 0;
+ pev->counter_value_hi = 0;
+ }
+
+ pev->time = currentTime.milliseconds;
+ pev->count = num_events - i - 1; /* events remaining */
+ pev->destroyed = pTrigger->pSync->beingDestroyed;
+ }
+ /* swapping will be taken care of by this */
+ WriteEventsToClient(client, num_events, (xEvent *)pEvents);
+ free(pEvents);
+}
+
+
+/* This function is called when an alarm's counter is destroyed.
+ * It is plugged into pTrigger->CounterDestroyed (for alarm triggers).
+ */
+static void
+SyncAlarmCounterDestroyed(SyncTrigger *pTrigger)
+{
+ SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
+
+ pAlarm->state = XSyncAlarmInactive;
+ SyncSendAlarmNotifyEvents(pAlarm);
+ pTrigger->pSync = NULL;
+}
+
+
+/* This function is called when an alarm "goes off."
+ * It is plugged into pTrigger->TriggerFired (for alarm triggers).
+ */
+static void
+SyncAlarmTriggerFired(SyncTrigger *pTrigger)
+{
+ SyncAlarm *pAlarm = (SyncAlarm *)pTrigger;
+ SyncCounter *pCounter;
+ CARD64 new_test_value;
+
+ assert(!pTrigger->pSync || (SYNC_COUNTER == pTrigger->pSync->type));
+ pCounter = (SyncCounter *)pTrigger->pSync;
+
+ /* no need to check alarm unless it's active */
+ if (pAlarm->state != XSyncAlarmActive)
+ return;
+
+ /* " if the counter value is None, or if the delta is 0 and
+ * the test-type is PositiveComparison or NegativeComparison,
+ * no change is made to value (test-value) and the alarm
+ * state is changed to Inactive before the event is generated."
+ */
+ if (pCounter == NULL
+ || (XSyncValueIsZero(pAlarm->delta)
+ && (pAlarm->trigger.test_type == XSyncPositiveComparison
+ || pAlarm->trigger.test_type == XSyncNegativeComparison)))
+ pAlarm->state = XSyncAlarmInactive;
+
+ new_test_value = pAlarm->trigger.test_value;
+
+ if (pAlarm->state == XSyncAlarmActive)
+ {
+ Bool overflow;
+ CARD64 oldvalue;
+ SyncTrigger *paTrigger = &pAlarm->trigger;
+ SyncCounter *paCounter;
+
+ assert(!paTrigger->pSync || (SYNC_COUNTER == paTrigger->pSync->type));
+ paCounter = (SyncCounter *)pTrigger->pSync;
+
+ /* "The alarm is updated by repeatedly adding delta to the
+ * value of the trigger and re-initializing it until it
+ * becomes FALSE."
+ */
+ oldvalue = paTrigger->test_value;
+
+ /* XXX really should do something smarter here */
+
+ do
+ {
+ XSyncValueAdd(&paTrigger->test_value, paTrigger->test_value,
+ pAlarm->delta, &overflow);
+ } while (!overflow &&
+ (*paTrigger->CheckTrigger)(paTrigger,
+ paCounter->value));
+
+ new_test_value = paTrigger->test_value;
+ paTrigger->test_value = oldvalue;
+
+ /* "If this update would cause value to fall outside the range
+ * for an INT64...no change is made to value (test-value) and
+ * the alarm state is changed to Inactive before the event is
+ * generated."
+ */
+ if (overflow)
+ {
+ new_test_value = oldvalue;
+ pAlarm->state = XSyncAlarmInactive;
+ }
+ }
+ /* The AlarmNotify event has to have the "new state of the alarm"
+ * which we can't be sure of until this point. However, it has
+ * to have the "old" trigger test value. That's the reason for
+ * all the newvalue/oldvalue shuffling above. After we send the
+ * events, give the trigger its new test value.
+ */
+ SyncSendAlarmNotifyEvents(pAlarm);
+ pTrigger->test_value = new_test_value;
+}
+
+
+/* This function is called when an Await unblocks, either as a result
+ * of the trigger firing OR the counter being destroyed.
+ * It goes into pTrigger->TriggerFired AND pTrigger->CounterDestroyed
+ * (for Await triggers).
+ */
+static void
+SyncAwaitTriggerFired(SyncTrigger *pTrigger)
+{
+ SyncAwait *pAwait = (SyncAwait *)pTrigger;
+ int numwaits;
+ SyncAwaitUnion *pAwaitUnion;
+ SyncAwait **ppAwait;
+ int num_events = 0;
+
+ pAwaitUnion = (SyncAwaitUnion *)pAwait->pHeader;
+ numwaits = pAwaitUnion->header.num_waitconditions;
+ ppAwait = malloc(numwaits * sizeof(SyncAwait *));
+ if (!ppAwait)
+ goto bail;
+
+ pAwait = &(pAwaitUnion+1)->await;
+
+ /* "When a client is unblocked, all the CounterNotify events for
+ * the Await request are generated contiguously. If count is 0
+ * there are no more events to follow for this request. If
+ * count is n, there are at least n more events to follow."
+ *
+ * Thus, it is best to find all the counters for which events
+ * need to be sent first, so that an accurate count field can
+ * be stored in the events.
+ */
+ for ( ; numwaits; numwaits--, pAwait++)
+ {
+ CARD64 diff;
+ Bool overflow, diffgreater, diffequal;
+
+ /* "A CounterNotify event with the destroyed flag set to TRUE is
+ * always generated if the counter for one of the triggers is
+ * destroyed."
+ */
+ if (pAwait->trigger.pSync->beingDestroyed)
+ {
+ ppAwait[num_events++] = pAwait;
+ continue;
+ }
+
+ if (SYNC_COUNTER == pAwait->trigger.pSync->type)
+ {
+ SyncCounter *pCounter = (SyncCounter *) pAwait->trigger.pSync;
+
+ /* "The difference between the counter and the test value is
+ * calculated by subtracting the test value from the value of
+ * the counter."
+ */
+ XSyncValueSubtract(&diff, pCounter->value,
+ pAwait->trigger.test_value, &overflow);
+
+ /* "If the difference lies outside the range for an INT64, an
+ * event is not generated."
+ */
+ if (overflow)
+ continue;
+ diffgreater = XSyncValueGreaterThan(diff, pAwait->event_threshold);
+ diffequal = XSyncValueEqual(diff, pAwait->event_threshold);
+
+ /* "If the test-type is PositiveTransition or
+ * PositiveComparison, a CounterNotify event is generated if
+ * the difference is at least event-threshold. If the test-type
+ * is NegativeTransition or NegativeComparison, a CounterNotify
+ * event is generated if the difference is at most
+ * event-threshold."
+ */
+
+ if ( ((pAwait->trigger.test_type == XSyncPositiveComparison ||
+ pAwait->trigger.test_type == XSyncPositiveTransition)
+ && (diffgreater || diffequal))
+ ||
+ ((pAwait->trigger.test_type == XSyncNegativeComparison ||
+ pAwait->trigger.test_type == XSyncNegativeTransition)
+ && (!diffgreater) /* less or equal */
+ )
+ )
+ {
+ ppAwait[num_events++] = pAwait;
+ }
+ }
+ }
+ if (num_events)
+ SyncSendCounterNotifyEvents(pAwaitUnion->header.client, ppAwait,
+ num_events);
+ free(ppAwait);
+
+bail:
+ /* unblock the client */
+ AttendClient(pAwaitUnion->header.client);
+ /* delete the await */
+ FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
+}
+
+
+/* This function should always be used to change a counter's value so that
+ * any triggers depending on the counter will be checked.
+ */
+void
+SyncChangeCounter(SyncCounter *pCounter, CARD64 newval)
+{
+ SyncTriggerList *ptl, *pnext;
+ CARD64 oldval;
+
+ oldval = pCounter->value;
+ pCounter->value = newval;
+
+ /* run through triggers to see if any become true */
+ for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext)
+ {
+ pnext = ptl->next;
+ if ((*ptl->pTrigger->CheckTrigger)(ptl->pTrigger, oldval))
+ (*ptl->pTrigger->TriggerFired)(ptl->pTrigger);
+ }
+
+ if (IsSystemCounter(pCounter))
+ {
+ SyncComputeBracketValues(pCounter);
+ }
+}
+
+
+/* loosely based on dix/events.c/EventSelectForWindow */
+static Bool
+SyncEventSelectForAlarm(SyncAlarm *pAlarm, ClientPtr client, Bool wantevents)
+{
+ SyncAlarmClientList *pClients;
+
+ if (client == pAlarm->client) /* alarm owner */
+ {
+ pAlarm->events = wantevents;
+ return Success;
+ }
+
+ /* see if the client is already on the list (has events selected) */
+
+ for (pClients = pAlarm->pEventClients; pClients;
+ pClients = pClients->next)
+ {
+ if (pClients->client == client)
+ {
+ /* client's presence on the list indicates desire for
+ * events. If the client doesn't want events, remove it
+ * from the list. If the client does want events, do
+ * nothing, since it's already got them.
+ */
+ if (!wantevents)
+ {
+ FreeResource(pClients->delete_id, RT_NONE);
+ }
+ return Success;
+ }
+ }
+
+ /* if we get here, this client does not currently have
+ * events selected on the alarm
+ */
+
+ if (!wantevents)
+ /* client doesn't want events, and we just discovered that it
+ * doesn't have them, so there's nothing to do.
+ */
+ return Success;
+
+ /* add new client to pAlarm->pEventClients */
+
+ pClients = malloc(sizeof(SyncAlarmClientList));
+ if (!pClients)
+ return BadAlloc;
+
+ /* register it as a resource so it will be cleaned up
+ * if the client dies
+ */
+
+ pClients->delete_id = FakeClientID(client->index);
+ if (!AddResource(pClients->delete_id, RTAlarmClient, pAlarm))
+ {
+ free(pClients);
+ return BadAlloc;
+ }
+
+ /* link it into list after we know all the allocations succeed */
+
+ pClients->next = pAlarm->pEventClients;
+ pAlarm->pEventClients = pClients;
+ pClients->client = client;
+ return Success;
+}
+
+/*
+ * ** SyncChangeAlarmAttributes ** This is used by CreateAlarm and ChangeAlarm
+ */
+static int
+SyncChangeAlarmAttributes(ClientPtr client, SyncAlarm *pAlarm, Mask mask,
+ CARD32 *values)
+{
+ int status;
+ XSyncCounter counter;
+ Mask origmask = mask;
+
+ counter =
+ pAlarm->trigger.pSync ? pAlarm->trigger.pSync->id : None;
+
+ while (mask)
+ {
+ int index2 = lowbit(mask);
+ mask &= ~index2;
+ switch (index2)
+ {
+ case XSyncCACounter:
+ mask &= ~XSyncCACounter;
+ /* sanity check in SyncInitTrigger */
+ counter = *values++;
+ break;
+
+ case XSyncCAValueType:
+ mask &= ~XSyncCAValueType;
+ /* sanity check in SyncInitTrigger */
+ pAlarm->trigger.value_type = *values++;
+ break;
+
+ case XSyncCAValue:
+ mask &= ~XSyncCAValue;
+ XSyncIntsToValue(&pAlarm->trigger.wait_value, values[1], values[0]);
+ values += 2;
+ break;
+
+ case XSyncCATestType:
+ mask &= ~XSyncCATestType;
+ /* sanity check in SyncInitTrigger */
+ pAlarm->trigger.test_type = *values++;
+ break;
+
+ case XSyncCADelta:
+ mask &= ~XSyncCADelta;
+ XSyncIntsToValue(&pAlarm->delta, values[1], values[0]);
+ values += 2;
+ break;
+
+ case XSyncCAEvents:
+ mask &= ~XSyncCAEvents;
+ if ((*values != xTrue) && (*values != xFalse))
+ {
+ client->errorValue = *values;
+ return BadValue;
+ }
+ status = SyncEventSelectForAlarm(pAlarm, client,
+ (Bool)(*values++));
+ if (status != Success)
+ return status;
+ break;
+
+ default:
+ client->errorValue = mask;
+ return BadValue;
+ }
+ }
+
+ /* "If the test-type is PositiveComparison or PositiveTransition
+ * and delta is less than zero, or if the test-type is
+ * NegativeComparison or NegativeTransition and delta is
+ * greater than zero, a Match error is generated."
+ */
+ if (origmask & (XSyncCADelta|XSyncCATestType))
+ {
+ CARD64 zero;
+ XSyncIntToValue(&zero, 0);
+ if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) ||
+ (pAlarm->trigger.test_type == XSyncPositiveTransition))
+ && XSyncValueLessThan(pAlarm->delta, zero))
+ ||
+ (((pAlarm->trigger.test_type == XSyncNegativeComparison) ||
+ (pAlarm->trigger.test_type == XSyncNegativeTransition))
+ && XSyncValueGreaterThan(pAlarm->delta, zero))
+ )
+ {
+ return BadMatch;
+ }
+ }
+
+ /* postpone this until now, when we're sure nothing else can go wrong */
+ if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter,
+ origmask & XSyncCAAllTrigger)) != Success)
+ return status;
+
+ /* XXX spec does not really say to do this - needs clarification */
+ pAlarm->state = XSyncAlarmActive;
+ return Success;
+}
+
+static SyncObject *
+SyncCreate(ClientPtr client, XID id, unsigned char type)
+{
+ SyncObject *pSync;
+ RESTYPE resType;
+
+ switch (type) {
+ case SYNC_COUNTER:
+ resType = RTCounter;
+ pSync = malloc(sizeof(SyncCounter));
+ break;
+ case SYNC_FENCE:
+ resType = RTFence;
+ pSync = dixAllocateObjectWithPrivates(SyncFence,
+ PRIVATE_SYNC_FENCE);
+ break;
+ default:
+ return NULL;
+ }
+
+ if (!pSync)
+ return NULL;
+
+ if (!AddResource(id, resType, (pointer) pSync))
+ {
+ switch (type) {
+ case SYNC_FENCE:
+ dixFreeObjectWithPrivates((SyncFence *)pSync, PRIVATE_SYNC_FENCE);
+ break;
+ default:
+ free(pSync);
+ }
+
+ return NULL;
+ }
+
+ pSync->client = client;
+ pSync->id = id;
+ pSync->pTriglist = NULL;
+ pSync->beingDestroyed = FALSE;
+ pSync->type = type;
+
+ return pSync;
+}
+
+
+static SyncCounter *
+SyncCreateCounter(ClientPtr client, XSyncCounter id, CARD64 initialvalue)
+{
+ SyncCounter *pCounter;
+
+ if (!(pCounter = (SyncCounter *)SyncCreate(client,
+ id,
+ SYNC_COUNTER)))
+ return NULL;
+
+ pCounter->value = initialvalue;
+ pCounter->pSysCounterInfo = NULL;
+ return pCounter;
+}
+
+static int FreeCounter(void *, XID);
+
+/*
+ * ***** System Counter utilities
+ */
+
+pointer
+SyncCreateSystemCounter(
+ char *name,
+ CARD64 initial,
+ CARD64 resolution,
+ SyncCounterType counterType,
+ void (*QueryValue)(pointer /* pCounter */,
+ CARD64 * /* pValue_return */),
+ void (*BracketValues)(pointer /* pCounter */,
+ CARD64 * /* pbracket_less */,
+ CARD64 * /* pbracket_greater */)
+ )
+{
+ SyncCounter *pCounter;
+
+ SysCounterList = realloc(SysCounterList,
+ (SyncNumSystemCounters+1)*sizeof(SyncCounter *));
+ if (!SysCounterList)
+ return NULL;
+
+ /* this function may be called before SYNC has been initialized, so we
+ * have to make sure RTCounter is created.
+ */
+ if (RTCounter == 0)
+ {
+ RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
+ if (RTCounter == 0)
+ {
+ return NULL;
+ }
+ }
+
+ pCounter = SyncCreateCounter(NULL, FakeClientID(0), initial);
+
+ if (pCounter)
+ {
+ SysCounterInfo *psci;
+
+ psci = malloc(sizeof(SysCounterInfo));
+ if (!psci)
+ {
+ FreeResource(pCounter->sync.id, RT_NONE);
+ return pCounter;
+ }
+ pCounter->pSysCounterInfo = psci;
+ psci->name = name;
+ psci->resolution = resolution;
+ psci->counterType = counterType;
+ psci->QueryValue = QueryValue;
+ psci->BracketValues = BracketValues;
+ XSyncMaxValue(&psci->bracket_greater);
+ XSyncMinValue(&psci->bracket_less);
+ SysCounterList[SyncNumSystemCounters++] = pCounter;
+ }
+ return pCounter;
+}
+
+void
+SyncDestroySystemCounter(pointer pSysCounter)
+{
+ SyncCounter *pCounter = (SyncCounter *)pSysCounter;
+ FreeResource(pCounter->sync.id, RT_NONE);
+}
+
+static void
+SyncComputeBracketValues(SyncCounter *pCounter)
+{
+ SyncTriggerList *pCur;
+ SyncTrigger *pTrigger;
+ SysCounterInfo *psci;
+ CARD64 *pnewgtval = NULL;
+ CARD64 *pnewltval = NULL;
+ SyncCounterType ct;
+
+ if (!pCounter)
+ return;
+
+ psci = pCounter->pSysCounterInfo;
+ ct = pCounter->pSysCounterInfo->counterType;
+ if (ct == XSyncCounterNeverChanges)
+ return;
+
+ XSyncMaxValue(&psci->bracket_greater);
+ XSyncMinValue(&psci->bracket_less);
+
+ for (pCur = pCounter->sync.pTriglist; pCur; pCur = pCur->next)
+ {
+ pTrigger = pCur->pTrigger;
+
+ if (pTrigger->test_type == XSyncPositiveComparison &&
+ ct != XSyncCounterNeverIncreases)
+ {
+ if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
+ XSyncValueLessThan(pTrigger->test_value,
+ psci->bracket_greater))
+ {
+ psci->bracket_greater = pTrigger->test_value;
+ pnewgtval = &psci->bracket_greater;
+ }
+ }
+ else if (pTrigger->test_type == XSyncNegativeComparison &&
+ ct != XSyncCounterNeverDecreases)
+ {
+ if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
+ XSyncValueGreaterThan(pTrigger->test_value,
+ psci->bracket_less))
+ {
+ psci->bracket_less = pTrigger->test_value;
+ pnewltval = &psci->bracket_less;
+ }
+ }
+ else if (pTrigger->test_type == XSyncNegativeTransition &&
+ ct != XSyncCounterNeverIncreases)
+ {
+ if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) &&
+ XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less))
+ {
+ psci->bracket_less = pTrigger->test_value;
+ pnewltval = &psci->bracket_less;
+ } else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) &&
+ XSyncValueLessThan(pTrigger->test_value,
+ psci->bracket_greater))
+ {
+ /*
+ * The value is exactly equal to our threshold. We want one
+ * more event in the positive direction to ensure we pick up
+ * when the value *exceeds* this threshold.
+ */
+ psci->bracket_greater = pTrigger->test_value;
+ pnewgtval = &psci->bracket_greater;
+ }
+ }
+ else if (pTrigger->test_type == XSyncPositiveTransition &&
+ ct != XSyncCounterNeverDecreases)
+ {
+ if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) &&
+ XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater))
+ {
+ psci->bracket_greater = pTrigger->test_value;
+ pnewgtval = &psci->bracket_greater;
+ } else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) &&
+ XSyncValueGreaterThan(pTrigger->test_value,
+ psci->bracket_less))
+ {
+ /*
+ * The value is exactly equal to our threshold. We want one
+ * more event in the negative direction to ensure we pick up
+ * when the value is less than this threshold.
+ */
+ psci->bracket_less = pTrigger->test_value;
+ pnewltval = &psci->bracket_less;
+ }
+ }
+ } /* end for each trigger */
+
+ if (pnewgtval || pnewltval)
+ {
+ (*psci->BracketValues)((pointer)pCounter, pnewltval, pnewgtval);
+ }
+}
+
+/*
+ * ***** Resource delete functions
+ */
+
+/* ARGSUSED */
+static int
+FreeAlarm(void *addr, XID id)
+{
+ SyncAlarm *pAlarm = (SyncAlarm *) addr;
+
+ pAlarm->state = XSyncAlarmDestroyed;
+
+ SyncSendAlarmNotifyEvents(pAlarm);
+
+ /* delete event selections */
+
+ while (pAlarm->pEventClients)
+ FreeResource(pAlarm->pEventClients->delete_id, RT_NONE);
+
+ SyncDeleteTriggerFromSyncObject(&pAlarm->trigger);
+
+ free(pAlarm);
+ return Success;
+}
+
+
+/*
+ * ** Cleanup after the destruction of a Counter
+ */
+/* ARGSUSED */
+static int
+FreeCounter(void *env, XID id)
+{
+ SyncCounter *pCounter = (SyncCounter *) env;
+ SyncTriggerList *ptl, *pnext;
+
+ pCounter->sync.beingDestroyed = TRUE;
+ /* tell all the counter's triggers that the counter has been destroyed */
+ for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext)
+ {
+ (*ptl->pTrigger->CounterDestroyed)(ptl->pTrigger);
+ pnext = ptl->next;
+ free(ptl); /* destroy the trigger list as we go */
+ }
+ if (IsSystemCounter(pCounter))
+ {
+ int i, found = 0;
+
+ free(pCounter->pSysCounterInfo);
+
+ /* find the counter in the list of system counters and remove it */
+
+ if (SysCounterList)
+ {
+ for (i = 0; i < SyncNumSystemCounters; i++)
+ {
+ if (SysCounterList[i] == pCounter)
+ {
+ found = i;
+ break;
+ }
+ }
+ if (found < (SyncNumSystemCounters-1))
+ {
+ for (i = found; i < SyncNumSystemCounters-1; i++)
+ {
+ SysCounterList[i] = SysCounterList[i+1];
+ }
+ }
+ }
+ SyncNumSystemCounters--;
+ }
+ free(pCounter);
+ return Success;
+}
+
+/*
+ * ** Cleanup after Await
+ */
+/* ARGSUSED */
+static int
+FreeAwait(void *addr, XID id)
+{
+ SyncAwaitUnion *pAwaitUnion = (SyncAwaitUnion *) addr;
+ SyncAwait *pAwait;
+ int numwaits;
+
+ pAwait = &(pAwaitUnion+1)->await; /* first await on list */
+
+ /* remove triggers from counters */
+
+ for (numwaits = pAwaitUnion->header.num_waitconditions; numwaits;
+ numwaits--, pAwait++)
+ {
+ /* If the counter is being destroyed, FreeCounter will delete
+ * the trigger list itself, so don't do it here.
+ */
+ SyncObject *pSync = pAwait->trigger.pSync;
+ if (pSync && !pSync->beingDestroyed)
+ SyncDeleteTriggerFromSyncObject(&pAwait->trigger);
+ }
+ free(pAwaitUnion);
+ return Success;
+}
+
+/* loosely based on dix/events.c/OtherClientGone */
+static int
+FreeAlarmClient(void *value, XID id)
+{
+ SyncAlarm *pAlarm = (SyncAlarm *)value;
+ SyncAlarmClientList *pCur, *pPrev;
+
+ for (pPrev = NULL, pCur = pAlarm->pEventClients;
+ pCur;
+ pPrev = pCur, pCur = pCur->next)
+ {
+ if (pCur->delete_id == id)
+ {
+ if (pPrev)
+ pPrev->next = pCur->next;
+ else
+ pAlarm->pEventClients = pCur->next;
+ free(pCur);
+ return Success;
+ }
+ }
+ FatalError("alarm client not on event list");
+ /*NOTREACHED*/
+}
+
+
+/*
+ * ***** Proc functions
+ */
+
+
+/*
+ * ** Initialize the extension
+ */
+static int
+ProcSyncInitialize(ClientPtr client)
+{
+ xSyncInitializeReply rep;
+ int n;
+
+ REQUEST_SIZE_MATCH(xSyncInitializeReq);
+
+ memset(&rep, 0, sizeof(xSyncInitializeReply));
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.majorVersion = SERVER_SYNC_MAJOR_VERSION;
+ rep.minorVersion = SERVER_SYNC_MINOR_VERSION;
+ rep.length = 0;
+
+ if (client->swapped)
+ {
+ swaps(&rep.sequenceNumber, n);
+ }
+ WriteToClient(client, sizeof(rep), (char *) &rep);
+ return Success;
+}
+
+/*
+ * ** Get list of system counters available through the extension
+ */
+static int
+ProcSyncListSystemCounters(ClientPtr client)
+{
+ xSyncListSystemCountersReply rep;
+ int i, len;
+ xSyncSystemCounter *list = NULL, *walklist = NULL;
+
+ REQUEST_SIZE_MATCH(xSyncListSystemCountersReq);
+
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.nCounters = SyncNumSystemCounters;
+
+ for (i = len = 0; i < SyncNumSystemCounters; i++)
+ {
+ char *name = SysCounterList[i]->pSysCounterInfo->name;
+ /* pad to 4 byte boundary */
+ len += pad_to_int32(sz_xSyncSystemCounter + strlen(name));
+ }
+
+ if (len)
+ {
+ walklist = list = malloc(len);
+ if (!list)
+ return BadAlloc;
+ }
+
+ rep.length = bytes_to_int32(len);
+
+ if (client->swapped)
+ {
+ char n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.nCounters, n);
+ }
+
+ for (i = 0; i < SyncNumSystemCounters; i++)
+ {
+ int namelen;
+ char *pname_in_reply;
+ SysCounterInfo *psci = SysCounterList[i]->pSysCounterInfo;
+
+ walklist->counter = SysCounterList[i]->sync.id;
+ walklist->resolution_hi = XSyncValueHigh32(psci->resolution);
+ walklist->resolution_lo = XSyncValueLow32(psci->resolution);
+ namelen = strlen(psci->name);
+ walklist->name_length = namelen;
+
+ if (client->swapped)
+ {
+ char n;
+ swapl(&walklist->counter, n);
+ swapl(&walklist->resolution_hi, n);
+ swapl(&walklist->resolution_lo, n);
+ swaps(&walklist->name_length, n);
+ }
+
+ pname_in_reply = ((char *)walklist) + sz_xSyncSystemCounter;
+ strncpy(pname_in_reply, psci->name, namelen);
+ walklist = (xSyncSystemCounter *) (((char *)walklist) +
+ pad_to_int32(sz_xSyncSystemCounter + namelen));
+ }
+
+ WriteToClient(client, sizeof(rep), (char *) &rep);
+ if (len)
+ {
+ WriteToClient(client, len, (char *) list);
+ free(list);
+ }
+
+ return Success;
+}
+
+/*
+ * ** Set client Priority
+ */
+static int
+ProcSyncSetPriority(ClientPtr client)
+{
+ REQUEST(xSyncSetPriorityReq);
+ ClientPtr priorityclient;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncSetPriorityReq);
+
+ if (stuff->id == None)
+ priorityclient = client;
+ else {
+ rc = dixLookupClient(&priorityclient, stuff->id, client,
+ DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+ }
+
+ if (priorityclient->priority != stuff->priority)
+ {
+ priorityclient->priority = stuff->priority;
+
+ /* The following will force the server back into WaitForSomething
+ * so that the change in this client's priority is immediately
+ * reflected.
+ */
+ isItTimeToYield = TRUE;
+ dispatchException |= DE_PRIORITYCHANGE;
+ }
+ return Success;
+}
+
+/*
+ * ** Get client Priority
+ */
+static int
+ProcSyncGetPriority(ClientPtr client)
+{
+ REQUEST(xSyncGetPriorityReq);
+ xSyncGetPriorityReply rep;
+ ClientPtr priorityclient;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncGetPriorityReq);
+
+ if (stuff->id == None)
+ priorityclient = client;
+ else {
+ rc = dixLookupClient(&priorityclient, stuff->id, client,
+ DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ }
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ rep.priority = priorityclient->priority;
+
+ if (client->swapped)
+ {
+ char n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.priority, n);
+ }
+
+ WriteToClient(client, sizeof(xSyncGetPriorityReply), (char *) &rep);
+
+ return Success;
+}
+
+/*
+ * ** Create a new counter
+ */
+static int
+ProcSyncCreateCounter(ClientPtr client)
+{
+ REQUEST(xSyncCreateCounterReq);
+ CARD64 initial;
+
+ REQUEST_SIZE_MATCH(xSyncCreateCounterReq);
+
+ LEGAL_NEW_RESOURCE(stuff->cid, client);
+
+ XSyncIntsToValue(&initial, stuff->initial_value_lo, stuff->initial_value_hi);
+ if (!SyncCreateCounter(client, stuff->cid, initial))
+ return BadAlloc;
+
+ return Success;
+}
+
+/*
+ * ** Set Counter value
+ */
+static int
+ProcSyncSetCounter(ClientPtr client)
+{
+ REQUEST(xSyncSetCounterReq);
+ SyncCounter *pCounter;
+ CARD64 newvalue;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncSetCounterReq);
+
+ rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
+ client, DixWriteAccess);
+ if (rc != Success)
+ return rc;
+
+ if (IsSystemCounter(pCounter))
+ {
+ client->errorValue = stuff->cid;
+ return BadAccess;
+ }
+
+ XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
+ SyncChangeCounter(pCounter, newvalue);
+ return Success;
+}
+
+/*
+ * ** Change Counter value
+ */
+static int
+ProcSyncChangeCounter(ClientPtr client)
+{
+ REQUEST(xSyncChangeCounterReq);
+ SyncCounter *pCounter;
+ CARD64 newvalue;
+ Bool overflow;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncChangeCounterReq);
+
+ rc = dixLookupResourceByType((pointer *)&pCounter, stuff->cid, RTCounter,
+ client, DixWriteAccess);
+ if (rc != Success)
+ return rc;
+
+ if (IsSystemCounter(pCounter))
+ {
+ client->errorValue = stuff->cid;
+ return BadAccess;
+ }
+
+ XSyncIntsToValue(&newvalue, stuff->value_lo, stuff->value_hi);
+ XSyncValueAdd(&newvalue, pCounter->value, newvalue, &overflow);
+ if (overflow)
+ {
+ /* XXX 64 bit value can't fit in 32 bits; do the best we can */
+ client->errorValue = stuff->value_hi;
+ return BadValue;
+ }
+ SyncChangeCounter(pCounter, newvalue);
+ return Success;
+}
+
+/*
+ * ** Destroy a counter
+ */
+static int
+ProcSyncDestroyCounter(ClientPtr client)
+{
+ REQUEST(xSyncDestroyCounterReq);
+ SyncCounter *pCounter;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncDestroyCounterReq);
+
+ rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter, RTCounter,
+ client, DixDestroyAccess);
+ if (rc != Success)
+ return rc;
+
+ if (IsSystemCounter(pCounter))
+ {
+ client->errorValue = stuff->counter;
+ return BadAccess;
+ }
+ FreeResource(pCounter->sync.id, RT_NONE);
+ return Success;
+}
+
+static SyncAwaitUnion*
+SyncAwaitPrologue(ClientPtr client, int items)
+{
+ SyncAwaitUnion *pAwaitUnion;
+
+ /* all the memory for the entire await list is allocated
+ * here in one chunk
+ */
+ pAwaitUnion = malloc((items+1) * sizeof(SyncAwaitUnion));
+ if (!pAwaitUnion)
+ return NULL;
+
+ /* first item is the header, remainder are real wait conditions */
+
+ pAwaitUnion->header.delete_id = FakeClientID(client->index);
+ if (!AddResource(pAwaitUnion->header.delete_id, RTAwait, pAwaitUnion))
+ {
+ free(pAwaitUnion);
+ return NULL;
+ }
+
+ pAwaitUnion->header.client = client;
+ pAwaitUnion->header.num_waitconditions = 0;
+
+ return pAwaitUnion;
+}
+
+static void
+SyncAwaitEpilogue(ClientPtr client, int items, SyncAwaitUnion *pAwaitUnion)
+{
+ SyncAwait *pAwait;
+ int i;
+
+ IgnoreClient(client);
+
+ /* see if any of the triggers are already true */
+
+ pAwait = &(pAwaitUnion+1)->await; /* skip over header */
+ for (i = 0; i < items; i++, pAwait++)
+ {
+ CARD64 value;
+
+ /* don't have to worry about NULL counters because the request
+ * errors before we get here out if they occur
+ */
+ switch (pAwait->trigger.pSync->type) {
+ case SYNC_COUNTER:
+ value = ((SyncCounter *)pAwait->trigger.pSync)->value;
+ break;
+ default:
+ XSyncIntToValue(&value, 0);
+ }
+
+ if ((*pAwait->trigger.CheckTrigger)(&pAwait->trigger, value))
+ {
+ (*pAwait->trigger.TriggerFired)(&pAwait->trigger);
+ break; /* once is enough */
+ }
+ }
+}
+
+/*
+ * ** Await
+ */
+static int
+ProcSyncAwait(ClientPtr client)
+{
+ REQUEST(xSyncAwaitReq);
+ int len, items;
+ int i;
+ xSyncWaitCondition *pProtocolWaitConds;
+ SyncAwaitUnion *pAwaitUnion;
+ SyncAwait *pAwait;
+ int status;
+
+ REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
+
+ len = client->req_len << 2;
+ len -= sz_xSyncAwaitReq;
+ items = len / sz_xSyncWaitCondition;
+
+ if (items * sz_xSyncWaitCondition != len)
+ {
+ return BadLength;
+ }
+ if (items == 0)
+ {
+ client->errorValue = items; /* XXX protocol change */
+ return BadValue;
+ }
+
+ if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
+ return BadAlloc;
+
+ /* don't need to do any more memory allocation for this request! */
+
+ pProtocolWaitConds = (xSyncWaitCondition *) & stuff[1];
+
+ pAwait = &(pAwaitUnion+1)->await; /* skip over header */
+ for (i = 0; i < items; i++, pProtocolWaitConds++, pAwait++)
+ {
+ if (pProtocolWaitConds->counter == None) /* XXX protocol change */
+ {
+ /* this should take care of removing any triggers created by
+ * this request that have already been registered on sync objects
+ */
+ FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
+ client->errorValue = pProtocolWaitConds->counter;
+ return SyncErrorBase + XSyncBadCounter;
+ }
+
+ /* sanity checks are in SyncInitTrigger */
+ pAwait->trigger.pSync = NULL;
+ pAwait->trigger.value_type = pProtocolWaitConds->value_type;
+ XSyncIntsToValue(&pAwait->trigger.wait_value,
+ pProtocolWaitConds->wait_value_lo,
+ pProtocolWaitConds->wait_value_hi);
+ pAwait->trigger.test_type = pProtocolWaitConds->test_type;
+
+ status = SyncInitTrigger(client, &pAwait->trigger,
+ pProtocolWaitConds->counter, RTCounter,
+ XSyncCAAllTrigger);
+ if (status != Success)
+ {
+ /* this should take care of removing any triggers created by
+ * this request that have already been registered on sync objects
+ */
+ FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
+ return status;
+ }
+ /* this is not a mistake -- same function works for both cases */
+ pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
+ pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
+ XSyncIntsToValue(&pAwait->event_threshold,
+ pProtocolWaitConds->event_threshold_lo,
+ pProtocolWaitConds->event_threshold_hi);
+ pAwait->pHeader = &pAwaitUnion->header;
+ pAwaitUnion->header.num_waitconditions++;
+ }
+
+ SyncAwaitEpilogue(client, items, pAwaitUnion);
+
+ return Success;
+}
+
+
+/*
+ * ** Query a counter
+ */
+static int
+ProcSyncQueryCounter(ClientPtr client)
+{
+ REQUEST(xSyncQueryCounterReq);
+ xSyncQueryCounterReply rep;
+ SyncCounter *pCounter;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncQueryCounterReq);
+
+ rc = dixLookupResourceByType((pointer *)&pCounter, stuff->counter,
+ RTCounter, client, DixReadAccess);
+ if (rc != Success)
+ return rc;
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+
+ /* if system counter, ask it what the current value is */
+
+ if (IsSystemCounter(pCounter))
+ {
+ (*pCounter->pSysCounterInfo->QueryValue) ((pointer) pCounter,
+ &pCounter->value);
+ }
+
+ rep.value_hi = XSyncValueHigh32(pCounter->value);
+ rep.value_lo = XSyncValueLow32(pCounter->value);
+ if (client->swapped)
+ {
+ char n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.value_hi, n);
+ swapl(&rep.value_lo, n);
+ }
+ WriteToClient(client, sizeof(xSyncQueryCounterReply), (char *) &rep);
+ return Success;
+}
+
+
+/*
+ * ** Create Alarm
+ */
+static int
+ProcSyncCreateAlarm(ClientPtr client)
+{
+ REQUEST(xSyncCreateAlarmReq);
+ SyncAlarm *pAlarm;
+ int status;
+ unsigned long len, vmask;
+ SyncTrigger *pTrigger;
+
+ REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
+
+ LEGAL_NEW_RESOURCE(stuff->id, client);
+
+ vmask = stuff->valueMask;
+ len = client->req_len - bytes_to_int32(sizeof(xSyncCreateAlarmReq));
+ /* the "extra" call to Ones accounts for the presence of 64 bit values */
+ if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
+ return BadLength;
+
+ if (!(pAlarm = malloc(sizeof(SyncAlarm))))
+ {
+ return BadAlloc;
+ }
+
+ /* set up defaults */
+
+ pTrigger = &pAlarm->trigger;
+ pTrigger->pSync = NULL;
+ pTrigger->value_type = XSyncAbsolute;
+ XSyncIntToValue(&pTrigger->wait_value, 0L);
+ pTrigger->test_type = XSyncPositiveComparison;
+ pTrigger->TriggerFired = SyncAlarmTriggerFired;
+ pTrigger->CounterDestroyed = SyncAlarmCounterDestroyed;
+ status = SyncInitTrigger(client, pTrigger, None, RTCounter,
+ XSyncCAAllTrigger);
+ if (status != Success)
+ {
+ free(pAlarm);
+ return status;
+ }
+
+ pAlarm->client = client;
+ pAlarm->alarm_id = stuff->id;
+ XSyncIntToValue(&pAlarm->delta, 1L);
+ pAlarm->events = TRUE;
+ pAlarm->state = XSyncAlarmInactive;
+ pAlarm->pEventClients = NULL;
+ status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
+ (CARD32 *)&stuff[1]);
+ if (status != Success)
+ {
+ free(pAlarm);
+ return status;
+ }
+
+ if (!AddResource(stuff->id, RTAlarm, pAlarm))
+ {
+ free(pAlarm);
+ return BadAlloc;
+ }
+
+ /* see if alarm already triggered. NULL counter will not trigger
+ * in CreateAlarm and sets alarm state to Inactive.
+ */
+
+ if (!pTrigger->pSync)
+ {
+ pAlarm->state = XSyncAlarmInactive; /* XXX protocol change */
+ }
+ else
+ {
+ SyncCounter *pCounter;
+
+ assert(SYNC_COUNTER == pTrigger->pSync->type);
+ pCounter = (SyncCounter *)pTrigger->pSync;
+
+ if ((*pTrigger->CheckTrigger)(pTrigger, pCounter->value))
+ (*pTrigger->TriggerFired)(pTrigger);
+ }
+
+ return Success;
+}
+
+/*
+ * ** Change Alarm
+ */
+static int
+ProcSyncChangeAlarm(ClientPtr client)
+{
+ REQUEST(xSyncChangeAlarmReq);
+ SyncAlarm *pAlarm;
+ SyncCounter *pCounter = NULL;
+ long vmask;
+ int len, status;
+
+ REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
+
+ status = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
+ client, DixWriteAccess);
+ if (status != Success)
+ return status;
+
+ vmask = stuff->valueMask;
+ len = client->req_len - bytes_to_int32(sizeof(xSyncChangeAlarmReq));
+ /* the "extra" call to Ones accounts for the presence of 64 bit values */
+ if (len != (Ones(vmask) + Ones(vmask & (XSyncCAValue|XSyncCADelta))))
+ return BadLength;
+
+ if ((status = SyncChangeAlarmAttributes(client, pAlarm, vmask,
+ (CARD32 *)&stuff[1])) != Success)
+ return status;
+
+ if (pAlarm->trigger.pSync)
+ {
+ assert(SYNC_COUNTER == pAlarm->trigger.pSync->type);
+ pCounter = (SyncCounter *)pAlarm->trigger.pSync;
+ }
+
+ /* see if alarm already triggered. NULL counter WILL trigger
+ * in ChangeAlarm.
+ */
+
+ if (!pCounter ||
+ (*pAlarm->trigger.CheckTrigger)(&pAlarm->trigger, pCounter->value))
+ {
+ (*pAlarm->trigger.TriggerFired)(&pAlarm->trigger);
+ }
+ return Success;
+}
+
+static int
+ProcSyncQueryAlarm(ClientPtr client)
+{
+ REQUEST(xSyncQueryAlarmReq);
+ SyncAlarm *pAlarm;
+ xSyncQueryAlarmReply rep;
+ SyncTrigger *pTrigger;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncQueryAlarmReq);
+
+ rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
+ client, DixReadAccess);
+ if (rc != Success)
+ return rc;
+
+ rep.type = X_Reply;
+ rep.length = bytes_to_int32(sizeof(xSyncQueryAlarmReply) - sizeof(xGenericReply));
+ rep.sequenceNumber = client->sequence;
+
+ pTrigger = &pAlarm->trigger;
+ rep.counter = (pTrigger->pSync) ? pTrigger->pSync->id : None;
+
+#if 0 /* XXX unclear what to do, depends on whether relative value-types
+ * are "consumed" immediately and are considered absolute from then
+ * on.
+ */
+ rep.value_type = pTrigger->value_type;
+ rep.wait_value_hi = XSyncValueHigh32(pTrigger->wait_value);
+ rep.wait_value_lo = XSyncValueLow32(pTrigger->wait_value);
+#else
+ rep.value_type = XSyncAbsolute;
+ rep.wait_value_hi = XSyncValueHigh32(pTrigger->test_value);
+ rep.wait_value_lo = XSyncValueLow32(pTrigger->test_value);
+#endif
+
+ rep.test_type = pTrigger->test_type;
+ rep.delta_hi = XSyncValueHigh32(pAlarm->delta);
+ rep.delta_lo = XSyncValueLow32(pAlarm->delta);
+ rep.events = pAlarm->events;
+ rep.state = pAlarm->state;
+
+ if (client->swapped)
+ {
+ char n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.counter, n);
+ swapl(&rep.wait_value_hi, n);
+ swapl(&rep.wait_value_lo, n);
+ swapl(&rep.test_type, n);
+ swapl(&rep.delta_hi, n);
+ swapl(&rep.delta_lo, n);
+ }
+
+ WriteToClient(client, sizeof(xSyncQueryAlarmReply), (char *) &rep);
+ return Success;
+}
+
+static int
+ProcSyncDestroyAlarm(ClientPtr client)
+{
+ SyncAlarm *pAlarm;
+ int rc;
+ REQUEST(xSyncDestroyAlarmReq);
+
+ REQUEST_SIZE_MATCH(xSyncDestroyAlarmReq);
+
+ rc = dixLookupResourceByType((pointer *)&pAlarm, stuff->alarm, RTAlarm,
+ client, DixDestroyAccess);
+ if (rc != Success)
+ return rc;
+
+ FreeResource(stuff->alarm, RT_NONE);
+ return Success;
+}
+
+static int
+ProcSyncCreateFence(ClientPtr client)
+{
+ REQUEST(xSyncCreateFenceReq);
+ DrawablePtr pDraw;
+ SyncFence *pFence;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncCreateFenceReq);
+
+ rc = dixLookupDrawable(&pDraw, stuff->d, client, M_ANY, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ LEGAL_NEW_RESOURCE(stuff->fid, client);
+
+ if (!(pFence = (SyncFence *)SyncCreate(client,
+ stuff->fid,
+ SYNC_FENCE)))
+ return BadAlloc;
+
+ miSyncInitFence(pDraw->pScreen, pFence, stuff->initially_triggered);
+
+ return client->noClientException;
+}
+
+static int
+FreeFence(void *obj, XID id)
+{
+ SyncFence *pFence = (SyncFence *) obj;
+
+ miSyncDestroyFence(pFence);
+
+ return Success;
+}
+
+int SyncVerifyFence(SyncFence **ppSyncFence, XID fid,
+ ClientPtr client, Mask mode)
+{
+ int rc = dixLookupResourceByType((pointer *)ppSyncFence, fid, RTFence,
+ client, mode);
+
+ if (rc != Success)
+ client->errorValue = fid;
+
+ return rc;
+}
+
+static int
+ProcSyncTriggerFence(ClientPtr client)
+{
+ REQUEST(xSyncTriggerFenceReq);
+ SyncFence *pFence;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncTriggerFenceReq);
+
+ rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
+ client, DixWriteAccess);
+ if (rc != Success)
+ return rc;
+
+ miSyncTriggerFence(pFence);
+
+ return client->noClientException;
+}
+
+static int
+ProcSyncResetFence(ClientPtr client)
+{
+ REQUEST(xSyncResetFenceReq);
+ SyncFence *pFence;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncResetFenceReq);
+
+ rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
+ client, DixWriteAccess);
+ if (rc != Success)
+ return rc;
+
+ if (pFence->funcs.CheckTriggered(pFence) != TRUE)
+ return BadMatch;
+
+ pFence->funcs.Reset(pFence);
+
+ return client->noClientException;
+}
+
+static int
+ProcSyncDestroyFence(ClientPtr client)
+{
+ REQUEST(xSyncDestroyFenceReq);
+ SyncFence *pFence;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncDestroyFenceReq);
+
+ rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid, RTFence,
+ client, DixDestroyAccess);
+ if (rc != Success)
+ return rc;
+
+ FreeResource(stuff->fid, RT_NONE);
+ return client->noClientException;
+}
+
+static int
+ProcSyncQueryFence(ClientPtr client)
+{
+ REQUEST(xSyncQueryFenceReq);
+ xSyncQueryFenceReply rep;
+ SyncFence *pFence;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xSyncQueryFenceReq);
+
+ rc = dixLookupResourceByType((pointer *)&pFence, stuff->fid,
+ RTFence, client, DixReadAccess);
+ if (rc != Success)
+ return rc;
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+
+ rep.triggered = pFence->funcs.CheckTriggered(pFence);
+
+ if (client->swapped)
+ {
+ char n;
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ }
+
+ WriteToClient(client, sizeof(xSyncQueryFenceReply), (char *) &rep);
+ return client->noClientException;
+}
+
+static int
+ProcSyncAwaitFence(ClientPtr client)
+{
+ REQUEST(xSyncAwaitFenceReq);
+ SyncAwaitUnion *pAwaitUnion;
+ SyncAwait *pAwait;
+ /* Use CARD32 rather than XSyncFence because XIDs are hard-coded to
+ * CARD32 in protocol definitions */
+ CARD32 *pProtocolFences;
+ int status;
+ int len;
+ int items;
+ int i;
+
+ REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
+
+ len = client->req_len << 2;
+ len -= sz_xSyncAwaitFenceReq;
+ items = len / sizeof(CARD32);
+
+ if (items * sizeof(CARD32) != len)
+ {
+ return BadLength;
+ }
+ if (items == 0)
+ {
+ client->errorValue = items; /* XXX protocol change */
+ return BadValue;
+ }
+
+ if (!(pAwaitUnion = SyncAwaitPrologue(client, items)))
+ return BadAlloc;
+
+ /* don't need to do any more memory allocation for this request! */
+
+ pProtocolFences = (CARD32 *) & stuff[1];
+
+ pAwait = &(pAwaitUnion+1)->await; /* skip over header */
+ for (i = 0; i < items; i++, pProtocolFences++, pAwait++)
+ {
+ if (*pProtocolFences == None) /* XXX protocol change */
+ {
+ /* this should take care of removing any triggers created by
+ * this request that have already been registered on sync objects
+ */
+ FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
+ client->errorValue = *pProtocolFences;
+ return SyncErrorBase + XSyncBadCounter;
+ }
+
+ pAwait->trigger.pSync = NULL;
+ /* Provide acceptable values for these unused fields to
+ * satisfy SyncInitTrigger's validation logic
+ */
+ pAwait->trigger.value_type = XSyncAbsolute;
+ XSyncIntToValue(&pAwait->trigger.wait_value, 0);
+ pAwait->trigger.test_type = 0;
+
+ status = SyncInitTrigger(client, &pAwait->trigger,
+ *pProtocolFences, RTFence,
+ XSyncCAAllTrigger);
+ if (status != Success)
+ {
+ /* this should take care of removing any triggers created by
+ * this request that have already been registered on sync objects
+ */
+ FreeResource(pAwaitUnion->header.delete_id, RT_NONE);
+ return status;
+ }
+ /* this is not a mistake -- same function works for both cases */
+ pAwait->trigger.TriggerFired = SyncAwaitTriggerFired;
+ pAwait->trigger.CounterDestroyed = SyncAwaitTriggerFired;
+ /* event_threshold is unused for fence syncs */
+ XSyncIntToValue(&pAwait->event_threshold, 0);
+ pAwait->pHeader = &pAwaitUnion->header;
+ pAwaitUnion->header.num_waitconditions++;
+ }
+
+ SyncAwaitEpilogue(client, items, pAwaitUnion);
+
+ return client->noClientException;
+}
+
+/*
+ * ** Given an extension request, call the appropriate request procedure
+ */
+static int
+ProcSyncDispatch(ClientPtr client)
+{
+ REQUEST(xReq);
+
+ switch (stuff->data)
+ {
+ case X_SyncInitialize:
+ return ProcSyncInitialize(client);
+ case X_SyncListSystemCounters:
+ return ProcSyncListSystemCounters(client);
+ case X_SyncCreateCounter:
+ return ProcSyncCreateCounter(client);
+ case X_SyncSetCounter:
+ return ProcSyncSetCounter(client);
+ case X_SyncChangeCounter:
+ return ProcSyncChangeCounter(client);
+ case X_SyncQueryCounter:
+ return ProcSyncQueryCounter(client);
+ case X_SyncDestroyCounter:
+ return ProcSyncDestroyCounter(client);
+ case X_SyncAwait:
+ return ProcSyncAwait(client);
+ case X_SyncCreateAlarm:
+ return ProcSyncCreateAlarm(client);
+ case X_SyncChangeAlarm:
+ return ProcSyncChangeAlarm(client);
+ case X_SyncQueryAlarm:
+ return ProcSyncQueryAlarm(client);
+ case X_SyncDestroyAlarm:
+ return ProcSyncDestroyAlarm(client);
+ case X_SyncSetPriority:
+ return ProcSyncSetPriority(client);
+ case X_SyncGetPriority:
+ return ProcSyncGetPriority(client);
+ case X_SyncCreateFence:
+ return ProcSyncCreateFence(client);
+ case X_SyncTriggerFence:
+ return ProcSyncTriggerFence(client);
+ case X_SyncResetFence:
+ return ProcSyncResetFence(client);
+ case X_SyncDestroyFence:
+ return ProcSyncDestroyFence(client);
+ case X_SyncQueryFence:
+ return ProcSyncQueryFence(client);
+ case X_SyncAwaitFence:
+ return ProcSyncAwaitFence(client);
+ default:
+ return BadRequest;
+ }
+}
+
+/*
+ * Boring Swapping stuff ...
+ */
+
+static int
+SProcSyncInitialize(ClientPtr client)
+{
+ REQUEST(xSyncInitializeReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncInitializeReq);
+
+ return ProcSyncInitialize(client);
+}
+
+static int
+SProcSyncListSystemCounters(ClientPtr client)
+{
+ REQUEST(xSyncListSystemCountersReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncListSystemCountersReq);
+
+ return ProcSyncListSystemCounters(client);
+}
+
+static int
+SProcSyncCreateCounter(ClientPtr client)
+{
+ REQUEST(xSyncCreateCounterReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncCreateCounterReq);
+ swapl(&stuff->cid, n);
+ swapl(&stuff->initial_value_lo, n);
+ swapl(&stuff->initial_value_hi, n);
+
+ return ProcSyncCreateCounter(client);
+}
+
+static int
+SProcSyncSetCounter(ClientPtr client)
+{
+ REQUEST(xSyncSetCounterReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncSetCounterReq);
+ swapl(&stuff->cid, n);
+ swapl(&stuff->value_lo, n);
+ swapl(&stuff->value_hi, n);
+
+ return ProcSyncSetCounter(client);
+}
+
+static int
+SProcSyncChangeCounter(ClientPtr client)
+{
+ REQUEST(xSyncChangeCounterReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncChangeCounterReq);
+ swapl(&stuff->cid, n);
+ swapl(&stuff->value_lo, n);
+ swapl(&stuff->value_hi, n);
+
+ return ProcSyncChangeCounter(client);
+}
+
+static int
+SProcSyncQueryCounter(ClientPtr client)
+{
+ REQUEST(xSyncQueryCounterReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncQueryCounterReq);
+ swapl(&stuff->counter, n);
+
+ return ProcSyncQueryCounter(client);
+}
+
+static int
+SProcSyncDestroyCounter(ClientPtr client)
+{
+ REQUEST(xSyncDestroyCounterReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncDestroyCounterReq);
+ swapl(&stuff->counter, n);
+
+ return ProcSyncDestroyCounter(client);
+}
+
+static int
+SProcSyncAwait(ClientPtr client)
+{
+ REQUEST(xSyncAwaitReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xSyncAwaitReq);
+ SwapRestL(stuff);
+
+ return ProcSyncAwait(client);
+}
+
+static int
+SProcSyncCreateAlarm(ClientPtr client)
+{
+ REQUEST(xSyncCreateAlarmReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xSyncCreateAlarmReq);
+ swapl(&stuff->id, n);
+ swapl(&stuff->valueMask, n);
+ SwapRestL(stuff);
+
+ return ProcSyncCreateAlarm(client);
+}
+
+static int
+SProcSyncChangeAlarm(ClientPtr client)
+{
+ REQUEST(xSyncChangeAlarmReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xSyncChangeAlarmReq);
+ swapl(&stuff->alarm, n);
+ swapl(&stuff->valueMask, n);
+ SwapRestL(stuff);
+ return ProcSyncChangeAlarm(client);
+}
+
+static int
+SProcSyncQueryAlarm(ClientPtr client)
+{
+ REQUEST(xSyncQueryAlarmReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncQueryAlarmReq);
+ swapl(&stuff->alarm, n);
+
+ return ProcSyncQueryAlarm(client);
+}
+
+static int
+SProcSyncDestroyAlarm(ClientPtr client)
+{
+ REQUEST(xSyncDestroyAlarmReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncDestroyAlarmReq);
+ swapl(&stuff->alarm, n);
+
+ return ProcSyncDestroyAlarm(client);
+}
+
+static int
+SProcSyncSetPriority(ClientPtr client)
+{
+ REQUEST(xSyncSetPriorityReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncSetPriorityReq);
+ swapl(&stuff->id, n);
+ swapl(&stuff->priority, n);
+
+ return ProcSyncSetPriority(client);
+}
+
+static int
+SProcSyncGetPriority(ClientPtr client)
+{
+ REQUEST(xSyncGetPriorityReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncGetPriorityReq);
+ swapl(&stuff->id, n);
+
+ return ProcSyncGetPriority(client);
+}
+
+static int
+SProcSyncCreateFence(ClientPtr client)
+{
+ REQUEST(xSyncCreateFenceReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncCreateFenceReq);
+ swapl(&stuff->fid, n);
+
+ return ProcSyncCreateFence(client);
+}
+
+static int
+SProcSyncTriggerFence(ClientPtr client)
+{
+ REQUEST(xSyncTriggerFenceReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncTriggerFenceReq);
+ swapl(&stuff->fid, n);
+
+ return ProcSyncTriggerFence(client);
+}
+
+static int
+SProcSyncResetFence(ClientPtr client)
+{
+ REQUEST(xSyncResetFenceReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncResetFenceReq);
+ swapl(&stuff->fid, n);
+
+ return ProcSyncResetFence(client);
+}
+
+static int
+SProcSyncDestroyFence(ClientPtr client)
+{
+ REQUEST(xSyncDestroyFenceReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncDestroyFenceReq);
+ swapl(&stuff->fid, n);
+
+ return ProcSyncDestroyFence(client);
+}
+
+static int
+SProcSyncQueryFence(ClientPtr client)
+{
+ REQUEST(xSyncQueryFenceReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_SIZE_MATCH (xSyncQueryFenceReq);
+ swapl(&stuff->fid, n);
+
+ return ProcSyncQueryFence(client);
+}
+
+static int
+SProcSyncAwaitFence(ClientPtr client)
+{
+ REQUEST(xSyncAwaitFenceReq);
+ char n;
+
+ swaps(&stuff->length, n);
+ REQUEST_AT_LEAST_SIZE(xSyncAwaitFenceReq);
+ SwapRestL(stuff);
+
+ return ProcSyncAwaitFence(client);
+}
+
+static int
+SProcSyncDispatch(ClientPtr client)
+{
+ REQUEST(xReq);
+
+ switch (stuff->data)
+ {
+ case X_SyncInitialize:
+ return SProcSyncInitialize(client);
+ case X_SyncListSystemCounters:
+ return SProcSyncListSystemCounters(client);
+ case X_SyncCreateCounter:
+ return SProcSyncCreateCounter(client);
+ case X_SyncSetCounter:
+ return SProcSyncSetCounter(client);
+ case X_SyncChangeCounter:
+ return SProcSyncChangeCounter(client);
+ case X_SyncQueryCounter:
+ return SProcSyncQueryCounter(client);
+ case X_SyncDestroyCounter:
+ return SProcSyncDestroyCounter(client);
+ case X_SyncAwait:
+ return SProcSyncAwait(client);
+ case X_SyncCreateAlarm:
+ return SProcSyncCreateAlarm(client);
+ case X_SyncChangeAlarm:
+ return SProcSyncChangeAlarm(client);
+ case X_SyncQueryAlarm:
+ return SProcSyncQueryAlarm(client);
+ case X_SyncDestroyAlarm:
+ return SProcSyncDestroyAlarm(client);
+ case X_SyncSetPriority:
+ return SProcSyncSetPriority(client);
+ case X_SyncGetPriority:
+ return SProcSyncGetPriority(client);
+ case X_SyncCreateFence:
+ return SProcSyncCreateFence(client);
+ case X_SyncTriggerFence:
+ return SProcSyncTriggerFence(client);
+ case X_SyncResetFence:
+ return SProcSyncResetFence(client);
+ case X_SyncDestroyFence:
+ return SProcSyncDestroyFence(client);
+ case X_SyncQueryFence:
+ return SProcSyncQueryFence(client);
+ case X_SyncAwaitFence:
+ return SProcSyncAwaitFence(client);
+ default:
+ return BadRequest;
+ }
+}
+
+/*
+ * Event Swapping
+ */
+
+static void
+SCounterNotifyEvent(xSyncCounterNotifyEvent *from, xSyncCounterNotifyEvent *to)
+{
+ to->type = from->type;
+ to->kind = from->kind;
+ cpswaps(from->sequenceNumber, to->sequenceNumber);
+ cpswapl(from->counter, to->counter);
+ cpswapl(from->wait_value_lo, to->wait_value_lo);
+ cpswapl(from->wait_value_hi, to->wait_value_hi);
+ cpswapl(from->counter_value_lo, to->counter_value_lo);
+ cpswapl(from->counter_value_hi, to->counter_value_hi);
+ cpswapl(from->time, to->time);
+ cpswaps(from->count, to->count);
+ to->destroyed = from->destroyed;
+}
+
+
+static void
+SAlarmNotifyEvent(xSyncAlarmNotifyEvent *from, xSyncAlarmNotifyEvent *to)
+{
+ to->type = from->type;
+ to->kind = from->kind;
+ cpswaps(from->sequenceNumber, to->sequenceNumber);
+ cpswapl(from->alarm, to->alarm);
+ cpswapl(from->counter_value_lo, to->counter_value_lo);
+ cpswapl(from->counter_value_hi, to->counter_value_hi);
+ cpswapl(from->alarm_value_lo, to->alarm_value_lo);
+ cpswapl(from->alarm_value_hi, to->alarm_value_hi);
+ cpswapl(from->time, to->time);
+ to->state = from->state;
+}
+
+/*
+ * ** Close everything down. ** This is fairly simple for now.
+ */
+/* ARGSUSED */
+static void
+SyncResetProc(ExtensionEntry *extEntry)
+{
+ free(SysCounterList);
+ SysCounterList = NULL;
+ RTCounter = 0;
+}
+
+/*
+ * ** Initialise the extension.
+ */
+void
+SyncExtensionInit(void)
+{
+ ExtensionEntry *extEntry;
+ int s;
+
+ for (s = 0; s < screenInfo.numScreens; s++)
+ miSyncSetup(screenInfo.screens[s]);
+
+ if (RTCounter == 0)
+ {
+ RTCounter = CreateNewResourceType(FreeCounter, "SyncCounter");
+ }
+ RTAlarm = CreateNewResourceType(FreeAlarm, "SyncAlarm");
+ RTAwait = CreateNewResourceType(FreeAwait, "SyncAwait");
+ RTFence = CreateNewResourceType(FreeFence, "SyncFence");
+ if (RTAwait)
+ RTAwait |= RC_NEVERRETAIN;
+ RTAlarmClient = CreateNewResourceType(FreeAlarmClient, "SyncAlarmClient");
+ if (RTAlarmClient)
+ RTAlarmClient |= RC_NEVERRETAIN;
+
+ if (RTCounter == 0 || RTAwait == 0 || RTAlarm == 0 ||
+ RTAlarmClient == 0 ||
+ (extEntry = AddExtension(SYNC_NAME,
+ XSyncNumberEvents, XSyncNumberErrors,
+ ProcSyncDispatch, SProcSyncDispatch,
+ SyncResetProc,
+ StandardMinorOpcode)) == NULL)
+ {
+ ErrorF("Sync Extension %d.%d failed to Initialise\n",
+ SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
+ return;
+ }
+
+ SyncEventBase = extEntry->eventBase;
+ SyncErrorBase = extEntry->errorBase;
+ EventSwapVector[SyncEventBase + XSyncCounterNotify] = (EventSwapPtr) SCounterNotifyEvent;
+ EventSwapVector[SyncEventBase + XSyncAlarmNotify] = (EventSwapPtr) SAlarmNotifyEvent;
+
+ SetResourceTypeErrorValue(RTCounter, SyncErrorBase + XSyncBadCounter);
+ SetResourceTypeErrorValue(RTAlarm, SyncErrorBase + XSyncBadAlarm);
+ SetResourceTypeErrorValue(RTFence, SyncErrorBase + XSyncBadFence);
+
+ /*
+ * Although SERVERTIME is implemented by the OS layer, we initialise it
+ * here because doing it in OsInit() is too early. The resource database
+ * is not initialised when OsInit() is called. This is just about OK
+ * because there is always a servertime counter.
+ */
+ SyncInitServerTime();
+ SyncInitIdleTime();
+
+#ifdef DEBUG
+ fprintf(stderr, "Sync Extension %d.%d\n",
+ SYNC_MAJOR_VERSION, SYNC_MINOR_VERSION);
+#endif
+}
+
+
+/*
+ * ***** SERVERTIME implementation - should go in its own file in OS directory?
+ */
+
+
+
+static pointer ServertimeCounter;
+static XSyncValue Now;
+static XSyncValue *pnext_time;
+
+#define GetTime()\
+{\
+ unsigned long millis = GetTimeInMillis();\
+ unsigned long maxis = XSyncValueHigh32(Now);\
+ if (millis < XSyncValueLow32(Now)) maxis++;\
+ XSyncIntsToValue(&Now, millis, maxis);\
+}
+
+/*
+*** Server Block Handler
+*** code inspired by multibuffer extension (now deprecated)
+ */
+/*ARGSUSED*/
+static void
+ServertimeBlockHandler(void *env, struct timeval **wt, void *LastSelectMask)
+{
+ XSyncValue delay;
+ unsigned long timeout;
+
+ if (pnext_time)
+ {
+ GetTime();
+
+ if (XSyncValueGreaterOrEqual(Now, *pnext_time))
+ {
+ timeout = 0;
+ }
+ else
+ {
+ Bool overflow;
+ XSyncValueSubtract(&delay, *pnext_time, Now, &overflow);
+ (void)overflow;
+ timeout = XSyncValueLow32(delay);
+ }
+ AdjustWaitForDelay(wt, timeout); /* os/utils.c */
+ }
+}
+
+/*
+*** Wakeup Handler
+ */
+/*ARGSUSED*/
+static void
+ServertimeWakeupHandler(void *env, int rc, void *LastSelectMask)
+{
+ if (pnext_time)
+ {
+ GetTime();
+
+ if (XSyncValueGreaterOrEqual(Now, *pnext_time))
+ {
+ SyncChangeCounter(ServertimeCounter, Now);
+ }
+ }
+}
+
+static void
+ServertimeQueryValue(void *pCounter, CARD64 *pValue_return)
+{
+ GetTime();
+ *pValue_return = Now;
+}
+
+static void
+ServertimeBracketValues(void *pCounter, CARD64 *pbracket_less,
+ CARD64 *pbracket_greater)
+{
+ if (!pnext_time && pbracket_greater)
+ {
+ RegisterBlockAndWakeupHandlers(ServertimeBlockHandler,
+ ServertimeWakeupHandler,
+ NULL);
+ }
+ else if (pnext_time && !pbracket_greater)
+ {
+ RemoveBlockAndWakeupHandlers(ServertimeBlockHandler,
+ ServertimeWakeupHandler,
+ NULL);
+ }
+ pnext_time = pbracket_greater;
+}
+
+static void
+SyncInitServerTime(void)
+{
+ CARD64 resolution;
+
+ XSyncIntsToValue(&Now, GetTimeInMillis(), 0);
+ XSyncIntToValue(&resolution, 4);
+ ServertimeCounter = SyncCreateSystemCounter("SERVERTIME", Now, resolution,
+ XSyncCounterNeverDecreases,
+ ServertimeQueryValue, ServertimeBracketValues);
+ pnext_time = NULL;
+}
+
+
+
+/*
+ * IDLETIME implementation
+ */
+
+static SyncCounter *IdleTimeCounter;
+static XSyncValue *pIdleTimeValueLess;
+static XSyncValue *pIdleTimeValueGreater;
+
+static void
+IdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return)
+{
+ CARD32 idle = GetTimeInMillis() - lastDeviceEventTime.milliseconds;
+ XSyncIntsToValue (pValue_return, idle, 0);
+}
+
+static void
+IdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask)
+{
+ XSyncValue idle, old_idle;
+ SyncTriggerList *list = IdleTimeCounter->sync.pTriglist;
+ SyncTrigger *trig;
+
+ if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
+ return;
+
+ old_idle = IdleTimeCounter->value;
+ IdleTimeQueryValue (NULL, &idle);
+ IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
+
+ if (pIdleTimeValueLess &&
+ XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))
+ {
+ /*
+ * We've been idle for less than the threshold value, and someone
+ * wants to know about that, but now we need to know whether they
+ * want level or edge trigger. Check the trigger list against the
+ * current idle time, and if any succeed, bomb out of select()
+ * immediately so we can reschedule.
+ */
+
+ for (list = IdleTimeCounter->sync.pTriglist; list; list = list->next) {
+ trig = list->pTrigger;
+ if (trig->CheckTrigger(trig, old_idle)) {
+ AdjustWaitForDelay(wt, 0);
+ break;
+ }
+ }
+ /*
+ * We've been called exactly on the idle time, but we have a
+ * NegativeTransition trigger which requires a transition from an
+ * idle time greater than this. Schedule a wakeup for the next
+ * millisecond so we won't miss a transition.
+ */
+ if (XSyncValueEqual (idle, *pIdleTimeValueLess))
+ AdjustWaitForDelay(wt, 1);
+ }
+ else if (pIdleTimeValueGreater)
+ {
+ /*
+ * There's a threshold in the positive direction. If we've been
+ * idle less than it, schedule a wakeup for sometime in the future.
+ * If we've been idle more than it, and someone wants to know about
+ * that level-triggered, schedule an immediate wakeup.
+ */
+ unsigned long timeout = -1;
+
+ if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) {
+ XSyncValue value;
+ Bool overflow;
+
+ XSyncValueSubtract (&value, *pIdleTimeValueGreater,
+ idle, &overflow);
+ timeout = min(timeout, XSyncValueLow32 (value));
+ } else {
+ for (list = IdleTimeCounter->sync.pTriglist; list; list = list->next) {
+ trig = list->pTrigger;
+ if (trig->CheckTrigger(trig, old_idle)) {
+ timeout = min(timeout, 0);
+ break;
+ }
+ }
+ }
+
+ AdjustWaitForDelay (wt, timeout);
+ }
+
+ IdleTimeCounter->value = old_idle; /* pop */
+}
+
+static void
+IdleTimeWakeupHandler (pointer env, int rc, pointer LastSelectMask)
+{
+ XSyncValue idle;
+
+ if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
+ return;
+
+ IdleTimeQueryValue (NULL, &idle);
+
+ if ((pIdleTimeValueGreater &&
+ XSyncValueGreaterOrEqual (idle, *pIdleTimeValueGreater)) ||
+ (pIdleTimeValueLess &&
+ XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)))
+ {
+ SyncChangeCounter (IdleTimeCounter, idle);
+ }
+}
+
+static void
+IdleTimeBracketValues (pointer pCounter, CARD64 *pbracket_less,
+ CARD64 *pbracket_greater)
+{
+ Bool registered = (pIdleTimeValueLess || pIdleTimeValueGreater);
+
+ if (registered && !pbracket_less && !pbracket_greater)
+ {
+ RemoveBlockAndWakeupHandlers(IdleTimeBlockHandler,
+ IdleTimeWakeupHandler,
+ NULL);
+ }
+ else if (!registered && (pbracket_less || pbracket_greater))
+ {
+ RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
+ IdleTimeWakeupHandler,
+ NULL);
+ }
+
+ pIdleTimeValueGreater = pbracket_greater;
+ pIdleTimeValueLess = pbracket_less;
+}
+
+static void
+SyncInitIdleTime (void)
+{
+ CARD64 resolution;
+ XSyncValue idle;
+
+ IdleTimeQueryValue (NULL, &idle);
+ XSyncIntToValue (&resolution, 4);
+
+ IdleTimeCounter = SyncCreateSystemCounter ("IDLETIME", idle, resolution,
+ XSyncCounterUnrestricted,
+ IdleTimeQueryValue,
+ IdleTimeBracketValues);
+
+ pIdleTimeValueLess = pIdleTimeValueGreater = NULL;
+}
diff --git a/xorg-server/hw/xfree86/loader/sdksyms.sh b/xorg-server/hw/xfree86/loader/sdksyms.sh
index c25aaf010..f60b8ed74 100644
--- a/xorg-server/hw/xfree86/loader/sdksyms.sh
+++ b/xorg-server/hw/xfree86/loader/sdksyms.sh
@@ -1,420 +1,424 @@
-#!/bin/sh
-
-cat > sdksyms.c << EOF
-/* This file is automatically generated by sdksyms.sh. */
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-
-#ifdef HAVE_XORG_CONFIG_H
-#include <xorg-config.h>
-#endif
-
-
-/* These must be included first */
-#include "misc.h"
-#include "miscstruct.h"
-
-
-/* render/Makefile.am */
-#include "picture.h"
-#include "mipict.h"
-#include "glyphstr.h"
-#include "picturestr.h"
-
-
-/* fb/Makefile.am -- module */
-/*
-#include "fb.h"
-#include "fbrop.h"
-#include "fboverlay.h"
-#include "wfbrename.h"
-#include "fbpict.h"
- */
-
-
-/* miext/shadow/Makefile.am -- module */
-/*
-#include "shadow.h"
- */
-
-
-/* miext/damage/Makefile.am */
-#include "damage.h"
-#include "damagestr.h"
-
-/* miext/sync/Makefile.am */
-#include "misync.h"
-#include "misyncstr.h"
-
-/* Xext/Makefile.am -- half is module, half is builtin */
-/*
-#include "xvdix.h"
-#include "xvmcext.h"
- */
-#include "geext.h"
-#include "geint.h"
-#include "shmint.h"
-#include "syncsdk.h"
-#if XINERAMA
-# include "panoramiXsrv.h"
-# include "panoramiX.h"
-#endif
-
-
-/* hw/xfree86/int10/Makefile.am -- module */
-/*
-#include "xf86int10.h"
- */
-
-
-/* hw/xfree86/i2c/Makefile.am -- "mostly" modules */
-#include "xf86i2c.h"
-/*
-#include "bt829.h"
-#include "fi1236.h"
-#include "msp3430.h"
-#include "tda8425.h"
-#include "tda9850.h"
-#include "tda9885.h"
-#include "uda1380.h"
-#include "i2c_def.h"
- */
-
-
-/* hw/xfree86/modes/Makefile.am */
-#include "xf86Crtc.h"
-#include "xf86Modes.h"
-#include "xf86RandR12.h"
-/* #include "xf86Rename.h" */
-
-
-/* hw/xfree86/ddc/Makefile.am */
-#include "edid.h"
-#include "xf86DDC.h"
-
-
-/* hw/xfree86/dri2/Makefile.am -- module */
-/*
-#if DRI2
-# include "dri2.h"
-#endif
- */
-
-
-/* hw/xfree86/vgahw/Makefile.am -- module */
-/*
-#include "vgaHW.h"
- */
-
-
-/* hw/xfree86/fbdevhw/Makefile.am -- module */
-/*
-#include "fbdevhw.h"
- */
-
-
-/* hw/xfree86/common/Makefile.am */
-#include "compiler.h"
-#include "fourcc.h"
-#include "xf86.h"
-#include "xf86Module.h"
-#include "xf86Opt.h"
-#include "xf86PciInfo.h"
-#include "xf86Priv.h"
-#include "xf86Privstr.h"
-#include "xf86cmap.h"
-#include "xf86fbman.h"
-#include "xf86str.h"
-#include "xf86Xinput.h"
-#include "xf86VGAarbiter.h"
-#include "xisb.h"
-#if XV
-# include "xf86xv.h"
-# include "xf86xvmc.h"
-# include "xf86xvpriv.h"
-#endif
-/* XF86VidMode code is in libextmod module */
-/*
-#if XF86VIDMODE
-# include "vidmodeproc.h"
-#endif
- */
-#include "xorgVersion.h"
-#if defined(__sparc__) || defined(__sparc)
-# include "xf86sbusBus.h"
-#endif
-
-
-/* hw/xfree86/ramdac/Makefile.am */
-#include "BT.h"
-#include "IBM.h"
-#include "TI.h"
-#include "xf86Cursor.h"
-#include "xf86RamDac.h"
-
-
-/* hw/xfree86/shadowfb/Makefile.am -- module */
-/*
-#include "shadowfb.h"
- */
-
-
-/* hw/xfree86/os-support/solaris/Makefile.am */
-#if defined(sun386)
-# include "agpgart.h"
-#endif
-
-
-/* hw/xfree86/os-support/Makefile.am */
-#include "xf86_OSproc.h"
-#include "xf86_OSlib.h"
-
-
-/* hw/xfree86/os-support/bus/Makefile.am */
-#include "xf86Pci.h"
-#if defined(__sparc__) || defined(__sparc)
-# include "xf86Sbus.h"
-#endif
-
-
-/* hw/xfree86/xaa/Makefile.am -- module */
-/*
-#include "xaa.h"
-#include "xaalocal.h"
-#include "xaarop.h"
- */
-
-
-/* hw/xfree86/dixmods/extmod/Makefile.am -- module */
-/*
-#include "dgaproc.h"
- */
-
-
-/* hw/xfree86/parser/Makefile.am */
-#include "xf86Parser.h"
-#include "xf86Optrec.h"
-
-
-/* hw/xfree86/vbe/Makefile.am -- module */
-/*
-#include "vbe.h"
-#include "vbeModes.h"
- */
-
-
-/* hw/xfree86/dri/Makefile.am -- module */
-/*
-#if XF86DRI
-# include "dri.h"
-# include "sarea.h"
-# include "dristruct.h"
-#endif
- */
-
-
-/* mi/Makefile.am */
-#include "micmap.h"
-#include "miline.h"
-#include "mipointer.h"
-#include "mi.h"
-#include "mibstore.h"
-#include "migc.h"
-#include "mipointrst.h"
-#include "mizerarc.h"
-#include "micoord.h"
-#include "mifillarc.h"
-#include "mispans.h"
-#include "miwideline.h"
-#include "mistruct.h"
-#include "mifpoly.h"
-#include "mioverlay.h"
-
-
-/* randr/Makefile.am */
-#include "randrstr.h"
-#include "rrtransform.h"
-
-
-/* dbe/Makefile.am -- module */
-/*
-#include "dbestruct.h"
- */
-
-
-/* exa/Makefile.am -- module */
-/*
-#include "exa.h"
- */
-
-
-/* xfixes/Makefile.am */
-#include "xfixes.h"
-
-
-/* include/Makefile.am */
-#include "XIstubs.h"
-#include "Xprintf.h"
-#include "closestr.h"
-#include "closure.h"
-#include "colormap.h"
-#include "colormapst.h"
-#include "hotplug.h"
-#include "cursor.h"
-#include "cursorstr.h"
-#include "dix.h"
-#include "dixaccess.h"
-#include "dixevents.h"
-#include "dixfont.h"
-#include "dixfontstr.h"
-#include "dixgrabs.h"
-#include "dixstruct.h"
-#include "exevents.h"
-#include "extension.h"
-#include "extinit.h"
-#include "extnsionst.h"
-#include "gc.h"
-#include "gcstruct.h"
-#include "globals.h"
-#include "input.h"
-#include "inputstr.h"
-/* already included */
-/*
-#include "misc.h"
-#include "miscstruct.h"
- */
-#include "opaque.h"
-#include "os.h"
-#include "pixmap.h"
-#include "pixmapstr.h"
-#include "privates.h"
-#include "property.h"
-#include "propertyst.h"
-#include "ptrveloc.h"
-#include "region.h"
-#include "regionstr.h"
-#include "registry.h"
-#include "resource.h"
-#include "rgb.h"
-#include "screenint.h"
-#include "scrnintstr.h"
-#include "selection.h"
-#include "servermd.h"
-#include "site.h"
-#include "swaprep.h"
-#include "swapreq.h"
-#include "validate.h"
-#include "window.h"
-#include "windowstr.h"
-#include "xace.h"
-#include "xkbfile.h"
-#include "xkbsrv.h"
-#include "xkbstr.h"
-#include "xkbrules.h"
-#include "xserver-properties.h"
-
-EOF
-
-topdir=$1
-shift
-LC_ALL=C
-export LC_ALL
-${CPP:-cpp} "$@" -DXorgLoader sdksyms.c | ${AWK:-awk} -v topdir=$topdir '
-BEGIN {
- sdk = 0;
- print("/*");
- print(" * These symbols are referenced to ensure they");
- print(" * will be available in the X Server binary.");
- print(" */");
- printf("/* topdir=%s */\n", topdir);
- print("_X_HIDDEN void *xorg_symbols[] = {");
-
- printf("sdksyms.c:") > "sdksyms.dep";
-}
-/^# [0-9]+ "/ {
- # Process text after a include in a relative path or when the
- # processed file has a basename matching $top_srcdir.
- # Note that indexing starts at 1; 0 means no match, and there
- # is a starting ".
- sdk = $3 !~ /^"\// || index($3, topdir) == 2;
-
- if (sdk && $3 ~ /\.h"$/) {
- # remove quotes
- gsub(/"/, "", $3);
- line = $2;
- header = $3;
- if (! headers[$3]) {
- printf(" \\\n %s", $3) >> "sdksyms.dep";
- headers[$3] = 1;
- }
- }
- next;
-}
-
-/^extern[ ]/ {
- if (sdk) {
- n = 3;
-
- # skip attribute, if any
- while ($n ~ /^(__attribute__|__global)/ ||
- # skip modifiers, if any
- $n ~ /^\*?(unsigned|const|volatile|struct)$/ ||
- # skip pointer
- $n ~ /\*$/)
- n++;
-
- # type specifier may not be set, as in
- # extern _X_EXPORT unsigned name(...)
- if ($n !~ /[^a-zA-Z0-9_]/)
- n++;
-
- # match
- # extern _X_EXPORT type (* name[])(...)
- if ($n ~ /^[^a-zA-Z0-9_]+$/)
- n++;
-
- # match
- # extern _X_EXPORT const name *const ...
- if ($n ~ /^([^a-zA-Z0-9_]+)?const$/)
- n++;
-
- # actual name may be in the next line, as in
- # extern _X_EXPORT type
- # possibly ending with a *
- # name(...)
- if ($n == "" || $n ~ /^\*+$/) {
- getline;
- n = 1;
- }
-
- # dont modify $0 or $n
- symbol = $n;
-
- # remove starting non word chars
- sub(/^[^a-zA-Z0-9_]+/, "",symbol);
-
- # remove from first non word to end of line
- sub(/[^a-zA-Z0-9_].*/, "", symbol);
-
- #print;
- printf(" (void *) &%-50s /* %s:%s */\n", symbol ",", header, line);
- }
-}
-
-{
- line++;
-}
-
-END {
- print("};");
-
- print("") >> "sdksyms.dep";
-}' > _sdksyms.c
-
-STATUS=$?
-
-cat _sdksyms.c >> sdksyms.c
-rm _sdksyms.c
-
-[ $? != 0 ] && exit $?
-
-exit $STATUS
+#!/bin/sh
+
+cat > sdksyms.c << EOF
+/* This file is automatically generated by sdksyms.sh. */
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+
+/* These must be included first */
+#include "misc.h"
+#include "miscstruct.h"
+
+
+/* render/Makefile.am */
+#include "picture.h"
+#include "mipict.h"
+#include "glyphstr.h"
+#include "picturestr.h"
+
+
+/* fb/Makefile.am -- module */
+/*
+#include "fb.h"
+#include "fbrop.h"
+#include "fboverlay.h"
+#include "wfbrename.h"
+#include "fbpict.h"
+ */
+
+
+/* miext/shadow/Makefile.am -- module */
+/*
+#include "shadow.h"
+ */
+
+
+/* miext/damage/Makefile.am */
+#include "damage.h"
+#include "damagestr.h"
+
+/* miext/sync/Makefile.am */
+#include "misync.h"
+#include "misyncstr.h"
+
+/* Xext/Makefile.am -- half is module, half is builtin */
+/*
+#include "xvdix.h"
+#include "xvmcext.h"
+ */
+#include "geext.h"
+#include "geint.h"
+#include "shmint.h"
+#include "syncsdk.h"
+#if XINERAMA
+# include "panoramiXsrv.h"
+# include "panoramiX.h"
+#endif
+
+
+/* hw/xfree86/int10/Makefile.am -- module */
+/*
+#include "xf86int10.h"
+ */
+
+
+/* hw/xfree86/i2c/Makefile.am -- "mostly" modules */
+#include "xf86i2c.h"
+/*
+#include "bt829.h"
+#include "fi1236.h"
+#include "msp3430.h"
+#include "tda8425.h"
+#include "tda9850.h"
+#include "tda9885.h"
+#include "uda1380.h"
+#include "i2c_def.h"
+ */
+
+
+/* hw/xfree86/modes/Makefile.am */
+#include "xf86Crtc.h"
+#include "xf86Modes.h"
+#include "xf86RandR12.h"
+/* #include "xf86Rename.h" */
+
+
+/* hw/xfree86/ddc/Makefile.am */
+#include "edid.h"
+#include "xf86DDC.h"
+
+
+/* hw/xfree86/dri2/Makefile.am -- module */
+/*
+#if DRI2
+# include "dri2.h"
+#endif
+ */
+
+
+/* hw/xfree86/vgahw/Makefile.am -- module */
+/*
+#include "vgaHW.h"
+ */
+
+
+/* hw/xfree86/fbdevhw/Makefile.am -- module */
+/*
+#include "fbdevhw.h"
+ */
+
+
+/* hw/xfree86/common/Makefile.am */
+#include "compiler.h"
+#include "fourcc.h"
+#include "xf86.h"
+#include "xf86Module.h"
+#include "xf86Opt.h"
+#include "xf86PciInfo.h"
+#include "xf86Priv.h"
+#include "xf86Privstr.h"
+#include "xf86cmap.h"
+#include "xf86fbman.h"
+#include "xf86str.h"
+#include "xf86Xinput.h"
+#include "xf86VGAarbiter.h"
+#include "xisb.h"
+#if XV
+# include "xf86xv.h"
+# include "xf86xvmc.h"
+# include "xf86xvpriv.h"
+#endif
+/* XF86VidMode code is in libextmod module */
+/*
+#if XF86VIDMODE
+# include "vidmodeproc.h"
+#endif
+ */
+#include "xorgVersion.h"
+#if defined(__sparc__) || defined(__sparc)
+# include "xf86sbusBus.h"
+#endif
+
+
+/* hw/xfree86/ramdac/Makefile.am */
+#include "BT.h"
+#include "IBM.h"
+#include "TI.h"
+#include "xf86Cursor.h"
+#include "xf86RamDac.h"
+
+
+/* hw/xfree86/shadowfb/Makefile.am -- module */
+/*
+#include "shadowfb.h"
+ */
+
+
+/* hw/xfree86/os-support/solaris/Makefile.am */
+#if defined(sun386)
+# include "agpgart.h"
+#endif
+
+
+/* hw/xfree86/os-support/Makefile.am */
+#include "xf86_OSproc.h"
+#include "xf86_OSlib.h"
+
+
+/* hw/xfree86/os-support/bus/Makefile.am */
+#include "xf86Pci.h"
+#if defined(__sparc__) || defined(__sparc)
+# include "xf86Sbus.h"
+#endif
+
+
+/* hw/xfree86/xaa/Makefile.am -- module */
+/*
+#include "xaa.h"
+#include "xaalocal.h"
+#include "xaarop.h"
+ */
+
+
+/* hw/xfree86/dixmods/extmod/Makefile.am -- module */
+/*
+#include "dgaproc.h"
+ */
+
+
+/* hw/xfree86/parser/Makefile.am */
+#include "xf86Parser.h"
+#include "xf86Optrec.h"
+
+
+/* hw/xfree86/vbe/Makefile.am -- module */
+/*
+#include "vbe.h"
+#include "vbeModes.h"
+ */
+
+
+/* hw/xfree86/dri/Makefile.am -- module */
+/*
+#if XF86DRI
+# include "dri.h"
+# include "sarea.h"
+# include "dristruct.h"
+#endif
+ */
+
+
+/* mi/Makefile.am */
+#include "micmap.h"
+#include "miline.h"
+#include "mipointer.h"
+#include "mi.h"
+#include "mibstore.h"
+#include "migc.h"
+#include "mipointrst.h"
+#include "mizerarc.h"
+#include "micoord.h"
+#include "mifillarc.h"
+#include "mispans.h"
+#include "miwideline.h"
+#include "mistruct.h"
+#include "mifpoly.h"
+#include "mioverlay.h"
+
+
+/* randr/Makefile.am */
+#include "randrstr.h"
+#include "rrtransform.h"
+
+
+/* dbe/Makefile.am -- module */
+/*
+#include "dbestruct.h"
+ */
+
+
+/* exa/Makefile.am -- module */
+/*
+#include "exa.h"
+ */
+
+
+/* xfixes/Makefile.am */
+#include "xfixes.h"
+
+
+/* include/Makefile.am */
+#include "XIstubs.h"
+#include "Xprintf.h"
+#include "closestr.h"
+#include "closure.h"
+#include "colormap.h"
+#include "colormapst.h"
+#include "hotplug.h"
+#include "cursor.h"
+#include "cursorstr.h"
+#include "dix.h"
+#include "dixaccess.h"
+#include "dixevents.h"
+#include "dixfont.h"
+#include "dixfontstr.h"
+#include "dixgrabs.h"
+#include "dixstruct.h"
+#include "exevents.h"
+#include "extension.h"
+#include "extinit.h"
+#include "extnsionst.h"
+#include "gc.h"
+#include "gcstruct.h"
+#include "globals.h"
+#include "input.h"
+#include "inputstr.h"
+/* already included */
+/*
+#include "misc.h"
+#include "miscstruct.h"
+ */
+#include "opaque.h"
+#include "os.h"
+#include "pixmap.h"
+#include "pixmapstr.h"
+#include "privates.h"
+#include "property.h"
+#include "propertyst.h"
+#include "ptrveloc.h"
+#include "region.h"
+#include "regionstr.h"
+#include "registry.h"
+#include "resource.h"
+#include "rgb.h"
+#include "screenint.h"
+#include "scrnintstr.h"
+#include "selection.h"
+#include "servermd.h"
+#include "site.h"
+#include "swaprep.h"
+#include "swapreq.h"
+#include "validate.h"
+#include "window.h"
+#include "windowstr.h"
+#include "xace.h"
+#include "xkbfile.h"
+#include "xkbsrv.h"
+#include "xkbstr.h"
+#include "xkbrules.h"
+#include "xserver-properties.h"
+
+EOF
+
+topdir=$1
+shift
+LC_ALL=C
+export LC_ALL
+${CPP:-cpp} "$@" -DXorgLoader sdksyms.c | ${AWK:-awk} -v topdir=$topdir '
+BEGIN {
+ sdk = 0;
+ print("/*");
+ print(" * These symbols are referenced to ensure they");
+ print(" * will be available in the X Server binary.");
+ print(" */");
+ printf("/* topdir=%s */\n", topdir);
+ print("_X_HIDDEN void *xorg_symbols[] = {");
+
+ printf("sdksyms.c:") > "sdksyms.dep";
+}
+/^# [0-9]+ "/ {
+ # Process text after a include in a relative path or when the
+ # processed file has a basename matching $top_srcdir.
+ # Note that indexing starts at 1; 0 means no match, and there
+ # is a starting ".
+ sdk = $3 !~ /^"\// || index($3, topdir) == 2;
+
+ if (sdk && $3 ~ /\.h"$/) {
+ # remove quotes
+ gsub(/"/, "", $3);
+ line = $2;
+ header = $3;
+ if (! headers[$3]) {
+ printf(" \\\n %s", $3) >> "sdksyms.dep";
+ headers[$3] = 1;
+ }
+ }
+ next;
+}
+
+/^extern[ ]/ {
+ if (sdk) {
+ n = 3;
+
+ # skip attribute, if any
+ while ($n ~ /^(__attribute__|__global)/ ||
+ # skip modifiers, if any
+ $n ~ /^\*?(unsigned|const|volatile|struct)$/ ||
+ # skip pointer
+ $n ~ /^[a-zA-Z0-9_]*\*$/)
+ n++;
+
+ # type specifier may not be set, as in
+ # extern _X_EXPORT unsigned name(...)
+ if ($n !~ /[^a-zA-Z0-9_]/)
+ n++;
+
+ # go back if we are at the parameter list already
+ if ($n ~ /^[(]([^*].*)?$/)
+ n--;
+
+ # match
+ # extern _X_EXPORT type (* name[])(...)
+ if ($n ~ /^[^a-zA-Z0-9_]+$/)
+ n++;
+
+ # match
+ # extern _X_EXPORT const name *const ...
+ if ($n ~ /^([^a-zA-Z0-9_]+)?const$/)
+ n++;
+
+ # actual name may be in the next line, as in
+ # extern _X_EXPORT type
+ # possibly ending with a *
+ # name(...)
+ if ($n == "" || $n ~ /^\*+$/) {
+ getline;
+ n = 1;
+ }
+
+ # dont modify $0 or $n
+ symbol = $n;
+
+ # remove starting non word chars
+ sub(/^[^a-zA-Z0-9_]+/, "",symbol);
+
+ # remove from first non word to end of line
+ sub(/[^a-zA-Z0-9_].*/, "", symbol);
+
+ #print;
+ printf(" (void *) &%-50s /* %s:%s */\n", symbol ",", header, line);
+ }
+}
+
+{
+ line++;
+}
+
+END {
+ print("};");
+
+ print("") >> "sdksyms.dep";
+}' > _sdksyms.c
+
+STATUS=$?
+
+cat _sdksyms.c >> sdksyms.c
+rm _sdksyms.c
+
+[ $? != 0 ] && exit $?
+
+exit $STATUS
diff --git a/xorg-server/hw/xfree86/modes/xf86EdidModes.c b/xorg-server/hw/xfree86/modes/xf86EdidModes.c
index f8cd9a0ca..d9ece7a14 100644
--- a/xorg-server/hw/xfree86/modes/xf86EdidModes.c
+++ b/xorg-server/hw/xfree86/modes/xf86EdidModes.c
@@ -1,1211 +1,1216 @@
-/*
- * Copyright 2006 Luc Verhaegen.
- * Copyright 2008 Red Hat, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * @file This file covers code to convert a xf86MonPtr containing EDID-probed
- * information into a list of modes, including applying monitor-specific
- * quirks to fix broken EDID data.
- */
-#ifdef HAVE_XORG_CONFIG_H
-#include <xorg-config.h>
-#else
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#endif
-
-#define _PARSE_EDID_
-#include "xf86.h"
-#include "xf86DDC.h"
-#include <X11/Xatom.h>
-#include "property.h"
-#include "propertyst.h"
-#include "xf86Crtc.h"
-#include <string.h>
-#include <math.h>
-
-static void handle_detailed_rblank(struct detailed_monitor_section *det_mon,
- void *data)
-{
- if (det_mon->type == DS_RANGES)
- if (det_mon->section.ranges.supported_blanking & CVT_REDUCED)
- *(Bool*)data = TRUE;
-}
-
-static Bool
-xf86MonitorSupportsReducedBlanking(xf86MonPtr DDC)
-{
- /* EDID 1.4 explicitly defines RB support */
- if (DDC->ver.revision >= 4) {
- Bool ret = FALSE;
-
- xf86ForEachDetailedBlock(DDC, handle_detailed_rblank, &ret);
- return ret;
- }
-
- /* For anything older, assume digital means RB support. Boo. */
- if (DDC->features.input_type)
- return TRUE;
-
- return FALSE;
-}
-
-static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC)
-{
- /* Belinea 10 15 55 */
- if (memcmp (DDC->vendor.name, "MAX", 4) == 0 &&
- ((DDC->vendor.prod_id == 1516) ||
- (DDC->vendor.prod_id == 0x77e)))
- return TRUE;
-
- /* Acer AL1706 */
- if (memcmp (DDC->vendor.name, "ACR", 4) == 0 &&
- DDC->vendor.prod_id == 44358)
- return TRUE;
-
- /* Bug #10814: Samsung SyncMaster 225BW */
- if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
- DDC->vendor.prod_id == 596)
- return TRUE;
-
- /* Bug #10545: Samsung SyncMaster 226BW */
- if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
- DDC->vendor.prod_id == 638)
- return TRUE;
-
- /* Acer F51 */
- if (memcmp (DDC->vendor.name, "API", 4) == 0 &&
- DDC->vendor.prod_id == 0x7602)
- return TRUE;
-
-
- return FALSE;
-}
-
-static Bool quirk_prefer_large_75 (int scrnIndex, xf86MonPtr DDC)
-{
- /* Bug #11603: Funai Electronics PM36B */
- if (memcmp (DDC->vendor.name, "FCM", 4) == 0 &&
- DDC->vendor.prod_id == 13600)
- return TRUE;
-
- return FALSE;
-}
-
-static Bool quirk_detailed_h_in_cm (int scrnIndex, xf86MonPtr DDC)
-{
- /* Bug #11603: Funai Electronics PM36B */
- if (memcmp (DDC->vendor.name, "FCM", 4) == 0 &&
- DDC->vendor.prod_id == 13600)
- return TRUE;
-
- return FALSE;
-}
-
-static Bool quirk_detailed_v_in_cm (int scrnIndex, xf86MonPtr DDC)
-{
- /* Bug #11603: Funai Electronics PM36B */
- if (memcmp (DDC->vendor.name, "FCM", 4) == 0 &&
- DDC->vendor.prod_id == 13600)
- return TRUE;
-
- /* Bug #21000: LGPhilipsLCD LP154W01-TLAJ */
- if (memcmp (DDC->vendor.name, "LPL", 4) == 0 &&
- DDC->vendor.prod_id == 47360)
- return TRUE;
-
- /* Bug #10304: LGPhilipsLCD LP154W01-A5 */
- if (memcmp(DDC->vendor.name, "LPL", 4) == 0 &&
- DDC->vendor.prod_id == 0)
- return TRUE;
-
- /* Bug #24482: LGPhilipsLCD LP154W01-TLA1 */
- if (memcmp(DDC->vendor.name, "LPL", 4) == 0 &&
- DDC->vendor.prod_id == 0x2a00)
- return TRUE;
-
- /* Bug #21750: Samsung Syncmaster 2333HD */
- if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
- DDC->vendor.prod_id == 1157)
- return TRUE;
-
- return FALSE;
-}
-
-static Bool quirk_detailed_use_maximum_size (int scrnIndex, xf86MonPtr DDC)
-{
- /* Bug #21324: Iiyama Vision Master 450 */
- if (memcmp (DDC->vendor.name, "IVM", 4) == 0 &&
- DDC->vendor.prod_id == 6400)
- return TRUE;
-
- return FALSE;
-}
-
-static Bool quirk_135_clock_too_high (int scrnIndex, xf86MonPtr DDC)
-{
- /* Envision Peripherals, Inc. EN-7100e. See bug #9550. */
- if (memcmp (DDC->vendor.name, "EPI", 4) == 0 &&
- DDC->vendor.prod_id == 59264)
- return TRUE;
-
- return FALSE;
-}
-
-static Bool quirk_first_detailed_preferred (int scrnIndex, xf86MonPtr DDC)
-{
- /* Philips 107p5 CRT. Reported on xorg@ with pastebin. */
- if (memcmp (DDC->vendor.name, "PHL", 4) == 0 &&
- DDC->vendor.prod_id == 57364)
- return TRUE;
-
- /* Proview AY765C 17" LCD. See bug #15160*/
- if (memcmp (DDC->vendor.name, "PTS", 4) == 0 &&
- DDC->vendor.prod_id == 765)
- return TRUE;
-
- /* ACR of some sort RH #284231 */
- if (memcmp (DDC->vendor.name, "ACR", 4) == 0 &&
- DDC->vendor.prod_id == 2423)
- return TRUE;
-
- /* Peacock Ergovision 19. See rh#492359 */
- if (memcmp (DDC->vendor.name, "PEA", 4) == 0 &&
- DDC->vendor.prod_id == 9003)
- return TRUE;
-
- return FALSE;
-}
-
-static Bool quirk_detailed_sync_pp(int scrnIndex, xf86MonPtr DDC)
-{
- /* Bug #12439: Samsung SyncMaster 205BW */
- if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
- DDC->vendor.prod_id == 541)
- return TRUE;
- return FALSE;
-}
-
-/* This should probably be made more generic */
-static Bool quirk_dvi_single_link(int scrnIndex, xf86MonPtr DDC)
-{
- /* Red Hat bug #453106: Apple 23" Cinema Display */
- if (memcmp (DDC->vendor.name, "APL", 4) == 0 &&
- DDC->vendor.prod_id == 0x921c)
- return TRUE;
- return FALSE;
-}
-
-typedef struct {
- Bool (*detect) (int scrnIndex, xf86MonPtr DDC);
- ddc_quirk_t quirk;
- char *description;
-} ddc_quirk_map_t;
-
-static const ddc_quirk_map_t ddc_quirks[] = {
- {
- quirk_prefer_large_60, DDC_QUIRK_PREFER_LARGE_60,
- "Detailed timing is not preferred, use largest mode at 60Hz"
- },
- {
- quirk_135_clock_too_high, DDC_QUIRK_135_CLOCK_TOO_HIGH,
- "Recommended 135MHz pixel clock is too high"
- },
- {
- quirk_prefer_large_75, DDC_QUIRK_PREFER_LARGE_75,
- "Detailed timing is not preferred, use largest mode at 75Hz"
- },
- {
- quirk_detailed_h_in_cm, DDC_QUIRK_DETAILED_H_IN_CM,
- "Detailed timings give horizontal size in cm."
- },
- {
- quirk_detailed_v_in_cm, DDC_QUIRK_DETAILED_V_IN_CM,
- "Detailed timings give vertical size in cm."
- },
- {
- quirk_detailed_use_maximum_size, DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE,
- "Use maximum size instead of detailed timing sizes."
- },
- {
- quirk_first_detailed_preferred, DDC_QUIRK_FIRST_DETAILED_PREFERRED,
- "First detailed timing was not marked as preferred."
- },
- {
- quirk_detailed_sync_pp, DDC_QUIRK_DETAILED_SYNC_PP,
- "Use +hsync +vsync for detailed timing."
- },
- {
- quirk_dvi_single_link, DDC_QUIRK_DVI_SINGLE_LINK,
- "Forcing maximum pixel clock to single DVI link."
- },
- {
- NULL, DDC_QUIRK_NONE,
- "No known quirks"
- },
-};
-
-/*
- * These more or less come from the DMT spec. The 720x400 modes are
- * inferred from historical 80x25 practice. The 640x480@67 and 832x624@75
- * modes are old-school Mac modes. The EDID spec says the 1152x864@75 mode
- * should be 1152x870, again for the Mac, but instead we use the x864 DMT
- * mode.
- *
- * The DMT modes have been fact-checked; the rest are mild guesses.
- */
-#define MODEPREFIX NULL, NULL, NULL, 0, M_T_DRIVER
-#define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0
-
-static const DisplayModeRec DDCEstablishedModes[17] = {
- { MODEPREFIX, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */
- { MODEPREFIX, 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */
- { MODEPREFIX, 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */
- { MODEPREFIX, 31500, 640, 664, 704, 832, 0, 480, 489, 492, 520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */
- { MODEPREFIX, 30240, 640, 704, 768, 864, 0, 480, 483, 486, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@67Hz */
- { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */
- { MODEPREFIX, 35500, 720, 738, 846, 900, 0, 400, 421, 423, 449, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 720x400@88Hz */
- { MODEPREFIX, 28320, 720, 738, 846, 900, 0, 400, 412, 414, 449, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@70Hz */
- { MODEPREFIX, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */
- { MODEPREFIX, 78750, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */
- { MODEPREFIX, 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */
- { MODEPREFIX, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */
- { MODEPREFIX, 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 772, 817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz */
- { MODEPREFIX, 57284, 832, 864, 928, 1152, 0, 624, 625, 628, 667, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 832x624@75Hz */
- { MODEPREFIX, 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */
- { MODEPREFIX, 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */
- { MODEPREFIX, 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */
-};
-
-static DisplayModePtr
-DDCModesFromEstablished(int scrnIndex, struct established_timings *timing,
- ddc_quirk_t quirks)
-{
- DisplayModePtr Modes = NULL, Mode = NULL;
- CARD32 bits = (timing->t1) | (timing->t2 << 8) |
- ((timing->t_manu & 0x80) << 9);
- int i;
-
- for (i = 0; i < 17; i++) {
- if (bits & (0x01 << i)) {
- Mode = xf86DuplicateMode(&DDCEstablishedModes[i]);
- Modes = xf86ModesAdd(Modes, Mode);
- }
- }
-
- return Modes;
-}
-
-/* Autogenerated from the DMT spec */
-const DisplayModeRec DMTModes[] = {
- { MODEPREFIX, 31500, 640, 672, 736, 832, 0, 350, 382, 385, 445, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x350@85Hz */
- { MODEPREFIX, 31500, 640, 672, 736, 832, 0, 400, 401, 404, 445, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 640x400@85Hz */
- { MODEPREFIX, 35500, 720, 756, 828, 936, 0, 400, 401, 404, 446, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@85Hz */
- { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */
- { MODEPREFIX, 31500, 640, 664, 704, 832, 0, 480, 489, 492, 520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */
- { MODEPREFIX, 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */
- { MODEPREFIX, 36000, 640, 696, 752, 832, 0, 480, 481, 484, 509, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@85Hz */
- { MODEPREFIX, 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */
- { MODEPREFIX, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */
- { MODEPREFIX, 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */
- { MODEPREFIX, 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */
- { MODEPREFIX, 56250, 800, 832, 896, 1048, 0, 600, 601, 604, 631, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@85Hz */
- { MODEPREFIX, 73250, 800, 848, 880, 960, 0, 600, 603, 607, 636, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 800x600@120Hz RB */
- { MODEPREFIX, 33750, 848, 864, 976, 1088, 0, 480, 486, 494, 517, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 848x480@60Hz */
- { MODEPREFIX, 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 772, 817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz (interlaced) */
- { MODEPREFIX, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */
- { MODEPREFIX, 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */
- { MODEPREFIX, 78750, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */
- { MODEPREFIX, 94500, 1024, 1072, 1168, 1376, 0, 768, 769, 772, 808, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@85Hz */
- { MODEPREFIX, 115500, 1024, 1072, 1104, 1184, 0, 768, 771, 775, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@120Hz RB */
- { MODEPREFIX, 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */
- { MODEPREFIX, 68250, 1280, 1328, 1360, 1440, 0, 768, 771, 778, 790, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@60Hz RB */
- { MODEPREFIX, 79500, 1280, 1344, 1472, 1664, 0, 768, 771, 778, 798, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@60Hz */
- { MODEPREFIX, 102250, 1280, 1360, 1488, 1696, 0, 768, 771, 778, 805, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@75Hz */
- { MODEPREFIX, 117500, 1280, 1360, 1496, 1712, 0, 768, 771, 778, 809, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@85Hz */
- { MODEPREFIX, 140250, 1280, 1328, 1360, 1440, 0, 768, 771, 778, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@120Hz RB */
- { MODEPREFIX, 71000, 1280, 1328, 1360, 1440, 0, 800, 803, 809, 823, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@60Hz RB */
- { MODEPREFIX, 83500, 1280, 1352, 1480, 1680, 0, 800, 803, 809, 831, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@60Hz */
- { MODEPREFIX, 106500, 1280, 1360, 1488, 1696, 0, 800, 803, 809, 838, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@75Hz */
- { MODEPREFIX, 122500, 1280, 1360, 1496, 1712, 0, 800, 803, 809, 843, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@85Hz */
- { MODEPREFIX, 146250, 1280, 1328, 1360, 1440, 0, 800, 803, 809, 847, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@120Hz RB */
- { MODEPREFIX, 108000, 1280, 1376, 1488, 1800, 0, 960, 961, 964, 1000, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@60Hz */
- { MODEPREFIX, 148500, 1280, 1344, 1504, 1728, 0, 960, 961, 964, 1011, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@85Hz */
- { MODEPREFIX, 175500, 1280, 1328, 1360, 1440, 0, 960, 963, 967, 1017, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x960@120Hz RB */
- { MODEPREFIX, 108000, 1280, 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@60Hz */
- { MODEPREFIX, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */
- { MODEPREFIX, 157500, 1280, 1344, 1504, 1728, 0, 1024, 1025, 1028, 1072, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@85Hz */
- { MODEPREFIX, 187250, 1280, 1328, 1360, 1440, 0, 1024, 1027, 1034, 1084, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x1024@120Hz RB */
- { MODEPREFIX, 85500, 1360, 1424, 1536, 1792, 0, 768, 771, 777, 795, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1360x768@60Hz */
- { MODEPREFIX, 148250, 1360, 1408, 1440, 1520, 0, 768, 771, 776, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1360x768@120Hz RB */
- { MODEPREFIX, 101000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@60Hz RB */
- { MODEPREFIX, 121750, 1400, 1488, 1632, 1864, 0, 1050, 1053, 1057, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@60Hz */
- { MODEPREFIX, 156000, 1400, 1504, 1648, 1896, 0, 1050, 1053, 1057, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@75Hz */
- { MODEPREFIX, 179500, 1400, 1504, 1656, 1912, 0, 1050, 1053, 1057, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@85Hz */
- { MODEPREFIX, 208000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@120Hz RB */
- { MODEPREFIX, 88750, 1440, 1488, 1520, 1600, 0, 900, 903, 909, 926, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@60Hz RB */
- { MODEPREFIX, 106500, 1440, 1520, 1672, 1904, 0, 900, 903, 909, 934, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@60Hz */
- { MODEPREFIX, 136750, 1440, 1536, 1688, 1936, 0, 900, 903, 909, 942, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@75Hz */
- { MODEPREFIX, 157000, 1440, 1544, 1696, 1952, 0, 900, 903, 909, 948, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@85Hz */
- { MODEPREFIX, 182750, 1440, 1488, 1520, 1600, 0, 900, 903, 909, 953, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@120Hz RB */
- { MODEPREFIX, 162000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@60Hz */
- { MODEPREFIX, 175500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@65Hz */
- { MODEPREFIX, 189000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@70Hz */
- { MODEPREFIX, 202500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@75Hz */
- { MODEPREFIX, 229500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@85Hz */
- { MODEPREFIX, 268250, 1600, 1648, 1680, 1760, 0, 1200, 1203, 1207, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1600x1200@120Hz RB */
- { MODEPREFIX, 119000, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@60Hz RB */
- { MODEPREFIX, 146250, 1680, 1784, 1960, 2240, 0, 1050, 1053, 1059, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@60Hz */
- { MODEPREFIX, 187000, 1680, 1800, 1976, 2272, 0, 1050, 1053, 1059, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@75Hz */
- { MODEPREFIX, 214750, 1680, 1808, 1984, 2288, 0, 1050, 1053, 1059, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@85Hz */
- { MODEPREFIX, 245500, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@120Hz RB */
- { MODEPREFIX, 204750, 1792, 1920, 2120, 2448, 0, 1344, 1345, 1348, 1394, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@60Hz */
- { MODEPREFIX, 261000, 1792, 1888, 2104, 2456, 0, 1344, 1345, 1348, 1417, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@75Hz */
- { MODEPREFIX, 333250, 1792, 1840, 1872, 1952, 0, 1344, 1347, 1351, 1423, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1792x1344@120Hz RB */
- { MODEPREFIX, 218250, 1856, 1952, 2176, 2528, 0, 1392, 1393, 1396, 1439, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@60Hz */
- { MODEPREFIX, 288000, 1856, 1984, 2208, 2560, 0, 1392, 1393, 1396, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@75Hz */
- { MODEPREFIX, 356500, 1856, 1904, 1936, 2016, 0, 1392, 1395, 1399, 1474, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1856x1392@120Hz RB */
- { MODEPREFIX, 154000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1235, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@60Hz RB */
- { MODEPREFIX, 193250, 1920, 2056, 2256, 2592, 0, 1200, 1203, 1209, 1245, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@60Hz */
- { MODEPREFIX, 245250, 1920, 2056, 2264, 2608, 0, 1200, 1203, 1209, 1255, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@75Hz */
- { MODEPREFIX, 281250, 1920, 2064, 2272, 2624, 0, 1200, 1203, 1209, 1262, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@85Hz */
- { MODEPREFIX, 317000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@120Hz RB */
- { MODEPREFIX, 234000, 1920, 2048, 2256, 2600, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@60Hz */
- { MODEPREFIX, 297000, 1920, 2064, 2288, 2640, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@75Hz */
- { MODEPREFIX, 380500, 1920, 1968, 2000, 2080, 0, 1440, 1443, 1447, 1525, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1440@120Hz RB */
- { MODEPREFIX, 268500, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1646, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@60Hz RB */
- { MODEPREFIX, 348500, 2560, 2752, 3032, 3504, 0, 1600, 1603, 1609, 1658, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@60Hz */
- { MODEPREFIX, 443250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1672, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@75Hz */
- { MODEPREFIX, 505250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@85Hz */
- { MODEPREFIX, 552750, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1694, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@120Hz RB */
-};
-
-#define LEVEL_DMT 0
-#define LEVEL_GTF 1
-#define LEVEL_CVT 2
-
-static int
-MonitorStandardTimingLevel(xf86MonPtr DDC)
-{
- if (DDC->ver.revision >= 2) {
- if (DDC->ver.revision >= 4 && CVT_SUPPORTED(DDC->features.msc)) {
- return LEVEL_CVT;
- }
- return LEVEL_GTF;
- }
- return LEVEL_DMT;
-}
-
-static int
-ModeRefresh(const DisplayModeRec *mode)
-{
- return (int)(xf86ModeVRefresh(mode) + 0.5);
-}
-
-/*
- * If rb is not set, then we'll not consider reduced-blanking modes as
- * part of the DMT pool. For the 'standard' EDID mode descriptor there's
- * no way to specify whether the mode should be RB or not.
- */
-DisplayModePtr
-FindDMTMode(int hsize, int vsize, int refresh, Bool rb)
-{
- int i;
- const DisplayModeRec *ret;
-
- for (i = 0; i < sizeof(DMTModes) / sizeof(DisplayModeRec); i++) {
- ret = &DMTModes[i];
-
- if (!rb && xf86ModeIsReduced(ret))
- continue;
-
- if (ret->HDisplay == hsize &&
- ret->VDisplay == vsize &&
- refresh == ModeRefresh(ret))
- return xf86DuplicateMode(ret);
- }
-
- return NULL;
-}
-
-/*
- * Appendix B of the EDID 1.4 spec defines the right thing to do here.
- * If the timing given here matches a mode defined in the VESA DMT standard,
- * we _must_ use that. If the device supports CVT modes, then we should
- * generate a CVT timing. If both of the above fail, use GTF.
- *
- * There are some wrinkles here. EDID 1.1 and 1.0 sinks can't really
- * "support" GTF, since it wasn't a standard yet; so if they ask for a
- * timing in this section that isn't defined in DMT, returning a GTF mode
- * may not actually be valid. EDID 1.3 sinks often report support for
- * some CVT modes, but they are not required to support CVT timings for
- * modes in the standard timing descriptor, so we should _not_ treat them
- * as CVT-compliant (unless specified in an extension block I suppose).
- *
- * EDID 1.4 requires that all sink devices support both GTF and CVT timings
- * for modes in this section, but does say that CVT is preferred.
- */
-static DisplayModePtr
-DDCModesFromStandardTiming(struct std_timings *timing, ddc_quirk_t quirks,
- int timing_level, Bool rb)
-{
- DisplayModePtr Modes = NULL, Mode = NULL;
- int i, hsize, vsize, refresh;
-
- for (i = 0; i < STD_TIMINGS; i++) {
- hsize = timing[i].hsize;
- vsize = timing[i].vsize;
- refresh = timing[i].refresh;
-
- /* HDTV hack, because you can't say 1366 */
- if (refresh == 60 &&
- ((hsize == 1360 && vsize == 765) ||
- (hsize == 1368 && vsize == 769))) {
- Mode = xf86CVTMode(1366, 768, 60, FALSE, FALSE);
- Mode->HDisplay = 1366;
- Mode->HSyncStart--;
- Mode->HSyncEnd--;
- } else if (hsize && vsize && refresh) {
- Mode = FindDMTMode(hsize, vsize, refresh, rb);
-
- if (!Mode) {
- if (timing_level == LEVEL_CVT)
- /* pass rb here too? */
- Mode = xf86CVTMode(hsize, vsize, refresh, FALSE, FALSE);
- else if (timing_level == LEVEL_GTF)
- Mode = xf86GTFMode(hsize, vsize, refresh, FALSE, FALSE);
- }
-
- }
-
- if (Mode) {
- Mode->type = M_T_DRIVER;
- Modes = xf86ModesAdd(Modes, Mode);
- }
- Mode = NULL;
- }
-
- return Modes;
-}
-
-static void
-DDCModeDoInterlaceQuirks(DisplayModePtr mode)
-{
- /*
- * EDID is delightfully ambiguous about how interlaced modes are to be
- * encoded. X's internal representation is of frame height, but some
- * HDTV detailed timings are encoded as field height.
- *
- * The format list here is from CEA, in frame size. Technically we
- * should be checking refresh rate too. Whatever.
- */
- static const struct {
- int w, h;
- } cea_interlaced[] = {
- { 1920, 1080 },
- { 720, 480 },
- { 1440, 480 },
- { 2880, 480 },
- { 720, 576 },
- { 1440, 576 },
- { 2880, 576 },
- };
- static const int n_modes = sizeof(cea_interlaced)/sizeof(cea_interlaced[0]);
- int i;
-
- for (i = 0; i < n_modes; i++) {
- if ((mode->HDisplay == cea_interlaced[i].w) &&
- (mode->VDisplay == cea_interlaced[i].h / 2)) {
- mode->VDisplay *= 2;
- mode->VSyncStart *= 2;
- mode->VSyncEnd *= 2;
- mode->VTotal *= 2;
- mode->VTotal |= 1;
- }
- }
-
- mode->Flags |= V_INTERLACE;
-}
-
-/*
- *
- */
-static DisplayModePtr
-DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing,
- Bool preferred, ddc_quirk_t quirks)
-{
- DisplayModePtr Mode;
-
- /*
- * Refuse to create modes that are insufficiently large. 64 is a random
- * number, maybe the spec says something about what the minimum is. In
- * particular I see this frequently with _old_ EDID, 1.0 or so, so maybe
- * our parser is just being too aggresive there.
- */
- if (timing->h_active < 64 || timing->v_active < 64) {
- xf86DrvMsg(scrnIndex, X_INFO,
- "%s: Ignoring tiny %dx%d mode\n", __func__,
- timing->h_active, timing->v_active);
- return NULL;
- }
-
- /* We don't do stereo */
- if (timing->stereo) {
- xf86DrvMsg(scrnIndex, X_INFO,
- "%s: Ignoring: We don't handle stereo.\n", __func__);
- return NULL;
- }
-
- /* We only do seperate sync currently */
- if (timing->sync != 0x03) {
- xf86DrvMsg(scrnIndex, X_INFO,
- "%s: %dx%d Warning: We only handle separate"
- " sync.\n", __func__, timing->h_active, timing->v_active);
- }
-
- Mode = xnfcalloc(1, sizeof(DisplayModeRec));
-
- Mode->type = M_T_DRIVER;
- if (preferred)
- Mode->type |= M_T_PREFERRED;
-
- if( ( quirks & DDC_QUIRK_135_CLOCK_TOO_HIGH ) &&
- timing->clock == 135000000 )
- Mode->Clock = 108880;
- else
- Mode->Clock = timing->clock / 1000.0;
-
- Mode->HDisplay = timing->h_active;
- Mode->HSyncStart = timing->h_active + timing->h_sync_off;
- Mode->HSyncEnd = Mode->HSyncStart + timing->h_sync_width;
- Mode->HTotal = timing->h_active + timing->h_blanking;
-
- Mode->VDisplay = timing->v_active;
- Mode->VSyncStart = timing->v_active + timing->v_sync_off;
- Mode->VSyncEnd = Mode->VSyncStart + timing->v_sync_width;
- Mode->VTotal = timing->v_active + timing->v_blanking;
-
- /* perform basic check on the detail timing */
- if (Mode->HSyncEnd > Mode->HTotal || Mode->VSyncEnd > Mode->VTotal) {
- free(Mode);
- return NULL;
- }
-
- /* We ignore h/v_size and h/v_border for now. */
-
- if (timing->interlaced)
- DDCModeDoInterlaceQuirks(Mode);
-
- if (quirks & DDC_QUIRK_DETAILED_SYNC_PP)
- Mode->Flags |= V_PVSYNC | V_PHSYNC;
- else {
- if (timing->misc & 0x02)
- Mode->Flags |= V_PVSYNC;
- else
- Mode->Flags |= V_NVSYNC;
-
- if (timing->misc & 0x01)
- Mode->Flags |= V_PHSYNC;
- else
- Mode->Flags |= V_NHSYNC;
- }
-
- xf86SetModeDefaultName(Mode);
-
- return Mode;
-}
-
-static DisplayModePtr
-DDCModesFromCVT(int scrnIndex, struct cvt_timings *t)
-{
- DisplayModePtr modes = NULL;
- int i;
-
- for (i = 0; i < 4; i++) {
- if (t[i].height) {
- if (t[i].rates & 0x10)
- modes = xf86ModesAdd(modes,
- xf86CVTMode(t[i].width, t[i].height, 50, 0, 0));
- if (t[i].rates & 0x08)
- modes = xf86ModesAdd(modes,
- xf86CVTMode(t[i].width, t[i].height, 60, 0, 0));
- if (t[i].rates & 0x04)
- modes = xf86ModesAdd(modes,
- xf86CVTMode(t[i].width, t[i].height, 75, 0, 0));
- if (t[i].rates & 0x02)
- modes = xf86ModesAdd(modes,
- xf86CVTMode(t[i].width, t[i].height, 85, 0, 0));
- if (t[i].rates & 0x01)
- modes = xf86ModesAdd(modes,
- xf86CVTMode(t[i].width, t[i].height, 60, 1, 0));
- } else break;
- }
-
- return modes;
-}
-
-static const struct {
- short w;
- short h;
- short r;
- short rb;
-} EstIIIModes[] = {
- /* byte 6 */
- { 640, 350, 85, 0 },
- { 640, 400, 85, 0 },
- { 720, 400, 85, 0 },
- { 640, 480, 85, 0 },
- { 848, 480, 60, 0 },
- { 800, 600, 85, 0 },
- { 1024, 768, 85, 0 },
- { 1152, 864, 75, 0 },
- /* byte 7 */
- { 1280, 768, 60, 1 },
- { 1280, 768, 60, 0 },
- { 1280, 768, 75, 0 },
- { 1280, 768, 85, 0 },
- { 1280, 960, 60, 0 },
- { 1280, 960, 85, 0 },
- { 1280, 1024, 60, 0 },
- { 1280, 1024, 85, 0 },
- /* byte 8 */
- { 1360, 768, 60, 0 },
- { 1440, 900, 60, 1 },
- { 1440, 900, 60, 0 },
- { 1440, 900, 75, 0 },
- { 1440, 900, 85, 0 },
- { 1400, 1050, 60, 1 },
- { 1400, 1050, 60, 0 },
- { 1400, 1050, 75, 0 },
- /* byte 9 */
- { 1400, 1050, 85, 0 },
- { 1680, 1050, 60, 1 },
- { 1680, 1050, 60, 0 },
- { 1680, 1050, 75, 0 },
- { 1680, 1050, 85, 0 },
- { 1600, 1200, 60, 0 },
- { 1600, 1200, 65, 0 },
- { 1600, 1200, 70, 0 },
- /* byte 10 */
- { 1600, 1200, 75, 0 },
- { 1600, 1200, 85, 0 },
- { 1792, 1344, 60, 0 },
- { 1792, 1344, 85, 0 },
- { 1856, 1392, 60, 0 },
- { 1856, 1392, 75, 0 },
- { 1920, 1200, 60, 1 },
- { 1920, 1200, 60, 0 },
- /* byte 11 */
- { 1920, 1200, 75, 0 },
- { 1920, 1200, 85, 0 },
- { 1920, 1440, 60, 0 },
- { 1920, 1440, 75, 0 },
-};
-
-static DisplayModePtr
-DDCModesFromEstIII(unsigned char *est)
-{
- DisplayModePtr modes = NULL;
- int i, j, m;
-
- for (i = 0; i < 6; i++) {
- for (j = 7; j > 0; j--) {
- if (est[i] & (1 << j)) {
- m = (i * 8) + (7 - j);
- modes = xf86ModesAdd(modes,
- FindDMTMode(EstIIIModes[m].w,
- EstIIIModes[m].h,
- EstIIIModes[m].r,
- EstIIIModes[m].rb));
- }
- }
- }
-
- return modes;
-}
-
-/*
- * This is only valid when the sink claims to be continuous-frequency
- * but does not supply a detailed range descriptor. Such sinks are
- * arguably broken. Currently the mode validation code isn't aware of
- * this; the non-RANDR code even punts the decision of optional sync
- * range checking to the driver. Loss.
- */
-static void
-DDCGuessRangesFromModes(int scrnIndex, MonPtr Monitor, DisplayModePtr Modes)
-{
- DisplayModePtr Mode = Modes;
-
- if (!Monitor || !Modes)
- return;
-
- /* set up the ranges for scanning through the modes */
- Monitor->nHsync = 1;
- Monitor->hsync[0].lo = 1024.0;
- Monitor->hsync[0].hi = 0.0;
-
- Monitor->nVrefresh = 1;
- Monitor->vrefresh[0].lo = 1024.0;
- Monitor->vrefresh[0].hi = 0.0;
-
- while (Mode) {
- if (!Mode->HSync)
- Mode->HSync = ((float) Mode->Clock ) / ((float) Mode->HTotal);
-
- if (!Mode->VRefresh)
- Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) /
- ((float) (Mode->HTotal * Mode->VTotal));
-
- if (Mode->HSync < Monitor->hsync[0].lo)
- Monitor->hsync[0].lo = Mode->HSync;
-
- if (Mode->HSync > Monitor->hsync[0].hi)
- Monitor->hsync[0].hi = Mode->HSync;
-
- if (Mode->VRefresh < Monitor->vrefresh[0].lo)
- Monitor->vrefresh[0].lo = Mode->VRefresh;
-
- if (Mode->VRefresh > Monitor->vrefresh[0].hi)
- Monitor->vrefresh[0].hi = Mode->VRefresh;
-
- Mode = Mode->next;
- }
-}
-
-ddc_quirk_t
-xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose)
-{
- ddc_quirk_t quirks;
- int i;
-
- quirks = DDC_QUIRK_NONE;
- for (i = 0; ddc_quirks[i].detect; i++) {
- if (ddc_quirks[i].detect (scrnIndex, DDC)) {
- if (verbose) {
- xf86DrvMsg (scrnIndex, X_INFO, " EDID quirk: %s\n",
- ddc_quirks[i].description);
- }
- quirks |= ddc_quirks[i].quirk;
- }
- }
-
- return quirks;
-}
-
-void xf86DetTimingApplyQuirks(struct detailed_monitor_section *det_mon,
- ddc_quirk_t quirks,
- int hsize, int vsize)
-{
- if (det_mon->type != DT)
- return;
-
- if (quirks & DDC_QUIRK_DETAILED_H_IN_CM)
- det_mon->section.d_timings.h_size *= 10;
-
- if (quirks & DDC_QUIRK_DETAILED_V_IN_CM)
- det_mon->section.d_timings.v_size *= 10;
-
- if (quirks & DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
- det_mon->section.d_timings.h_size = 10 * hsize;
- det_mon->section.d_timings.v_size = 10 * vsize;
- }
-}
-
-/**
- * Applies monitor-specific quirks to the decoded EDID information.
- *
- * Note that some quirks applying to the mode list are still implemented in
- * xf86DDCGetModes.
- */
-void
-xf86DDCApplyQuirks(int scrnIndex, xf86MonPtr DDC)
-{
- ddc_quirk_t quirks = xf86DDCDetectQuirks (scrnIndex, DDC, FALSE);
- int i;
-
- for (i = 0; i < DET_TIMINGS; i++) {
- xf86DetTimingApplyQuirks(DDC->det_mon + i, quirks,
- DDC->features.hsize,
- DDC->features.vsize);
- }
-}
-
-/**
- * Walks the modes list, finding the mode with the largest area which is
- * closest to the target refresh rate, and marks it as the only preferred mode.
-*/
-static void
-xf86DDCSetPreferredRefresh(int scrnIndex, DisplayModePtr modes,
- float target_refresh)
-{
- DisplayModePtr mode, best = modes;
-
- for (mode = modes; mode; mode = mode->next)
- {
- mode->type &= ~M_T_PREFERRED;
-
- if (mode == best) continue;
-
- if (mode->HDisplay * mode->VDisplay >
- best->HDisplay * best->VDisplay)
- {
- best = mode;
- continue;
- }
- if (mode->HDisplay * mode->VDisplay ==
- best->HDisplay * best->VDisplay)
- {
- double mode_refresh = xf86ModeVRefresh (mode);
- double best_refresh = xf86ModeVRefresh (best);
- double mode_dist = fabs(mode_refresh - target_refresh);
- double best_dist = fabs(best_refresh - target_refresh);
-
- if (mode_dist < best_dist)
- {
- best = mode;
- continue;
- }
- }
- }
- if (best)
- best->type |= M_T_PREFERRED;
-}
-
-#define CEA_VIDEO_MODES_NUM 64
-static const DisplayModeRec CEAVideoModes[CEA_VIDEO_MODES_NUM] = {
- { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 1:640x480@60Hz */
- { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 2:720x480@60Hz */
- { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 3:720x480@60Hz */
- { MODEPREFIX, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 4: 1280x720@60Hz */
- { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 5:1920x1080i@60Hz */
- { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 6:1440x480i@60Hz */
- { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 7:1440x480i@60Hz */
- { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 8:1440x240@60Hz */
- { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 9:1440x240@60Hz */
- { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 10:2880x480i@60Hz */
- { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 11:2880x480i@60Hz */
- { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 12:2880x240@60Hz */
- { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 13:2880x240@60Hz */
- { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 14:1440x480@60Hz */
- { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 15:1440x480@60Hz */
- { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 16:1920x1080@60Hz */
- { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 17:720x576@50Hz */
- { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 18:720x576@50Hz */
- { MODEPREFIX, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 19: 1280x720@50Hz */
- { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 20:1920x1080i@50Hz */
- { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 21:1440x576i@50Hz */
- { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 22:1440x576i@50Hz */
- { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 23:1440x288@50Hz */
- { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 24:1440x288@50Hz */
- { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 25:2880x576i@50Hz */
- { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 26:2880x576i@50Hz */
- { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 27:2880x288@50Hz */
- { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 28:2880x288@50Hz */
- { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 29:1440x576@50Hz */
- { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 30:1440x576@50Hz */
- { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 31:1920x1080@50Hz */
- { MODEPREFIX, 74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 32:1920x1080@24Hz */
- { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 33:1920x1080@25Hz */
- { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 34:1920x1080@30Hz */
- { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 35:2880x480@60Hz */
- { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 36:2880x480@60Hz */
- { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 37:2880x576@50Hz */
- { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 38:2880x576@50Hz */
- { MODEPREFIX, 72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, V_PHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 39:1920x1080i@50Hz */
- { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 40:1920x1080i@100Hz */
- { MODEPREFIX, 148500, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 41:1280x720@100Hz */
- { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 42:720x576@100Hz */
- { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 43:720x576@100Hz */
- { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 44:1440x576i@100Hz */
- { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 45:1440x576i@100Hz */
- { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 46:1920x1080i@120Hz */
- { MODEPREFIX, 148500, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 47:1280x720@120Hz */
- { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 48:720x480@120Hz */
- { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 49:720x480@120Hz */
- { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 50:1440x480i@120Hz */
- { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 51:1440x480i@120Hz */
- { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 52:720x576@200Hz */
- { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 53:720x576@200Hz */
- { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 54:1440x576i@200Hz */
- { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 55:1440x576i@200Hz */
- { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 56:720x480@240Hz */
- { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 57:720x480@240Hz */
- { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 58:1440x480i@240 */
- { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 59:1440x480i@240 */
- { MODEPREFIX, 59400, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 60: 1280x720@24Hz */
- { MODEPREFIX, 74250, 3700, 3740, 1430, 3960, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 61: 1280x720@25Hz */
- { MODEPREFIX, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 62: 1280x720@30Hz */
- { MODEPREFIX, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 63: 1920x1080@120Hz */
- { MODEPREFIX, 297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 64:1920x1080@100Hz */
-};
-
-/* chose mode line by cea short video descriptor*/
-static void handle_cea_svd(struct cea_video_block *video, void *data)
-{
- DisplayModePtr Mode;
- DisplayModePtr *Modes = (DisplayModePtr *) data;
- int vid;
-
- vid = video ->video_code & 0x7f;
- if (vid < CEA_VIDEO_MODES_NUM) {
- Mode = xf86DuplicateMode(CEAVideoModes + vid);
- *Modes = xf86ModesAdd(*Modes, Mode);
- }
-}
-
-static DisplayModePtr
-DDCModesFromCEAExtension(int scrnIndex, xf86MonPtr MonPtr)
-{
- DisplayModePtr Modes = NULL;
-
- xf86ForEachVideoBlock(MonPtr,
- handle_cea_svd,
- &Modes);
-
- return Modes;
-}
-
-struct det_modes_parameter {
- xf86MonPtr DDC;
- ddc_quirk_t quirks;
- DisplayModePtr Modes;
- Bool rb;
- Bool preferred;
- int timing_level;
-};
-
-static void handle_detailed_modes(struct detailed_monitor_section *det_mon,
- void *data)
-{
- DisplayModePtr Mode;
- struct det_modes_parameter *p = (struct det_modes_parameter *)data;
-
- xf86DetTimingApplyQuirks(det_mon,p->quirks,
- p->DDC->features.hsize,
- p->DDC->features.vsize);
-
- switch (det_mon->type) {
- case DT:
- Mode = DDCModeFromDetailedTiming(p->DDC->scrnIndex,
- &det_mon->section.d_timings,
- p->preferred,
- p->quirks);
- p->preferred = FALSE;
- p->Modes = xf86ModesAdd(p->Modes, Mode);
- break;
- case DS_STD_TIMINGS:
- Mode = DDCModesFromStandardTiming(det_mon->section.std_t,
- p->quirks, p->timing_level,p->rb);
- p->Modes = xf86ModesAdd(p->Modes, Mode);
- break;
- case DS_CVT:
- Mode = DDCModesFromCVT(p->DDC->scrnIndex, det_mon->section.cvt);
- p->Modes = xf86ModesAdd(p->Modes, Mode);
- break;
- case DS_EST_III:
- Mode = DDCModesFromEstIII(det_mon->section.est_iii);
- p->Modes = xf86ModesAdd(p->Modes, Mode);
- break;
- default:
- break;
- }
-}
-
-DisplayModePtr
-xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
-{
- DisplayModePtr Modes = NULL, Mode;
- ddc_quirk_t quirks;
- Bool preferred, rb;
- int timing_level;
- struct det_modes_parameter p;
-
- xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n",
- DDC->vendor.name, DDC->vendor.prod_id);
-
- quirks = xf86DDCDetectQuirks(scrnIndex, DDC, TRUE);
-
- preferred = PREFERRED_TIMING_MODE(DDC->features.msc);
- if (DDC->ver.revision >= 4)
- preferred = TRUE;
- if (quirks & DDC_QUIRK_FIRST_DETAILED_PREFERRED)
- preferred = TRUE;
- if (quirks & (DDC_QUIRK_PREFER_LARGE_60 | DDC_QUIRK_PREFER_LARGE_75))
- preferred = FALSE;
-
- rb = xf86MonitorSupportsReducedBlanking(DDC);
-
- timing_level = MonitorStandardTimingLevel(DDC);
-
- p.quirks = quirks;
- p.DDC = DDC;
- p.Modes = Modes;
- p.rb = rb;
- p.preferred = preferred;
- p.timing_level = timing_level;
- xf86ForEachDetailedBlock(DDC, handle_detailed_modes, &p);
- Modes = p.Modes;
-
- /* Add established timings */
- Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks);
- Modes = xf86ModesAdd(Modes, Mode);
-
- /* Add standard timings */
- Mode = DDCModesFromStandardTiming(DDC->timings2, quirks, timing_level, rb);
- Modes = xf86ModesAdd(Modes, Mode);
-
- /* Add cea-extension mode timings */
- Mode = DDCModesFromCEAExtension(scrnIndex,DDC);
- Modes = xf86ModesAdd(Modes, Mode);
-
- if (quirks & DDC_QUIRK_PREFER_LARGE_60)
- xf86DDCSetPreferredRefresh(scrnIndex, Modes, 60);
-
- if (quirks & DDC_QUIRK_PREFER_LARGE_75)
- xf86DDCSetPreferredRefresh(scrnIndex, Modes, 75);
-
- Modes = xf86PruneDuplicateModes(Modes);
-
- return Modes;
-}
-
-struct det_mon_parameter {
- MonPtr Monitor;
- ddc_quirk_t quirks;
- Bool have_hsync;
- Bool have_vrefresh;
- Bool have_maxpixclock;
-};
-
-static void handle_detailed_monset(struct detailed_monitor_section *det_mon,
- void *data)
-{
- int clock;
- struct det_mon_parameter *p = (struct det_mon_parameter *)data;
- int scrnIndex = ((xf86MonPtr)(p->Monitor->DDC))->scrnIndex;
-
- switch (det_mon->type) {
- case DS_RANGES:
- if (!p->have_hsync) {
- if (!p->Monitor->nHsync)
- xf86DrvMsg(scrnIndex, X_INFO,
- "Using EDID range info for horizontal sync\n");
- p->Monitor->hsync[p->Monitor->nHsync].lo =
- det_mon->section.ranges.min_h;
- p->Monitor->hsync[p->Monitor->nHsync].hi =
- det_mon->section.ranges.max_h;
- p->Monitor->nHsync++;
- } else {
- xf86DrvMsg(scrnIndex, X_INFO,
- "Using hsync ranges from config file\n");
- }
-
- if (!p->have_vrefresh) {
- if (!p->Monitor->nVrefresh)
- xf86DrvMsg(scrnIndex, X_INFO,
- "Using EDID range info for vertical refresh\n");
- p->Monitor->vrefresh[p->Monitor->nVrefresh].lo =
- det_mon->section.ranges.min_v;
- p->Monitor->vrefresh[p->Monitor->nVrefresh].hi =
- det_mon->section.ranges.max_v;
- p->Monitor->nVrefresh++;
- } else {
- xf86DrvMsg(scrnIndex, X_INFO,
- "Using vrefresh ranges from config file\n");
- }
-
- clock = det_mon->section.ranges.max_clock * 1000;
- if (p->quirks & DDC_QUIRK_DVI_SINGLE_LINK)
- clock = min(clock, 165000);
- if (!p->have_maxpixclock && clock > p->Monitor->maxPixClock)
- p->Monitor->maxPixClock = clock;
-
- break;
- default:
- break;
- }
-}
-
-/*
- * Fill out MonPtr with xf86MonPtr information.
- */
-void
-xf86EdidMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC)
-{
- DisplayModePtr Modes = NULL, Mode;
- struct det_mon_parameter p;
-
- if (!Monitor || !DDC)
- return;
-
- Monitor->DDC = DDC;
-
- if (Monitor->widthmm <= 0 || Monitor->heightmm <= 0) {
- Monitor->widthmm = 10 * DDC->features.hsize;
- Monitor->heightmm = 10 * DDC->features.vsize;
- }
-
- Monitor->reducedblanking = xf86MonitorSupportsReducedBlanking(DDC);
-
- Modes = xf86DDCGetModes(scrnIndex, DDC);
-
- /* Go through the detailed monitor sections */
- p.Monitor = Monitor;
- p.quirks = xf86DDCDetectQuirks(scrnIndex, Monitor->DDC, FALSE);
- p.have_hsync = (Monitor->nHsync != 0);
- p.have_vrefresh = (Monitor->nVrefresh != 0);
- p.have_maxpixclock = (Monitor->maxPixClock != 0);
- xf86ForEachDetailedBlock(DDC, handle_detailed_monset, &p);
-
- if (Modes) {
- /* Print Modes */
- xf86DrvMsg(scrnIndex, X_INFO, "Printing DDC gathered Modelines:\n");
-
- Mode = Modes;
- while (Mode) {
- xf86PrintModeline(scrnIndex, Mode);
- Mode = Mode->next;
- }
-
- /* Do we still need ranges to be filled in? */
- if (!Monitor->nHsync || !Monitor->nVrefresh)
- DDCGuessRangesFromModes(scrnIndex, Monitor, Modes);
-
- /* look for last Mode */
- Mode = Modes;
-
- while (Mode->next)
- Mode = Mode->next;
-
- /* add to MonPtr */
- if (Monitor->Modes) {
- Monitor->Last->next = Modes;
- Modes->prev = Monitor->Last;
- Monitor->Last = Mode;
- } else {
- Monitor->Modes = Modes;
- Monitor->Last = Mode;
- }
- }
-}
+/*
+ * Copyright 2006 Luc Verhaegen.
+ * Copyright 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file This file covers code to convert a xf86MonPtr containing EDID-probed
+ * information into a list of modes, including applying monitor-specific
+ * quirks to fix broken EDID data.
+ */
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#else
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#endif
+
+#define _PARSE_EDID_
+#include "xf86.h"
+#include "xf86DDC.h"
+#include <X11/Xatom.h>
+#include "property.h"
+#include "propertyst.h"
+#include "xf86Crtc.h"
+#include <string.h>
+#include <math.h>
+
+static void handle_detailed_rblank(struct detailed_monitor_section *det_mon,
+ void *data)
+{
+ if (det_mon->type == DS_RANGES)
+ if (det_mon->section.ranges.supported_blanking & CVT_REDUCED)
+ *(Bool*)data = TRUE;
+}
+
+static Bool
+xf86MonitorSupportsReducedBlanking(xf86MonPtr DDC)
+{
+ /* EDID 1.4 explicitly defines RB support */
+ if (DDC->ver.revision >= 4) {
+ Bool ret = FALSE;
+
+ xf86ForEachDetailedBlock(DDC, handle_detailed_rblank, &ret);
+ return ret;
+ }
+
+ /* For anything older, assume digital means RB support. Boo. */
+ if (DDC->features.input_type)
+ return TRUE;
+
+ return FALSE;
+}
+
+static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC)
+{
+ /* Belinea 10 15 55 */
+ if (memcmp (DDC->vendor.name, "MAX", 4) == 0 &&
+ ((DDC->vendor.prod_id == 1516) ||
+ (DDC->vendor.prod_id == 0x77e)))
+ return TRUE;
+
+ /* Acer AL1706 */
+ if (memcmp (DDC->vendor.name, "ACR", 4) == 0 &&
+ DDC->vendor.prod_id == 44358)
+ return TRUE;
+
+ /* Bug #10814: Samsung SyncMaster 225BW */
+ if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
+ DDC->vendor.prod_id == 596)
+ return TRUE;
+
+ /* Bug #10545: Samsung SyncMaster 226BW */
+ if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
+ DDC->vendor.prod_id == 638)
+ return TRUE;
+
+ /* Acer F51 */
+ if (memcmp (DDC->vendor.name, "API", 4) == 0 &&
+ DDC->vendor.prod_id == 0x7602)
+ return TRUE;
+
+
+ return FALSE;
+}
+
+static Bool quirk_prefer_large_75 (int scrnIndex, xf86MonPtr DDC)
+{
+ /* Bug #11603: Funai Electronics PM36B */
+ if (memcmp (DDC->vendor.name, "FCM", 4) == 0 &&
+ DDC->vendor.prod_id == 13600)
+ return TRUE;
+
+ return FALSE;
+}
+
+static Bool quirk_detailed_h_in_cm (int scrnIndex, xf86MonPtr DDC)
+{
+ /* Bug #11603: Funai Electronics PM36B */
+ if (memcmp (DDC->vendor.name, "FCM", 4) == 0 &&
+ DDC->vendor.prod_id == 13600)
+ return TRUE;
+
+ return FALSE;
+}
+
+static Bool quirk_detailed_v_in_cm (int scrnIndex, xf86MonPtr DDC)
+{
+ /* Bug #11603: Funai Electronics PM36B */
+ if (memcmp (DDC->vendor.name, "FCM", 4) == 0 &&
+ DDC->vendor.prod_id == 13600)
+ return TRUE;
+
+ /* Bug #21000: LGPhilipsLCD LP154W01-TLAJ */
+ if (memcmp (DDC->vendor.name, "LPL", 4) == 0 &&
+ DDC->vendor.prod_id == 47360)
+ return TRUE;
+
+ /* Bug #10304: LGPhilipsLCD LP154W01-A5 */
+ if (memcmp(DDC->vendor.name, "LPL", 4) == 0 &&
+ DDC->vendor.prod_id == 0)
+ return TRUE;
+
+ /* Bug #24482: LGPhilipsLCD LP154W01-TLA1 */
+ if (memcmp(DDC->vendor.name, "LPL", 4) == 0 &&
+ DDC->vendor.prod_id == 0x2a00)
+ return TRUE;
+
+ /* Bug #28414: HP Compaq NC8430 LP154W01-TLA8 */
+ if (memcmp (DDC->vendor.name, "LPL", 4) == 0 &&
+ DDC->vendor.prod_id == 5750)
+ return TRUE;
+
+ /* Bug #21750: Samsung Syncmaster 2333HD */
+ if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
+ DDC->vendor.prod_id == 1157)
+ return TRUE;
+
+ return FALSE;
+}
+
+static Bool quirk_detailed_use_maximum_size (int scrnIndex, xf86MonPtr DDC)
+{
+ /* Bug #21324: Iiyama Vision Master 450 */
+ if (memcmp (DDC->vendor.name, "IVM", 4) == 0 &&
+ DDC->vendor.prod_id == 6400)
+ return TRUE;
+
+ return FALSE;
+}
+
+static Bool quirk_135_clock_too_high (int scrnIndex, xf86MonPtr DDC)
+{
+ /* Envision Peripherals, Inc. EN-7100e. See bug #9550. */
+ if (memcmp (DDC->vendor.name, "EPI", 4) == 0 &&
+ DDC->vendor.prod_id == 59264)
+ return TRUE;
+
+ return FALSE;
+}
+
+static Bool quirk_first_detailed_preferred (int scrnIndex, xf86MonPtr DDC)
+{
+ /* Philips 107p5 CRT. Reported on xorg@ with pastebin. */
+ if (memcmp (DDC->vendor.name, "PHL", 4) == 0 &&
+ DDC->vendor.prod_id == 57364)
+ return TRUE;
+
+ /* Proview AY765C 17" LCD. See bug #15160*/
+ if (memcmp (DDC->vendor.name, "PTS", 4) == 0 &&
+ DDC->vendor.prod_id == 765)
+ return TRUE;
+
+ /* ACR of some sort RH #284231 */
+ if (memcmp (DDC->vendor.name, "ACR", 4) == 0 &&
+ DDC->vendor.prod_id == 2423)
+ return TRUE;
+
+ /* Peacock Ergovision 19. See rh#492359 */
+ if (memcmp (DDC->vendor.name, "PEA", 4) == 0 &&
+ DDC->vendor.prod_id == 9003)
+ return TRUE;
+
+ return FALSE;
+}
+
+static Bool quirk_detailed_sync_pp(int scrnIndex, xf86MonPtr DDC)
+{
+ /* Bug #12439: Samsung SyncMaster 205BW */
+ if (memcmp (DDC->vendor.name, "SAM", 4) == 0 &&
+ DDC->vendor.prod_id == 541)
+ return TRUE;
+ return FALSE;
+}
+
+/* This should probably be made more generic */
+static Bool quirk_dvi_single_link(int scrnIndex, xf86MonPtr DDC)
+{
+ /* Red Hat bug #453106: Apple 23" Cinema Display */
+ if (memcmp (DDC->vendor.name, "APL", 4) == 0 &&
+ DDC->vendor.prod_id == 0x921c)
+ return TRUE;
+ return FALSE;
+}
+
+typedef struct {
+ Bool (*detect) (int scrnIndex, xf86MonPtr DDC);
+ ddc_quirk_t quirk;
+ char *description;
+} ddc_quirk_map_t;
+
+static const ddc_quirk_map_t ddc_quirks[] = {
+ {
+ quirk_prefer_large_60, DDC_QUIRK_PREFER_LARGE_60,
+ "Detailed timing is not preferred, use largest mode at 60Hz"
+ },
+ {
+ quirk_135_clock_too_high, DDC_QUIRK_135_CLOCK_TOO_HIGH,
+ "Recommended 135MHz pixel clock is too high"
+ },
+ {
+ quirk_prefer_large_75, DDC_QUIRK_PREFER_LARGE_75,
+ "Detailed timing is not preferred, use largest mode at 75Hz"
+ },
+ {
+ quirk_detailed_h_in_cm, DDC_QUIRK_DETAILED_H_IN_CM,
+ "Detailed timings give horizontal size in cm."
+ },
+ {
+ quirk_detailed_v_in_cm, DDC_QUIRK_DETAILED_V_IN_CM,
+ "Detailed timings give vertical size in cm."
+ },
+ {
+ quirk_detailed_use_maximum_size, DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE,
+ "Use maximum size instead of detailed timing sizes."
+ },
+ {
+ quirk_first_detailed_preferred, DDC_QUIRK_FIRST_DETAILED_PREFERRED,
+ "First detailed timing was not marked as preferred."
+ },
+ {
+ quirk_detailed_sync_pp, DDC_QUIRK_DETAILED_SYNC_PP,
+ "Use +hsync +vsync for detailed timing."
+ },
+ {
+ quirk_dvi_single_link, DDC_QUIRK_DVI_SINGLE_LINK,
+ "Forcing maximum pixel clock to single DVI link."
+ },
+ {
+ NULL, DDC_QUIRK_NONE,
+ "No known quirks"
+ },
+};
+
+/*
+ * These more or less come from the DMT spec. The 720x400 modes are
+ * inferred from historical 80x25 practice. The 640x480@67 and 832x624@75
+ * modes are old-school Mac modes. The EDID spec says the 1152x864@75 mode
+ * should be 1152x870, again for the Mac, but instead we use the x864 DMT
+ * mode.
+ *
+ * The DMT modes have been fact-checked; the rest are mild guesses.
+ */
+#define MODEPREFIX NULL, NULL, NULL, 0, M_T_DRIVER
+#define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0
+
+static const DisplayModeRec DDCEstablishedModes[17] = {
+ { MODEPREFIX, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */
+ { MODEPREFIX, 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */
+ { MODEPREFIX, 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */
+ { MODEPREFIX, 31500, 640, 664, 704, 832, 0, 480, 489, 492, 520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */
+ { MODEPREFIX, 30240, 640, 704, 768, 864, 0, 480, 483, 486, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@67Hz */
+ { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */
+ { MODEPREFIX, 35500, 720, 738, 846, 900, 0, 400, 421, 423, 449, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 720x400@88Hz */
+ { MODEPREFIX, 28320, 720, 738, 846, 900, 0, 400, 412, 414, 449, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@70Hz */
+ { MODEPREFIX, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */
+ { MODEPREFIX, 78750, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */
+ { MODEPREFIX, 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */
+ { MODEPREFIX, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */
+ { MODEPREFIX, 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 772, 817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz */
+ { MODEPREFIX, 57284, 832, 864, 928, 1152, 0, 624, 625, 628, 667, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 832x624@75Hz */
+ { MODEPREFIX, 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */
+ { MODEPREFIX, 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */
+ { MODEPREFIX, 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */
+};
+
+static DisplayModePtr
+DDCModesFromEstablished(int scrnIndex, struct established_timings *timing,
+ ddc_quirk_t quirks)
+{
+ DisplayModePtr Modes = NULL, Mode = NULL;
+ CARD32 bits = (timing->t1) | (timing->t2 << 8) |
+ ((timing->t_manu & 0x80) << 9);
+ int i;
+
+ for (i = 0; i < 17; i++) {
+ if (bits & (0x01 << i)) {
+ Mode = xf86DuplicateMode(&DDCEstablishedModes[i]);
+ Modes = xf86ModesAdd(Modes, Mode);
+ }
+ }
+
+ return Modes;
+}
+
+/* Autogenerated from the DMT spec */
+const DisplayModeRec DMTModes[] = {
+ { MODEPREFIX, 31500, 640, 672, 736, 832, 0, 350, 382, 385, 445, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x350@85Hz */
+ { MODEPREFIX, 31500, 640, 672, 736, 832, 0, 400, 401, 404, 445, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 640x400@85Hz */
+ { MODEPREFIX, 35500, 720, 756, 828, 936, 0, 400, 401, 404, 446, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@85Hz */
+ { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */
+ { MODEPREFIX, 31500, 640, 664, 704, 832, 0, 480, 489, 492, 520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */
+ { MODEPREFIX, 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */
+ { MODEPREFIX, 36000, 640, 696, 752, 832, 0, 480, 481, 484, 509, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@85Hz */
+ { MODEPREFIX, 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */
+ { MODEPREFIX, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */
+ { MODEPREFIX, 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */
+ { MODEPREFIX, 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */
+ { MODEPREFIX, 56250, 800, 832, 896, 1048, 0, 600, 601, 604, 631, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@85Hz */
+ { MODEPREFIX, 73250, 800, 848, 880, 960, 0, 600, 603, 607, 636, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 800x600@120Hz RB */
+ { MODEPREFIX, 33750, 848, 864, 976, 1088, 0, 480, 486, 494, 517, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 848x480@60Hz */
+ { MODEPREFIX, 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 772, 817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz (interlaced) */
+ { MODEPREFIX, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */
+ { MODEPREFIX, 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */
+ { MODEPREFIX, 78750, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */
+ { MODEPREFIX, 94500, 1024, 1072, 1168, 1376, 0, 768, 769, 772, 808, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@85Hz */
+ { MODEPREFIX, 115500, 1024, 1072, 1104, 1184, 0, 768, 771, 775, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@120Hz RB */
+ { MODEPREFIX, 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */
+ { MODEPREFIX, 68250, 1280, 1328, 1360, 1440, 0, 768, 771, 778, 790, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@60Hz RB */
+ { MODEPREFIX, 79500, 1280, 1344, 1472, 1664, 0, 768, 771, 778, 798, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@60Hz */
+ { MODEPREFIX, 102250, 1280, 1360, 1488, 1696, 0, 768, 771, 778, 805, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@75Hz */
+ { MODEPREFIX, 117500, 1280, 1360, 1496, 1712, 0, 768, 771, 778, 809, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x768@85Hz */
+ { MODEPREFIX, 140250, 1280, 1328, 1360, 1440, 0, 768, 771, 778, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x768@120Hz RB */
+ { MODEPREFIX, 71000, 1280, 1328, 1360, 1440, 0, 800, 803, 809, 823, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@60Hz RB */
+ { MODEPREFIX, 83500, 1280, 1352, 1480, 1680, 0, 800, 803, 809, 831, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@60Hz */
+ { MODEPREFIX, 106500, 1280, 1360, 1488, 1696, 0, 800, 803, 809, 838, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@75Hz */
+ { MODEPREFIX, 122500, 1280, 1360, 1496, 1712, 0, 800, 803, 809, 843, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x800@85Hz */
+ { MODEPREFIX, 146250, 1280, 1328, 1360, 1440, 0, 800, 803, 809, 847, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x800@120Hz RB */
+ { MODEPREFIX, 108000, 1280, 1376, 1488, 1800, 0, 960, 961, 964, 1000, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@60Hz */
+ { MODEPREFIX, 148500, 1280, 1344, 1504, 1728, 0, 960, 961, 964, 1011, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x960@85Hz */
+ { MODEPREFIX, 175500, 1280, 1328, 1360, 1440, 0, 960, 963, 967, 1017, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x960@120Hz RB */
+ { MODEPREFIX, 108000, 1280, 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@60Hz */
+ { MODEPREFIX, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */
+ { MODEPREFIX, 157500, 1280, 1344, 1504, 1728, 0, 1024, 1025, 1028, 1072, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@85Hz */
+ { MODEPREFIX, 187250, 1280, 1328, 1360, 1440, 0, 1024, 1027, 1034, 1084, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1280x1024@120Hz RB */
+ { MODEPREFIX, 85500, 1360, 1424, 1536, 1792, 0, 768, 771, 777, 795, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1360x768@60Hz */
+ { MODEPREFIX, 148250, 1360, 1408, 1440, 1520, 0, 768, 771, 776, 813, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1360x768@120Hz RB */
+ { MODEPREFIX, 101000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@60Hz RB */
+ { MODEPREFIX, 121750, 1400, 1488, 1632, 1864, 0, 1050, 1053, 1057, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@60Hz */
+ { MODEPREFIX, 156000, 1400, 1504, 1648, 1896, 0, 1050, 1053, 1057, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@75Hz */
+ { MODEPREFIX, 179500, 1400, 1504, 1656, 1912, 0, 1050, 1053, 1057, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1400x1050@85Hz */
+ { MODEPREFIX, 208000, 1400, 1448, 1480, 1560, 0, 1050, 1053, 1057, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1400x1050@120Hz RB */
+ { MODEPREFIX, 88750, 1440, 1488, 1520, 1600, 0, 900, 903, 909, 926, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@60Hz RB */
+ { MODEPREFIX, 106500, 1440, 1520, 1672, 1904, 0, 900, 903, 909, 934, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@60Hz */
+ { MODEPREFIX, 136750, 1440, 1536, 1688, 1936, 0, 900, 903, 909, 942, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@75Hz */
+ { MODEPREFIX, 157000, 1440, 1544, 1696, 1952, 0, 900, 903, 909, 948, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1440x900@85Hz */
+ { MODEPREFIX, 182750, 1440, 1488, 1520, 1600, 0, 900, 903, 909, 953, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1440x900@120Hz RB */
+ { MODEPREFIX, 162000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@60Hz */
+ { MODEPREFIX, 175500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@65Hz */
+ { MODEPREFIX, 189000, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@70Hz */
+ { MODEPREFIX, 202500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@75Hz */
+ { MODEPREFIX, 229500, 1600, 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1600x1200@85Hz */
+ { MODEPREFIX, 268250, 1600, 1648, 1680, 1760, 0, 1200, 1203, 1207, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1600x1200@120Hz RB */
+ { MODEPREFIX, 119000, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1080, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@60Hz RB */
+ { MODEPREFIX, 146250, 1680, 1784, 1960, 2240, 0, 1050, 1053, 1059, 1089, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@60Hz */
+ { MODEPREFIX, 187000, 1680, 1800, 1976, 2272, 0, 1050, 1053, 1059, 1099, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@75Hz */
+ { MODEPREFIX, 214750, 1680, 1808, 1984, 2288, 0, 1050, 1053, 1059, 1105, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1680x1050@85Hz */
+ { MODEPREFIX, 245500, 1680, 1728, 1760, 1840, 0, 1050, 1053, 1059, 1112, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1680x1050@120Hz RB */
+ { MODEPREFIX, 204750, 1792, 1920, 2120, 2448, 0, 1344, 1345, 1348, 1394, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@60Hz */
+ { MODEPREFIX, 261000, 1792, 1888, 2104, 2456, 0, 1344, 1345, 1348, 1417, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1792x1344@75Hz */
+ { MODEPREFIX, 333250, 1792, 1840, 1872, 1952, 0, 1344, 1347, 1351, 1423, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1792x1344@120Hz RB */
+ { MODEPREFIX, 218250, 1856, 1952, 2176, 2528, 0, 1392, 1393, 1396, 1439, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@60Hz */
+ { MODEPREFIX, 288000, 1856, 1984, 2208, 2560, 0, 1392, 1393, 1396, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1856x1392@75Hz */
+ { MODEPREFIX, 356500, 1856, 1904, 1936, 2016, 0, 1392, 1395, 1399, 1474, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1856x1392@120Hz RB */
+ { MODEPREFIX, 154000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1235, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@60Hz RB */
+ { MODEPREFIX, 193250, 1920, 2056, 2256, 2592, 0, 1200, 1203, 1209, 1245, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@60Hz */
+ { MODEPREFIX, 245250, 1920, 2056, 2264, 2608, 0, 1200, 1203, 1209, 1255, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@75Hz */
+ { MODEPREFIX, 281250, 1920, 2064, 2272, 2624, 0, 1200, 1203, 1209, 1262, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1200@85Hz */
+ { MODEPREFIX, 317000, 1920, 1968, 2000, 2080, 0, 1200, 1203, 1209, 1271, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1200@120Hz RB */
+ { MODEPREFIX, 234000, 1920, 2048, 2256, 2600, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@60Hz */
+ { MODEPREFIX, 297000, 1920, 2064, 2288, 2640, 0, 1440, 1441, 1444, 1500, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 1920x1440@75Hz */
+ { MODEPREFIX, 380500, 1920, 1968, 2000, 2080, 0, 1440, 1443, 1447, 1525, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 1920x1440@120Hz RB */
+ { MODEPREFIX, 268500, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1646, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@60Hz RB */
+ { MODEPREFIX, 348500, 2560, 2752, 3032, 3504, 0, 1600, 1603, 1609, 1658, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@60Hz */
+ { MODEPREFIX, 443250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1672, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@75Hz */
+ { MODEPREFIX, 505250, 2560, 2768, 3048, 3536, 0, 1600, 1603, 1609, 1682, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 2560x1600@85Hz */
+ { MODEPREFIX, 552750, 2560, 2608, 2640, 2720, 0, 1600, 1603, 1609, 1694, 0, V_PHSYNC | V_NVSYNC, MODESUFFIX }, /* 2560x1600@120Hz RB */
+};
+
+#define LEVEL_DMT 0
+#define LEVEL_GTF 1
+#define LEVEL_CVT 2
+
+static int
+MonitorStandardTimingLevel(xf86MonPtr DDC)
+{
+ if (DDC->ver.revision >= 2) {
+ if (DDC->ver.revision >= 4 && CVT_SUPPORTED(DDC->features.msc)) {
+ return LEVEL_CVT;
+ }
+ return LEVEL_GTF;
+ }
+ return LEVEL_DMT;
+}
+
+static int
+ModeRefresh(const DisplayModeRec *mode)
+{
+ return (int)(xf86ModeVRefresh(mode) + 0.5);
+}
+
+/*
+ * If rb is not set, then we'll not consider reduced-blanking modes as
+ * part of the DMT pool. For the 'standard' EDID mode descriptor there's
+ * no way to specify whether the mode should be RB or not.
+ */
+DisplayModePtr
+FindDMTMode(int hsize, int vsize, int refresh, Bool rb)
+{
+ int i;
+ const DisplayModeRec *ret;
+
+ for (i = 0; i < sizeof(DMTModes) / sizeof(DisplayModeRec); i++) {
+ ret = &DMTModes[i];
+
+ if (!rb && xf86ModeIsReduced(ret))
+ continue;
+
+ if (ret->HDisplay == hsize &&
+ ret->VDisplay == vsize &&
+ refresh == ModeRefresh(ret))
+ return xf86DuplicateMode(ret);
+ }
+
+ return NULL;
+}
+
+/*
+ * Appendix B of the EDID 1.4 spec defines the right thing to do here.
+ * If the timing given here matches a mode defined in the VESA DMT standard,
+ * we _must_ use that. If the device supports CVT modes, then we should
+ * generate a CVT timing. If both of the above fail, use GTF.
+ *
+ * There are some wrinkles here. EDID 1.1 and 1.0 sinks can't really
+ * "support" GTF, since it wasn't a standard yet; so if they ask for a
+ * timing in this section that isn't defined in DMT, returning a GTF mode
+ * may not actually be valid. EDID 1.3 sinks often report support for
+ * some CVT modes, but they are not required to support CVT timings for
+ * modes in the standard timing descriptor, so we should _not_ treat them
+ * as CVT-compliant (unless specified in an extension block I suppose).
+ *
+ * EDID 1.4 requires that all sink devices support both GTF and CVT timings
+ * for modes in this section, but does say that CVT is preferred.
+ */
+static DisplayModePtr
+DDCModesFromStandardTiming(struct std_timings *timing, ddc_quirk_t quirks,
+ int timing_level, Bool rb)
+{
+ DisplayModePtr Modes = NULL, Mode = NULL;
+ int i, hsize, vsize, refresh;
+
+ for (i = 0; i < STD_TIMINGS; i++) {
+ hsize = timing[i].hsize;
+ vsize = timing[i].vsize;
+ refresh = timing[i].refresh;
+
+ /* HDTV hack, because you can't say 1366 */
+ if (refresh == 60 &&
+ ((hsize == 1360 && vsize == 765) ||
+ (hsize == 1368 && vsize == 769))) {
+ Mode = xf86CVTMode(1366, 768, 60, FALSE, FALSE);
+ Mode->HDisplay = 1366;
+ Mode->HSyncStart--;
+ Mode->HSyncEnd--;
+ } else if (hsize && vsize && refresh) {
+ Mode = FindDMTMode(hsize, vsize, refresh, rb);
+
+ if (!Mode) {
+ if (timing_level == LEVEL_CVT)
+ /* pass rb here too? */
+ Mode = xf86CVTMode(hsize, vsize, refresh, FALSE, FALSE);
+ else if (timing_level == LEVEL_GTF)
+ Mode = xf86GTFMode(hsize, vsize, refresh, FALSE, FALSE);
+ }
+
+ }
+
+ if (Mode) {
+ Mode->type = M_T_DRIVER;
+ Modes = xf86ModesAdd(Modes, Mode);
+ }
+ Mode = NULL;
+ }
+
+ return Modes;
+}
+
+static void
+DDCModeDoInterlaceQuirks(DisplayModePtr mode)
+{
+ /*
+ * EDID is delightfully ambiguous about how interlaced modes are to be
+ * encoded. X's internal representation is of frame height, but some
+ * HDTV detailed timings are encoded as field height.
+ *
+ * The format list here is from CEA, in frame size. Technically we
+ * should be checking refresh rate too. Whatever.
+ */
+ static const struct {
+ int w, h;
+ } cea_interlaced[] = {
+ { 1920, 1080 },
+ { 720, 480 },
+ { 1440, 480 },
+ { 2880, 480 },
+ { 720, 576 },
+ { 1440, 576 },
+ { 2880, 576 },
+ };
+ static const int n_modes = sizeof(cea_interlaced)/sizeof(cea_interlaced[0]);
+ int i;
+
+ for (i = 0; i < n_modes; i++) {
+ if ((mode->HDisplay == cea_interlaced[i].w) &&
+ (mode->VDisplay == cea_interlaced[i].h / 2)) {
+ mode->VDisplay *= 2;
+ mode->VSyncStart *= 2;
+ mode->VSyncEnd *= 2;
+ mode->VTotal *= 2;
+ mode->VTotal |= 1;
+ }
+ }
+
+ mode->Flags |= V_INTERLACE;
+}
+
+/*
+ *
+ */
+static DisplayModePtr
+DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing,
+ Bool preferred, ddc_quirk_t quirks)
+{
+ DisplayModePtr Mode;
+
+ /*
+ * Refuse to create modes that are insufficiently large. 64 is a random
+ * number, maybe the spec says something about what the minimum is. In
+ * particular I see this frequently with _old_ EDID, 1.0 or so, so maybe
+ * our parser is just being too aggresive there.
+ */
+ if (timing->h_active < 64 || timing->v_active < 64) {
+ xf86DrvMsg(scrnIndex, X_INFO,
+ "%s: Ignoring tiny %dx%d mode\n", __func__,
+ timing->h_active, timing->v_active);
+ return NULL;
+ }
+
+ /* We don't do stereo */
+ if (timing->stereo) {
+ xf86DrvMsg(scrnIndex, X_INFO,
+ "%s: Ignoring: We don't handle stereo.\n", __func__);
+ return NULL;
+ }
+
+ /* We only do seperate sync currently */
+ if (timing->sync != 0x03) {
+ xf86DrvMsg(scrnIndex, X_INFO,
+ "%s: %dx%d Warning: We only handle separate"
+ " sync.\n", __func__, timing->h_active, timing->v_active);
+ }
+
+ Mode = xnfcalloc(1, sizeof(DisplayModeRec));
+
+ Mode->type = M_T_DRIVER;
+ if (preferred)
+ Mode->type |= M_T_PREFERRED;
+
+ if( ( quirks & DDC_QUIRK_135_CLOCK_TOO_HIGH ) &&
+ timing->clock == 135000000 )
+ Mode->Clock = 108880;
+ else
+ Mode->Clock = timing->clock / 1000.0;
+
+ Mode->HDisplay = timing->h_active;
+ Mode->HSyncStart = timing->h_active + timing->h_sync_off;
+ Mode->HSyncEnd = Mode->HSyncStart + timing->h_sync_width;
+ Mode->HTotal = timing->h_active + timing->h_blanking;
+
+ Mode->VDisplay = timing->v_active;
+ Mode->VSyncStart = timing->v_active + timing->v_sync_off;
+ Mode->VSyncEnd = Mode->VSyncStart + timing->v_sync_width;
+ Mode->VTotal = timing->v_active + timing->v_blanking;
+
+ /* perform basic check on the detail timing */
+ if (Mode->HSyncEnd > Mode->HTotal || Mode->VSyncEnd > Mode->VTotal) {
+ free(Mode);
+ return NULL;
+ }
+
+ /* We ignore h/v_size and h/v_border for now. */
+
+ if (timing->interlaced)
+ DDCModeDoInterlaceQuirks(Mode);
+
+ if (quirks & DDC_QUIRK_DETAILED_SYNC_PP)
+ Mode->Flags |= V_PVSYNC | V_PHSYNC;
+ else {
+ if (timing->misc & 0x02)
+ Mode->Flags |= V_PVSYNC;
+ else
+ Mode->Flags |= V_NVSYNC;
+
+ if (timing->misc & 0x01)
+ Mode->Flags |= V_PHSYNC;
+ else
+ Mode->Flags |= V_NHSYNC;
+ }
+
+ xf86SetModeDefaultName(Mode);
+
+ return Mode;
+}
+
+static DisplayModePtr
+DDCModesFromCVT(int scrnIndex, struct cvt_timings *t)
+{
+ DisplayModePtr modes = NULL;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (t[i].height) {
+ if (t[i].rates & 0x10)
+ modes = xf86ModesAdd(modes,
+ xf86CVTMode(t[i].width, t[i].height, 50, 0, 0));
+ if (t[i].rates & 0x08)
+ modes = xf86ModesAdd(modes,
+ xf86CVTMode(t[i].width, t[i].height, 60, 0, 0));
+ if (t[i].rates & 0x04)
+ modes = xf86ModesAdd(modes,
+ xf86CVTMode(t[i].width, t[i].height, 75, 0, 0));
+ if (t[i].rates & 0x02)
+ modes = xf86ModesAdd(modes,
+ xf86CVTMode(t[i].width, t[i].height, 85, 0, 0));
+ if (t[i].rates & 0x01)
+ modes = xf86ModesAdd(modes,
+ xf86CVTMode(t[i].width, t[i].height, 60, 1, 0));
+ } else break;
+ }
+
+ return modes;
+}
+
+static const struct {
+ short w;
+ short h;
+ short r;
+ short rb;
+} EstIIIModes[] = {
+ /* byte 6 */
+ { 640, 350, 85, 0 },
+ { 640, 400, 85, 0 },
+ { 720, 400, 85, 0 },
+ { 640, 480, 85, 0 },
+ { 848, 480, 60, 0 },
+ { 800, 600, 85, 0 },
+ { 1024, 768, 85, 0 },
+ { 1152, 864, 75, 0 },
+ /* byte 7 */
+ { 1280, 768, 60, 1 },
+ { 1280, 768, 60, 0 },
+ { 1280, 768, 75, 0 },
+ { 1280, 768, 85, 0 },
+ { 1280, 960, 60, 0 },
+ { 1280, 960, 85, 0 },
+ { 1280, 1024, 60, 0 },
+ { 1280, 1024, 85, 0 },
+ /* byte 8 */
+ { 1360, 768, 60, 0 },
+ { 1440, 900, 60, 1 },
+ { 1440, 900, 60, 0 },
+ { 1440, 900, 75, 0 },
+ { 1440, 900, 85, 0 },
+ { 1400, 1050, 60, 1 },
+ { 1400, 1050, 60, 0 },
+ { 1400, 1050, 75, 0 },
+ /* byte 9 */
+ { 1400, 1050, 85, 0 },
+ { 1680, 1050, 60, 1 },
+ { 1680, 1050, 60, 0 },
+ { 1680, 1050, 75, 0 },
+ { 1680, 1050, 85, 0 },
+ { 1600, 1200, 60, 0 },
+ { 1600, 1200, 65, 0 },
+ { 1600, 1200, 70, 0 },
+ /* byte 10 */
+ { 1600, 1200, 75, 0 },
+ { 1600, 1200, 85, 0 },
+ { 1792, 1344, 60, 0 },
+ { 1792, 1344, 85, 0 },
+ { 1856, 1392, 60, 0 },
+ { 1856, 1392, 75, 0 },
+ { 1920, 1200, 60, 1 },
+ { 1920, 1200, 60, 0 },
+ /* byte 11 */
+ { 1920, 1200, 75, 0 },
+ { 1920, 1200, 85, 0 },
+ { 1920, 1440, 60, 0 },
+ { 1920, 1440, 75, 0 },
+};
+
+static DisplayModePtr
+DDCModesFromEstIII(unsigned char *est)
+{
+ DisplayModePtr modes = NULL;
+ int i, j, m;
+
+ for (i = 0; i < 6; i++) {
+ for (j = 7; j > 0; j--) {
+ if (est[i] & (1 << j)) {
+ m = (i * 8) + (7 - j);
+ modes = xf86ModesAdd(modes,
+ FindDMTMode(EstIIIModes[m].w,
+ EstIIIModes[m].h,
+ EstIIIModes[m].r,
+ EstIIIModes[m].rb));
+ }
+ }
+ }
+
+ return modes;
+}
+
+/*
+ * This is only valid when the sink claims to be continuous-frequency
+ * but does not supply a detailed range descriptor. Such sinks are
+ * arguably broken. Currently the mode validation code isn't aware of
+ * this; the non-RANDR code even punts the decision of optional sync
+ * range checking to the driver. Loss.
+ */
+static void
+DDCGuessRangesFromModes(int scrnIndex, MonPtr Monitor, DisplayModePtr Modes)
+{
+ DisplayModePtr Mode = Modes;
+
+ if (!Monitor || !Modes)
+ return;
+
+ /* set up the ranges for scanning through the modes */
+ Monitor->nHsync = 1;
+ Monitor->hsync[0].lo = 1024.0;
+ Monitor->hsync[0].hi = 0.0;
+
+ Monitor->nVrefresh = 1;
+ Monitor->vrefresh[0].lo = 1024.0;
+ Monitor->vrefresh[0].hi = 0.0;
+
+ while (Mode) {
+ if (!Mode->HSync)
+ Mode->HSync = ((float) Mode->Clock ) / ((float) Mode->HTotal);
+
+ if (!Mode->VRefresh)
+ Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) /
+ ((float) (Mode->HTotal * Mode->VTotal));
+
+ if (Mode->HSync < Monitor->hsync[0].lo)
+ Monitor->hsync[0].lo = Mode->HSync;
+
+ if (Mode->HSync > Monitor->hsync[0].hi)
+ Monitor->hsync[0].hi = Mode->HSync;
+
+ if (Mode->VRefresh < Monitor->vrefresh[0].lo)
+ Monitor->vrefresh[0].lo = Mode->VRefresh;
+
+ if (Mode->VRefresh > Monitor->vrefresh[0].hi)
+ Monitor->vrefresh[0].hi = Mode->VRefresh;
+
+ Mode = Mode->next;
+ }
+}
+
+ddc_quirk_t
+xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose)
+{
+ ddc_quirk_t quirks;
+ int i;
+
+ quirks = DDC_QUIRK_NONE;
+ for (i = 0; ddc_quirks[i].detect; i++) {
+ if (ddc_quirks[i].detect (scrnIndex, DDC)) {
+ if (verbose) {
+ xf86DrvMsg (scrnIndex, X_INFO, " EDID quirk: %s\n",
+ ddc_quirks[i].description);
+ }
+ quirks |= ddc_quirks[i].quirk;
+ }
+ }
+
+ return quirks;
+}
+
+void xf86DetTimingApplyQuirks(struct detailed_monitor_section *det_mon,
+ ddc_quirk_t quirks,
+ int hsize, int vsize)
+{
+ if (det_mon->type != DT)
+ return;
+
+ if (quirks & DDC_QUIRK_DETAILED_H_IN_CM)
+ det_mon->section.d_timings.h_size *= 10;
+
+ if (quirks & DDC_QUIRK_DETAILED_V_IN_CM)
+ det_mon->section.d_timings.v_size *= 10;
+
+ if (quirks & DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
+ det_mon->section.d_timings.h_size = 10 * hsize;
+ det_mon->section.d_timings.v_size = 10 * vsize;
+ }
+}
+
+/**
+ * Applies monitor-specific quirks to the decoded EDID information.
+ *
+ * Note that some quirks applying to the mode list are still implemented in
+ * xf86DDCGetModes.
+ */
+void
+xf86DDCApplyQuirks(int scrnIndex, xf86MonPtr DDC)
+{
+ ddc_quirk_t quirks = xf86DDCDetectQuirks (scrnIndex, DDC, FALSE);
+ int i;
+
+ for (i = 0; i < DET_TIMINGS; i++) {
+ xf86DetTimingApplyQuirks(DDC->det_mon + i, quirks,
+ DDC->features.hsize,
+ DDC->features.vsize);
+ }
+}
+
+/**
+ * Walks the modes list, finding the mode with the largest area which is
+ * closest to the target refresh rate, and marks it as the only preferred mode.
+*/
+static void
+xf86DDCSetPreferredRefresh(int scrnIndex, DisplayModePtr modes,
+ float target_refresh)
+{
+ DisplayModePtr mode, best = modes;
+
+ for (mode = modes; mode; mode = mode->next)
+ {
+ mode->type &= ~M_T_PREFERRED;
+
+ if (mode == best) continue;
+
+ if (mode->HDisplay * mode->VDisplay >
+ best->HDisplay * best->VDisplay)
+ {
+ best = mode;
+ continue;
+ }
+ if (mode->HDisplay * mode->VDisplay ==
+ best->HDisplay * best->VDisplay)
+ {
+ double mode_refresh = xf86ModeVRefresh (mode);
+ double best_refresh = xf86ModeVRefresh (best);
+ double mode_dist = fabs(mode_refresh - target_refresh);
+ double best_dist = fabs(best_refresh - target_refresh);
+
+ if (mode_dist < best_dist)
+ {
+ best = mode;
+ continue;
+ }
+ }
+ }
+ if (best)
+ best->type |= M_T_PREFERRED;
+}
+
+#define CEA_VIDEO_MODES_NUM 64
+static const DisplayModeRec CEAVideoModes[CEA_VIDEO_MODES_NUM] = {
+ { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 1:640x480@60Hz */
+ { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 2:720x480@60Hz */
+ { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 3:720x480@60Hz */
+ { MODEPREFIX, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 4: 1280x720@60Hz */
+ { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 5:1920x1080i@60Hz */
+ { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 6:1440x480i@60Hz */
+ { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 7:1440x480i@60Hz */
+ { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 8:1440x240@60Hz */
+ { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 9:1440x240@60Hz */
+ { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 10:2880x480i@60Hz */
+ { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 11:2880x480i@60Hz */
+ { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 12:2880x240@60Hz */
+ { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 13:2880x240@60Hz */
+ { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 14:1440x480@60Hz */
+ { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 15:1440x480@60Hz */
+ { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 16:1920x1080@60Hz */
+ { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 17:720x576@50Hz */
+ { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 18:720x576@50Hz */
+ { MODEPREFIX, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 19: 1280x720@50Hz */
+ { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 20:1920x1080i@50Hz */
+ { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 21:1440x576i@50Hz */
+ { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 22:1440x576i@50Hz */
+ { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 23:1440x288@50Hz */
+ { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 24:1440x288@50Hz */
+ { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 25:2880x576i@50Hz */
+ { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 26:2880x576i@50Hz */
+ { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 27:2880x288@50Hz */
+ { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 28:2880x288@50Hz */
+ { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 29:1440x576@50Hz */
+ { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 30:1440x576@50Hz */
+ { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 31:1920x1080@50Hz */
+ { MODEPREFIX, 74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 32:1920x1080@24Hz */
+ { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 33:1920x1080@25Hz */
+ { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 34:1920x1080@30Hz */
+ { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 35:2880x480@60Hz */
+ { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 36:2880x480@60Hz */
+ { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 37:2880x576@50Hz */
+ { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 38:2880x576@50Hz */
+ { MODEPREFIX, 72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, V_PHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 39:1920x1080i@50Hz */
+ { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 40:1920x1080i@100Hz */
+ { MODEPREFIX, 148500, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 41:1280x720@100Hz */
+ { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 42:720x576@100Hz */
+ { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 43:720x576@100Hz */
+ { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 44:1440x576i@100Hz */
+ { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 45:1440x576i@100Hz */
+ { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 46:1920x1080i@120Hz */
+ { MODEPREFIX, 148500, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 47:1280x720@120Hz */
+ { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 48:720x480@120Hz */
+ { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 49:720x480@120Hz */
+ { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 50:1440x480i@120Hz */
+ { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 51:1440x480i@120Hz */
+ { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 52:720x576@200Hz */
+ { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 53:720x576@200Hz */
+ { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 54:1440x576i@200Hz */
+ { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 55:1440x576i@200Hz */
+ { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 56:720x480@240Hz */
+ { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 57:720x480@240Hz */
+ { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 58:1440x480i@240 */
+ { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 59:1440x480i@240 */
+ { MODEPREFIX, 59400, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 60: 1280x720@24Hz */
+ { MODEPREFIX, 74250, 3700, 3740, 1430, 3960, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 61: 1280x720@25Hz */
+ { MODEPREFIX, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 62: 1280x720@30Hz */
+ { MODEPREFIX, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 63: 1920x1080@120Hz */
+ { MODEPREFIX, 297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 64:1920x1080@100Hz */
+};
+
+/* chose mode line by cea short video descriptor*/
+static void handle_cea_svd(struct cea_video_block *video, void *data)
+{
+ DisplayModePtr Mode;
+ DisplayModePtr *Modes = (DisplayModePtr *) data;
+ int vid;
+
+ vid = video ->video_code & 0x7f;
+ if (vid < CEA_VIDEO_MODES_NUM) {
+ Mode = xf86DuplicateMode(CEAVideoModes + vid);
+ *Modes = xf86ModesAdd(*Modes, Mode);
+ }
+}
+
+static DisplayModePtr
+DDCModesFromCEAExtension(int scrnIndex, xf86MonPtr MonPtr)
+{
+ DisplayModePtr Modes = NULL;
+
+ xf86ForEachVideoBlock(MonPtr,
+ handle_cea_svd,
+ &Modes);
+
+ return Modes;
+}
+
+struct det_modes_parameter {
+ xf86MonPtr DDC;
+ ddc_quirk_t quirks;
+ DisplayModePtr Modes;
+ Bool rb;
+ Bool preferred;
+ int timing_level;
+};
+
+static void handle_detailed_modes(struct detailed_monitor_section *det_mon,
+ void *data)
+{
+ DisplayModePtr Mode;
+ struct det_modes_parameter *p = (struct det_modes_parameter *)data;
+
+ xf86DetTimingApplyQuirks(det_mon,p->quirks,
+ p->DDC->features.hsize,
+ p->DDC->features.vsize);
+
+ switch (det_mon->type) {
+ case DT:
+ Mode = DDCModeFromDetailedTiming(p->DDC->scrnIndex,
+ &det_mon->section.d_timings,
+ p->preferred,
+ p->quirks);
+ p->preferred = FALSE;
+ p->Modes = xf86ModesAdd(p->Modes, Mode);
+ break;
+ case DS_STD_TIMINGS:
+ Mode = DDCModesFromStandardTiming(det_mon->section.std_t,
+ p->quirks, p->timing_level,p->rb);
+ p->Modes = xf86ModesAdd(p->Modes, Mode);
+ break;
+ case DS_CVT:
+ Mode = DDCModesFromCVT(p->DDC->scrnIndex, det_mon->section.cvt);
+ p->Modes = xf86ModesAdd(p->Modes, Mode);
+ break;
+ case DS_EST_III:
+ Mode = DDCModesFromEstIII(det_mon->section.est_iii);
+ p->Modes = xf86ModesAdd(p->Modes, Mode);
+ break;
+ default:
+ break;
+ }
+}
+
+DisplayModePtr
+xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
+{
+ DisplayModePtr Modes = NULL, Mode;
+ ddc_quirk_t quirks;
+ Bool preferred, rb;
+ int timing_level;
+ struct det_modes_parameter p;
+
+ xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n",
+ DDC->vendor.name, DDC->vendor.prod_id);
+
+ quirks = xf86DDCDetectQuirks(scrnIndex, DDC, TRUE);
+
+ preferred = PREFERRED_TIMING_MODE(DDC->features.msc);
+ if (DDC->ver.revision >= 4)
+ preferred = TRUE;
+ if (quirks & DDC_QUIRK_FIRST_DETAILED_PREFERRED)
+ preferred = TRUE;
+ if (quirks & (DDC_QUIRK_PREFER_LARGE_60 | DDC_QUIRK_PREFER_LARGE_75))
+ preferred = FALSE;
+
+ rb = xf86MonitorSupportsReducedBlanking(DDC);
+
+ timing_level = MonitorStandardTimingLevel(DDC);
+
+ p.quirks = quirks;
+ p.DDC = DDC;
+ p.Modes = Modes;
+ p.rb = rb;
+ p.preferred = preferred;
+ p.timing_level = timing_level;
+ xf86ForEachDetailedBlock(DDC, handle_detailed_modes, &p);
+ Modes = p.Modes;
+
+ /* Add established timings */
+ Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks);
+ Modes = xf86ModesAdd(Modes, Mode);
+
+ /* Add standard timings */
+ Mode = DDCModesFromStandardTiming(DDC->timings2, quirks, timing_level, rb);
+ Modes = xf86ModesAdd(Modes, Mode);
+
+ /* Add cea-extension mode timings */
+ Mode = DDCModesFromCEAExtension(scrnIndex,DDC);
+ Modes = xf86ModesAdd(Modes, Mode);
+
+ if (quirks & DDC_QUIRK_PREFER_LARGE_60)
+ xf86DDCSetPreferredRefresh(scrnIndex, Modes, 60);
+
+ if (quirks & DDC_QUIRK_PREFER_LARGE_75)
+ xf86DDCSetPreferredRefresh(scrnIndex, Modes, 75);
+
+ Modes = xf86PruneDuplicateModes(Modes);
+
+ return Modes;
+}
+
+struct det_mon_parameter {
+ MonPtr Monitor;
+ ddc_quirk_t quirks;
+ Bool have_hsync;
+ Bool have_vrefresh;
+ Bool have_maxpixclock;
+};
+
+static void handle_detailed_monset(struct detailed_monitor_section *det_mon,
+ void *data)
+{
+ int clock;
+ struct det_mon_parameter *p = (struct det_mon_parameter *)data;
+ int scrnIndex = ((xf86MonPtr)(p->Monitor->DDC))->scrnIndex;
+
+ switch (det_mon->type) {
+ case DS_RANGES:
+ if (!p->have_hsync) {
+ if (!p->Monitor->nHsync)
+ xf86DrvMsg(scrnIndex, X_INFO,
+ "Using EDID range info for horizontal sync\n");
+ p->Monitor->hsync[p->Monitor->nHsync].lo =
+ det_mon->section.ranges.min_h;
+ p->Monitor->hsync[p->Monitor->nHsync].hi =
+ det_mon->section.ranges.max_h;
+ p->Monitor->nHsync++;
+ } else {
+ xf86DrvMsg(scrnIndex, X_INFO,
+ "Using hsync ranges from config file\n");
+ }
+
+ if (!p->have_vrefresh) {
+ if (!p->Monitor->nVrefresh)
+ xf86DrvMsg(scrnIndex, X_INFO,
+ "Using EDID range info for vertical refresh\n");
+ p->Monitor->vrefresh[p->Monitor->nVrefresh].lo =
+ det_mon->section.ranges.min_v;
+ p->Monitor->vrefresh[p->Monitor->nVrefresh].hi =
+ det_mon->section.ranges.max_v;
+ p->Monitor->nVrefresh++;
+ } else {
+ xf86DrvMsg(scrnIndex, X_INFO,
+ "Using vrefresh ranges from config file\n");
+ }
+
+ clock = det_mon->section.ranges.max_clock * 1000;
+ if (p->quirks & DDC_QUIRK_DVI_SINGLE_LINK)
+ clock = min(clock, 165000);
+ if (!p->have_maxpixclock && clock > p->Monitor->maxPixClock)
+ p->Monitor->maxPixClock = clock;
+
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * Fill out MonPtr with xf86MonPtr information.
+ */
+void
+xf86EdidMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC)
+{
+ DisplayModePtr Modes = NULL, Mode;
+ struct det_mon_parameter p;
+
+ if (!Monitor || !DDC)
+ return;
+
+ Monitor->DDC = DDC;
+
+ if (Monitor->widthmm <= 0 || Monitor->heightmm <= 0) {
+ Monitor->widthmm = 10 * DDC->features.hsize;
+ Monitor->heightmm = 10 * DDC->features.vsize;
+ }
+
+ Monitor->reducedblanking = xf86MonitorSupportsReducedBlanking(DDC);
+
+ Modes = xf86DDCGetModes(scrnIndex, DDC);
+
+ /* Go through the detailed monitor sections */
+ p.Monitor = Monitor;
+ p.quirks = xf86DDCDetectQuirks(scrnIndex, Monitor->DDC, FALSE);
+ p.have_hsync = (Monitor->nHsync != 0);
+ p.have_vrefresh = (Monitor->nVrefresh != 0);
+ p.have_maxpixclock = (Monitor->maxPixClock != 0);
+ xf86ForEachDetailedBlock(DDC, handle_detailed_monset, &p);
+
+ if (Modes) {
+ /* Print Modes */
+ xf86DrvMsg(scrnIndex, X_INFO, "Printing DDC gathered Modelines:\n");
+
+ Mode = Modes;
+ while (Mode) {
+ xf86PrintModeline(scrnIndex, Mode);
+ Mode = Mode->next;
+ }
+
+ /* Do we still need ranges to be filled in? */
+ if (!Monitor->nHsync || !Monitor->nVrefresh)
+ DDCGuessRangesFromModes(scrnIndex, Monitor, Modes);
+
+ /* look for last Mode */
+ Mode = Modes;
+
+ while (Mode->next)
+ Mode = Mode->next;
+
+ /* add to MonPtr */
+ if (Monitor->Modes) {
+ Monitor->Last->next = Modes;
+ Modes->prev = Monitor->Last;
+ Monitor->Last = Mode;
+ } else {
+ Monitor->Modes = Modes;
+ Monitor->Last = Mode;
+ }
+ }
+}
diff --git a/xorg-server/hw/xfree86/parser/Makefile.am b/xorg-server/hw/xfree86/parser/Makefile.am
index 6fe7b87c1..fb5d49e88 100644
--- a/xorg-server/hw/xfree86/parser/Makefile.am
+++ b/xorg-server/hw/xfree86/parser/Makefile.am
@@ -1,51 +1,51 @@
-if INSTALL_LIBXF86CONFIG
-noinst_LTLIBRARIES = libxf86config_internal.la
-lib_LIBRARIES = libxf86config.a
-LIBHEADERS = \
- xf86Optrec.h \
- xf86Parser.h
-else
-noinst_LTLIBRARIES = libxf86config_internal.la
-endif
-
-INTERNAL_SOURCES= \
- Device.c \
- Files.c \
- Flags.c \
- Input.c \
- InputClass.c \
- Layout.c \
- Module.c \
- Video.c \
- Monitor.c \
- Pointer.c \
- Screen.c \
- Vendor.c \
- read.c \
- scan.c \
- write.c \
- DRI.c \
- Extensions.c
-
-libxf86config_internal_la_SOURCES = \
- $(INTERNAL_SOURCES)
-
-libxf86config_a_SOURCES = \
- $(TOP_SRCDIR)/os/xprintf.c \
- $(INTERNAL_SOURCES)
-libxf86config_a_CFLAGS = $(AM_CFLAGS)
-
-AM_CFLAGS = $(DIX_CFLAGS) $(XORG_CFLAGS) \
- -DSYSCONFDIR=\"$(sysconfdir)\" \
- -DDATADIR=\"$(datadir)\"
-
-EXTRA_DIST = \
- Configint.h \
- configProcs.h \
- xf86Optrec.h \
- xf86Parser.h \
- xf86tokens.h
-
-sdk_HEADERS = \
- xf86Parser.h \
- xf86Optrec.h
+if INSTALL_LIBXF86CONFIG
+noinst_LTLIBRARIES = libxf86config_internal.la
+lib_LIBRARIES = libxf86config.a
+LIBHEADERS = \
+ xf86Optrec.h \
+ xf86Parser.h
+else
+noinst_LTLIBRARIES = libxf86config_internal.la
+endif
+
+INTERNAL_SOURCES= \
+ Device.c \
+ Files.c \
+ Flags.c \
+ Input.c \
+ InputClass.c \
+ Layout.c \
+ Module.c \
+ Video.c \
+ Monitor.c \
+ Pointer.c \
+ Screen.c \
+ Vendor.c \
+ read.c \
+ scan.c \
+ write.c \
+ DRI.c \
+ Extensions.c
+
+libxf86config_internal_la_SOURCES = \
+ $(INTERNAL_SOURCES)
+
+libxf86config_a_SOURCES = \
+ $(top_srcdir)/os/xprintf.c \
+ $(INTERNAL_SOURCES)
+libxf86config_a_CFLAGS = $(AM_CFLAGS)
+
+AM_CFLAGS = $(DIX_CFLAGS) $(XORG_CFLAGS) \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DDATADIR=\"$(datadir)\"
+
+EXTRA_DIST = \
+ Configint.h \
+ configProcs.h \
+ xf86Optrec.h \
+ xf86Parser.h \
+ xf86tokens.h
+
+sdk_HEADERS = \
+ xf86Parser.h \
+ xf86Optrec.h
diff --git a/xorg-server/os/xprintf.c b/xorg-server/os/xprintf.c
index 218c3c91f..254b7374a 100644
--- a/xorg-server/os/xprintf.c
+++ b/xorg-server/os/xprintf.c
@@ -1,226 +1,226 @@
-/**
- * @file
- *
- * @section DESCRIPTION
- *
- * These functions provide a portable implementation of the common (but not
- * yet universal) asprintf & vasprintf routines to allocate a buffer big
- * enough to sprintf the arguments to. The XNF variants terminate the server
- * if the allocation fails.
- */
-/*
- * Copyright (c) 2004 Alexander Gottwald
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Except as contained in this notice, the name(s) of the above copyright
- * holders shall not be used in advertising or otherwise to promote the sale,
- * use or other dealings in this Software without prior written authorization.
- */
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <X11/Xos.h>
-#include "os.h"
-#include <stdarg.h>
-#include <stdio.h>
-
-#ifdef asprintf
-# undef asprintf
-#endif
-#ifdef vasprintf
-# undef vasprintf
-#endif
-
-#ifndef va_copy
-# ifdef __va_copy
-# define va_copy __va_copy
-# else
-# error "no working va_copy was found"
-# endif
-#endif
-
-/**
- * Varargs sprintf that allocates a string buffer the right size for
- * the pattern & data provided and prints the requested data to it.
- *
- * @param ret Pointer to which the newly allocated buffer is written
- * (contents undefined on error)
- * @param format printf style format string
- * @param va variable argument list
- * @return size of allocated buffer, or -1 on error.
- */
-int
-Xvasprintf(char **ret, const char * _X_RESTRICT_KYWD format, va_list va)
-{
-#ifdef HAVE_VASPRINTF
- return vasprintf(ret, format, va);
-#else
- int size;
- va_list va2;
-
- va_copy(va2, va);
- size = vsnprintf(NULL, 0, format, va2);
- va_end(va2);
-
- *ret = malloc(size + 1);
- if (*ret == NULL)
- return -1;
-
- vsnprintf(*ret, size + 1, format, va);
- ret[size] = 0;
- return size;
-#endif
-}
-
-#ifndef HAVE_VASPRINTF
-# define vasprintf Xvasprintf
-#endif
-
-/**
- * sprintf that allocates a string buffer the right size for
- * the pattern & data provided and prints the requested data to it.
- *
- * @param ret Pointer to which the newly allocated buffer is written
- * (contents undefined on error)
- * @param format printf style format string
- * @param ... arguments for specified format
- * @return size of allocated buffer, or -1 on error.
- */
-int
-Xasprintf(char ** ret, const char * _X_RESTRICT_KYWD format, ...)
-{
- int size;
- va_list va;
- va_start(va, format);
- size = vasprintf(ret, format, va);
- va_end(va);
- return size;
-}
-
-/**
- * Varargs sprintf that allocates a string buffer the right size for
- * the pattern & data provided and prints the requested data to it.
- * On failure, issues a FatalError message and aborts the server.
- *
- * @param ret Pointer to which the newly allocated buffer is written
- * (contents undefined on error)
- * @param format printf style format string
- * @param va variable argument list
- * @return size of allocated buffer
- */
-int
-XNFvasprintf(char **ret, const char * _X_RESTRICT_KYWD format, va_list va)
-{
- int size = vasprintf(ret, format, va);
- if ((size == -1) || (*ret == NULL)) {
- Error("XNFvasprintf");
- FatalError("XNFvasprintf failed");
- }
- return size;
-}
-
-/**
- * sprintf that allocates a string buffer the right size for
- * the pattern & data provided and prints the requested data to it.
- * On failure, issues a FatalError message and aborts the server.
- *
- * @param ret Pointer to which the newly allocated buffer is written
- * (contents undefined on error)
- * @param format printf style format string
- * @param ... arguments for specified format
- * @return size of allocated buffer
- */
-int
-XNFasprintf(char ** ret, const char * _X_RESTRICT_KYWD format, ...)
-{
- int size;
- va_list va;
- va_start(va, format);
- size = XNFvasprintf(ret, format, va);
- va_end(va);
- return size;
-}
-
-/* Old api, now deprecated, may be removed in the future */
-char *
-Xvprintf(const char *format, va_list va)
-{
- char *ret;
-
- if (vasprintf(&ret, format, va) == -1)
- ret = NULL;
-
- return ret;
-}
-
-char *Xprintf(const char *format, ...)
-{
- char *ret;
- va_list va;
- va_start(va, format);
- if (vasprintf(&ret, format, va) == -1)
- ret = NULL;
- va_end(va);
- return ret;
-}
-
-char *
-XNFvprintf(const char *format, va_list va)
-{
- char *ret;
-
- XNFvasprintf(&ret, format, va);
-
- return ret;
-}
-
-char *XNFprintf(const char *format, ...)
-{
- char *ret;
- va_list va;
- va_start(va, format);
- XNFvasprintf(&ret, format, va);
- va_end(va);
- return ret;
-}
+/**
+ * @file
+ *
+ * @section DESCRIPTION
+ *
+ * These functions provide a portable implementation of the common (but not
+ * yet universal) asprintf & vasprintf routines to allocate a buffer big
+ * enough to sprintf the arguments to. The XNF variants terminate the server
+ * if the allocation fails.
+ */
+/*
+ * Copyright (c) 2004 Alexander Gottwald
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name(s) of the above copyright
+ * holders shall not be used in advertising or otherwise to promote the sale,
+ * use or other dealings in this Software without prior written authorization.
+ */
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/Xos.h>
+#include "os.h"
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef asprintf
+# undef asprintf
+#endif
+#ifdef vasprintf
+# undef vasprintf
+#endif
+
+#ifndef va_copy
+# ifdef __va_copy
+# define va_copy __va_copy
+# else
+# error "no working va_copy was found"
+# endif
+#endif
+
+/**
+ * Varargs sprintf that allocates a string buffer the right size for
+ * the pattern & data provided and prints the requested data to it.
+ *
+ * @param ret Pointer to which the newly allocated buffer is written
+ * (contents undefined on error)
+ * @param format printf style format string
+ * @param va variable argument list
+ * @return size of allocated buffer, or -1 on error.
+ */
+int
+Xvasprintf(char **ret, const char * _X_RESTRICT_KYWD format, va_list va)
+{
+#ifdef HAVE_VASPRINTF
+ return vasprintf(ret, format, va);
+#else
+ int size;
+ va_list va2;
+
+ va_copy(va2, va);
+ size = vsnprintf(NULL, 0, format, va2);
+ va_end(va2);
+
+ *ret = malloc(size + 1);
+ if (*ret == NULL)
+ return -1;
+
+ vsnprintf(*ret, size + 1, format, va);
+ (*ret)[size] = 0;
+ return size;
+#endif
+}
+
+#ifndef HAVE_VASPRINTF
+# define vasprintf Xvasprintf
+#endif
+
+/**
+ * sprintf that allocates a string buffer the right size for
+ * the pattern & data provided and prints the requested data to it.
+ *
+ * @param ret Pointer to which the newly allocated buffer is written
+ * (contents undefined on error)
+ * @param format printf style format string
+ * @param ... arguments for specified format
+ * @return size of allocated buffer, or -1 on error.
+ */
+int
+Xasprintf(char ** ret, const char * _X_RESTRICT_KYWD format, ...)
+{
+ int size;
+ va_list va;
+ va_start(va, format);
+ size = vasprintf(ret, format, va);
+ va_end(va);
+ return size;
+}
+
+/**
+ * Varargs sprintf that allocates a string buffer the right size for
+ * the pattern & data provided and prints the requested data to it.
+ * On failure, issues a FatalError message and aborts the server.
+ *
+ * @param ret Pointer to which the newly allocated buffer is written
+ * (contents undefined on error)
+ * @param format printf style format string
+ * @param va variable argument list
+ * @return size of allocated buffer
+ */
+int
+XNFvasprintf(char **ret, const char * _X_RESTRICT_KYWD format, va_list va)
+{
+ int size = vasprintf(ret, format, va);
+ if ((size == -1) || (*ret == NULL)) {
+ Error("XNFvasprintf");
+ FatalError("XNFvasprintf failed");
+ }
+ return size;
+}
+
+/**
+ * sprintf that allocates a string buffer the right size for
+ * the pattern & data provided and prints the requested data to it.
+ * On failure, issues a FatalError message and aborts the server.
+ *
+ * @param ret Pointer to which the newly allocated buffer is written
+ * (contents undefined on error)
+ * @param format printf style format string
+ * @param ... arguments for specified format
+ * @return size of allocated buffer
+ */
+int
+XNFasprintf(char ** ret, const char * _X_RESTRICT_KYWD format, ...)
+{
+ int size;
+ va_list va;
+ va_start(va, format);
+ size = XNFvasprintf(ret, format, va);
+ va_end(va);
+ return size;
+}
+
+/* Old api, now deprecated, may be removed in the future */
+char *
+Xvprintf(const char *format, va_list va)
+{
+ char *ret;
+
+ if (vasprintf(&ret, format, va) == -1)
+ ret = NULL;
+
+ return ret;
+}
+
+char *Xprintf(const char *format, ...)
+{
+ char *ret;
+ va_list va;
+ va_start(va, format);
+ if (vasprintf(&ret, format, va) == -1)
+ ret = NULL;
+ va_end(va);
+ return ret;
+}
+
+char *
+XNFvprintf(const char *format, va_list va)
+{
+ char *ret;
+
+ XNFvasprintf(&ret, format, va);
+
+ return ret;
+}
+
+char *XNFprintf(const char *format, ...)
+{
+ char *ret;
+ va_list va;
+ va_start(va, format);
+ XNFvasprintf(&ret, format, va);
+ va_end(va);
+ return ret;
+}
diff --git a/xorg-server/randr/rrscreen.c b/xorg-server/randr/rrscreen.c
index 318dfaa91..0efc62e87 100644
--- a/xorg-server/randr/rrscreen.c
+++ b/xorg-server/randr/rrscreen.c
@@ -1,1025 +1,1037 @@
-/*
- * Copyright © 2006 Keith Packard
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation, and
- * that the name of the copyright holders not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission. The copyright holders make no representations
- * about the suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
- */
-
-#include "randrstr.h"
-
-static const int padlength[4] = {0, 3, 2, 1};
-
-static CARD16
-RR10CurrentSizeID (ScreenPtr pScreen);
-
-/*
- * Edit connection information block so that new clients
- * see the current screen size on connect
- */
-static void
-RREditConnectionInfo (ScreenPtr pScreen)
-{
- xConnSetup *connSetup;
- char *vendor;
- xPixmapFormat *formats;
- xWindowRoot *root;
- xDepth *depth;
- xVisualType *visual;
- int screen = 0;
- int d;
-
- connSetup = (xConnSetup *) ConnectionInfo;
- vendor = (char *) connSetup + sizeof (xConnSetup);
- formats = (xPixmapFormat *) ((char *) vendor +
- connSetup->nbytesVendor +
- padlength[connSetup->nbytesVendor & 3]);
- root = (xWindowRoot *) ((char *) formats +
- sizeof (xPixmapFormat) * screenInfo.numPixmapFormats);
- while (screen != pScreen->myNum)
- {
- depth = (xDepth *) ((char *) root +
- sizeof (xWindowRoot));
- for (d = 0; d < root->nDepths; d++)
- {
- visual = (xVisualType *) ((char *) depth +
- sizeof (xDepth));
- depth = (xDepth *) ((char *) visual +
- depth->nVisuals * sizeof (xVisualType));
- }
- root = (xWindowRoot *) ((char *) depth);
- screen++;
- }
- root->pixWidth = pScreen->width;
- root->pixHeight = pScreen->height;
- root->mmWidth = pScreen->mmWidth;
- root->mmHeight = pScreen->mmHeight;
-}
-
-void
-RRSendConfigNotify (ScreenPtr pScreen)
-{
- WindowPtr pWin = pScreen->root;
- xEvent event;
-
- event.u.u.type = ConfigureNotify;
- event.u.configureNotify.window = pWin->drawable.id;
- event.u.configureNotify.aboveSibling = None;
- event.u.configureNotify.x = 0;
- event.u.configureNotify.y = 0;
-
- /* XXX xinerama stuff ? */
-
- event.u.configureNotify.width = pWin->drawable.width;
- event.u.configureNotify.height = pWin->drawable.height;
- event.u.configureNotify.borderWidth = wBorderWidth (pWin);
- event.u.configureNotify.override = pWin->overrideRedirect;
- DeliverEvents(pWin, &event, 1, NullWindow);
-}
-
-void
-RRDeliverScreenEvent (ClientPtr client, WindowPtr pWin, ScreenPtr pScreen)
-{
- rrScrPriv (pScreen);
- xRRScreenChangeNotifyEvent se;
- RRCrtcPtr crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL;
- WindowPtr pRoot = pScreen->root;
-
- se.type = RRScreenChangeNotify + RREventBase;
- se.rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0);
- se.timestamp = pScrPriv->lastSetTime.milliseconds;
- se.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
- se.root = pRoot->drawable.id;
- se.window = pWin->drawable.id;
- se.subpixelOrder = PictureGetSubpixelOrder (pScreen);
-
- se.sizeID = RR10CurrentSizeID (pScreen);
-
- if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) {
- se.widthInPixels = pScreen->height;
- se.heightInPixels = pScreen->width;
- se.widthInMillimeters = pScreen->mmHeight;
- se.heightInMillimeters = pScreen->mmWidth;
- } else {
- se.widthInPixels = pScreen->width;
- se.heightInPixels = pScreen->height;
- se.widthInMillimeters = pScreen->mmWidth;
- se.heightInMillimeters = pScreen->mmHeight;
- }
-
- WriteEventsToClient (client, 1, (xEvent *) &se);
-}
-
-/*
- * Notify the extension that the screen size has been changed.
- * The driver is responsible for calling this whenever it has changed
- * the size of the screen
- */
-void
-RRScreenSizeNotify (ScreenPtr pScreen)
-{
- rrScrPriv(pScreen);
- /*
- * Deliver ConfigureNotify events when root changes
- * pixel size
- */
- if (pScrPriv->width == pScreen->width &&
- pScrPriv->height == pScreen->height &&
- pScrPriv->mmWidth == pScreen->mmWidth &&
- pScrPriv->mmHeight == pScreen->mmHeight)
- return;
-
- pScrPriv->width = pScreen->width;
- pScrPriv->height = pScreen->height;
- pScrPriv->mmWidth = pScreen->mmWidth;
- pScrPriv->mmHeight = pScreen->mmHeight;
- pScrPriv->changed = TRUE;
-/* pScrPriv->sizeChanged = TRUE; */
-
- RRTellChanged (pScreen);
- RRSendConfigNotify (pScreen);
- RREditConnectionInfo (pScreen);
-
- RRPointerScreenConfigured (pScreen);
- /*
- * Fix pointer bounds and location
- */
- ScreenRestructured (pScreen);
-}
-
-/*
- * Request that the screen be resized
- */
-Bool
-RRScreenSizeSet (ScreenPtr pScreen,
- CARD16 width,
- CARD16 height,
- CARD16 pixWidth,
- CARD16 pixHeight,
- CARD32 mmWidth,
- CARD32 mmHeight)
-{
- rrScrPriv(pScreen);
-
-#if RANDR_12_INTERFACE
- if (pScrPriv->rrScreenSetSize)
- {
- return (*pScrPriv->rrScreenSetSize) (pScreen,
- width, height,
- pixWidth, pixHeight,
- mmWidth, mmHeight);
- }
-#endif
-#if RANDR_10_INTERFACE
- if (pScrPriv->rrSetConfig)
- {
- return TRUE; /* can't set size separately */
- }
-#endif
- return FALSE;
-}
-
-/*
- * Compute an RRScreenConfig from the current screen information
- */
-void
-RRScreenCurrentConfig(ScreenPtr screen,
- RRScreenConfigPtr screen_config)
-{
- PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
- WindowPtr root = screen->root;
-
- screen_config->screen_pixmap_width = screen_pixmap->drawable.width;
- screen_config->screen_pixmap_height = screen_pixmap->drawable.height;
- screen_config->screen_width = root->drawable.width;
- screen_config->screen_height = root->drawable.height;
- screen_config->mm_width = screen->mmWidth;
- screen_config->mm_height = screen->mmHeight;
-}
-
-/*
- * Retrieve valid screen size range
- */
-int
-ProcRRGetScreenSizeRange (ClientPtr client)
-{
- REQUEST(xRRGetScreenSizeRangeReq);
- xRRGetScreenSizeRangeReply rep;
- WindowPtr pWin;
- ScreenPtr pScreen;
- rrScrPrivPtr pScrPriv;
- int rc;
-
- REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
- rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
- if (rc != Success)
- return rc;
-
- pScreen = pWin->drawable.pScreen;
- pScrPriv = rrGetScrPriv(pScreen);
-
- rep.type = X_Reply;
- rep.pad = 0;
- rep.sequenceNumber = client->sequence;
- rep.length = 0;
-
- if (pScrPriv)
- {
- if (!RRGetInfo (pScreen, FALSE))
- return BadAlloc;
- rep.minWidth = pScrPriv->minWidth;
- rep.minHeight = pScrPriv->minHeight;
- rep.maxWidth = pScrPriv->maxWidth;
- rep.maxHeight = pScrPriv->maxHeight;
- }
- else
- {
- rep.maxWidth = rep.minWidth = pScreen->width;
- rep.maxHeight = rep.minHeight = pScreen->height;
- }
- if (client->swapped)
- {
- int n;
-
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swaps(&rep.minWidth, n);
- swaps(&rep.minHeight, n);
- swaps(&rep.maxWidth, n);
- swaps(&rep.maxHeight, n);
- }
- WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), (char *)&rep);
- return Success;
-}
-
-int
-ProcRRSetScreenSize (ClientPtr client)
-{
- REQUEST(xRRSetScreenSizeReq);
- WindowPtr pWin;
- ScreenPtr pScreen;
- rrScrPrivPtr pScrPriv;
- int i, rc;
-
- REQUEST_SIZE_MATCH(xRRSetScreenSizeReq);
- rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
- if (rc != Success)
- return rc;
-
- pScreen = pWin->drawable.pScreen;
- pScrPriv = rrGetScrPriv(pScreen);
- if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width)
- {
- client->errorValue = stuff->width;
- return BadValue;
- }
- if (stuff->height < pScrPriv->minHeight ||
- pScrPriv->maxHeight < stuff->height)
- {
- client->errorValue = stuff->height;
- return BadValue;
- }
- for (i = 0; i < pScrPriv->numCrtcs; i++)
- {
- RRCrtcPtr crtc = pScrPriv->crtcs[i];
- RRModePtr mode = crtc->mode;
- if (mode)
- {
- int source_width = mode->mode.width;
- int source_height = mode->mode.height;
- Rotation rotation = crtc->rotation;
-
- if (rotation == RR_Rotate_90 || rotation == RR_Rotate_270)
- {
- source_width = mode->mode.height;
- source_height = mode->mode.width;
- }
-
- if (crtc->x + source_width > stuff->width ||
- crtc->y + source_height > stuff->height)
- return BadMatch;
- }
- }
- if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0)
- {
- client->errorValue = 0;
- return BadValue;
- }
- if (!RRScreenSizeSet (pScreen,
- stuff->width, stuff->height,
- stuff->width, stuff->height,
- stuff->widthInMillimeters,
- stuff->heightInMillimeters))
- {
- return BadMatch;
- }
- return Success;
-}
-
-static int
-rrGetScreenResources(ClientPtr client, Bool query)
-{
- REQUEST(xRRGetScreenResourcesReq);
- xRRGetScreenResourcesReply rep;
- WindowPtr pWin;
- ScreenPtr pScreen;
- rrScrPrivPtr pScrPriv;
- CARD8 *extra;
- unsigned long extraLen;
- int i, n, rc, has_primary = 0;
- RRCrtc *crtcs;
- RROutput *outputs;
- xRRModeInfo *modeinfos;
- CARD8 *names;
-
- REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq);
- rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
- if (rc != Success)
- return rc;
-
- pScreen = pWin->drawable.pScreen;
- pScrPriv = rrGetScrPriv(pScreen);
- rep.pad = 0;
-
- if (query && pScrPriv)
- if (!RRGetInfo (pScreen, query))
- return BadAlloc;
-
- if (!pScrPriv)
- {
- rep.type = X_Reply;
- rep.sequenceNumber = client->sequence;
- rep.length = 0;
- rep.timestamp = currentTime.milliseconds;
- rep.configTimestamp = currentTime.milliseconds;
- rep.nCrtcs = 0;
- rep.nOutputs = 0;
- rep.nModes = 0;
- rep.nbytesNames = 0;
- extra = NULL;
- extraLen = 0;
- }
- else
- {
- RRModePtr *modes;
- int num_modes;
-
- modes = RRModesForScreen (pScreen, &num_modes);
- if (!modes)
- return BadAlloc;
-
- rep.type = X_Reply;
- rep.sequenceNumber = client->sequence;
- rep.length = 0;
- rep.timestamp = pScrPriv->lastSetTime.milliseconds;
- rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
- rep.nCrtcs = pScrPriv->numCrtcs;
- rep.nOutputs = pScrPriv->numOutputs;
- rep.nModes = num_modes;
- rep.nbytesNames = 0;
-
- for (i = 0; i < num_modes; i++)
- rep.nbytesNames += modes[i]->mode.nameLength;
-
- rep.length = (pScrPriv->numCrtcs +
- pScrPriv->numOutputs +
- num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
- bytes_to_int32(rep.nbytesNames));
-
- extraLen = rep.length << 2;
- if (extraLen)
- {
- extra = malloc(extraLen);
- if (!extra)
- {
- free(modes);
- return BadAlloc;
- }
- }
- else
- extra = NULL;
-
- crtcs = (RRCrtc *) extra;
- outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs);
- modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs);
- names = (CARD8 *) (modeinfos + num_modes);
-
- if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc)
- {
- has_primary = 1;
- crtcs[0] = pScrPriv->primaryOutput->crtc->id;
- if (client->swapped)
- swapl (&crtcs[0], n);
- }
-
- for (i = 0; i < pScrPriv->numCrtcs; i++)
- {
- if (has_primary &&
- pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i])
- {
- has_primary = 0;
- continue;
- }
- crtcs[i + has_primary] = pScrPriv->crtcs[i]->id;
- if (client->swapped)
- swapl (&crtcs[i + has_primary], n);
- }
-
- for (i = 0; i < pScrPriv->numOutputs; i++)
- {
- outputs[i] = pScrPriv->outputs[i]->id;
- if (client->swapped)
- swapl (&outputs[i], n);
- }
-
- for (i = 0; i < num_modes; i++)
- {
- RRModePtr mode = modes[i];
- modeinfos[i] = mode->mode;
- if (client->swapped)
- {
- swapl (&modeinfos[i].id, n);
- swaps (&modeinfos[i].width, n);
- swaps (&modeinfos[i].height, n);
- swapl (&modeinfos[i].dotClock, n);
- swaps (&modeinfos[i].hSyncStart, n);
- swaps (&modeinfos[i].hSyncEnd, n);
- swaps (&modeinfos[i].hTotal, n);
- swaps (&modeinfos[i].hSkew, n);
- swaps (&modeinfos[i].vSyncStart, n);
- swaps (&modeinfos[i].vSyncEnd, n);
- swaps (&modeinfos[i].vTotal, n);
- swaps (&modeinfos[i].nameLength, n);
- swapl (&modeinfos[i].modeFlags, n);
- }
- memcpy (names, mode->name,
- mode->mode.nameLength);
- names += mode->mode.nameLength;
- }
- free(modes);
- assert (bytes_to_int32((char *) names - (char *) extra) == rep.length);
- }
-
- if (client->swapped) {
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swapl(&rep.timestamp, n);
- swapl(&rep.configTimestamp, n);
- swaps(&rep.nCrtcs, n);
- swaps(&rep.nOutputs, n);
- swaps(&rep.nModes, n);
- swaps(&rep.nbytesNames, n);
- }
- WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *)&rep);
- if (extraLen)
- {
- WriteToClient (client, extraLen, (char *) extra);
- free(extra);
- }
- return Success;
-}
-
-int
-ProcRRGetScreenResources (ClientPtr client)
-{
- return rrGetScreenResources(client, TRUE);
-}
-
-int
-ProcRRGetScreenResourcesCurrent (ClientPtr client)
-{
- return rrGetScreenResources(client, FALSE);
-}
-
-typedef struct _RR10Data {
- RRScreenSizePtr sizes;
- int nsize;
- int nrefresh;
- int size;
- CARD16 refresh;
-} RR10DataRec, *RR10DataPtr;
-
-/*
- * Convert 1.2 monitor data into 1.0 screen data
- */
-static RR10DataPtr
-RR10GetData (ScreenPtr pScreen, RROutputPtr output)
-{
- RR10DataPtr data;
- RRScreenSizePtr size;
- int nmode = output->numModes + output->numUserModes;
- int o, os, l, r;
- RRScreenRatePtr refresh;
- CARD16 vRefresh;
- RRModePtr mode;
- Bool *used;
-
- /* Make sure there is plenty of space for any combination */
- data = malloc (sizeof (RR10DataRec) +
- sizeof (RRScreenSize) * nmode +
- sizeof (RRScreenRate) * nmode +
- sizeof (Bool) * nmode);
- if (!data)
- return NULL;
- size = (RRScreenSizePtr) (data + 1);
- refresh = (RRScreenRatePtr) (size + nmode);
- used = (Bool *) (refresh + nmode);
- memset (used, '\0', sizeof (Bool) * nmode);
- data->sizes = size;
- data->nsize = 0;
- data->nrefresh = 0;
- data->size = 0;
- data->refresh = 0;
-
- /*
- * find modes not yet listed
- */
- for (o = 0; o < output->numModes + output->numUserModes; o++)
- {
- if (used[o]) continue;
-
- if (o < output->numModes)
- mode = output->modes[o];
- else
- mode = output->userModes[o - output->numModes];
-
- l = data->nsize;
- size[l].id = data->nsize;
- size[l].width = mode->mode.width;
- size[l].height = mode->mode.height;
- if (output->mmWidth && output->mmHeight) {
- size[l].mmWidth = output->mmWidth;
- size[l].mmHeight = output->mmHeight;
- } else {
- size[l].mmWidth = pScreen->mmWidth;
- size[l].mmHeight = pScreen->mmHeight;
- }
- size[l].nRates = 0;
- size[l].pRates = &refresh[data->nrefresh];
- data->nsize++;
-
- /*
- * Find all modes with matching size
- */
- for (os = o; os < output->numModes + output->numUserModes; os++)
- {
- if (os < output->numModes)
- mode = output->modes[os];
- else
- mode = output->userModes[os - output->numModes];
- if (mode->mode.width == size[l].width &&
- mode->mode.height == size[l].height)
- {
- vRefresh = RRVerticalRefresh (&mode->mode);
- used[os] = TRUE;
-
- for (r = 0; r < size[l].nRates; r++)
- if (vRefresh == size[l].pRates[r].rate)
- break;
- if (r == size[l].nRates)
- {
- size[l].pRates[r].rate = vRefresh;
- size[l].pRates[r].mode = mode;
- size[l].nRates++;
- data->nrefresh++;
- }
- if (mode == output->crtc->mode)
- {
- data->size = l;
- data->refresh = vRefresh;
- }
- }
- }
- }
- return data;
-}
-
-int
-ProcRRGetScreenInfo (ClientPtr client)
-{
- REQUEST(xRRGetScreenInfoReq);
- xRRGetScreenInfoReply rep;
- WindowPtr pWin;
- int n, rc;
- ScreenPtr pScreen;
- rrScrPrivPtr pScrPriv;
- CARD8 *extra;
- unsigned long extraLen;
- RROutputPtr output;
-
- REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
- rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
- if (rc != Success)
- return rc;
-
- pScreen = pWin->drawable.pScreen;
- pScrPriv = rrGetScrPriv(pScreen);
- rep.pad = 0;
-
- if (pScrPriv)
- if (!RRGetInfo (pScreen, TRUE))
- return BadAlloc;
-
- output = RRFirstOutput (pScreen);
-
- if (!pScrPriv || !output)
- {
- rep.type = X_Reply;
- rep.setOfRotations = RR_Rotate_0;
- rep.sequenceNumber = client->sequence;
- rep.length = 0;
- rep.root = pWin->drawable.pScreen->root->drawable.id;
- rep.timestamp = currentTime.milliseconds;
- rep.configTimestamp = currentTime.milliseconds;
- rep.nSizes = 0;
- rep.sizeID = 0;
- rep.rotation = RR_Rotate_0;
- rep.rate = 0;
- rep.nrateEnts = 0;
- extra = 0;
- extraLen = 0;
- }
- else
- {
- int i, j;
- xScreenSizes *size;
- CARD16 *rates;
- CARD8 *data8;
- Bool has_rate = RRClientKnowsRates (client);
- RR10DataPtr pData;
- RRScreenSizePtr pSize;
-
- pData = RR10GetData (pScreen, output);
- if (!pData)
- return BadAlloc;
-
- rep.type = X_Reply;
- rep.setOfRotations = output->crtc->rotations;
- rep.sequenceNumber = client->sequence;
- rep.length = 0;
- rep.root = pWin->drawable.pScreen->root->drawable.id;
- rep.timestamp = pScrPriv->lastSetTime.milliseconds;
- rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
- rep.rotation = output->crtc->rotation;
- rep.nSizes = pData->nsize;
- rep.nrateEnts = pData->nrefresh + pData->nsize;
- rep.sizeID = pData->size;
- rep.rate = pData->refresh;
-
- extraLen = rep.nSizes * sizeof (xScreenSizes);
- if (has_rate)
- extraLen += rep.nrateEnts * sizeof (CARD16);
-
- if (extraLen)
- {
- extra = (CARD8 *) malloc(extraLen);
- if (!extra)
- {
- free(pData);
- return BadAlloc;
- }
- }
- else
- extra = NULL;
-
- /*
- * First comes the size information
- */
- size = (xScreenSizes *) extra;
- rates = (CARD16 *) (size + rep.nSizes);
- for (i = 0; i < pData->nsize; i++)
- {
- pSize = &pData->sizes[i];
- size->widthInPixels = pSize->width;
- size->heightInPixels = pSize->height;
- size->widthInMillimeters = pSize->mmWidth;
- size->heightInMillimeters = pSize->mmHeight;
- if (client->swapped)
- {
- swaps (&size->widthInPixels, n);
- swaps (&size->heightInPixels, n);
- swaps (&size->widthInMillimeters, n);
- swaps (&size->heightInMillimeters, n);
- }
- size++;
- if (has_rate)
- {
- *rates = pSize->nRates;
- if (client->swapped)
- {
- swaps (rates, n);
- }
- rates++;
- for (j = 0; j < pSize->nRates; j++)
- {
- *rates = pSize->pRates[j].rate;
- if (client->swapped)
- {
- swaps (rates, n);
- }
- rates++;
- }
- }
- }
- free(pData);
-
- data8 = (CARD8 *) rates;
-
- if (data8 - (CARD8 *) extra != extraLen)
- FatalError ("RRGetScreenInfo bad extra len %ld != %ld\n",
- (unsigned long)(data8 - (CARD8 *) extra), extraLen);
- rep.length = bytes_to_int32(extraLen);
- }
- if (client->swapped) {
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swapl(&rep.timestamp, n);
- swaps(&rep.rotation, n);
- swaps(&rep.nSizes, n);
- swaps(&rep.sizeID, n);
- swaps(&rep.rate, n);
- swaps(&rep.nrateEnts, n);
- }
- WriteToClient(client, sizeof(xRRGetScreenInfoReply), (char *)&rep);
- if (extraLen)
- {
- WriteToClient (client, extraLen, (char *) extra);
- free(extra);
- }
- return Success;
-}
-
-int
-ProcRRSetScreenConfig (ClientPtr client)
-{
- REQUEST(xRRSetScreenConfigReq);
- xRRSetScreenConfigReply rep;
- DrawablePtr pDraw;
- int n, rc;
- ScreenPtr pScreen;
- rrScrPrivPtr pScrPriv;
- TimeStamp time;
- int i;
- Rotation rotation;
- int rate;
- Bool has_rate;
- RROutputPtr output;
- RRCrtcPtr crtc;
- RRModePtr mode;
- RR10DataPtr pData = NULL;
- RRScreenSizePtr pSize;
- int width, height;
-
- UpdateCurrentTime ();
-
- if (RRClientKnowsRates (client))
- {
- REQUEST_SIZE_MATCH (xRRSetScreenConfigReq);
- has_rate = TRUE;
- }
- else
- {
- REQUEST_SIZE_MATCH (xRR1_0SetScreenConfigReq);
- has_rate = FALSE;
- }
-
- rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess);
- if (rc != Success) {
- client->errorValue = stuff->drawable;
- return rc;
- }
-
- pScreen = pDraw->pScreen;
-
- pScrPriv = rrGetScrPriv(pScreen);
-
- time = ClientTimeToServerTime(stuff->timestamp);
-
- if (!pScrPriv)
- {
- time = currentTime;
- rep.status = RRSetConfigFailed;
- goto sendReply;
- }
- if (!RRGetInfo (pScreen, FALSE))
- return BadAlloc;
-
- output = RRFirstOutput (pScreen);
- if (!output)
- {
- time = currentTime;
- rep.status = RRSetConfigFailed;
- goto sendReply;
- }
-
- crtc = output->crtc;
-
- /*
- * If the client's config timestamp is not the same as the last config
- * timestamp, then the config information isn't up-to-date and
- * can't even be validated.
- *
- * Note that the client only knows about the milliseconds part of the
- * timestamp, so using CompareTimeStamps here would cause randr to suddenly
- * stop working after several hours have passed (freedesktop bug #6502).
- */
- if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds)
- {
- rep.status = RRSetConfigInvalidConfigTime;
- goto sendReply;
- }
-
- pData = RR10GetData (pScreen, output);
- if (!pData)
- return BadAlloc;
-
- if (stuff->sizeID >= pData->nsize)
- {
- /*
- * Invalid size ID
- */
- client->errorValue = stuff->sizeID;
- free(pData);
- return BadValue;
- }
- pSize = &pData->sizes[stuff->sizeID];
-
- /*
- * Validate requested rotation
- */
- rotation = (Rotation) stuff->rotation;
-
- /* test the rotation bits only! */
- switch (rotation & 0xf) {
- case RR_Rotate_0:
- case RR_Rotate_90:
- case RR_Rotate_180:
- case RR_Rotate_270:
- break;
- default:
- /*
- * Invalid rotation
- */
- client->errorValue = stuff->rotation;
- free(pData);
- return BadValue;
- }
-
- if ((~crtc->rotations) & rotation)
- {
- /*
- * requested rotation or reflection not supported by screen
- */
- client->errorValue = stuff->rotation;
- free(pData);
- return BadMatch;
- }
-
- /*
- * Validate requested refresh
- */
- if (has_rate)
- rate = (int) stuff->rate;
- else
- rate = 0;
-
- if (rate)
- {
- for (i = 0; i < pSize->nRates; i++)
- {
- if (pSize->pRates[i].rate == rate)
- break;
- }
- if (i == pSize->nRates)
- {
- /*
- * Invalid rate
- */
- client->errorValue = rate;
- free(pData);
- return BadValue;
- }
- mode = pSize->pRates[i].mode;
- }
- else
- mode = pSize->pRates[0].mode;
-
- /*
- * Make sure the requested set-time is not older than
- * the last set-time
- */
- if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0)
- {
- rep.status = RRSetConfigInvalidTime;
- goto sendReply;
- }
-
- /*
- * If the screen size is changing, adjust all of the other outputs
- * to fit the new size, mirroring as much as possible
- */
- width = mode->mode.width;
- height = mode->mode.height;
- if (rotation & (RR_Rotate_90|RR_Rotate_270))
- {
- width = mode->mode.height;
- height = mode->mode.width;
- }
- if (width != pScreen->width || height != pScreen->height)
- {
- int c;
-
- for (c = 0; c < pScrPriv->numCrtcs; c++)
- {
- if (!RRCrtcSet (pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0,
- 0, NULL, NULL))
- {
- rep.status = RRSetConfigFailed;
- /* XXX recover from failure */
- goto sendReply;
- }
- }
- if (!RRScreenSizeSet (pScreen, width, height, width, height,
- pScreen->mmWidth, pScreen->mmHeight))
- {
- rep.status = RRSetConfigFailed;
- /* XXX recover from failure */
- goto sendReply;
- }
- }
-
- if (!RRCrtcSet (crtc, mode, 0, 0, stuff->rotation, 1, &output, NULL))
- rep.status = RRSetConfigFailed;
- else {
- pScrPriv->lastSetTime = time;
- rep.status = RRSetConfigSuccess;
- }
-
- /*
- * XXX Configure other crtcs to mirror as much as possible
- */
-
-sendReply:
-
- free(pData);
-
- rep.type = X_Reply;
- /* rep.status has already been filled in */
- rep.length = 0;
- rep.sequenceNumber = client->sequence;
-
- rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
- rep.newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds;
- rep.root = pDraw->pScreen->root->drawable.id;
-
- if (client->swapped)
- {
- swaps(&rep.sequenceNumber, n);
- swapl(&rep.length, n);
- swapl(&rep.newTimestamp, n);
- swapl(&rep.newConfigTimestamp, n);
- swapl(&rep.root, n);
- }
- WriteToClient(client, sizeof(xRRSetScreenConfigReply), (char *)&rep);
-
- return Success;
-}
-
-static CARD16
-RR10CurrentSizeID (ScreenPtr pScreen)
-{
- CARD16 sizeID = 0xffff;
- RROutputPtr output = RRFirstOutput (pScreen);
-
- if (output)
- {
- RR10DataPtr data = RR10GetData (pScreen, output);
- if (data)
- {
- int i;
- for (i = 0; i < data->nsize; i++)
- if (data->sizes[i].width == pScreen->width &&
- data->sizes[i].height == pScreen->height)
- {
- sizeID = (CARD16) i;
- break;
- }
- free(data);
- }
- }
- return sizeID;
-}
+/*
+ * Copyright © 2006 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "randrstr.h"
+
+static const int padlength[4] = {0, 3, 2, 1};
+
+static CARD16
+RR10CurrentSizeID (ScreenPtr pScreen);
+
+/*
+ * Edit connection information block so that new clients
+ * see the current screen size on connect
+ */
+static void
+RREditConnectionInfo (ScreenPtr pScreen)
+{
+ xConnSetup *connSetup;
+ char *vendor;
+ xPixmapFormat *formats;
+ xWindowRoot *root;
+ xDepth *depth;
+ xVisualType *visual;
+ int screen = 0;
+ int d;
+
+ connSetup = (xConnSetup *) ConnectionInfo;
+ vendor = (char *) connSetup + sizeof (xConnSetup);
+ formats = (xPixmapFormat *) ((char *) vendor +
+ connSetup->nbytesVendor +
+ padlength[connSetup->nbytesVendor & 3]);
+ root = (xWindowRoot *) ((char *) formats +
+ sizeof (xPixmapFormat) * screenInfo.numPixmapFormats);
+ while (screen != pScreen->myNum)
+ {
+ depth = (xDepth *) ((char *) root +
+ sizeof (xWindowRoot));
+ for (d = 0; d < root->nDepths; d++)
+ {
+ visual = (xVisualType *) ((char *) depth +
+ sizeof (xDepth));
+ depth = (xDepth *) ((char *) visual +
+ depth->nVisuals * sizeof (xVisualType));
+ }
+ root = (xWindowRoot *) ((char *) depth);
+ screen++;
+ }
+ root->pixWidth = pScreen->width;
+ root->pixHeight = pScreen->height;
+ root->mmWidth = pScreen->mmWidth;
+ root->mmHeight = pScreen->mmHeight;
+}
+
+void
+RRSendConfigNotify (ScreenPtr pScreen)
+{
+ WindowPtr pWin = pScreen->root;
+ xEvent event;
+
+ event.u.u.type = ConfigureNotify;
+ event.u.configureNotify.window = pWin->drawable.id;
+ event.u.configureNotify.aboveSibling = None;
+ event.u.configureNotify.x = 0;
+ event.u.configureNotify.y = 0;
+
+ /* XXX xinerama stuff ? */
+
+ event.u.configureNotify.width = pWin->drawable.width;
+ event.u.configureNotify.height = pWin->drawable.height;
+ event.u.configureNotify.borderWidth = wBorderWidth (pWin);
+ event.u.configureNotify.override = pWin->overrideRedirect;
+ DeliverEvents(pWin, &event, 1, NullWindow);
+}
+
+void
+RRDeliverScreenEvent (ClientPtr client, WindowPtr pWin, ScreenPtr pScreen)
+{
+ rrScrPriv (pScreen);
+ xRRScreenChangeNotifyEvent se;
+ RRCrtcPtr crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL;
+ WindowPtr pRoot = pScreen->root;
+
+ se.type = RRScreenChangeNotify + RREventBase;
+ se.rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0);
+ se.timestamp = pScrPriv->lastSetTime.milliseconds;
+ se.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
+ se.root = pRoot->drawable.id;
+ se.window = pWin->drawable.id;
+ se.subpixelOrder = PictureGetSubpixelOrder (pScreen);
+
+ se.sizeID = RR10CurrentSizeID (pScreen);
+
+ if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) {
+ se.widthInPixels = pScreen->height;
+ se.heightInPixels = pScreen->width;
+ se.widthInMillimeters = pScreen->mmHeight;
+ se.heightInMillimeters = pScreen->mmWidth;
+ } else {
+ se.widthInPixels = pScreen->width;
+ se.heightInPixels = pScreen->height;
+ se.widthInMillimeters = pScreen->mmWidth;
+ se.heightInMillimeters = pScreen->mmHeight;
+ }
+
+ WriteEventsToClient (client, 1, (xEvent *) &se);
+}
+
+/*
+ * Notify the extension that the screen size has been changed.
+ * The driver is responsible for calling this whenever it has changed
+ * the size of the screen
+ */
+void
+RRScreenSizeNotify (ScreenPtr pScreen)
+{
+ rrScrPriv(pScreen);
+ /*
+ * Deliver ConfigureNotify events when root changes
+ * pixel size
+ */
+ if (pScrPriv->width == pScreen->width &&
+ pScrPriv->height == pScreen->height &&
+ pScrPriv->mmWidth == pScreen->mmWidth &&
+ pScrPriv->mmHeight == pScreen->mmHeight)
+ return;
+
+ pScrPriv->width = pScreen->width;
+ pScrPriv->height = pScreen->height;
+ pScrPriv->mmWidth = pScreen->mmWidth;
+ pScrPriv->mmHeight = pScreen->mmHeight;
+ pScrPriv->changed = TRUE;
+/* pScrPriv->sizeChanged = TRUE; */
+
+ RRTellChanged (pScreen);
+ RRSendConfigNotify (pScreen);
+ RREditConnectionInfo (pScreen);
+
+ RRPointerScreenConfigured (pScreen);
+ /*
+ * Fix pointer bounds and location
+ */
+ ScreenRestructured (pScreen);
+}
+
+/*
+ * Request that the screen be resized
+ */
+Bool
+RRScreenSizeSet (ScreenPtr pScreen,
+ CARD16 width,
+ CARD16 height,
+ CARD16 pixWidth,
+ CARD16 pixHeight,
+ CARD32 mmWidth,
+ CARD32 mmHeight)
+{
+ rrScrPriv(pScreen);
+
+#if RANDR_12_INTERFACE
+ if (pScrPriv->rrScreenSetSize)
+ {
+ return (*pScrPriv->rrScreenSetSize) (pScreen,
+ width, height,
+ pixWidth, pixHeight,
+ mmWidth, mmHeight);
+ }
+#endif
+#if RANDR_10_INTERFACE
+ if (pScrPriv->rrSetConfig)
+ {
+ return TRUE; /* can't set size separately */
+ }
+#endif
+ return FALSE;
+}
+
+/*
+ * Compute an RRScreenConfig from the current screen information
+ */
+void
+RRScreenCurrentConfig(ScreenPtr screen,
+ RRScreenConfigPtr screen_config)
+{
+ PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
+ WindowPtr root = screen->root;
+
+ screen_config->screen_pixmap_width = screen_pixmap->drawable.width;
+ screen_config->screen_pixmap_height = screen_pixmap->drawable.height;
+ screen_config->screen_width = root->drawable.width;
+ screen_config->screen_height = root->drawable.height;
+ screen_config->mm_width = screen->mmWidth;
+ screen_config->mm_height = screen->mmHeight;
+}
+
+/*
+ * Retrieve valid screen size range
+ */
+int
+ProcRRGetScreenSizeRange (ClientPtr client)
+{
+ REQUEST(xRRGetScreenSizeRangeReq);
+ xRRGetScreenSizeRangeReply rep;
+ WindowPtr pWin;
+ ScreenPtr pScreen;
+ rrScrPrivPtr pScrPriv;
+ int rc;
+
+ REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ pScreen = pWin->drawable.pScreen;
+ pScrPriv = rrGetScrPriv(pScreen);
+
+ rep.type = X_Reply;
+ rep.pad = 0;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 0;
+
+ if (pScrPriv)
+ {
+ if (!RRGetInfo (pScreen, FALSE))
+ return BadAlloc;
+ rep.minWidth = pScrPriv->minWidth;
+ rep.minHeight = pScrPriv->minHeight;
+ rep.maxWidth = pScrPriv->maxWidth;
+ rep.maxHeight = pScrPriv->maxHeight;
+ }
+ else
+ {
+ rep.maxWidth = rep.minWidth = pScreen->width;
+ rep.maxHeight = rep.minHeight = pScreen->height;
+ }
+ if (client->swapped)
+ {
+ int n;
+
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swaps(&rep.minWidth, n);
+ swaps(&rep.minHeight, n);
+ swaps(&rep.maxWidth, n);
+ swaps(&rep.maxHeight, n);
+ }
+ WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), (char *)&rep);
+ return Success;
+}
+
+int
+ProcRRSetScreenSize (ClientPtr client)
+{
+ REQUEST(xRRSetScreenSizeReq);
+ WindowPtr pWin;
+ ScreenPtr pScreen;
+ rrScrPrivPtr pScrPriv;
+ int i, rc;
+
+ REQUEST_SIZE_MATCH(xRRSetScreenSizeReq);
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ pScreen = pWin->drawable.pScreen;
+ pScrPriv = rrGetScrPriv(pScreen);
+ if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width)
+ {
+ client->errorValue = stuff->width;
+ return BadValue;
+ }
+ if (stuff->height < pScrPriv->minHeight ||
+ pScrPriv->maxHeight < stuff->height)
+ {
+ client->errorValue = stuff->height;
+ return BadValue;
+ }
+ for (i = 0; i < pScrPriv->numCrtcs; i++)
+ {
+ RRCrtcPtr crtc = pScrPriv->crtcs[i];
+ RRModePtr mode = crtc->mode;
+ if (mode)
+ {
+ int source_width = mode->mode.width;
+ int source_height = mode->mode.height;
+ Rotation rotation = crtc->rotation;
+
+ if (rotation == RR_Rotate_90 || rotation == RR_Rotate_270)
+ {
+ source_width = mode->mode.height;
+ source_height = mode->mode.width;
+ }
+
+ if (crtc->x + source_width > stuff->width ||
+ crtc->y + source_height > stuff->height)
+ return BadMatch;
+ }
+ }
+ if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0)
+ {
+ client->errorValue = 0;
+ return BadValue;
+ }
+ if (!RRScreenSizeSet (pScreen,
+ stuff->width, stuff->height,
+ stuff->width, stuff->height,
+ stuff->widthInMillimeters,
+ stuff->heightInMillimeters))
+ {
+ return BadMatch;
+ }
+ return Success;
+}
+
+static int
+rrGetScreenResources(ClientPtr client, Bool query)
+{
+ REQUEST(xRRGetScreenResourcesReq);
+ xRRGetScreenResourcesReply rep;
+ WindowPtr pWin;
+ ScreenPtr pScreen;
+ rrScrPrivPtr pScrPriv;
+ CARD8 *extra;
+ unsigned long extraLen;
+ int i, n, rc, has_primary = 0;
+ RRCrtc *crtcs;
+ RROutput *outputs;
+ xRRModeInfo *modeinfos;
+ CARD8 *names;
+
+ REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq);
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ pScreen = pWin->drawable.pScreen;
+ pScrPriv = rrGetScrPriv(pScreen);
+ rep.pad = 0;
+
+ if (query && pScrPriv)
+ if (!RRGetInfo (pScreen, query))
+ return BadAlloc;
+
+ if (!pScrPriv)
+ {
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 0;
+ rep.timestamp = currentTime.milliseconds;
+ rep.configTimestamp = currentTime.milliseconds;
+ rep.nCrtcs = 0;
+ rep.nOutputs = 0;
+ rep.nModes = 0;
+ rep.nbytesNames = 0;
+ extra = NULL;
+ extraLen = 0;
+ }
+ else
+ {
+ RRModePtr *modes;
+ int num_modes;
+
+ modes = RRModesForScreen (pScreen, &num_modes);
+ if (!modes)
+ return BadAlloc;
+
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 0;
+ rep.timestamp = pScrPriv->lastSetTime.milliseconds;
+ rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
+ rep.nCrtcs = pScrPriv->numCrtcs;
+ rep.nOutputs = pScrPriv->numOutputs;
+ rep.nModes = num_modes;
+ rep.nbytesNames = 0;
+
+ for (i = 0; i < num_modes; i++)
+ rep.nbytesNames += modes[i]->mode.nameLength;
+
+ rep.length = (pScrPriv->numCrtcs +
+ pScrPriv->numOutputs +
+ num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
+ bytes_to_int32(rep.nbytesNames));
+
+ extraLen = rep.length << 2;
+ if (extraLen)
+ {
+ extra = malloc(extraLen);
+ if (!extra)
+ {
+ free(modes);
+ return BadAlloc;
+ }
+ }
+ else
+ extra = NULL;
+
+ crtcs = (RRCrtc *) extra;
+ outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs);
+ modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs);
+ names = (CARD8 *) (modeinfos + num_modes);
+
+ if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc)
+ {
+ has_primary = 1;
+ crtcs[0] = pScrPriv->primaryOutput->crtc->id;
+ if (client->swapped)
+ swapl (&crtcs[0], n);
+ }
+
+ for (i = 0; i < pScrPriv->numCrtcs; i++)
+ {
+ if (has_primary &&
+ pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i])
+ {
+ has_primary = 0;
+ continue;
+ }
+ crtcs[i + has_primary] = pScrPriv->crtcs[i]->id;
+ if (client->swapped)
+ swapl (&crtcs[i + has_primary], n);
+ }
+
+ for (i = 0; i < pScrPriv->numOutputs; i++)
+ {
+ outputs[i] = pScrPriv->outputs[i]->id;
+ if (client->swapped)
+ swapl (&outputs[i], n);
+ }
+
+ for (i = 0; i < num_modes; i++)
+ {
+ RRModePtr mode = modes[i];
+ modeinfos[i] = mode->mode;
+ if (client->swapped)
+ {
+ swapl (&modeinfos[i].id, n);
+ swaps (&modeinfos[i].width, n);
+ swaps (&modeinfos[i].height, n);
+ swapl (&modeinfos[i].dotClock, n);
+ swaps (&modeinfos[i].hSyncStart, n);
+ swaps (&modeinfos[i].hSyncEnd, n);
+ swaps (&modeinfos[i].hTotal, n);
+ swaps (&modeinfos[i].hSkew, n);
+ swaps (&modeinfos[i].vSyncStart, n);
+ swaps (&modeinfos[i].vSyncEnd, n);
+ swaps (&modeinfos[i].vTotal, n);
+ swaps (&modeinfos[i].nameLength, n);
+ swapl (&modeinfos[i].modeFlags, n);
+ }
+ memcpy (names, mode->name,
+ mode->mode.nameLength);
+ names += mode->mode.nameLength;
+ }
+ free(modes);
+ assert (bytes_to_int32((char *) names - (char *) extra) == rep.length);
+ }
+
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.timestamp, n);
+ swapl(&rep.configTimestamp, n);
+ swaps(&rep.nCrtcs, n);
+ swaps(&rep.nOutputs, n);
+ swaps(&rep.nModes, n);
+ swaps(&rep.nbytesNames, n);
+ }
+ WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *)&rep);
+ if (extraLen)
+ {
+ WriteToClient (client, extraLen, (char *) extra);
+ free(extra);
+ }
+ return Success;
+}
+
+int
+ProcRRGetScreenResources (ClientPtr client)
+{
+ return rrGetScreenResources(client, TRUE);
+}
+
+int
+ProcRRGetScreenResourcesCurrent (ClientPtr client)
+{
+ return rrGetScreenResources(client, FALSE);
+}
+
+typedef struct _RR10Data {
+ RRScreenSizePtr sizes;
+ int nsize;
+ int nrefresh;
+ int size;
+ CARD16 refresh;
+} RR10DataRec, *RR10DataPtr;
+
+/*
+ * Convert 1.2 monitor data into 1.0 screen data
+ */
+static RR10DataPtr
+RR10GetData (ScreenPtr pScreen, RROutputPtr output)
+{
+ RR10DataPtr data;
+ RRScreenSizePtr size;
+ int nmode = output->numModes + output->numUserModes;
+ int o, os, l, r;
+ RRScreenRatePtr refresh;
+ CARD16 vRefresh;
+ RRModePtr mode;
+ Bool *used;
+
+ /* Make sure there is plenty of space for any combination */
+ data = malloc (sizeof (RR10DataRec) +
+ sizeof (RRScreenSize) * nmode +
+ sizeof (RRScreenRate) * nmode +
+ sizeof (Bool) * nmode);
+ if (!data)
+ return NULL;
+ size = (RRScreenSizePtr) (data + 1);
+ refresh = (RRScreenRatePtr) (size + nmode);
+ used = (Bool *) (refresh + nmode);
+ memset (used, '\0', sizeof (Bool) * nmode);
+ data->sizes = size;
+ data->nsize = 0;
+ data->nrefresh = 0;
+ data->size = 0;
+ data->refresh = 0;
+
+ /*
+ * find modes not yet listed
+ */
+ for (o = 0; o < output->numModes + output->numUserModes; o++)
+ {
+ if (used[o]) continue;
+
+ if (o < output->numModes)
+ mode = output->modes[o];
+ else
+ mode = output->userModes[o - output->numModes];
+
+ l = data->nsize;
+ size[l].id = data->nsize;
+ size[l].width = mode->mode.width;
+ size[l].height = mode->mode.height;
+ if (output->mmWidth && output->mmHeight) {
+ size[l].mmWidth = output->mmWidth;
+ size[l].mmHeight = output->mmHeight;
+ } else {
+ size[l].mmWidth = pScreen->mmWidth;
+ size[l].mmHeight = pScreen->mmHeight;
+ }
+ size[l].nRates = 0;
+ size[l].pRates = &refresh[data->nrefresh];
+ data->nsize++;
+
+ /*
+ * Find all modes with matching size
+ */
+ for (os = o; os < output->numModes + output->numUserModes; os++)
+ {
+ if (os < output->numModes)
+ mode = output->modes[os];
+ else
+ mode = output->userModes[os - output->numModes];
+ if (mode->mode.width == size[l].width &&
+ mode->mode.height == size[l].height)
+ {
+ vRefresh = RRVerticalRefresh (&mode->mode);
+ used[os] = TRUE;
+
+ for (r = 0; r < size[l].nRates; r++)
+ if (vRefresh == size[l].pRates[r].rate)
+ break;
+ if (r == size[l].nRates)
+ {
+ size[l].pRates[r].rate = vRefresh;
+ size[l].pRates[r].mode = mode;
+ size[l].nRates++;
+ data->nrefresh++;
+ }
+ if (mode == output->crtc->mode)
+ {
+ data->size = l;
+ data->refresh = vRefresh;
+ }
+ }
+ }
+ }
+ return data;
+}
+
+int
+ProcRRGetScreenInfo (ClientPtr client)
+{
+ REQUEST(xRRGetScreenInfoReq);
+ xRRGetScreenInfoReply rep;
+ WindowPtr pWin;
+ int n, rc;
+ ScreenPtr pScreen;
+ rrScrPrivPtr pScrPriv;
+ CARD8 *extra;
+ unsigned long extraLen;
+ RROutputPtr output;
+
+ REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ pScreen = pWin->drawable.pScreen;
+ pScrPriv = rrGetScrPriv(pScreen);
+ rep.pad = 0;
+
+ if (pScrPriv)
+ if (!RRGetInfo (pScreen, TRUE))
+ return BadAlloc;
+
+ output = RRFirstOutput (pScreen);
+
+ if (!pScrPriv || !output)
+ {
+ rep.type = X_Reply;
+ rep.setOfRotations = RR_Rotate_0;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 0;
+ rep.root = pWin->drawable.pScreen->root->drawable.id;
+ rep.timestamp = currentTime.milliseconds;
+ rep.configTimestamp = currentTime.milliseconds;
+ rep.nSizes = 0;
+ rep.sizeID = 0;
+ rep.rotation = RR_Rotate_0;
+ rep.rate = 0;
+ rep.nrateEnts = 0;
+ extra = 0;
+ extraLen = 0;
+ }
+ else
+ {
+ int i, j;
+ xScreenSizes *size;
+ CARD16 *rates;
+ CARD8 *data8;
+ Bool has_rate = RRClientKnowsRates (client);
+ RR10DataPtr pData;
+ RRScreenSizePtr pSize;
+
+ pData = RR10GetData (pScreen, output);
+ if (!pData)
+ return BadAlloc;
+
+ rep.type = X_Reply;
+ rep.setOfRotations = output->crtc->rotations;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 0;
+ rep.root = pWin->drawable.pScreen->root->drawable.id;
+ rep.timestamp = pScrPriv->lastSetTime.milliseconds;
+ rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
+ rep.rotation = output->crtc->rotation;
+ rep.nSizes = pData->nsize;
+ rep.nrateEnts = pData->nrefresh + pData->nsize;
+ rep.sizeID = pData->size;
+ rep.rate = pData->refresh;
+
+ extraLen = rep.nSizes * sizeof (xScreenSizes);
+ if (has_rate)
+ extraLen += rep.nrateEnts * sizeof (CARD16);
+
+ if (extraLen)
+ {
+ extra = (CARD8 *) malloc(extraLen);
+ if (!extra)
+ {
+ free(pData);
+ return BadAlloc;
+ }
+ }
+ else
+ extra = NULL;
+
+ /*
+ * First comes the size information
+ */
+ size = (xScreenSizes *) extra;
+ rates = (CARD16 *) (size + rep.nSizes);
+ for (i = 0; i < pData->nsize; i++)
+ {
+ pSize = &pData->sizes[i];
+ size->widthInPixels = pSize->width;
+ size->heightInPixels = pSize->height;
+ size->widthInMillimeters = pSize->mmWidth;
+ size->heightInMillimeters = pSize->mmHeight;
+ if (client->swapped)
+ {
+ swaps (&size->widthInPixels, n);
+ swaps (&size->heightInPixels, n);
+ swaps (&size->widthInMillimeters, n);
+ swaps (&size->heightInMillimeters, n);
+ }
+ size++;
+ if (has_rate)
+ {
+ *rates = pSize->nRates;
+ if (client->swapped)
+ {
+ swaps (rates, n);
+ }
+ rates++;
+ for (j = 0; j < pSize->nRates; j++)
+ {
+ *rates = pSize->pRates[j].rate;
+ if (client->swapped)
+ {
+ swaps (rates, n);
+ }
+ rates++;
+ }
+ }
+ }
+ free(pData);
+
+ data8 = (CARD8 *) rates;
+
+ if (data8 - (CARD8 *) extra != extraLen)
+ FatalError ("RRGetScreenInfo bad extra len %ld != %ld\n",
+ (unsigned long)(data8 - (CARD8 *) extra), extraLen);
+ rep.length = bytes_to_int32(extraLen);
+ }
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.timestamp, n);
+ swaps(&rep.rotation, n);
+ swaps(&rep.nSizes, n);
+ swaps(&rep.sizeID, n);
+ swaps(&rep.rate, n);
+ swaps(&rep.nrateEnts, n);
+ }
+ WriteToClient(client, sizeof(xRRGetScreenInfoReply), (char *)&rep);
+ if (extraLen)
+ {
+ WriteToClient (client, extraLen, (char *) extra);
+ free(extra);
+ }
+ return Success;
+}
+
+int
+ProcRRSetScreenConfig (ClientPtr client)
+{
+ REQUEST(xRRSetScreenConfigReq);
+ xRRSetScreenConfigReply rep;
+ DrawablePtr pDraw;
+ int n, rc;
+ ScreenPtr pScreen;
+ rrScrPrivPtr pScrPriv;
+ TimeStamp time;
+ int i;
+ Rotation rotation;
+ int rate;
+ Bool has_rate;
+ RROutputPtr output;
+ RRCrtcPtr crtc;
+ RRModePtr mode;
+ RR10DataPtr pData = NULL;
+ RRScreenSizePtr pSize;
+ int width, height;
+
+ UpdateCurrentTime ();
+
+ if (RRClientKnowsRates (client))
+ {
+ REQUEST_SIZE_MATCH (xRRSetScreenConfigReq);
+ has_rate = TRUE;
+ }
+ else
+ {
+ REQUEST_SIZE_MATCH (xRR1_0SetScreenConfigReq);
+ has_rate = FALSE;
+ }
+
+ rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess);
+ if (rc != Success) {
+ client->errorValue = stuff->drawable;
+ return rc;
+ }
+
+ pScreen = pDraw->pScreen;
+
+ pScrPriv = rrGetScrPriv(pScreen);
+
+ time = ClientTimeToServerTime(stuff->timestamp);
+
+ if (!pScrPriv)
+ {
+ time = currentTime;
+ rep.status = RRSetConfigFailed;
+ goto sendReply;
+ }
+ if (!RRGetInfo (pScreen, FALSE))
+ return BadAlloc;
+
+ output = RRFirstOutput (pScreen);
+ if (!output)
+ {
+ time = currentTime;
+ rep.status = RRSetConfigFailed;
+ goto sendReply;
+ }
+
+ crtc = output->crtc;
+
+ /*
+ * If the client's config timestamp is not the same as the last config
+ * timestamp, then the config information isn't up-to-date and
+ * can't even be validated.
+ *
+ * Note that the client only knows about the milliseconds part of the
+ * timestamp, so using CompareTimeStamps here would cause randr to suddenly
+ * stop working after several hours have passed (freedesktop bug #6502).
+ */
+ if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds)
+ {
+ rep.status = RRSetConfigInvalidConfigTime;
+ goto sendReply;
+ }
+
+ pData = RR10GetData (pScreen, output);
+ if (!pData)
+ return BadAlloc;
+
+ if (stuff->sizeID >= pData->nsize)
+ {
+ /*
+ * Invalid size ID
+ */
+ client->errorValue = stuff->sizeID;
+ free(pData);
+ return BadValue;
+ }
+ pSize = &pData->sizes[stuff->sizeID];
+
+ /*
+ * Validate requested rotation
+ */
+ rotation = (Rotation) stuff->rotation;
+
+ /* test the rotation bits only! */
+ switch (rotation & 0xf) {
+ case RR_Rotate_0:
+ case RR_Rotate_90:
+ case RR_Rotate_180:
+ case RR_Rotate_270:
+ break;
+ default:
+ /*
+ * Invalid rotation
+ */
+ client->errorValue = stuff->rotation;
+ free(pData);
+ return BadValue;
+ }
+
+ if ((~crtc->rotations) & rotation)
+ {
+ /*
+ * requested rotation or reflection not supported by screen
+ */
+ client->errorValue = stuff->rotation;
+ free(pData);
+ return BadMatch;
+ }
+
+ /*
+ * Validate requested refresh
+ */
+ if (has_rate)
+ rate = (int) stuff->rate;
+ else
+ rate = 0;
+
+ if (rate)
+ {
+ for (i = 0; i < pSize->nRates; i++)
+ {
+ if (pSize->pRates[i].rate == rate)
+ break;
+ }
+ if (i == pSize->nRates)
+ {
+ /*
+ * Invalid rate
+ */
+ client->errorValue = rate;
+ free(pData);
+ return BadValue;
+ }
+ mode = pSize->pRates[i].mode;
+ }
+ else
+ mode = pSize->pRates[0].mode;
+
+ /*
+ * Make sure the requested set-time is not older than
+ * the last set-time
+ */
+ if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0)
+ {
+ rep.status = RRSetConfigInvalidTime;
+ goto sendReply;
+ }
+
+ /*
+ * If the screen size is changing, adjust all of the other outputs
+ * to fit the new size, mirroring as much as possible
+ */
+ width = mode->mode.width;
+ height = mode->mode.height;
+ if (rotation & (RR_Rotate_90|RR_Rotate_270))
+ {
+ width = mode->mode.height;
+ height = mode->mode.width;
+ }
+
+ if (width < pScrPriv->minWidth || pScrPriv->maxWidth < width) {
+ client->errorValue = width;
+ free(pData);
+ return BadValue;
+ }
+ if (height < pScrPriv->minHeight || pScrPriv->maxHeight < height) {
+ client->errorValue = height;
+ free(pData);
+ return BadValue;
+ }
+
+ if (width != pScreen->width || height != pScreen->height)
+ {
+ int c;
+
+ for (c = 0; c < pScrPriv->numCrtcs; c++)
+ {
+ if (!RRCrtcSet (pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0,
+ 0, NULL, NULL))
+ {
+ rep.status = RRSetConfigFailed;
+ /* XXX recover from failure */
+ goto sendReply;
+ }
+ }
+ if (!RRScreenSizeSet (pScreen, width, height, width, height,
+ pScreen->mmWidth, pScreen->mmHeight))
+ {
+ rep.status = RRSetConfigFailed;
+ /* XXX recover from failure */
+ goto sendReply;
+ }
+ }
+
+ if (!RRCrtcSet (crtc, mode, 0, 0, stuff->rotation, 1, &output, NULL))
+ rep.status = RRSetConfigFailed;
+ else {
+ pScrPriv->lastSetTime = time;
+ rep.status = RRSetConfigSuccess;
+ }
+
+ /*
+ * XXX Configure other crtcs to mirror as much as possible
+ */
+
+sendReply:
+
+ free(pData);
+
+ rep.type = X_Reply;
+ /* rep.status has already been filled in */
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+
+ rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
+ rep.newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds;
+ rep.root = pDraw->pScreen->root->drawable.id;
+
+ if (client->swapped)
+ {
+ swaps(&rep.sequenceNumber, n);
+ swapl(&rep.length, n);
+ swapl(&rep.newTimestamp, n);
+ swapl(&rep.newConfigTimestamp, n);
+ swapl(&rep.root, n);
+ }
+ WriteToClient(client, sizeof(xRRSetScreenConfigReply), (char *)&rep);
+
+ return Success;
+}
+
+static CARD16
+RR10CurrentSizeID (ScreenPtr pScreen)
+{
+ CARD16 sizeID = 0xffff;
+ RROutputPtr output = RRFirstOutput (pScreen);
+
+ if (output)
+ {
+ RR10DataPtr data = RR10GetData (pScreen, output);
+ if (data)
+ {
+ int i;
+ for (i = 0; i < data->nsize; i++)
+ if (data->sizes[i].width == pScreen->width &&
+ data->sizes[i].height == pScreen->height)
+ {
+ sizeID = (CARD16) i;
+ break;
+ }
+ free(data);
+ }
+ }
+ return sizeID;
+}