1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright © 2017 Keith Packard
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission to use, copy, modify, distribute, and sell this software and its
5*4882a593Smuzhiyun * documentation for any purpose is hereby granted without fee, provided that
6*4882a593Smuzhiyun * the above copyright notice appear in all copies and that both that copyright
7*4882a593Smuzhiyun * notice and this permission notice appear in supporting documentation, and
8*4882a593Smuzhiyun * that the name of the copyright holders not be used in advertising or
9*4882a593Smuzhiyun * publicity pertaining to distribution of the software without specific,
10*4882a593Smuzhiyun * written prior permission. The copyright holders make no representations
11*4882a593Smuzhiyun * about the suitability of this software for any purpose. It is provided "as
12*4882a593Smuzhiyun * is" without express or implied warranty.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15*4882a593Smuzhiyun * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16*4882a593Smuzhiyun * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17*4882a593Smuzhiyun * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18*4882a593Smuzhiyun * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19*4882a593Smuzhiyun * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20*4882a593Smuzhiyun * OF THIS SOFTWARE.
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "randrstr.h"
24*4882a593Smuzhiyun #include "swaprep.h"
25*4882a593Smuzhiyun #include <unistd.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun RESTYPE RRLeaseType;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun /*
30*4882a593Smuzhiyun * Notify of some lease change
31*4882a593Smuzhiyun */
32*4882a593Smuzhiyun void
RRDeliverLeaseEvent(ClientPtr client,WindowPtr window)33*4882a593Smuzhiyun RRDeliverLeaseEvent(ClientPtr client, WindowPtr window)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun ScreenPtr screen = window->drawable.pScreen;
36*4882a593Smuzhiyun rrScrPrivPtr scr_priv = rrGetScrPriv(screen);
37*4882a593Smuzhiyun RRLeasePtr lease;
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun UpdateCurrentTimeIf();
40*4882a593Smuzhiyun xorg_list_for_each_entry(lease, &scr_priv->leases, list) {
41*4882a593Smuzhiyun if (lease->id != None && (lease->state == RRLeaseCreating ||
42*4882a593Smuzhiyun lease->state == RRLeaseTerminating))
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun xRRLeaseNotifyEvent le = (xRRLeaseNotifyEvent) {
45*4882a593Smuzhiyun .type = RRNotify + RREventBase,
46*4882a593Smuzhiyun .subCode = RRNotify_Lease,
47*4882a593Smuzhiyun .timestamp = currentTime.milliseconds,
48*4882a593Smuzhiyun .window = window->drawable.id,
49*4882a593Smuzhiyun .lease = lease->id,
50*4882a593Smuzhiyun .created = lease->state == RRLeaseCreating,
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun WriteEventsToClient(client, 1, (xEvent *) &le);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /*
58*4882a593Smuzhiyun * Change the state of a lease and let anyone watching leases know
59*4882a593Smuzhiyun */
60*4882a593Smuzhiyun static void
RRLeaseChangeState(RRLeasePtr lease,RRLeaseState old,RRLeaseState new)61*4882a593Smuzhiyun RRLeaseChangeState(RRLeasePtr lease, RRLeaseState old, RRLeaseState new)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun ScreenPtr screen = lease->screen;
64*4882a593Smuzhiyun rrScrPrivPtr scr_priv = rrGetScrPriv(screen);
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun lease->state = old;
67*4882a593Smuzhiyun scr_priv->leasesChanged = TRUE;
68*4882a593Smuzhiyun RRSetChanged(lease->screen);
69*4882a593Smuzhiyun RRTellChanged(lease->screen);
70*4882a593Smuzhiyun scr_priv->leasesChanged = FALSE;
71*4882a593Smuzhiyun lease->state = new;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /*
75*4882a593Smuzhiyun * Allocate and initialize a lease
76*4882a593Smuzhiyun */
77*4882a593Smuzhiyun static RRLeasePtr
RRLeaseAlloc(ScreenPtr screen,RRLease lid,int numCrtcs,int numOutputs)78*4882a593Smuzhiyun RRLeaseAlloc(ScreenPtr screen, RRLease lid, int numCrtcs, int numOutputs)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun RRLeasePtr lease;
81*4882a593Smuzhiyun lease = calloc(1,
82*4882a593Smuzhiyun sizeof(RRLeaseRec) +
83*4882a593Smuzhiyun numCrtcs * sizeof (RRCrtcPtr) +
84*4882a593Smuzhiyun numOutputs * sizeof(RROutputPtr));
85*4882a593Smuzhiyun if (!lease)
86*4882a593Smuzhiyun return NULL;
87*4882a593Smuzhiyun lease->screen = screen;
88*4882a593Smuzhiyun xorg_list_init(&lease->list);
89*4882a593Smuzhiyun lease->id = lid;
90*4882a593Smuzhiyun lease->state = RRLeaseCreating;
91*4882a593Smuzhiyun lease->numCrtcs = numCrtcs;
92*4882a593Smuzhiyun lease->numOutputs = numOutputs;
93*4882a593Smuzhiyun lease->crtcs = (RRCrtcPtr *) (lease + 1);
94*4882a593Smuzhiyun lease->outputs = (RROutputPtr *) (lease->crtcs + numCrtcs);
95*4882a593Smuzhiyun return lease;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /*
99*4882a593Smuzhiyun * Check if a crtc is leased
100*4882a593Smuzhiyun */
101*4882a593Smuzhiyun Bool
RRCrtcIsLeased(RRCrtcPtr crtc)102*4882a593Smuzhiyun RRCrtcIsLeased(RRCrtcPtr crtc)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun ScreenPtr screen = crtc->pScreen;
105*4882a593Smuzhiyun rrScrPrivPtr scr_priv = rrGetScrPriv(screen);
106*4882a593Smuzhiyun RRLeasePtr lease;
107*4882a593Smuzhiyun int c;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun xorg_list_for_each_entry(lease, &scr_priv->leases, list) {
110*4882a593Smuzhiyun for (c = 0; c < lease->numCrtcs; c++)
111*4882a593Smuzhiyun if (lease->crtcs[c] == crtc)
112*4882a593Smuzhiyun return TRUE;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun return FALSE;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /*
118*4882a593Smuzhiyun * Check if an output is leased
119*4882a593Smuzhiyun */
120*4882a593Smuzhiyun Bool
RROutputIsLeased(RROutputPtr output)121*4882a593Smuzhiyun RROutputIsLeased(RROutputPtr output)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun ScreenPtr screen = output->pScreen;
124*4882a593Smuzhiyun rrScrPrivPtr scr_priv = rrGetScrPriv(screen);
125*4882a593Smuzhiyun RRLeasePtr lease;
126*4882a593Smuzhiyun int o;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun xorg_list_for_each_entry(lease, &scr_priv->leases, list) {
129*4882a593Smuzhiyun for (o = 0; o < lease->numOutputs; o++)
130*4882a593Smuzhiyun if (lease->outputs[o] == output)
131*4882a593Smuzhiyun return TRUE;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun return FALSE;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /*
137*4882a593Smuzhiyun * A lease has been terminated.
138*4882a593Smuzhiyun * The driver is responsible for noticing and
139*4882a593Smuzhiyun * calling this function when that happens
140*4882a593Smuzhiyun */
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun void
RRLeaseTerminated(RRLeasePtr lease)143*4882a593Smuzhiyun RRLeaseTerminated(RRLeasePtr lease)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun /* Notify clients with events, but only if this isn't during lease creation */
146*4882a593Smuzhiyun if (lease->state == RRLeaseRunning)
147*4882a593Smuzhiyun RRLeaseChangeState(lease, RRLeaseTerminating, RRLeaseTerminating);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if (lease->id != None)
150*4882a593Smuzhiyun FreeResource(lease->id, RT_NONE);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun xorg_list_del(&lease->list);
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun /*
156*4882a593Smuzhiyun * A lease is completely shut down and is
157*4882a593Smuzhiyun * ready to be deallocated
158*4882a593Smuzhiyun */
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun void
RRLeaseFree(RRLeasePtr lease)161*4882a593Smuzhiyun RRLeaseFree(RRLeasePtr lease)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun free(lease);
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /*
167*4882a593Smuzhiyun * Ask the driver to terminate a lease. The
168*4882a593Smuzhiyun * driver will call RRLeaseTerminated when that has
169*4882a593Smuzhiyun * finished, which may be some time after this function returns
170*4882a593Smuzhiyun * if the driver operation is asynchronous
171*4882a593Smuzhiyun */
172*4882a593Smuzhiyun void
RRTerminateLease(RRLeasePtr lease)173*4882a593Smuzhiyun RRTerminateLease(RRLeasePtr lease)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun ScreenPtr screen = lease->screen;
176*4882a593Smuzhiyun rrScrPrivPtr scr_priv = rrGetScrPriv(screen);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun scr_priv->rrTerminateLease(screen, lease);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun /*
182*4882a593Smuzhiyun * Destroy a lease resource ID. All this
183*4882a593Smuzhiyun * does is note that the lease no longer has an ID, and
184*4882a593Smuzhiyun * so doesn't appear over the protocol anymore.
185*4882a593Smuzhiyun */
186*4882a593Smuzhiyun static int
RRLeaseDestroyResource(void * value,XID pid)187*4882a593Smuzhiyun RRLeaseDestroyResource(void *value, XID pid)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun RRLeasePtr lease = value;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun lease->id = None;
192*4882a593Smuzhiyun return 1;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun /*
196*4882a593Smuzhiyun * Create the lease resource type during server initialization
197*4882a593Smuzhiyun */
198*4882a593Smuzhiyun Bool
RRLeaseInit(void)199*4882a593Smuzhiyun RRLeaseInit(void)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun RRLeaseType = CreateNewResourceType(RRLeaseDestroyResource, "LEASE");
202*4882a593Smuzhiyun if (!RRLeaseType)
203*4882a593Smuzhiyun return FALSE;
204*4882a593Smuzhiyun return TRUE;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun int
ProcRRCreateLease(ClientPtr client)208*4882a593Smuzhiyun ProcRRCreateLease(ClientPtr client)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun REQUEST(xRRCreateLeaseReq);
211*4882a593Smuzhiyun xRRCreateLeaseReply rep;
212*4882a593Smuzhiyun WindowPtr window;
213*4882a593Smuzhiyun ScreenPtr screen;
214*4882a593Smuzhiyun rrScrPrivPtr scr_priv;
215*4882a593Smuzhiyun RRLeasePtr lease;
216*4882a593Smuzhiyun RRCrtc *crtcIds;
217*4882a593Smuzhiyun RROutput *outputIds;
218*4882a593Smuzhiyun int fd;
219*4882a593Smuzhiyun int rc;
220*4882a593Smuzhiyun unsigned long len;
221*4882a593Smuzhiyun int c, o;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun REQUEST_AT_LEAST_SIZE(xRRCreateLeaseReq);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun LEGAL_NEW_RESOURCE(stuff->lid, client);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
228*4882a593Smuzhiyun if (rc != Success)
229*4882a593Smuzhiyun return rc;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun len = client->req_len - bytes_to_int32(sizeof(xRRCreateLeaseReq));
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun if (len != stuff->nCrtcs + stuff->nOutputs)
234*4882a593Smuzhiyun return BadLength;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun screen = window->drawable.pScreen;
237*4882a593Smuzhiyun scr_priv = rrGetScrPriv(screen);
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun if (!scr_priv)
240*4882a593Smuzhiyun return BadMatch;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun if (!scr_priv->rrCreateLease)
243*4882a593Smuzhiyun return BadMatch;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun /* Allocate a structure to hold all of the lease information */
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun lease = RRLeaseAlloc(screen, stuff->lid, stuff->nCrtcs, stuff->nOutputs);
248*4882a593Smuzhiyun if (!lease)
249*4882a593Smuzhiyun return BadAlloc;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun /* Look up all of the crtcs */
252*4882a593Smuzhiyun crtcIds = (RRCrtc *) (stuff + 1);
253*4882a593Smuzhiyun for (c = 0; c < stuff->nCrtcs; c++) {
254*4882a593Smuzhiyun RRCrtcPtr crtc;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun rc = dixLookupResourceByType((void **)&crtc, crtcIds[c],
257*4882a593Smuzhiyun RRCrtcType, client, DixSetAttrAccess);
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun if (rc != Success) {
260*4882a593Smuzhiyun client->errorValue = crtcIds[c];
261*4882a593Smuzhiyun goto bail_lease;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (RRCrtcIsLeased(crtc)) {
265*4882a593Smuzhiyun client->errorValue = crtcIds[c];
266*4882a593Smuzhiyun rc = BadAccess;
267*4882a593Smuzhiyun goto bail_lease;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun lease->crtcs[c] = crtc;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /* Look up all of the outputs */
274*4882a593Smuzhiyun outputIds = (RROutput *) (crtcIds + stuff->nCrtcs);
275*4882a593Smuzhiyun for (o = 0; o < stuff->nOutputs; o++) {
276*4882a593Smuzhiyun RROutputPtr output;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun rc = dixLookupResourceByType((void **)&output, outputIds[o],
279*4882a593Smuzhiyun RROutputType, client, DixSetAttrAccess);
280*4882a593Smuzhiyun if (rc != Success) {
281*4882a593Smuzhiyun client->errorValue = outputIds[o];
282*4882a593Smuzhiyun goto bail_lease;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun if (RROutputIsLeased(output)) {
286*4882a593Smuzhiyun client->errorValue = outputIds[o];
287*4882a593Smuzhiyun rc = BadAccess;
288*4882a593Smuzhiyun goto bail_lease;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun lease->outputs[o] = output;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun rc = scr_priv->rrCreateLease(screen, lease, &fd);
295*4882a593Smuzhiyun if (rc != Success)
296*4882a593Smuzhiyun goto bail_lease;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun xorg_list_add(&scr_priv->leases, &lease->list);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun if (!AddResource(stuff->lid, RRLeaseType, lease)) {
301*4882a593Smuzhiyun close(fd);
302*4882a593Smuzhiyun return BadAlloc;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun if (WriteFdToClient(client, fd, TRUE) < 0) {
306*4882a593Smuzhiyun RRTerminateLease(lease);
307*4882a593Smuzhiyun close(fd);
308*4882a593Smuzhiyun return BadAlloc;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun RRLeaseChangeState(lease, RRLeaseCreating, RRLeaseRunning);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun rep = (xRRCreateLeaseReply) {
314*4882a593Smuzhiyun .type = X_Reply,
315*4882a593Smuzhiyun .nfd = 1,
316*4882a593Smuzhiyun .sequenceNumber = client->sequence,
317*4882a593Smuzhiyun .length = 0,
318*4882a593Smuzhiyun };
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (client->swapped) {
321*4882a593Smuzhiyun swaps(&rep.sequenceNumber);
322*4882a593Smuzhiyun swapl(&rep.length);
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun WriteToClient(client, sizeof (rep), &rep);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun return Success;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun bail_lease:
330*4882a593Smuzhiyun free(lease);
331*4882a593Smuzhiyun return rc;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun int
ProcRRFreeLease(ClientPtr client)335*4882a593Smuzhiyun ProcRRFreeLease(ClientPtr client)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun REQUEST(xRRFreeLeaseReq);
338*4882a593Smuzhiyun RRLeasePtr lease;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun REQUEST_SIZE_MATCH(xRRFreeLeaseReq);
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun VERIFY_RR_LEASE(stuff->lid, lease, DixDestroyAccess);
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun if (stuff->terminate)
345*4882a593Smuzhiyun RRTerminateLease(lease);
346*4882a593Smuzhiyun else
347*4882a593Smuzhiyun /* Get rid of the resource database entry */
348*4882a593Smuzhiyun FreeResource(stuff->lid, RT_NONE);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun return Success;
351*4882a593Smuzhiyun }
352