Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / os-support / linux / lnx_apm.c
CommitLineData
a09e091a
JB
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
14extern 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
37static PMClose lnxAPMOpen(void);
38static void lnxCloseAPM(void);
39static pointer APMihPtr = NULL;
40
41static 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#define numApmEvents (sizeof(LinuxToXF86) / sizeof(LinuxToXF86[0]))
66
67/*
68 * APM is still under construction.
69 * I'm not sure if the places where I initialize/deinitialize
70 * apm is correct. Also I don't know what to do in SETUP state.
71 * This depends if wakeup gets called in this situation, too.
72 * Also we need to check if the action that is taken on an
73 * event is reasonable.
74 */
75static int
76lnxPMGetEventFromOs(int fd, pmEvent * events, int num)
77{
78 int i, j, n;
79 apm_event_t linuxEvents[8];
80
81 if ((n = read(fd, linuxEvents, num * sizeof(apm_event_t))) == -1)
82 return 0;
83 n /= sizeof(apm_event_t);
84 if (n > num)
85 n = num;
86 for (i = 0; i < n; i++) {
87 for (j = 0; j < numApmEvents; j++)
88 if (LinuxToXF86[j].apmLinux == linuxEvents[i]) {
89 events[i] = LinuxToXF86[j].xf86;
90 break;
91 }
92 if (j == numApmEvents)
93 events[i] = XF86_APM_UNKNOWN;
94 }
95 return n;
96}
97
98static pmWait
99lnxPMConfirmEventToOs(int fd, pmEvent event)
100{
101 switch (event) {
102 case XF86_APM_SYS_STANDBY:
103 case XF86_APM_USER_STANDBY:
104 if (ioctl(fd, APM_IOC_STANDBY, NULL))
105 return PM_FAILED;
106 return PM_CONTINUE;
107 case XF86_APM_SYS_SUSPEND:
108 case XF86_APM_CRITICAL_SUSPEND:
109 case XF86_APM_USER_SUSPEND:
110 if (ioctl(fd, APM_IOC_SUSPEND, NULL)) {
111 /* I believe this is wrong (EE)
112 EBUSY is sent when a device refuses to be suspended.
113 In this case we still need to undo everything we have
114 done to suspend ourselves or we will stay in suspended
115 state forever. */
116 if (errno == EBUSY)
117 return PM_CONTINUE;
118 else
119 return PM_FAILED;
120 }
121 return PM_CONTINUE;
122 case XF86_APM_STANDBY_RESUME:
123 case XF86_APM_NORMAL_RESUME:
124 case XF86_APM_CRITICAL_RESUME:
125 case XF86_APM_STANDBY_FAILED:
126 case XF86_APM_SUSPEND_FAILED:
127 return PM_CONTINUE;
128 default:
129 return PM_NONE;
130 }
131}
132
133#endif // HAVE_APM
134
135PMClose
136xf86OSPMOpen(void)
137{
138 PMClose ret = NULL;
139
140#ifdef HAVE_ACPI
141 /* Favour ACPI over APM, but only when enabled */
142
143 if (!xf86acpiDisableFlag)
144 ret = lnxACPIOpen();
145
146 if (!ret)
147#endif
148#ifdef HAVE_APM
149 ret = lnxAPMOpen();
150#endif
151
152 return ret;
153}
154
155#ifdef HAVE_APM
156
157static PMClose
158lnxAPMOpen(void)
159{
160 int fd, pfd;
161
162 DebugF("APM: OSPMOpen called\n");
163 if (APMihPtr || !xf86Info.pmFlag)
164 return NULL;
165
166 DebugF("APM: Opening device\n");
167 if ((fd = open(APM_DEVICE, O_RDWR)) > -1) {
168 if (access(APM_PROC, R_OK) || ((pfd = open(APM_PROC, O_RDONLY)) == -1)) {
169 xf86MsgVerb(X_WARNING, 3, "Cannot open APM (%s) (%s)\n",
170 APM_PROC, strerror(errno));
171 close(fd);
172 return NULL;
173 }
174 else
175 close(pfd);
176 xf86PMGetEventFromOs = lnxPMGetEventFromOs;
177 xf86PMConfirmEventToOs = lnxPMConfirmEventToOs;
178 APMihPtr = xf86AddGeneralHandler(fd, xf86HandlePMEvents, NULL);
179 xf86MsgVerb(X_INFO, 3, "Open APM successful\n");
180 return lnxCloseAPM;
181 }
182 return NULL;
183}
184
185static void
186lnxCloseAPM(void)
187{
188 int fd;
189
190 DebugF("APM: Closing device\n");
191 if (APMihPtr) {
192 fd = xf86RemoveGeneralHandler(APMihPtr);
193 close(fd);
194 APMihPtr = NULL;
195 }
196}
197
198#endif // HAVE_APM