#ifdef HAVE_XORG_CONFIG_H #include #endif #include #include "os.h" #include "xf86.h" #include "xf86Priv.h" #define XF86_OS_PRIVS #include "xf86_OSproc.h" #ifdef HAVE_ACPI extern PMClose lnxACPIOpen(void); #endif #ifdef HAVE_APM #include #include #include #include #include #include #include #define APM_PROC "/proc/apm" #define APM_DEVICE "/dev/apm_bios" #ifndef APM_STANDBY_FAILED # define APM_STANDBY_FAILED 0xf000 #endif #ifndef APM_SUSPEND_FAILED # define APM_SUSPEND_FAILED 0xf001 #endif static PMClose lnxAPMOpen(void); static void lnxCloseAPM(void); static pointer APMihPtr = NULL; static struct { apm_event_t apmLinux; pmEvent xf86; } LinuxToXF86[] = { { APM_SYS_STANDBY, XF86_APM_SYS_STANDBY }, { APM_SYS_SUSPEND, XF86_APM_SYS_SUSPEND }, { APM_NORMAL_RESUME, XF86_APM_NORMAL_RESUME }, { APM_CRITICAL_RESUME, XF86_APM_CRITICAL_RESUME }, { APM_LOW_BATTERY, XF86_APM_LOW_BATTERY }, { APM_POWER_STATUS_CHANGE, XF86_APM_POWER_STATUS_CHANGE }, { APM_UPDATE_TIME, XF86_APM_UPDATE_TIME }, { APM_CRITICAL_SUSPEND, XF86_APM_CRITICAL_SUSPEND }, { APM_USER_STANDBY, XF86_APM_USER_STANDBY }, { APM_USER_SUSPEND, XF86_APM_USER_SUSPEND }, { APM_STANDBY_RESUME, XF86_APM_STANDBY_RESUME }, #if defined(APM_CAPABILITY_CHANGED) { APM_CAPABILITY_CHANGED, XF86_CAPABILITY_CHANGED }, #endif #if 0 { APM_STANDBY_FAILED, XF86_APM_STANDBY_FAILED }, { APM_SUSPEND_FAILED, XF86_APM_SUSPEND_FAILED } #endif }; #define numApmEvents (sizeof(LinuxToXF86) / sizeof(LinuxToXF86[0])) /* * APM is still under construction. * I'm not sure if the places where I initialize/deinitialize * apm is correct. Also I don't know what to do in SETUP state. * This depends if wakeup gets called in this situation, too. * Also we need to check if the action that is taken on an * event is reasonable. */ static int lnxPMGetEventFromOs(int fd, pmEvent *events, int num) { int i,j,n; apm_event_t linuxEvents[8]; if ((n = read( fd, linuxEvents, num * sizeof(apm_event_t) )) == -1) return 0; n /= sizeof(apm_event_t); if (n > num) n = num; for (i = 0; i < n; i++) { for (j = 0; j < numApmEvents; j++) if (LinuxToXF86[j].apmLinux == linuxEvents[i]) { events[i] = LinuxToXF86[j].xf86; break; } if (j == numApmEvents) events[i] = XF86_APM_UNKNOWN; } return n; } static pmWait lnxPMConfirmEventToOs(int fd, pmEvent event) { switch (event) { case XF86_APM_SYS_STANDBY: case XF86_APM_USER_STANDBY: if (ioctl( fd, APM_IOC_STANDBY, NULL )) return PM_FAILED; return PM_CONTINUE; case XF86_APM_SYS_SUSPEND: case XF86_APM_CRITICAL_SUSPEND: case XF86_APM_USER_SUSPEND: if (ioctl( fd, APM_IOC_SUSPEND, NULL )) { /* I believe this is wrong (EE) EBUSY is sent when a device refuses to be suspended. In this case we still need to undo everything we have done to suspend ourselves or we will stay in suspended state forever. */ if (errno == EBUSY) return PM_CONTINUE; else return PM_FAILED; } return PM_CONTINUE; case XF86_APM_STANDBY_RESUME: case XF86_APM_NORMAL_RESUME: case XF86_APM_CRITICAL_RESUME: case XF86_APM_STANDBY_FAILED: case XF86_APM_SUSPEND_FAILED: return PM_CONTINUE; default: return PM_NONE; } } #endif // HAVE_APM PMClose xf86OSPMOpen(void) { PMClose ret = NULL; #ifdef HAVE_ACPI /* Favour ACPI over APM, but only when enabled */ if (!xf86acpiDisableFlag) ret = lnxACPIOpen(); if (!ret) #endif #ifdef HAVE_APM ret = lnxAPMOpen(); #endif return ret; } #ifdef HAVE_APM static PMClose lnxAPMOpen(void) { int fd, pfd; DebugF("APM: OSPMOpen called\n"); if (APMihPtr || !xf86Info.pmFlag) return NULL; DebugF("APM: Opening device\n"); if ((fd = open( APM_DEVICE, O_RDWR )) > -1) { if (access( APM_PROC, R_OK ) || ((pfd = open( APM_PROC, O_RDONLY)) == -1)) { xf86MsgVerb(X_WARNING,3,"Cannot open APM (%s) (%s)\n", APM_PROC, strerror(errno)); close(fd); return NULL; } else close(pfd); xf86PMGetEventFromOs = lnxPMGetEventFromOs; xf86PMConfirmEventToOs = lnxPMConfirmEventToOs; APMihPtr = xf86AddGeneralHandler(fd, xf86HandlePMEvents, NULL); xf86MsgVerb(X_INFO,3,"Open APM successful\n"); return lnxCloseAPM; } return NULL; } static void lnxCloseAPM(void) { int fd; DebugF("APM: Closing device\n"); if (APMihPtr) { fd = xf86RemoveGeneralHandler(APMihPtr); close(fd); APMihPtr = NULL; } } #endif // HAVE_APM