lnx_apm.c (4997B)
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 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 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 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 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 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