tizen 2.4 release
[framework/uifw/xorg/server/xorg-server.git] / hw / xfree86 / os-support / linux / lnx_apm.c
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 #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  */
75 static int
76 lnxPMGetEventFromOs(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
98 static pmWait
99 lnxPMConfirmEventToOs(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
135 PMClose
136 xf86OSPMOpen(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
157 static PMClose
158 lnxAPMOpen(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
185 static void
186 lnxCloseAPM(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