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