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 
144     if (!ret)
145 #endif
146 #ifdef HAVE_APM
147         ret = lnxAPMOpen();
148 #endif
149 
150     return ret;
151 }
152 
153 #ifdef HAVE_APM
154 
155 static PMClose
lnxAPMOpen(void)156 lnxAPMOpen(void)
157 {
158     int fd, pfd;
159 
160     DebugF("APM: OSPMOpen called\n");
161     if (APMihPtr || !xf86Info.pmFlag)
162         return NULL;
163 
164     DebugF("APM: Opening device\n");
165     if ((fd = open(APM_DEVICE, O_RDWR)) > -1) {
166         if (access(APM_PROC, R_OK) || ((pfd = open(APM_PROC, O_RDONLY)) == -1)) {
167             xf86MsgVerb(X_WARNING, 3, "Cannot open APM (%s) (%s)\n",
168                         APM_PROC, strerror(errno));
169             close(fd);
170             return NULL;
171         }
172         else
173             close(pfd);
174         xf86PMGetEventFromOs = lnxPMGetEventFromOs;
175         xf86PMConfirmEventToOs = lnxPMConfirmEventToOs;
176         APMihPtr = xf86AddGeneralHandler(fd, xf86HandlePMEvents, NULL);
177         xf86MsgVerb(X_INFO, 3, "Open APM successful\n");
178         return lnxCloseAPM;
179     }
180     return NULL;
181 }
182 
183 static void
lnxCloseAPM(void)184 lnxCloseAPM(void)
185 {
186     int fd;
187 
188     DebugF("APM: Closing device\n");
189     if (APMihPtr) {
190         fd = xf86RemoveGeneralHandler(APMihPtr);
191         close(fd);
192         APMihPtr = NULL;
193     }
194 }
195 
196 #endif                          // HAVE_APM
197