1 
2 #ifdef HAVE_XORG_CONFIG_H
3 #include <xorg-config.h>
4 #endif
5 
6 #include <X11/X.h>
7 #include "os.h"
8 #include "xf86.h"
9 #include "xf86Priv.h"
10 #define XF86_OS_PRIVS
11 #include "xf86_OSproc.h"
12 
13 #ifdef HAVE_ACPI
14 extern PMClose lnxACPIOpen(void);
15 #endif
16 
17 #ifdef HAVE_APM
18 
19 #include <linux/apm_bios.h>
20 #include <unistd.h>
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 
27 #define APM_PROC   "/proc/apm"
28 #define APM_DEVICE "/dev/apm_bios"
29 
30 #ifndef APM_STANDBY_FAILED
31 #define APM_STANDBY_FAILED 0xf000
32 #endif
33 #ifndef APM_SUSPEND_FAILED
34 #define APM_SUSPEND_FAILED 0xf001
35 #endif
36 
37 static PMClose lnxAPMOpen(void);
38 static void lnxCloseAPM(void);
39 static void *APMihPtr = NULL;
40 
41 static struct {
42     apm_event_t apmLinux;
43     pmEvent xf86;
44 } LinuxToXF86[] = {
45     {APM_SYS_STANDBY, XF86_APM_SYS_STANDBY},
46     {APM_SYS_SUSPEND, XF86_APM_SYS_SUSPEND},
47     {APM_NORMAL_RESUME, XF86_APM_NORMAL_RESUME},
48     {APM_CRITICAL_RESUME, XF86_APM_CRITICAL_RESUME},
49     {APM_LOW_BATTERY, XF86_APM_LOW_BATTERY},
50     {APM_POWER_STATUS_CHANGE, XF86_APM_POWER_STATUS_CHANGE},
51     {APM_UPDATE_TIME, XF86_APM_UPDATE_TIME},
52     {APM_CRITICAL_SUSPEND, XF86_APM_CRITICAL_SUSPEND},
53     {APM_USER_STANDBY, XF86_APM_USER_STANDBY},
54     {APM_USER_SUSPEND, XF86_APM_USER_SUSPEND},
55     {APM_STANDBY_RESUME, XF86_APM_STANDBY_RESUME},
56 #if defined(APM_CAPABILITY_CHANGED)
57     {APM_CAPABILITY_CHANGED, XF86_CAPABILITY_CHANGED},
58 #endif
59 #if 0
60     {APM_STANDBY_FAILED, XF86_APM_STANDBY_FAILED},
61     {APM_SUSPEND_FAILED, XF86_APM_SUSPEND_FAILED}
62 #endif
63 };
64 
65 /*
66  * APM is still under construction.
67  * I'm not sure if the places where I initialize/deinitialize
68  * apm is correct. Also I don't know what to do in SETUP state.
69  * This depends if wakeup gets called in this situation, too.
70  * Also we need to check if the action that is taken on an
71  * event is reasonable.
72  */
73 static int
lnxPMGetEventFromOs(int fd,pmEvent * events,int num)74 lnxPMGetEventFromOs(int fd, pmEvent * events, int num)
75 {
76     int i, j, n;
77     apm_event_t linuxEvents[8];
78 
79     if ((n = read(fd, linuxEvents, num * sizeof(apm_event_t))) == -1)
80         return 0;
81     n /= sizeof(apm_event_t);
82     if (n > num)
83         n = num;
84     for (i = 0; i < n; i++) {
85         for (j = 0; j < ARRAY_SIZE(LinuxToXF86); j++)
86             if (LinuxToXF86[j].apmLinux == linuxEvents[i]) {
87                 events[i] = LinuxToXF86[j].xf86;
88                 break;
89             }
90         if (j == ARRAY_SIZE(LinuxToXF86))
91             events[i] = XF86_APM_UNKNOWN;
92     }
93     return n;
94 }
95 
96 static pmWait
lnxPMConfirmEventToOs(int fd,pmEvent event)97 lnxPMConfirmEventToOs(int fd, pmEvent event)
98 {
99     switch (event) {
100     case XF86_APM_SYS_STANDBY:
101     case XF86_APM_USER_STANDBY:
102         if (ioctl(fd, APM_IOC_STANDBY, NULL))
103             return PM_FAILED;
104         return PM_CONTINUE;
105     case XF86_APM_SYS_SUSPEND:
106     case XF86_APM_CRITICAL_SUSPEND:
107     case XF86_APM_USER_SUSPEND:
108         if (ioctl(fd, APM_IOC_SUSPEND, NULL)) {
109             /* I believe this is wrong (EE)
110                EBUSY is sent when a device refuses to be suspended.
111                In this case we still need to undo everything we have
112                done to suspend ourselves or we will stay in suspended
113                state forever. */
114             if (errno == EBUSY)
115                 return PM_CONTINUE;
116             else
117                 return PM_FAILED;
118         }
119         return PM_CONTINUE;
120     case XF86_APM_STANDBY_RESUME:
121     case XF86_APM_NORMAL_RESUME:
122     case XF86_APM_CRITICAL_RESUME:
123     case XF86_APM_STANDBY_FAILED:
124     case XF86_APM_SUSPEND_FAILED:
125         return PM_CONTINUE;
126     default:
127         return PM_NONE;
128     }
129 }
130 
131 #endif                          // HAVE_APM
132 
133 PMClose
xf86OSPMOpen(void)134 xf86OSPMOpen(void)
135 {
136     PMClose ret = NULL;
137 
138 #ifdef HAVE_ACPI
139     /* Favour ACPI over APM, but only when enabled */
140 
141     if (!xf86acpiDisableFlag) {
142         ret = lnxACPIOpen();
143         if (ret)
144             return ret;
145     }
146 #endif
147 #ifdef HAVE_APM
148     ret = lnxAPMOpen();
149 #endif
150 
151     return ret;
152 }
153 
154 #ifdef HAVE_APM
155 
156 static PMClose
lnxAPMOpen(void)157 lnxAPMOpen(void)
158 {
159     int fd, pfd;
160 
161     DebugF("APM: OSPMOpen called\n");
162     if (APMihPtr || !xf86Info.pmFlag)
163         return NULL;
164 
165     DebugF("APM: Opening device\n");
166     if ((fd = open(APM_DEVICE, O_RDWR)) > -1) {
167         if (access(APM_PROC, R_OK) || ((pfd = open(APM_PROC, O_RDONLY)) == -1)) {
168             xf86MsgVerb(X_WARNING, 3, "Cannot open APM (%s) (%s)\n",
169                         APM_PROC, strerror(errno));
170             close(fd);
171             return NULL;
172         }
173         else
174             close(pfd);
175         xf86PMGetEventFromOs = lnxPMGetEventFromOs;
176         xf86PMConfirmEventToOs = lnxPMConfirmEventToOs;
177         APMihPtr = xf86AddGeneralHandler(fd, xf86HandlePMEvents, NULL);
178         xf86MsgVerb(X_INFO, 3, "Open APM successful\n");
179         return lnxCloseAPM;
180     }
181     return NULL;
182 }
183 
184 static void
lnxCloseAPM(void)185 lnxCloseAPM(void)
186 {
187     int fd;
188 
189     DebugF("APM: Closing device\n");
190     if (APMihPtr) {
191         fd = xf86RemoveGeneralHandler(APMihPtr);
192         close(fd);
193         APMihPtr = NULL;
194     }
195 }
196 
197 #endif                          // HAVE_APM
198