1 /*
2  * Copyright (c) 2000-2002 by The XFree86 Project, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Except as contained in this notice, the name of the copyright holder(s)
23  * and author(s) shall not be used in advertising or otherwise to promote
24  * the sale, use or other dealings in this Software without prior written
25  * authorization from the copyright holder(s) and author(s).
26  */
27 
28 #ifdef HAVE_XORG_CONFIG_H
29 #include <xorg-config.h>
30 #endif
31 
32 #include <X11/X.h>
33 #include "xf86.h"
34 #include "xf86Priv.h"
35 #include "xf86Xinput.h"
36 #include "xf86_OSproc.h"
37 
38 int (*xf86PMGetEventFromOs) (int fd, pmEvent * events, int num) = NULL;
39 pmWait (*xf86PMConfirmEventToOs) (int fd, pmEvent event) = NULL;
40 
41 static Bool suspended = FALSE;
42 
43 static int
eventName(pmEvent event,const char ** str)44 eventName(pmEvent event, const char **str)
45 {
46     switch (event) {
47     case XF86_APM_SYS_STANDBY:
48         *str = "System Standby Request";
49         return 0;
50     case XF86_APM_SYS_SUSPEND:
51         *str = "System Suspend Request";
52         return 0;
53     case XF86_APM_CRITICAL_SUSPEND:
54         *str = "Critical Suspend";
55         return 0;
56     case XF86_APM_USER_STANDBY:
57         *str = "User System Standby Request";
58         return 0;
59     case XF86_APM_USER_SUSPEND:
60         *str = "User System Suspend Request";
61         return 0;
62     case XF86_APM_STANDBY_RESUME:
63         *str = "System Standby Resume";
64         return 0;
65     case XF86_APM_NORMAL_RESUME:
66         *str = "Normal Resume System";
67         return 0;
68     case XF86_APM_CRITICAL_RESUME:
69         *str = "Critical Resume System";
70         return 0;
71     case XF86_APM_LOW_BATTERY:
72         *str = "Battery Low";
73         return 3;
74     case XF86_APM_POWER_STATUS_CHANGE:
75         *str = "Power Status Change";
76         return 3;
77     case XF86_APM_UPDATE_TIME:
78         *str = "Update Time";
79         return 3;
80     case XF86_APM_CAPABILITY_CHANGED:
81         *str = "Capability Changed";
82         return 3;
83     case XF86_APM_STANDBY_FAILED:
84         *str = "Standby Request Failed";
85         return 0;
86     case XF86_APM_SUSPEND_FAILED:
87         *str = "Suspend Request Failed";
88         return 0;
89     default:
90         *str = "Unknown Event";
91         return 0;
92     }
93 }
94 
95 static void
suspend(pmEvent event,Bool undo)96 suspend(pmEvent event, Bool undo)
97 {
98     int i;
99     InputInfoPtr pInfo;
100 
101     for (i = 0; i < xf86NumScreens; i++) {
102         if (xf86Screens[i]->EnableDisableFBAccess)
103             (*xf86Screens[i]->EnableDisableFBAccess) (xf86Screens[i], FALSE);
104     }
105     pInfo = xf86InputDevs;
106     while (pInfo) {
107         DisableDevice(pInfo->dev, TRUE);
108         pInfo = pInfo->next;
109     }
110     input_lock();
111     for (i = 0; i < xf86NumScreens; i++) {
112         if (xf86Screens[i]->PMEvent)
113             xf86Screens[i]->PMEvent(xf86Screens[i], event, undo);
114         else {
115             xf86Screens[i]->LeaveVT(xf86Screens[i]);
116             xf86Screens[i]->vtSema = FALSE;
117         }
118     }
119 }
120 
121 static void
resume(pmEvent event,Bool undo)122 resume(pmEvent event, Bool undo)
123 {
124     int i;
125     InputInfoPtr pInfo;
126 
127     for (i = 0; i < xf86NumScreens; i++) {
128         if (xf86Screens[i]->PMEvent)
129             xf86Screens[i]->PMEvent(xf86Screens[i], event, undo);
130         else {
131             xf86Screens[i]->vtSema = TRUE;
132             xf86Screens[i]->EnterVT(xf86Screens[i]);
133         }
134     }
135     input_unlock();
136     for (i = 0; i < xf86NumScreens; i++) {
137         if (xf86Screens[i]->EnableDisableFBAccess)
138             (*xf86Screens[i]->EnableDisableFBAccess) (xf86Screens[i], TRUE);
139     }
140     dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset);
141     pInfo = xf86InputDevs;
142     while (pInfo) {
143         EnableDevice(pInfo->dev, TRUE);
144         pInfo = pInfo->next;
145     }
146 }
147 
148 static void
DoApmEvent(pmEvent event,Bool undo)149 DoApmEvent(pmEvent event, Bool undo)
150 {
151     int i;
152 
153     switch (event) {
154 #if 0
155     case XF86_APM_SYS_STANDBY:
156     case XF86_APM_USER_STANDBY:
157 #endif
158     case XF86_APM_SYS_SUSPEND:
159     case XF86_APM_CRITICAL_SUSPEND:    /*do we want to delay a critical suspend? */
160     case XF86_APM_USER_SUSPEND:
161         /* should we do this ? */
162         if (!undo && !suspended) {
163             suspend(event, undo);
164             suspended = TRUE;
165         }
166         else if (undo && suspended) {
167             resume(event, undo);
168             suspended = FALSE;
169         }
170         break;
171 #if 0
172     case XF86_APM_STANDBY_RESUME:
173 #endif
174     case XF86_APM_NORMAL_RESUME:
175     case XF86_APM_CRITICAL_RESUME:
176         if (suspended) {
177             resume(event, undo);
178             suspended = FALSE;
179         }
180         break;
181     default:
182         input_lock();
183         for (i = 0; i < xf86NumScreens; i++) {
184             if (xf86Screens[i]->PMEvent) {
185                 xf86Screens[i]->PMEvent(xf86Screens[i], event, undo);
186             }
187         }
188         input_unlock();
189         break;
190     }
191 }
192 
193 #define MAX_NO_EVENTS 8
194 
195 void
xf86HandlePMEvents(int fd,void * data)196 xf86HandlePMEvents(int fd, void *data)
197 {
198     pmEvent events[MAX_NO_EVENTS];
199     int i, n;
200     Bool wait = FALSE;
201 
202     if (!xf86PMGetEventFromOs)
203         return;
204 
205     if ((n = xf86PMGetEventFromOs(fd, events, MAX_NO_EVENTS))) {
206         do {
207             for (i = 0; i < n; i++) {
208                 const char *str = NULL;
209                 int verb = eventName(events[i], &str);
210 
211                 xf86MsgVerb(X_INFO, verb, "PM Event received: %s\n", str);
212                 DoApmEvent(events[i], FALSE);
213                 switch (xf86PMConfirmEventToOs(fd, events[i])) {
214                 case PM_WAIT:
215                     wait = TRUE;
216                     break;
217                 case PM_CONTINUE:
218                     wait = FALSE;
219                     break;
220                 case PM_FAILED:
221                     DoApmEvent(events[i], TRUE);
222                     wait = FALSE;
223                     break;
224                 default:
225                     break;
226                 }
227             }
228             if (wait)
229                 n = xf86PMGetEventFromOs(fd, events, MAX_NO_EVENTS);
230             else
231                 break;
232         } while (1);
233     }
234 }
235