From fe2ccbf887ddf31f99d6f630830e3180ff259e40 Mon Sep 17 00:00:00 2001 From: marha Date: Mon, 20 Dec 2010 09:39:54 +0000 Subject: xserver libXext git update 20-12-2010 --- libXext/specs/dbelib.tex | 620 --- libXext/specs/synclib.tex | 770 ---- xorg-server/Xext/sync.c | 5760 +++++++++++++------------- xorg-server/hw/xfree86/loader/sdksyms.sh | 844 ++-- xorg-server/hw/xfree86/modes/xf86EdidModes.c | 2427 +++++------ xorg-server/hw/xfree86/parser/Makefile.am | 102 +- xorg-server/os/xprintf.c | 452 +- xorg-server/randr/rrscreen.c | 2062 ++++----- 8 files changed, 5849 insertions(+), 7188 deletions(-) delete mode 100644 libXext/specs/dbelib.tex delete mode 100644 libXext/specs/synclib.tex diff --git a/libXext/specs/dbelib.tex b/libXext/specs/dbelib.tex deleted file mode 100644 index e9793bc32..000000000 --- a/libXext/specs/dbelib.tex +++ /dev/null @@ -1,620 +0,0 @@ -% edited for DP edits and code consistency w/ core protocol/xlib 3/30/96 -% split into separate library and protocol documentos 4/15/96 -\documentstyle{article} -\pagestyle{myheadings} -\markboth{Double Buffer Extension Specification}{Double Buffer Extension Specification} -\setlength{\parindent}{0 pt} -\setlength{\parskip}{6pt} -\setlength{\topsep}{0 pt} - -% Request names are literal symbols; therefore, use the same font for both. -\newcommand{\requestname}[1]{{\tt #1}} -\newcommand{\literal}[1]{\mbox{\tt #1}} - -\newcommand{\encodingsection}[1]{{\bf #1}} -\newcommand{\requestsection}[1]{{\bf #1}} - -% Font treatment of type names differs between protocol and library sections. -\newcommand{\libtypename}[1]{\mbox{\tt #1}} -\newcommand{\typename}[1]{\mbox{\rm #1}} % default font -\newcommand{\typeargname}[1]{\mbox{\rm #1}} % default font -\newcommand{\argname}[1]{\mbox{\it #1}} -\newcommand{\argdecl}[2]{\argname{#1} & : \typename{#2}\\} -\newcommand{\areplyargdecl}[2]{#1 & : \typename{#2}\\} - -\newenvironment{arequest}[1]{\requestsection{#1} \\ \begin{tabular}{ll}}{\end{tabular}} -\newcommand{\areply}{$\Rightarrow$\\} - -\newcommand{\etabstops}{\hspace*{0cm}\=\hspace*{1cm}\=\hspace*{5cm}\=\kill} - -\newcommand{\eargdecl}[3]{\> #1 \> \typename{#2} \> #3 \\} - -\newenvironment{keeptogether}{\vbox \bgroup}{\egroup} - -\newenvironment{erequest}[3]{\pagebreak[3] \begin{keeptogether} \encodingsection{#1} \begin{tabbing} \etabstops \eargdecl{1}{CARD8}{major-opcode} \eargdecl{1}{#2}{minor-opcode} \eargdecl{2}{#3}{request length}}{\end{tabbing} \end{keeptogether}} - -\newenvironment{eerror}[1]{\begin{keeptogether} \encodingsection{#1} \begin{tabbing} \etabstops }{\end{tabbing} \end{keeptogether}} - -\newenvironment{etypedef}[1]{\begin{keeptogether} \typename{#1} \begin{tabbing} \etabstops }{\end{tabbing} \end{keeptogether}} - -\newcommand{\cfunctionname}[1]{\mbox{\tt #1}} -\newcommand{\cfunctiondecl}[1]{\mbox{\rm #1}} -\newcommand{\cargdecl}[2]{\penalty -1\typename{#1} \argname{#2}} -\newenvironment{cfunction}[2]{\begin{sloppypar}\begin{keeptogether}\vspace{5mm}\typename{#1}\\ \cfunctiondecl{#2}\ (}{)\end{keeptogether}\end{sloppypar}{\hangafter=2 \hangindent=20pt \raggedright\par}} - -% make things easier with all the long names -\spaceskip .3333em plus 5em -\tolerance=2000 - -\begin{document} - -\title{Double Buffer Extension Library\\Protocol Version 1.0\\X Consortium Standard} -\author{Ian Elliott\\Hewlett-Packard Company \and David P. Wiggins\\X Consortium, Inc.} -\maketitle -\thispagestyle{empty} - -\eject - -Copyright \copyright 1989 X Consortium, Inc. and Digital Equipment Corporation. - -Copyright \copyright 1992 X Consortium, Inc. and Intergraph Corporation. - -Copyright \copyright 1993 X Consortium, Inc. and Silicon Graphics, Inc. - -Copyright \copyright 1994, 1995 X Consortium, Inc. and Hewlett-Packard Company. - -Permission to use, copy, modify, and distribute this documentation for -any purpose and without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. -Digital Equipment Corporation, Intergraph Corporation, Silicon -Graphics, Hewlett-Packard, and the X Consortium make no -representations about the suitability for any purpose of the -information in this document. This documentation is provided ``as is'' -without express or implied warranty. - -\eject - -\section{Introduction} - -The Double Buffer Extension (DBE) provides a standard way to utilize -double-buffering within the framework of the X Window System. -Double-buffering uses two buffers, called front and back, which hold -images. The front buffer is visible to the user; the back buffer is -not. Successive frames of an animation are rendered into the back -buffer while the previously rendered frame is displayed in the front -buffer. When a new frame is ready, the back and front buffers swap -roles, making the new frame visible. Ideally, this exchange appears to -happen instantaneously to the user and with no visual artifacts. Thus, -only completely rendered images are presented to the user, and they remain -visible during the entire time it takes to render a new frame. The -result is a flicker-free animation. - -\section{Goals} - -This extension should enable clients to: -\begin{itemize} - -\item Allocate and deallocate double-buffering for a window. - -\item Draw to and read from the front and back buffers associated with -a window. - -\item Swap the front and back buffers associated with a window. - -\item Specify a wide range of actions to be taken when a window is -swapped. This includes explicit, simple swap actions (defined -below), and more complex actions (for example, clearing ancillary buffers) -that can be put together within explicit ``begin'' and ``end'' -requests (defined below). - -\item Request that the front and back buffers associated with multiple -double-buffered windows be swapped simultaneously. - -\end{itemize} - -In addition, the extension should: - -\begin{itemize} - -\item Allow multiple clients to use double-buffering on the same window. - -\item Support a range of implementation methods that can capitalize on -existing hardware features. - -\item Add no new event types. - -\item Be reasonably easy to integrate with a variety of direct graphics -hardware access (DGHA) architectures. -\end{itemize} - -\section{Concepts} - -Normal windows are created using the core \requestname{CreateWindow} -request, which allocates a set of window attributes and, for -\literal{InputOutput} windows, a front buffer, -into which an image can be drawn. -The contents of this buffer will be displayed when the window is -visible. - -This extension enables applications to use double-buffering with a -window. This involves creating a second buffer, called a back buffer, -and associating one or more back buffer names (\typename{XID}s) with -the window for use when referring to (that is, drawing to or reading -from) the window's back buffer. The back buffer name is a -\typename{DRAWABLE} of type \typename{BACKBUFFER}. - -DBE provides a relative double-buffering model. One XID, the window, -always refers to the front buffer. One or more other XIDs, the back buffer -names, always refer to the back buffer. After a buffer swap, the -window continues to refer to the (new) front buffer, and the -back buffer name continues to refer to the (new) back buffer. Thus, -applications and toolkits that want to just render to the back buffer -always use the back buffer name for all drawing requests to the -window. Portions of an application that want to render to the front -buffer always use the window XID for all drawing requests to the -window. - -Multiple clients and toolkits can all use double-buffering on the same -window. DBE does not provide a request for querying whether a window -has double-buffering support, and if so, what the back buffer name is. -Given the asynchronous nature of the X Window System, this would cause -race conditions. Instead, DBE allows multiple back buffer names to -exist for the same window; they all refer to the same physical back -buffer. The first time a back buffer name is allocated for a window, -the window becomes double-buffered and the back buffer name is -associated with the window. Subsequently, the window already is a -double-buffered window, and nothing about the window changes when a -new back buffer name is allocated, except that the new back buffer -name is associated with the window. The window remains -double-buffered until either the window is destroyed or until all of -the back buffer names for the window are deallocated. - -In general, both the front and back buffers are treated the same. In -particular, here are some important characteristics: - -\begin{itemize} - -\item Only one buffer per window can be visible at a time (the -front buffer). - -\item Both buffers associated with a window have the same visual type, -depth, width, height, and shape as the window. - -\item Both buffers associated with a window are ``visible'' (or -``obscured'') in the same way. When an \literal{Expose} event is -generated for -a window, both buffers should be considered to be damaged in the -exposed area. Damage that occurs to either buffer will result in an -\literal{Expose} event on the window. When a double-buffered window is -exposed, -both buffers are tiled with the window background, exactly as stated -by the core protocol. Even though the back buffer is not visible, -terms such as obscure apply to the back buffer as well as to the front -buffer. - -\item It is acceptable at any time to pass a \typename{BACKBUFFER} in -any request, notably any core or extension drawing request, that -expects a \typename{DRAWABLE}. This enables an application to draw -directly into \typename{BACKBUFFER}s in the same fashion as it would -draw into any other \typename{DRAWABLE}. - -\item It is an error (\literal{Window}) to pass a \typename{BACKBUFFER} in a -core request that expects a Window. - -\item A \typename{BACKBUFFER} will never be sent by core X in a reply, -event, or error where a Window is specified. -\item If core X11 backing-store and save-under applies to a -double-buffered window, it applies to both buffers equally. - -\item If the core \requestname{ClearArea} request is executed on a -double-buffered window, the same area in both the front and back -buffers is cleared. - -\end{itemize} - -The effect of passing a window to a request that accepts a -\typename{DRAWABLE} is unchanged by this extension. The window and -front buffer are synonomous with each other. This includes obeying -the \requestname{GetImage} semantics and the subwindow-mode semantics -if a core graphics context is involved. Regardless of whether the -window was explicitly passed in a \requestname{GetImage} request, or -implicitly referenced (that is, one of the window's ancestors was passed -in the request), the front (that is, visible) buffer is always referenced. -Thus, DBE-na\"{\i}ve screen dump clients will always get the front buffer. -\requestname{GetImage} on a back buffer returns undefined image -contents for any obscured regions of the back buffer that fall within -the image. - -Drawing to a back buffer always uses the clip region that would be -used to draw to the front buffer with a GC subwindow-mode of -\literal{ClipByChildren}. If an ancestor of a double-buffered window is drawn -to with a core GC having a subwindow-mode of \literal{IncludeInferiors}, the -effect on the double-buffered window's back buffer depends on the -depth of the double-buffered window and the ancestor. If the depths -are the same, the contents of the back buffer of the double-buffered -window are not changed. If the depths are different, the contents of -the back buffer of the double-buffered window are undefined for the -pixels that the \literal{IncludeInferiors} drawing touched. - -DBE adds no new events. DBE does not extend the semantics of any -existing events with the exception of adding a new \typename{DRAWABLE} -type called \typename{BACKBUFFER}. If events, replies, or errors that -contain a \typename{DRAWABLE} (for example, \literal{GraphicsExpose}) are -generated in -response to a request, the \typename{DRAWABLE} returned will be the -one specified in the request. - -DBE advertises which visuals support double-buffering. - -DBE does not include any timing or synchronization facilities. -Applications that need such facilities (for example, to maintain a constant -frame rate) should investigate the Synchronization Extension, an X -Consortium standard. - -\subsection{Window Management Operations} - -The basic philosophy of DBE is that both buffers are treated the same by -core X window management operations. - -When the core \requestname{DestroyWindow} is executed on a -double-buffered window, both buffers associated with the window are -destroyed, and all back buffer names associated with the window are -freed. - -If the core \requestname{ConfigureWindow} request changes the size of -a window, both buffers assume the new size. If the window's size -increases, the effect on the buffers depends on whether the -implementation honors bit gravity for buffers. If bit gravity is -implemented, then the contents of both buffers are moved in accordance -with the window's bit gravity (see the core -\requestname{ConfigureWindow} request), and the remaining areas are -tiled with the window background. If bit gravity is not implemented, -then the entire unobscured region of both buffers is tiled with the -window background. In either case, \literal{Expose} events are generated for -the region that is tiled with the window background. - -If the core \requestname{GetGeometry} request is executed on a -\typename{BACKBUFFER}, the returned x, y, and border-width will be -zero. - -If the Shape extension \requestname{ShapeRectangles}, -\requestname{ShapeMask}, \requestname{ShapeCombine}, or -\requestname{ShapeOffset} request is executed on a double-buffered -window, both buffers are reshaped to match the new window shape. The -region difference is the following: - -\[ D = new shape - old shape \] - -It is tiled with the window background in both buffers, -and \literal{Expose} events are generated for D. - -\subsection{Complex Swap Actions} - -DBE has no explicit knowledge of ancillary buffers (for example, depth buffers -or alpha buffers), and only has a limited set of defined swap actions. -Some applications may need a richer set of swap actions than DBE -provides. Some DBE implementations have knowledge of ancillary -buffers, and/or can provide a rich set of swap actions. Instead of -continually extending DBE to increase its set of swap actions, DBE -provides a flexible ``idiom'' mechanism. If an application's needs -are served by the defined swap actions, it should use them; otherwise, -it should use the following method of expressing a complex swap action -as an idiom. Following this policy will ensure the best possible -performance across a wide variety of implementations. - -As suggested by the term ``idiom,'' a complex swap action should be -expressed as a group/series of requests. Taken together, this group -of requests may be combined into an atomic operation by the -implementation, in order to maximize performance. The set of idioms -actually recognized for optimization is implementation dependent. To -help with idiom expression and interpretation, an idiom must be -surrounded by two protocol requests: \requestname{DBEBeginIdiom} and -\requestname{DBEEndIdiom}. Unless this begin-end pair surrounds the -idiom, it may not be recognized by a given implementation, and -performance will suffer. - -For example, if an application wants to swap buffers for two windows, -and use core X to clear only certain planes of the back buffers, the -application would issue the following protocol requests as a group, and -in the following order: - -\begin{itemize} -\item \requestname{DBEBeginIdiom} request. -\item \requestname{DBESwapBuffers} request with XIDs for two windows, each -of which uses a swap action of \literal{Untouched}. -\item Core X \requestname{PolyFillRectangle} request to the back buffer of one window. -\item Core X \requestname{PolyFillRectangle} request to the back buffer of the other window. -\item \requestname{DBEEndIdiom} request. -\end{itemize} - -The \requestname{DBEBeginIdiom} and \requestname{DBEEndIdiom} requests -do not perform any actions themselves. They are treated as markers by -implementations that can combine certain groups/series of requests as -idioms, and are ignored by other implementations or for nonrecognized -groups/series of requests. If these requests are sent out of order, -or are mismatched, no errors are sent, and the requests are executed -as usual, though performance may suffer. - -An idiom need not include a \requestname{DBESwapBuffers} request. For -example, if a swap action of \literal{Copied} is desired, but only some of the -planes should be copied, a core X \requestname{CopyArea} request may -be used instead of \requestname{DBESwapBuffers}. If -\requestname{DBESwapBuffers} is included in an idiom, it should -immediately follow the \requestname{DBEBeginIdiom} request. Also, -when the \requestname{DBESwapBuffers} is included in an idiom, that -request's swap action will still be valid, and if the swap action -might overlap with another request, then the final result of the idiom -must be as if the separate requests were executed serially. For -example, if the specified swap action is \literal{Untouched}, and if a -\requestname{PolyFillRectangle} using a client clip rectangle is done -to the window's back buffer after the \requestname{DBESwapBuffers} -request, then the contents of the new back buffer (after the idiom) -will be the same as if the idiom was not recognized by the -implementation. - -It is highly recommended that Application Programming Interface (API) -providers define, and application developers use, ``convenience'' functions -that allow client applications to call one procedure that encapsulates common idioms. -These functions will generate the \requestname{DBEBeginIdiom} request, -the idiom requests, and \requestname{DBEEndIdiom} request. Usage of -these functions will ensure best possible performance across a wide -variety of implementations. - -\section{C Language Binding} - -The header for this extension is \verb||. All -identifier names provided by this header begin with Xdbe. - -\subsection{Types} - -The type \libtypename{XdbeBackBuffer} is a \libtypename{Drawable}. - -The type \libtypename{XdbeSwapAction} can be one of the constants -\literal{XdbeUndefined}, \literal{XdbeBackground}, -\literal{XdbeUntouched}, or \literal{XdbeCopied}. - -\subsection{C Functions} - -The C functions provide direct access to the protocol and add no -additional semantics. For complete details on the effects of these -functions, refer to the appropriate protocol request, which can be -derived by replacing Xdbe at the start of the function name with DBE\@. -All functions that have return type \libtypename{Status} will return -nonzero for success and zero for failure. - -% start marker -\begin{keeptogether} -\begin{cfunction}{Status}{XdbeQueryExtension} -\cargdecl{Display *}{dpy}, -\cargdecl{int *}{major\_version\_return}, -\cargdecl{int *}{minor\_version\_return} -\end{cfunction} -% end marker - -\cfunctionname{XdbeQueryExtension} sets major\_version\_return and -minor\_version\_return to the major and minor DBE protocol -version supported by the server. If the DBE library is compatible -with the version returned by the server, it returns -nonzero. If dpy does not support the DBE extension, or if -there was an error during communication with the server, or if the -server and library protocol versions are incompatible, it -returns zero. No other Xdbe functions may be called before this -function. If a client violates this rule, the effects of all -subsequent Xdbe calls that it makes are undefined. -\end{keeptogether} - -% start marker -\begin{keeptogether} -\begin{cfunction}{XdbeScreenVisualInfo *}{XdbeGetVisualInfo} -\cargdecl{Display *}{dpy}, -\cargdecl{Drawable *}{screen\_specifiers}, -\cargdecl{int *}{num\_screens} -\end{cfunction} -% end marker - -\cfunctionname{XdbeGetVisualInfo} returns information about which visuals support -double buffering. The argument num\_screens specifies how many -elements there are in the screen\_specifiers list. Each -drawable in screen\_specifiers designates a screen for which -the supported visuals are being requested. If num\_screens -is zero, information for all screens is requested. In this case, upon -return from this function, num\_screens will be set to the -number of screens that were found. If an error occurs, this function -returns NULL; otherwise, it returns a pointer to a list of -\libtypename{XdbeScreenVisualInfo} structures of length num\_screens. -The {\it n}th element in the returned list corresponds to the {\it n}th -drawable in the screen\_specifiers list, unless -num\_screens was passed in with the value zero, in which -case the {\it n}th element in the returned list corresponds to the -{\it n}th screen of the server, starting with screen zero. - -The \libtypename{XdbeScreenVisualInfo} structure has the following -fields: - -\begin{tabular}{lll} -\typename{int} & \argname{count} & number of items in visinfo \\ -\typename{XdbeVisualInfo *} & \argname{visinfo} & list of visuals and depths for this screen \\ -\end{tabular} - -The \libtypename{XdbeVisualInfo} structure has the following fields: - -\begin{tabular}{lll} -\typename{VisualID} & \argname{visual} & one visual ID that supports double-buffering\\ -\typename{int} & \argname{depth} & depth of visual in bits \\ -\typename{int} & \argname{perflevel} & performance level of visual \\ -\end{tabular} -\end{keeptogether} - -% start marker -\begin{keeptogether} -\begin{cfunction}{void }{XdbeFreeVisualInfo} -\cargdecl{XdbeScreenVisualInfo *}{visual\_info} -\end{cfunction} -% end marker - -\cfunctionname{XdbeFreeVisualInfo} frees the list of \libtypename{XdbeScreenVisualInfo} -returned by \cfunctionname{XdbeGetVisualInfo}. -\end{keeptogether} - -% start marker -\begin{keeptogether} -\begin{cfunction}{XdbeBackBuffer}{XdbeAllocateBackBufferName} -\cargdecl{Display *}{dpy}, -\cargdecl{Window}{window}, -\cargdecl{XdbeSwapAction}{swap\_action} -\end{cfunction} -% end marker - -\cfunctionname{XdbeAllocateBackBufferName} returns a drawable ID used to refer -to the back buffer of the specified window. -The swap\_action is a hint to indicate the swap action -that will likely be used in subsequent calls to -\cfunctionname{XdbeSwapBuffers}. -The actual swap action used in calls to -\cfunctionname{XdbeSwapBuffers} does not have -to be the same as the swap\_action passed to this function, -though clients are encouraged to provide accurate information whenever -possible. -\end{keeptogether} - -% start marker -\begin{keeptogether} -\begin{cfunction}{Status}{XdbeDeallocateBackBufferName} -\cargdecl{Display *}{dpy}, -\cargdecl{XdbeBackBuffer}{buffer} -\end{cfunction} -% end marker - -\cfunctionname{XdbeDeallocateBackBufferName} frees the specified -drawable ID, buffer, -that was obtained via \cfunctionname{XdbeAllocateBackBufferName}. The buffer -must be a valid name for the back buffer of a window, or an -\literal{XdbeBadBuffer} -error results. -\end{keeptogether} - -% start marker -\begin{keeptogether} -\begin{cfunction}{Status}{XdbeSwapBuffers} -\cargdecl{Display *}{dpy}, -\cargdecl{XdbeSwapInfo *}{swap\_info}, -\cargdecl{int}{num\_windows} -\end{cfunction} -% end marker - -\cfunctionname{XdbeSwapBuffers} swaps the front and back buffers for a list of windows. -The argument num\_windows specifies how many windows are to -have their buffers swapped; it is the number of elements in the -swap\_info array. The argument swap\_info -specifies the information needed per window to do the swap. - -The \libtypename{XdbeSwapInfo} structure has the following fields: - -\begin{tabular}{lll} -\typename{Window} & \argname{swap\_window} & window for which to swap buffers \\ -\typename{XdbeSwapAction} & \argname{swap\_action} & swap action to use for this swap\_window \\ -\end{tabular} -\end{keeptogether} - -% start marker -\begin{keeptogether} -\begin{cfunction}{Status}{XdbeBeginIdiom} -\cargdecl{Display *}{dpy} -\end{cfunction} -% end marker - -\cfunctionname{XdbeBeginIdiom} marks the beginning of an idiom sequence. -See section 3.2 -for a complete discussion of idioms. -\end{keeptogether} - -% start marker -\begin{keeptogether} -\begin{cfunction}{Status}{XdbeEndIdiom} -\cargdecl{Display *}{dpy} -\end{cfunction} -% end marker - -\cfunctionname{XdbeEndIdiom} marks the end of an idiom sequence. -\end{keeptogether} - -% start marker -\begin{keeptogether} -\begin{cfunction}{XdbeBackBufferAttributes *}{XdbeGetBackBufferAttributes} -\cargdecl{Display *}{dpy}, -\cargdecl{XdbeBackBuffer}{buffer} -\end{cfunction} -% end marker - -\cfunctionname{XdbeGetBackBufferAttributes} returns the attributes associated -with the specified buffer. - -The \libtypename{XdbeBackBufferAttributes} structure has the following fields: - -\begin{tabular}{lll} -\typename{Window} & \argname{window} & window that buffer belongs to \\ -\end{tabular} - -If buffer is not a valid \libtypename{XdbeBackBuffer}, -window is set to \literal{None}. - -The returned \libtypename{XdbeBackBufferAttributes} structure can be -freed with the Xlib function \cfunctionname{XFree}. -\end{keeptogether} - -\begin{keeptogether} -\subsection{Errors} - -The \libtypename{XdbeBufferError} structure has the following fields: - -\begin{tabular}{lll} -\typename{int} & \argname{type} \\ -\typename{Display *} & \argname{display}& Display the event was read from\\ -\typename{XdbeBackBuffer} & \argname{buffer}& resource id \\ -\typename{unsigned long} & \argname{serial}& serial number of failed request\\ -\typename{unsigned char} & \argname{error\_code}& error base + \literal{XdbeBadBuffer}\\ -\typename{unsigned char} & \argname{request\_code}& Major op-code of failed request\\ -\typename{unsigned char} & \argname{minor\_code}& Minor op-code of failed request\\ -\end{tabular} -\end{keeptogether} - -\pagebreak[4] -\section{Acknowledgements} - -We wish to thank the following individuals who have contributed their -time and talent toward shaping the DBE specification: - -T. Alex Chen, IBM; -Peter Daifuku, Silicon Graphics, Inc.; -Ian Elliott, Hewlett-Packard Company; -Stephen Gildea, X Consortium, Inc.; -Jim Graham, Sun; -Larry Hare, AGE Logic; -Jay Hersh, X Consortium, Inc.; -Daryl Huff, Sun; -Deron Dann Johnson, Sun; -Louis Khouw, Sun; -Mark Kilgard, Silicon Graphics, Inc.; -Rob Lembree, Digital Equipment Corporation; -Alan Ricker, Metheus; -Michael Rosenblum, Digital Equipment Corporation; -Bob Scheifler, X Consortium, Inc.; -Larry Seiler, Digital Equipment Corporation; -Jeanne Sparlin Smith, IBM; -Jeff Stevenson, Hewlett-Packard Company; -Walter Strand, Metheus; -Ken Tidwell, Hewlett-Packard Company; and -David P. Wiggins, X Consortium, Inc. - -Mark provided the impetus to start the DBE project. Ian wrote the -first draft of the specification. David served as architect. - -\section{References} - -Jeffrey Friedberg, Larry Seiler, and Jeff Vroom, ``Multi-buffering Extension -Specification Version 3.3.'' - -Tim Glauert, Dave Carver, Jim Gettys, and David P. Wiggins, -``X Synchronization Extension Version 3.0.'' - -\end{document} diff --git a/libXext/specs/synclib.tex b/libXext/specs/synclib.tex deleted file mode 100644 index 0775eb9fd..000000000 --- a/libXext/specs/synclib.tex +++ /dev/null @@ -1,770 +0,0 @@ -% Copyright 1991 by Olivetti Research Limited, Cambridge, England and -% Digital Equipment Corporation, Maynard, Massachusetts. -% -% 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 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. - -%\documentstyle[a4]{article} -\documentstyle{article} - -\setlength{\parindent}{0 pt} -\setlength{\parskip}{6pt} - -% Protocol Section -% For the DP book, these four should be assigned the font for global symbols. - -\newcommand{\request}[1]{{\bf #1}} -\newcommand{\event}[1]{{\bf #1}} -\newcommand{\error}[1]{{\bf #1}} -\newcommand{\enum}[1]{{\bf #1}} - -% The following fonts are not reassigned for the DP book. - -\newcommand{\system}[1]{{\sc #1}} -\newcommand{\param}[1]{{\it #1}} - -\newcommand{\eventdef}[1]{\item {\bf#1}} -\newcommand{\requestdef}[1]{\item {\bf#1}} -\newcommand{\errordef}[1]{\item {\bf#1}} - -\newcommand{\defn}[1]{{\bf #1}} - -\newcommand{\tabstopsA}{\hspace*{4cm}\=\hspace*{1cm}\=\hspace*{7cm}\=\kill} -\newcommand{\tabstopsB}{\hspace*{1cm}\=\hspace*{1cm}\=\hspace*{3cm}\=\kill} -\newcommand{\tabstopsC}{\hspace*{1cm}\=\hspace*{1cm}\=\hspace*{5cm}\=\kill} - -% commands for formatting the API -% For the DP book, these three should be assigned the font for global symbols. - -\newcommand{\cfunctionname}[1]{\mbox{\tt#1}} -\newcommand{\ctypename}[1]{\mbox{\tt#1}} -\newcommand{\cconst}[1]{\mbox{\tt#1}} - -% For the DP book, within function definitions, the type and name are in -% the ordinary font; therefore, ctypenamedef and cfunctionnamedef are used -% and defined below. -\newcommand{\ctypenamedef}[1]{\mbox{#1}} -\newcommand{\cfunctionnamedef}[1]{\mbox{#1}} -\newcommand{\cargname}[1]{\mbox{\it#1}} -\newcommand{\cstartfunction}[2]{\begin{sloppypar}\begin{samepage}\ctypenamedef{#1}\\ \cfunctionnamedef{#2}\ (} -\newcommand{\cargdecl}[2]{\penalty -1\ctypenamedef{#1} \cargname{#2}} -\newcommand{\cendfunctiondecl}{){\hangafter=2 \hangindent=20pt \raggedright\par}} -\newcommand{\cendfuncdescription}{\end{samepage}\end{sloppypar}} - -\newcommand{\cstartmacro}[2]{\begin{sloppypar}\begin{samepage}\ctypenamedef{#1}\\ \cfunctionnamedef{#2}\ (} -\newcommand{\cendmacrodecl}{)\par} -\newcommand{\cendmacrodescription}{\end{samepage}\end{sloppypar}} - -% make things easier with all the long names -\spaceskip .3333em plus 5em -\tolerance=2000 - -\begin{document} - -\begin{center} - -{\large X Synchronization Extension Library}\\[10pt] -{\large Version 3.0}\\[15pt] -{\large X Consortium Standard}\\[15pt] -{\large X Version 11, Release 6.8}\\[15pt] -{\it Tim Glauert}\\[0pt] -{\tt thg@cam-orl.co.uk}\\[0pt] -{\bf Olivetti Research / MultiWorks}\\[5pt] -{\it Dave Carver}\\[0pt] -{\tt dcc@athena.mit.edu}\\[0pt] -{\bf Digital Equipment Corporation,}\\[0pt] -{\bf MIT / Project Athena}\\[5pt] -{\it Jim Gettys}\\[0pt] -{\tt jg@crl.dec.com}\\[0pt] -{\bf Digital Equipment Corporation,}\\[0pt] -{\bf Cambridge Research Laboratory}\\[5pt] -{\it David P. Wiggins}\\[0pt] -{\tt dpw@x.org}\\[0pt] -{\bf X Consortium, Inc.}\\[0pt] - -\end {center} - -Copyright 1991 by Olivetti Research Limited, Cambridge, England and -Digital Equipment Corporation, Maynard, Massachusetts. - -{\small Permission to use, copy, modify, and distribute this documentation -for any purpose and without fee is hereby granted, provided that the above -copyright notice appear in all copies. Olivetti, Digital, MIT, and the -X Consortium -make no representations about the suitability for any purpose of the -information in this document. This documentation is provided as is without -express or implied warranty.} - -Copyright (c) 1991 X Consortium, Inc. - -{\small 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 -X CONSORTIUM 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 X Consortium 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 X Consortium.} -\eject - -\section{Synchronization Protocol} - -The core X protocol makes no guarantees about the relative order of execution -of requests for different clients. This means that any synchronization between -clients must be done at the client level in an operating system-dependent and -network-dependent manner. Even if there was an accepted standard for such -synchronization, the use of a network introduces unpredictable delays between -the synchronization of the clients and the delivery of the resulting requests -to the X server. - -The core X protocol also makes no guarantees about the time at which requests -are executed, which means that all clients with real-time constraints must -implement their timing on the host computer. Any such timings are subject to -error introduced by delays within the operating system and network and are -inefficient because of the need for round-trip requests that keep the client and -server synchronized. - -The synchronization extension provides primitives that allow synchronization -between clients to take place entirely within the X server. This removes any -error introduced by the network and makes it possible to synchronize clients -on different hosts running different operating systems. This is important for -multimedia applications, where audio, video, and graphics data streams are -being synchronized. The extension also provides internal timers within the X -server to which client requests can be synchronized. This allows simple -animation applications to be implemented without any round-trip requests and -makes best use of buffering within the client, network, and server. - -\subsection{Description} - -The mechanism used by this extension for synchronization within the X server -is to block the processing of requests from a client until a specific -synchronization condition occurs. When the condition occurs, the client is -released and processing of requests continues. Multiple clients may block on -the same condition to give inter-client synchronization. Alternatively, a -single client may block on a condition such as an animation frame marker. - -The extension adds \defn{Counter} and \defn{Alarm} to the set of resources -managed by the server. A counter has a 64-bit integer value that may be -increased or decreased by client requests or by the server internally. A -client can block by sending an \request{Await} request that waits until -one of a set of synchronization conditions, called TRIGGERs, becomes TRUE. - -The \request{CreateCounter} request allows a client to create a -\defn{Counter} that can be changed by explicit \request{SetCounter} and -\request{ChangeCounter} requests. These can be used to implement -synchronization between different clients. - -There are some counters, called \defn{System Counters}, that are changed by -the server internally rather than by client requests. The effect of any change -to a system counter is not visible until the server has finished processing the -current request. In other words, system counters are apparently updated in the -gaps between the execution of requests rather than during the actual execution -of a request. The extension provides a system counter that advances with the -server time as defined by the core protocol, and it may also provide counters -that advance with the real-world time or that change each time the CRT -screen is refreshed. Other extensions may provide their own -extension-specific system counters. - -The extension provides an \defn{Alarm} mechanism that allows clients to -receive an event on a regular basis when a particular counter is changed. - -\section{C Language Binding} - -The C routines provide direct access to the protocol and add -no additional semantics. - -The include file for this extension is \verb||. - -Most of the names in the language binding are derived from the -protocol names by prepending \cfunctionname{XSync} to the protocol name and changing -the capitalization. - -\subsection{C Functions} - -Most of the following functions generate SYNC protocol requests. - -% start marker -\cstartfunction{Status}{XSyncQueryExtension} -\cargdecl{Display *}{dpy}, -\cargdecl{int *}{event\_base\_return}, -\cargdecl{int *}{error\_base\_return} -\cendfunctiondecl -% end marker - -If dpy supports the SYNC extension, \cfunctionname{XSyncQueryExtension} -returns \cconst{True}, sets *event\_base\_return to the event number for the -first SYNC event, and sets -*error\_base\_return to the error number for the first SYNC -error. If dpy does not support the SYNC extension, it -returns \cconst{False}. -\cendfuncdescription - - -% start marker -\cstartfunction{Status}{XSyncInitialize} -\cargdecl{Display *}{dpy}, -\cargdecl{int *}{major\_version\_return}, -\cargdecl{int *}{minor\_version\_return} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncInitialize} sets *major\_version\_return and -*minor\_version\_return to the major/minor SYNC protocol -version supported by the server. If the XSync library is compatible -with the version returned by the server, this function returns \cconst{True}. -If dpy does not support the SYNC extension, or if there was an error during -communication with the server, or if the server and library protocol -versions are incompatible, this function returns \cconst{False}. The only -XSync function that may be called before this function is -\cfunctionname{XSyncQueryExtension}. If a client violates this rule, -the effects of all XSync calls that it makes are undefined. -\cendfuncdescription - - -% start marker -\cstartfunction{XSyncSystemCounter *}{XSyncListSystemCounters} -\cargdecl{Display *}{dpy}, -\cargdecl{int *}{n\_counters\_return} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncListSystemCounters} returns a pointer to an -array of system counters supported by the display and sets -*n\_counters\_return to the number of -counters in the array. The array should be freed with -\cfunctionname{XSyncFreeSystemCounterList}. If dpy does not -support the SYNC extension, -or if there was an error during communication with the -server, or if the server does not support any system counters, this -function returns NULL. - -\ctypename{XSyncSystemCounter} has the following fields: - -\begin{tabular}{lll} -char * & name; & /* null-terminated name of system counter */\\ -XSyncCounter & counter; & /* counter id of this system counter */\\ -XSyncValue & resolution; & /* resolution of this system counter */\\ -\end{tabular} -\cendfuncdescription - - -% start marker -\cstartfunction{void}{XSyncFreeSystemCounterList} -\cargdecl{XSyncSystemCounter *}{list} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncFreeSystemCounterList} frees the memory associated -with the system counter list returned by \cfunctionname{XSyncListSystemCounters}. -\cendfuncdescription - - -% start marker -\cstartfunction{XSyncCounter}{XSyncCreateCounter} -\cargdecl{Display *}{dpy}, -\cargdecl{XSyncValue}{initial\_value} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncCreateCounter} creates a counter on the dpy -with the given initial\_value and returns the counter ID. -It returns \cconst{None} if dpy does not -support the SYNC extension. -\cendfuncdescription - - -% start marker -\cstartfunction{Status}{XSyncSetCounter} -\cargdecl{Display *}{dpy}, -\cargdecl{XSyncCounter}{counter}, -\cargdecl{XSyncValue}{value} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncSetCounter} sets counter to value. -It returns \cconst{False} if dpy does not support the SYNC extension; -otherwise, it returns \cconst{True}. -\cendfuncdescription - - -% start marker -\cstartfunction{Status}{XSyncChangeCounter} -\cargdecl{Display *}{dpy}, -\cargdecl{XSyncCounter}{counter}, -\cargdecl{XSyncValue}{value} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncChangeCounter} adds value to counter. -It returns \cconst{False} if dpy does not support the SYNC extension; -otherwise, it returns \cconst{True}. -\cendfuncdescription - - -% start marker -\cstartfunction{Status}{XSyncDestroyCounter} -\cargdecl{Display *}{dpy}, -\cargdecl{XSyncCounter}{counter} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncDestroyCounter} destroys counter. -It returns \cconst{False} if dpy does not -support the SYNC extension; otherwise, it returns \cconst{True}. -\cendfuncdescription - - -% start marker -\cstartfunction{Status}{XSyncQueryCounter} -\cargdecl{Display *}{dpy}, -\cargdecl{XSyncCounter}{counter}, -\cargdecl{XSyncValue *}{value\_return} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncQueryCounter} sets *value\_return to the current value of -counter. It returns \cconst{False} if there was an error during -communication with the server or if dpy does not support -the SYNC extension; otherwise, it returns \cconst{True}. -\cendfuncdescription - - -% start marker -\cstartfunction{Status}{XSyncAwait} -\cargdecl{Display *}{dpy}, -\cargdecl{XSyncWaitCondition *}{wait\_list}, -\cargdecl{int}{n\_conditions} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncAwait} awaits on the conditions in wait\_list. -The n\_conditions is the number of wait conditions in -wait\_list. It returns \cconst{False} if dpy does not -support the SYNC extension; otherwise, it returns \cconst{True}. -The await is processed asynchronously by the server; -this function always returns immediately -after issuing the request. - -\ctypename{XSyncWaitCondition} has the following fields: - -\begin{tabular}{lll} -XSyncCounter & trigger.counter; & /* counter to trigger on */ \\ -XSyncValueType & trigger.value\_type; & /* absolute/relative */ \\ -XSyncValue & trigger.wait\_value; & /* value to compare counter to */ \\ -XSyncTestType & trigger.test\_type; & /* pos/neg comparison/transtion */ \\ -XSyncValue & event\_threshold; & /* send event if past threshold */ \\ -\end{tabular} - -\ctypename{XSyncValueType} can be either \cconst{XSyncAbsolute} or \cconst{XSyncRelative}. - -\ctypename{XSyncTestType} can be one of \cconst{XSyncPositiveTransition}, -\cconst{XSyncNegativeTransition}, \cconst{XSyncPositiveComparison}, or -\cconst{XSyncNegativeComparison}. -\cendfuncdescription - - -% start marker -\cstartfunction{XSyncAlarm}{XSyncCreateAlarm} -\cargdecl{Display *}{dpy}, -\cargdecl{unsigned long}{values\_mask}, -\cargdecl{XSyncAlarmAttributes *}{values} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncCreateAlarm} creates an alarm and returns the alarm ID. -It returns \cconst{None} if the display does not support the SYNC extension. -The values\_mask and values specify the alarm attributes. - -\ctypename{XSyncAlarmAttributes} has the following fields. The attribute\_mask -column specifies the symbol that the caller should OR into -values\_mask to indicate that the value for the corresponding -attribute was actually supplied. Default values are used for all -attributes that do not have their attribute\_mask OR'ed into -values\_mask. -See the protocol -description for \request{CreateAlarm} for the defaults. - -\begin{tabular}{lll} -type & field name & attribute\_mask \\ -XSyncCounter & trigger.counter; & \cconst{XSyncCACounter} \\ -XSyncValueType & trigger.value\_type; & \cconst{XSyncCAValueType} \\ -XSyncValue & trigger.wait\_value; & \cconst{XSyncCAValue} \\ -XSyncTestType & trigger.test\_type; & \cconst{XSyncCATestType} \\ -XSyncValue & delta; & \cconst{XSyncCADelta} \\ -Bool & events; & \cconst{XSyncCAEvents} \\ -XSyncAlarmState & state; & client cannot set this \\ -\end{tabular} -\cendfuncdescription - - -% start marker -\cstartfunction{Status}{XSyncDestroyAlarm} -\cargdecl{Display *}{dpy}, -\cargdecl{XSyncAlarm}{alarm} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncDestroyAlarm} destroys alarm. -It returns \cconst{False} if dpy does not -support the SYNC extension; otherwise, it returns \cconst{True}. -\cendfuncdescription - - -% start marker -\cstartfunction{Status}{XSyncQueryAlarm} -\cargdecl{Display *}{dpy}, -\cargdecl{XSyncAlarm}{alarm}, -\cargdecl{XSyncAlarmAttributes *}{values\_return} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncQueryAlarm} sets *values\_return to the alarm's -attributes. It returns \cconst{False} if there was an error -during communication with the server or if dpy does not support -the SYNC extension; otherwise, it returns \cconst{True}. -\cendfuncdescription - - -% start marker -\cstartfunction{Status}{XSyncChangeAlarm} -\cargdecl{Display *}{dpy}, -\cargdecl{XSyncAlarm}{alarm}, -\cargdecl{unsigned long}{values\_mask}, -\cargdecl{XSyncAlarmAttributes *}{values} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncChangeAlarm} changes alarm's attributes. -The attributes to change are specified as in \cfunctionname{XSyncCreateAlarm}. -It returns \cconst{False} if dpy does not support the SYNC extension; -otherwise, it returns \cconst{True}. -\cendfuncdescription - - -% start marker -\cstartfunction{Status}{XSyncSetPriority} -\cargdecl{Display *}{dpy}, -\cargdecl{XID}{client\_resource\_id}, -\cargdecl{int}{priority} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncSetPriority} sets the priority of the client owning -client\_resource\_id to priority. -If client\_resource\_id is \cconst{None}, -it sets the caller's priority. It returns \cconst{False} if dpy -does not support the SYNC extension; otherwise, it returns \cconst{True}. -\cendfuncdescription - - -% start marker -\cstartfunction{Status}{XSyncGetPriority} -\cargdecl{Display *}{dpy}, -\cargdecl{XID}{client\_resource\_id}, -\cargdecl{int *}{return\_priority} -\cendfunctiondecl -% end marker - -\cfunctionname{XSyncGetPriority} sets *return\_priority to the priority -of the client owning client\_resource\_id. -If client\_resource\_id is -\cconst{None}, it sets *return\_priority to the caller's priority. -It returns \cconst{False} if there was an error -during communication with the server or if dpy does not -support the SYNC extension; otherwise, it returns \cconst{True}. -\cendfuncdescription - -\subsection{C Macros/Functions} - -The following procedures manipulate 64-bit values. They are defined -both as macros and as functions. By default, the macro form is used. -To use the function form, \#undef the macro name to uncover the -function. - - -% start marker -\cstartmacro{void}{XSyncIntToValue} -\cargdecl{XSyncValue}{*pv}, -\cargdecl{int}{i} -\cendmacrodecl -% end marker - -Converts i to an \ctypename{XSyncValue} and stores it in -*pv. Performs sign extension (*pv will have the -same sign as i.) -\cendmacrodescription - - -% start marker -\cstartmacro{void}{XSyncIntsToValue} -\cargdecl{XSyncValue}{*pv}, -\cargdecl{unsigned int}{low}, -\cargdecl{int}{high} -\cendmacrodecl -% end marker - -Stores low in the low 32 bits of *pv and -high in the high 32 bits of *pv. -\cendmacrodescription - - -% start marker -\cstartmacro{Bool}{XSyncValueGreaterThan} -\cargdecl{XSyncValue}{a}, -\cargdecl{XSyncValue}{b} -\cendmacrodecl -% end marker - -Returns \cconst{True} if a is greater than b, -else returns \cconst{False}. -\cendmacrodescription - - -% start marker -\cstartmacro{Bool}{XSyncValueLessThan} -\cargdecl{XSyncValue}{a}, -\cargdecl{XSyncValue}{b} -\cendmacrodecl -% end marker - -Returns \cconst{True} if a is less than b, -else returns \cconst{False}. -\cendmacrodescription - - -% start marker -\cstartmacro{Bool}{XSyncValueGreaterOrEqual} -\cargdecl{XSyncValue}{a}, -\cargdecl{XSyncValue}{b} -\cendmacrodecl -% end marker - -Returns \cconst{True} if a is greater than or equal to b, -else returns \cconst{False}. -\cendmacrodescription - - -% start marker -\cstartmacro{Bool}{XSyncValueLessOrEqual} -\cargdecl{XSyncValue}{a}, -\cargdecl{XSyncValue}{b} -\cendmacrodecl -% end marker - -Returns \cconst{True} if a is less than or equal to b. -\cendmacrodescription - - -% start marker -\cstartmacro{Bool}{XSyncValueEqual} -\cargdecl{XSyncValue}{a}, -\cargdecl{XSyncValue}{b} -\cendmacrodecl -% end marker - -Returns \cconst{True} if a is equal to b, -else returns \cconst{False}. -\cendmacrodescription - - -% start marker -\cstartmacro{Bool}{XSyncValueIsNegative} -\cargdecl{XSyncValue}{v} -\cendmacrodecl -% end marker - -Returns \cconst{True} if v is negative, else returns -\cconst{False}. -\cendmacrodescription - - -% start marker -\cstartmacro{Bool}{XSyncValueIsZero} -\cargdecl{XSyncValue}{v} -\cendmacrodecl -% end marker - -Returns \cconst{True} if v is zero, -else returns \cconst{False}. -\cendmacrodescription - - -% start marker -\cstartmacro{Bool}{XSyncValueIsPositive} -\cargdecl{XSyncValue}{v} -\cendmacrodecl -% end marker - -Returns \cconst{True} if v is positive, else returns -\cconst{False}. -\cendmacrodescription - - -% start marker -\cstartmacro{unsigned int}{XSyncValueLow32} -\cargdecl{XSyncValue}{v} -\cendmacrodecl -% end marker - -Returns the low 32 bits of v. -\cendmacrodescription - - -% start marker -\cstartmacro{int}{XSyncValueHigh32} -\cargdecl{XSyncValue}{v} -\cendmacrodecl -% end marker - -Returns the high 32 bits of v. -\cendmacrodescription - - -% start marker -\cstartmacro{void}{XSyncValueAdd} -\cargdecl{XSyncValue *}{presult}, -\cargdecl{XSyncValue}{a}, -\cargdecl{XSyncValue}{b}, -\cargdecl{Bool *}{poverflow} -\cendmacrodecl -% end marker - -Adds a to b and stores the result in *presult. -If the result could not fit in 64 bits, *poverflow is set to -\cconst{True}, else it is set to \cconst{False}. -\cendmacrodescription - - -% start marker -\cstartmacro{void}{XSyncValueSubtract} -\cargdecl{XSyncValue *}{presult}, -\cargdecl{XSyncValue}{a}, -\cargdecl{XSyncValue}{b}, -\cargdecl{Bool *}{poverflow} -\cendmacrodecl -% end marker - -Subtracts b from a and stores the result in -*presult. -If the result could not fit in 64 bits, overflow is set to -\cconst{True}, else it is set to \cconst{False}. -\cendmacrodescription - - -% start marker -\cstartmacro{void}{XSyncMaxValue} -\cargdecl{XSyncValue *}{pv} -\cendmacrodecl -% end marker - -Sets *pv to the maximum value expressible in 64 bits. -\cendmacrodescription - - -% start marker -\cstartmacro{void}{XSyncMinValue} -\cargdecl{XSyncValue *}{pv} -\cendmacrodecl -% end marker - -Sets *pv to the minimum value expressible in 64 bits. -\cendmacrodescription - -\subsection{Events} - -Let \cargname{event\_base} be the value \cargname{event\_base\_return} -as defined in the function \cfunctionname{XSyncQueryExtension}. - -An \ctypename{XSyncCounterNotifyEvent}'s type field has the value -\cargname{event\_base} + \cconst{XSyncCounterNotify}. The fields of -this structure are: - -\begin{tabular}{lll} -int & type; & /* event base + \cconst{XSyncCounterNotify} */ \\ -unsigned long & serial; & /* number of last request processed by server */ \\ -Bool & send\_event;& /* true if this came from a SendEvent request */ \\ -Display * & display; & /* Display the event was read from */\\ -XSyncCounter & counter; & /* counter involved in await */\\ -XSyncValue & wait\_value; & /* value being waited for */\\ -XSyncValue & counter\_value; & /* counter value when this event was sent */\\ -Time & time; & /* milliseconds */\\ -int & count; & /* how many more events to come */\\ -Bool & destroyed; & /* True if counter was destroyed */\\ -\end{tabular} - -An \ctypename{XSyncAlarmNotifyEvent}'s type field has the value -\cargname{event\_base} + \cconst{XSyncAlarmNotify}. The fields of this -structure are: - -\begin{tabular}{lll} -int & type;& /* event base + \cconst{XSyncAlarmNotify} */\\ -unsigned long & serial;&/* number of last request processed by server */\\ -Bool & send\_event;& /* true if this came from a SendEvent request */\\ -Display * & display;& /* Display the event was read from */\\ -XSyncAlarm & alarm;& /* alarm that triggered */\\ -XSyncValue & counter\_value;&/* value that triggered the alarm */\\ -XSyncValue & alarm\_value;& /* test value of trigger in alarm */\\ -Time & time;& /* milliseconds */\\ -XSyncAlarmState & state;& /* new state of alarm */\\ -\end{tabular} - -\subsection{Errors} - -Let \cargname{error\_base} be the value \cargname{error\_base\_return} -as defined in the function \cfunctionname{XSyncQueryExtension}. - -An \ctypename{XSyncAlarmError}'s error\_code field has the value -\cargname{error\_base} + \cconst{XSyncBadAlarm}. The fields of -this structure are: - -\begin{tabular}{lll} -int & type; \\ -Display * & display;& /* Display the event was read from */\\ -XSyncAlarm & alarm;& /* resource id */\\ -unsigned long & serial;& /* serial number of failed request */\\ -unsigned char & error\_code;&/* error base + XSyncBadAlarm */\\ -unsigned char & request\_code;&/* Major op-code of failed request */\\ -unsigned char & minor\_code;&/* Minor op-code of failed request */\\ -\end{tabular} - -An \ctypename{XSyncCounterError}'s error\_code field has the value -\cargname{error\_base} + \cconst{XSyncBadCounter}. The fields of -this structure are: - -\begin{tabular}{lll} -int &type;\\ -Display * & display;& /* Display the event was read from */\\ -XSyncCounter & counter;& /* resource id */\\ -unsigned long & serial;& /* serial number of failed request */\\ -unsigned char & error\_code;&/* error base + XSyncBadCounter */\\ -unsigned char & request\_code;&/* Major op-code of failed request */\\ -unsigned char & minor\_code;& /* Minor op-code of failed request */\\ -\end{tabular} - -\end{document} 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 -#endif - -#include - -#include -#include -#include -#include "scrnintstr.h" -#include "os.h" -#include "extnsionst.h" -#include "dixstruct.h" -#include "pixmapstr.h" -#include "resource.h" -#include "opaque.h" -#include -#include "syncsrv.h" -#include "syncsdk.h" -#include "protocol-versions.h" - -#include -#if !defined(WIN32) -#include -#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 +#endif + +#include + +#include +#include +#include +#include "scrnintstr.h" +#include "os.h" +#include "extnsionst.h" +#include "dixstruct.h" +#include "pixmapstr.h" +#include "resource.h" +#include "opaque.h" +#include +#include "syncsrv.h" +#include "syncsdk.h" +#include "protocol-versions.h" + +#include +#if !defined(WIN32) +#include +#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 -#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 +#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 -#else -#ifdef HAVE_CONFIG_H -#include -#endif -#endif - -#define _PARSE_EDID_ -#include "xf86.h" -#include "xf86DDC.h" -#include -#include "property.h" -#include "propertyst.h" -#include "xf86Crtc.h" -#include -#include - -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 +#else +#ifdef HAVE_CONFIG_H +#include +#endif +#endif + +#define _PARSE_EDID_ +#include "xf86.h" +#include "xf86DDC.h" +#include +#include "property.h" +#include "propertyst.h" +#include "xf86Crtc.h" +#include +#include + +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 -#endif - -#include -#include "os.h" -#include -#include - -#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 +#endif + +#include +#include "os.h" +#include +#include + +#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; +} -- cgit v1.2.3