xref: /OK3568_Linux_fs/external/xserver/randr/rrlease.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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