|
|
|
@ -3,10 +3,13 @@ |
|
|
|
|
#include <stdio.h> |
|
|
|
|
#include <stdlib.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
#include <unistd.h> |
|
|
|
|
#include <X11/keysym.h> |
|
|
|
|
#include <X11/XF86keysym.h> |
|
|
|
|
#include <X11/Xlib.h> |
|
|
|
|
#include <X11/Xutil.h> |
|
|
|
|
|
|
|
|
|
// Types
|
|
|
|
|
enum State { |
|
|
|
|
StateNoInput, // Screen on / input lock
|
|
|
|
|
StateNoInputNoScreen, // Screen off / input lock
|
|
|
|
@ -14,7 +17,6 @@ enum State { |
|
|
|
|
StateSuspendPending, // Suspend 'woken up', must leave state in <10s, or kicks to StateSuspend
|
|
|
|
|
StateDead // Exit the appliation
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
enum Color { |
|
|
|
|
Red, |
|
|
|
|
Blue, |
|
|
|
@ -22,67 +24,80 @@ enum Color { |
|
|
|
|
Off |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static Display *dpy; |
|
|
|
|
static enum State state = StateNoInput; |
|
|
|
|
static int lastkeysym = NULL; |
|
|
|
|
static int lastkeyn = 0; |
|
|
|
|
static char oldbrightness[10] = "200"; |
|
|
|
|
static char * brightnessfile = "/sys/devices/platform/backlight/backlight/backlight/brightness"; |
|
|
|
|
static char * powerstatefile = "/sys/power/state"; |
|
|
|
|
// Fn declarations
|
|
|
|
|
void configuresuspendsettingsandwakeupsources(); |
|
|
|
|
void die(const char *err, ...); |
|
|
|
|
int getoldbrightness(); |
|
|
|
|
void lockscreen(Display *dpy, int screen); |
|
|
|
|
void readinputloop(Display *dpy, int screen); |
|
|
|
|
void setpineled(enum Color c); |
|
|
|
|
void syncstate(); |
|
|
|
|
void writefile(char *filepath, char *str); |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
writefile(char *filepath, char *str) |
|
|
|
|
{ |
|
|
|
|
int f; |
|
|
|
|
f = open(filepath, O_WRONLY); |
|
|
|
|
if (f != NULL) { |
|
|
|
|
write(f, str, strlen(str)); |
|
|
|
|
close(f); |
|
|
|
|
} else { |
|
|
|
|
fprintf(stderr, "Couldn't open filepath <%s>\n", filepath); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Variables
|
|
|
|
|
Display *dpy; |
|
|
|
|
enum State state = StateNoInput; |
|
|
|
|
KeySym lastkeysym = XK_Cancel; |
|
|
|
|
int lastkeyn = 0; |
|
|
|
|
char oldbrightness[10] = "200"; |
|
|
|
|
char * brightnessfile = "/sys/devices/platform/backlight/backlight/backlight/brightness"; |
|
|
|
|
char * powerstatefile = "/sys/power/state"; |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
setpineled(enum Color c) |
|
|
|
|
configuresuspendsettingsandwakeupsources() |
|
|
|
|
{ |
|
|
|
|
if (c == Red) { |
|
|
|
|
writefile("/sys/class/leds/red:indicator/brightness", "1"); |
|
|
|
|
writefile("/sys/class/leds/blue:indicator/brightness", "0"); |
|
|
|
|
} else if (c == Blue) { |
|
|
|
|
writefile("/sys/class/leds/red:indicator/brightness", "0"); |
|
|
|
|
writefile("/sys/class/leds/blue:indicator/brightness", "1"); |
|
|
|
|
} else if (c == Purple) { |
|
|
|
|
writefile("/sys/class/leds/red:indicator/brightness", "1"); |
|
|
|
|
writefile("/sys/class/leds/blue:indicator/brightness", "1"); |
|
|
|
|
} else if (c == Off) { |
|
|
|
|
writefile("/sys/class/leds/red:indicator/brightness", "0"); |
|
|
|
|
writefile("/sys/class/leds/blue:indicator/brightness", "0"); |
|
|
|
|
// Disable all wakeup sources
|
|
|
|
|
struct dirent *wakeupsource; |
|
|
|
|
char wakeuppath[100]; |
|
|
|
|
DIR *wakeupsources = opendir("/sys/class/wakeup"); |
|
|
|
|
if (wakeupsources == NULL) |
|
|
|
|
die("Couldn't open directory /sys/class/wakeup\n"); |
|
|
|
|
while ((wakeupsource = readdir(wakeupsources)) != NULL) { |
|
|
|
|
sprintf( |
|
|
|
|
wakeuppath,
|
|
|
|
|
"/sys/class/wakeup/%s/device/power/wakeup", |
|
|
|
|
wakeupsource->d_name |
|
|
|
|
); |
|
|
|
|
fprintf(stderr, "Disabling wakeup source: %s", wakeupsource->d_name); |
|
|
|
|
writefile(wakeuppath, "disabled"); |
|
|
|
|
fprintf(stderr, ".. ok\n"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
closedir(wakeupsources); |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
syncstate() |
|
|
|
|
{ |
|
|
|
|
if (state == StateSuspend) { |
|
|
|
|
setpineled(Red); |
|
|
|
|
configuresuspendsettingsandwakeupsources(); |
|
|
|
|
writefile(powerstatefile, "mem"); |
|
|
|
|
state = StateSuspendPending; |
|
|
|
|
syncstate(); |
|
|
|
|
} else if (state == StateNoInput) { |
|
|
|
|
setpineled(Blue); |
|
|
|
|
writefile(brightnessfile, oldbrightness); |
|
|
|
|
} else if (state == StateNoInputNoScreen || state == StateSuspendPending) { |
|
|
|
|
setpineled(Purple); |
|
|
|
|
writefile(brightnessfile, "0"); |
|
|
|
|
} else if (state == StateDead) { |
|
|
|
|
writefile(brightnessfile, oldbrightness); |
|
|
|
|
setpineled(Off); |
|
|
|
|
} |
|
|
|
|
// Enable powerbutton wakeup source
|
|
|
|
|
fprintf(stderr, "Enable powerbutton wakeup source\n"); |
|
|
|
|
writefile( |
|
|
|
|
"/sys/devices/platform/soc/1f03400.rsb/sunxi-rsb-3a3/axp221-pek/power/wakeup", |
|
|
|
|
"enabled" |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Enable rtc wakeup source
|
|
|
|
|
fprintf(stderr, "Enable rtc wakeup source\n"); |
|
|
|
|
writefile( |
|
|
|
|
"/sys/devices/platform/soc/1f00000.rtc/power/wakeup", |
|
|
|
|
"enabled" |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Temporary hack to disable USB driver that doesn't suspend
|
|
|
|
|
fprintf(stderr, "Disabling buggy USB driver\n"); |
|
|
|
|
writefile( |
|
|
|
|
"/sys/devices/platform/soc/1c19000.usb/driver/unbind", |
|
|
|
|
"1c19000.usb" |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Temporary hack to disable Bluetooth driver that crashes on suspend 1/5th the time
|
|
|
|
|
fprintf(stderr, "Disabling buggy Bluetooth driver\n"); |
|
|
|
|
writefile( |
|
|
|
|
"/sys/bus/serial/drivers/hci_uart_h5/unbind", |
|
|
|
|
"serial0-0" |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// E.g. make sure we're using CRUST
|
|
|
|
|
fprintf(stderr, "Flip mem_sleep setting to use crust\n"); |
|
|
|
|
writefile("/sys/power/mem_sleep", "deep"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
void |
|
|
|
|
die(const char *err, ...) |
|
|
|
|
{ |
|
|
|
|
fprintf(stderr, "Error: %s", err); |
|
|
|
@ -91,12 +106,33 @@ die(const char *err, ...) |
|
|
|
|
exit(1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Loosely derived from suckless' slock's lockscreen binding logic but
|
|
|
|
|
// alot more coarse, intentionally so can be triggered while grab_key
|
|
|
|
|
// for dwm multikey path already holding..
|
|
|
|
|
int |
|
|
|
|
getoldbrightness() { |
|
|
|
|
char * buffer = 0; |
|
|
|
|
long length; |
|
|
|
|
FILE * f = fopen(brightnessfile, "r"); |
|
|
|
|
if (f) { |
|
|
|
|
fseek(f, 0, SEEK_END); |
|
|
|
|
length = ftell(f); |
|
|
|
|
fseek(f, 0, SEEK_SET); |
|
|
|
|
buffer = malloc(length); |
|
|
|
|
if (buffer) { |
|
|
|
|
fread(buffer, 1, length, f); |
|
|
|
|
} |
|
|
|
|
fclose(f); |
|
|
|
|
} |
|
|
|
|
if (buffer) { |
|
|
|
|
sprintf(oldbrightness, "%d", atoi(buffer)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
lockscreen(Display *dpy, int screen) |
|
|
|
|
{ |
|
|
|
|
// Loosely derived from suckless' slock's lockscreen binding logic but
|
|
|
|
|
// alot more coarse, intentionally so can be triggered while grab_key
|
|
|
|
|
// for dwm multikey path already holding..
|
|
|
|
|
int i, ptgrab, kbgrab; |
|
|
|
|
Window root; |
|
|
|
|
root = RootWindow(dpy, screen); |
|
|
|
@ -128,7 +164,7 @@ readinputloop(Display *dpy, int screen) { |
|
|
|
|
int xfd; |
|
|
|
|
int selectresult; |
|
|
|
|
struct timeval xeventtimeout = {10, 0}; |
|
|
|
|
xfd = ConnectionNumber(dpy); |
|
|
|
|
xfd = ConnectionNumber(dpy); |
|
|
|
|
|
|
|
|
|
for (;;) { |
|
|
|
|
FD_ZERO(&fdset); |
|
|
|
@ -153,7 +189,7 @@ readinputloop(Display *dpy, int screen) { |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
lastkeyn = 0; |
|
|
|
|
lastkeysym = NULL; |
|
|
|
|
lastkeysym = XK_Cancel; |
|
|
|
|
switch (keysym) { |
|
|
|
|
case XF86XK_AudioRaiseVolume: |
|
|
|
|
state = StateSuspend; |
|
|
|
@ -176,83 +212,61 @@ readinputloop(Display *dpy, int screen) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int |
|
|
|
|
getoldbrightness() { |
|
|
|
|
char * buffer = 0; |
|
|
|
|
long length; |
|
|
|
|
FILE * f = fopen(brightnessfile, "r"); |
|
|
|
|
if (f) { |
|
|
|
|
fseek(f, 0, SEEK_END); |
|
|
|
|
length = ftell(f); |
|
|
|
|
fseek(f, 0, SEEK_SET); |
|
|
|
|
buffer = malloc(length); |
|
|
|
|
if (buffer) { |
|
|
|
|
fread(buffer, 1, length, f); |
|
|
|
|
} |
|
|
|
|
fclose(f); |
|
|
|
|
} |
|
|
|
|
if (buffer) { |
|
|
|
|
sprintf(oldbrightness, "%d", atoi(buffer)); |
|
|
|
|
void |
|
|
|
|
setpineled(enum Color c) |
|
|
|
|
{ |
|
|
|
|
if (c == Red) { |
|
|
|
|
writefile("/sys/class/leds/red:indicator/brightness", "1"); |
|
|
|
|
writefile("/sys/class/leds/blue:indicator/brightness", "0"); |
|
|
|
|
} else if (c == Blue) { |
|
|
|
|
writefile("/sys/class/leds/red:indicator/brightness", "0"); |
|
|
|
|
writefile("/sys/class/leds/blue:indicator/brightness", "1"); |
|
|
|
|
} else if (c == Purple) { |
|
|
|
|
writefile("/sys/class/leds/red:indicator/brightness", "1"); |
|
|
|
|
writefile("/sys/class/leds/blue:indicator/brightness", "1"); |
|
|
|
|
} else if (c == Off) { |
|
|
|
|
writefile("/sys/class/leds/red:indicator/brightness", "0"); |
|
|
|
|
writefile("/sys/class/leds/blue:indicator/brightness", "0"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
configuresuspendsettingsandwakeupsources() |
|
|
|
|
syncstate() |
|
|
|
|
{ |
|
|
|
|
// Disable all wakeup sources
|
|
|
|
|
struct dirent *wakeupsource; |
|
|
|
|
char wakeuppath[100]; |
|
|
|
|
DIR *wakeupsources = opendir("/sys/class/wakeup"); |
|
|
|
|
if (wakeupsources == NULL) |
|
|
|
|
die("Couldn't open directory /sys/class/wakeup\n"); |
|
|
|
|
while ((wakeupsource = readdir(wakeupsources)) != NULL) { |
|
|
|
|
sprintf( |
|
|
|
|
wakeuppath,
|
|
|
|
|
"/sys/class/wakeup/%s/device/power/wakeup", |
|
|
|
|
wakeupsource->d_name |
|
|
|
|
); |
|
|
|
|
fprintf(stderr, "Disabling wakeup source: %s", wakeupsource->d_name); |
|
|
|
|
writefile(wakeuppath, "disabled"); |
|
|
|
|
fprintf(stderr, ".. ok\n"); |
|
|
|
|
if (state == StateSuspend) { |
|
|
|
|
setpineled(Red); |
|
|
|
|
configuresuspendsettingsandwakeupsources(); |
|
|
|
|
writefile(powerstatefile, "mem"); |
|
|
|
|
state = StateSuspendPending; |
|
|
|
|
syncstate(); |
|
|
|
|
} else if (state == StateNoInput) { |
|
|
|
|
setpineled(Blue); |
|
|
|
|
writefile(brightnessfile, oldbrightness); |
|
|
|
|
} else if (state == StateNoInputNoScreen || state == StateSuspendPending) { |
|
|
|
|
setpineled(Purple); |
|
|
|
|
writefile(brightnessfile, "0"); |
|
|
|
|
} else if (state == StateDead) { |
|
|
|
|
writefile(brightnessfile, oldbrightness); |
|
|
|
|
setpineled(Off); |
|
|
|
|
} |
|
|
|
|
closedir(wakeupsources); |
|
|
|
|
|
|
|
|
|
// Enable powerbutton wakeup source
|
|
|
|
|
fprintf(stderr, "Enable powerbutton wakeup source\n"); |
|
|
|
|
writefile( |
|
|
|
|
"/sys/devices/platform/soc/1f03400.rsb/sunxi-rsb-3a3/axp221-pek/power/wakeup", |
|
|
|
|
"enabled" |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Enable rtc wakeup source
|
|
|
|
|
fprintf(stderr, "Enable rtc wakeup source\n"); |
|
|
|
|
writefile( |
|
|
|
|
"/sys/devices/platform/soc/1f00000.rtc/power/wakeup", |
|
|
|
|
"enabled" |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Temporary hack to disable USB driver that doesn't suspend
|
|
|
|
|
fprintf(stderr, "Disabling buggy USB driver\n"); |
|
|
|
|
writefile( |
|
|
|
|
"/sys/devices/platform/soc/1c19000.usb/driver/unbind", |
|
|
|
|
"1c19000.usb" |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// Temporary hack to disable Bluetooth driver that crashes on suspend 1/5th the time
|
|
|
|
|
fprintf(stderr, "Disabling buggy Bluetooth driver\n"); |
|
|
|
|
writefile( |
|
|
|
|
"/sys/bus/serial/drivers/hci_uart_h5/unbind", |
|
|
|
|
"serial0-0" |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// E.g. make sure we're using CRUST
|
|
|
|
|
fprintf(stderr, "Flip mem_sleep setting to use crust\n"); |
|
|
|
|
writefile("/sys/power/mem_sleep", "deep"); |
|
|
|
|
void |
|
|
|
|
writefile(char *filepath, char *str) |
|
|
|
|
{ |
|
|
|
|
int f; |
|
|
|
|
f = open(filepath, O_WRONLY); |
|
|
|
|
if (f != -1) { |
|
|
|
|
write(f, str, strlen(str)); |
|
|
|
|
close(f); |
|
|
|
|
} else { |
|
|
|
|
fprintf(stderr, "Couldn't open filepath <%s>\n", filepath); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int |
|
|
|
|
main(int argc, char **argv) { |
|
|
|
|
Screen *screen; |
|
|
|
|
int screen; |
|
|
|
|
|
|
|
|
|
if (setuid(0)) |
|
|
|
|
die("setuid(0) failed\n"); |
|
|
|
|