/* sonyfn: fnkey handler for the Sony Vaio FS series laptops * * Author: Pierre Poissinger * Modified by: Spencer Shimko * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include // osd stuff #include #include #include // input thing #include // sound stuff #include // keys #define FN_F2 1 // cut sound #define FN_F3 2 // volume - #define FN_F4 4 // volume + #define FN_F5 8 // Brightness - #define FN_F6 16 // Brightness + #define FN_F7 32 // LCD/SCREEN #define FN_F10 128 // Zoom in #define FN_F12 64 // Suspend #define S1_BTN 4096 // S1 custom button #define S2_BTN 8192 // S2 custom button #define FN_INPUT_VALUE 245 // Fn key generate a 245 value #define FN_INPUT_TYPE 4 // a 4 type #define FN_INPUT_CODE 4 // and a 4 code // config hard coded :p #define MIXER_DEV "/dev/mixer" // The FS series seems to support 8 brightness levels #define MAX_BRIGHT 8 #define MIN_BRIGHT 1 // the volume osd color #define OSD_VCOLOR "red" // the brightness osd color #define OSD_BCOLOR "blue" // the osd font... change the 7th position for size // or use xfontsel to explore the options #define OSD_FONT "-*-*-*-*-*-*-20-*-*-*-*-*-*-*" // the length of time the osd is shown #define OSD_TIME 3 // volume scaling factor for OSD #define OSD_VSCALE 250 // the onscreen display static xosd *disp_obj = '\0'; int osd_brightness(int level){ // the size of the increment static int inc_size = 100.0 / (MAX_BRIGHT - 1); int retval = 0; int pos; retval &= xosd_set_bar_length(disp_obj, 100); retval &= xosd_set_pos(disp_obj, XOSD_bottom); retval &= xosd_set_align(disp_obj, XOSD_center); retval &= xosd_set_shadow_offset(disp_obj, 1); retval &= xosd_set_outline_offset(disp_obj, 1); retval &= xosd_set_vertical_offset(disp_obj, 30); retval &= xosd_set_colour(disp_obj, OSD_BCOLOR); retval &= xosd_set_timeout(disp_obj, OSD_TIME); retval &= xosd_set_font(disp_obj, OSD_FONT); if (retval){ fprintf(stderr,"Failed setup onscreen display: %s\n", xosd_error); } else { if (level == MAX_BRIGHT){ pos = 100; } else { pos = level * inc_size - inc_size; } retval = xosd_display(disp_obj, 0, XOSD_slider, pos); retval = xosd_display(disp_obj, 1, XOSD_string, "Brightness"); if (retval == -1){ fprintf(stderr,"Failed to display information onscreen: %s\nAre you running X?\n", xosd_error); } } return 1; } int osd_volume(int level){ int retval = 0; retval &= xosd_set_bar_length(disp_obj, 100); retval &= xosd_set_pos(disp_obj, XOSD_bottom); retval &= xosd_set_align(disp_obj, XOSD_center); retval &= xosd_set_shadow_offset(disp_obj, 1); retval &= xosd_set_outline_offset(disp_obj, 1); retval &= xosd_set_vertical_offset(disp_obj, 30); retval &= xosd_set_colour(disp_obj, OSD_VCOLOR); retval &= xosd_set_timeout(disp_obj, OSD_TIME); retval &= xosd_set_font(disp_obj, OSD_FONT); if (retval){ fprintf(stderr,"Failed setup onscreen display: %s\n", xosd_error); } else { retval = xosd_display(disp_obj, 0, XOSD_slider, level / OSD_VSCALE); retval = xosd_display(disp_obj, 1, XOSD_string, "Volume"); if (retval == -1){ fprintf(stderr,"Failed to display information onscreen: %s\nAre you running X?\n", xosd_error); } } return 1; } // SOUND HANDLER int get_volume(int *value) { int mixer = open(MIXER_DEV, O_RDONLY); if (mixer) { ioctl(mixer, SOUND_MIXER_READ_VOLUME, value); close(mixer); return 0; } else return 1; } int set_volume(int *value) { int mixer = open(MIXER_DEV, O_RDWR); if (mixer) { ioctl(mixer, SOUND_MIXER_WRITE_VOLUME, value); close(mixer); osd_volume(*value); return 0; } else return 1; } int volume_up() { int value = 0; get_volume(&value); if (value < 0x5a5a) value += 0x0a0a; else value = 0x6464; set_volume(&value); return 0; } int volume_down() { int value = 0; get_volume(&value); if (value > 0x0a0a) value -= 0x0a0a; else value = 0; set_volume(&value); return 0; } int oldvalue; int mute() { int value; get_volume(&value); if (value) { oldvalue=value; value=0; set_volume(&value); } else { if (!oldvalue) { volume_up(); } else { set_volume(&oldvalue); } } return 0; } // END OF SOUND /* Return current brightness of the screen */ int getBrightness() { FILE* handle; int ret; if ((handle=fopen("/proc/acpi/sony/brightness","rb"))==NULL) { perror("Error opening /proc/acpi/sony/brightness"); exit(-1); } if (fscanf(handle,"%d",&ret)!=1) { perror("Error reading /proc/acpi/sony/brightness"); exit(-1); } fclose(handle); return ret; } /* Set the current brightness of the screen */ void setBrightness(int b) { FILE* handle; // validate values if (b > MAX_BRIGHT) { b = MAX_BRIGHT; } else if (b < MIN_BRIGHT) { b = MIN_BRIGHT; } if ((handle=fopen("/proc/acpi/sony/brightness","wb"))==NULL) { perror("Error opening /proc/acpi/sony/brightness"); exit(-1); } if (fprintf(handle,"%d",b)!=1) { perror("Error writing /proc/acpi/sony/brightness"); exit(-1); } fclose(handle); osd_brightness(b); } // Pool the fnkey status int getCodes() { FILE* handle; int ret; if ((handle=fopen("/proc/acpi/sony/fnkey","rb"))==NULL) { perror("Error opening /proc/acpi/sony/fnkey"); exit(-1); } if (fscanf(handle,"%d",&ret)!=1) { perror("Error reading /proc/acpi/sony/fnkey"); exit(-1); } fclose(handle); return ret; } // main and loop int main(int argc, char **argv) { // event interface int fd = -1; /* the file descriptor for the device */ int i; /* loop counter */ size_t read_bytes; /* how many bytes were read */ struct input_event ev[64]; /* the events (up to 64 at once) */ /* key code */ int key; /* used if event hit fn */ int hasSomething; // initialize the osd disp_obj = xosd_create(2); if (setlocale(LC_ALL, "") == NULL || !XSupportsLocale()) fprintf(stderr, "Locale not available, expect problems with fonts.\n"); /* open event interface*/ if (argc != 2) { /* i don't like outputs... fprintf(stderr, "Using /dev/input/event0 for input\n"); fprintf(stderr, "Overide with %s event-device\n", argv[0]); */ if ((fd = open("/dev/input/event0", O_RDONLY)) < 0) { perror("event interface open failed"); exit(1); } } else { if ((fd = open(argv[1], O_RDONLY)) < 0) { perror("event interface open failed"); exit(1); } } nice(10); // be a nice dirty code (less dirty but keep nice) while(1) { /* loop */ hasSomething=0; /* nothing yet */ /* read the event interface */ read_bytes = read(fd, ev, sizeof(struct input_event) * 64); if (read_bytes < (int) sizeof(struct input_event)) { perror("sonyfn: short read"); exit (1); } /* Loop for all readed events until we have something interesting.. */ for (i = 0;! hasSomething && ( i < (int) (read_bytes / sizeof(struct input_event)) ); i++) { hasSomething= (ev[i].type == FN_INPUT_TYPE) && (ev[i].code == FN_INPUT_CODE) && (ev[i].value == FN_INPUT_VALUE); } /* If we got a FN event, plz do something...*/ if ( hasSomething && (key=getCodes()) ) { if ((key & FN_F5)==FN_F5) { // lower brightness setBrightness(getBrightness()-1); } if ((key & FN_F6)==FN_F6) { // higher brightness setBrightness(getBrightness()+1); } if ((key & FN_F2)==FN_F2){ mute(); } if ((key & FN_F3)==FN_F3) { volume_down(); } if ((key & FN_F4)==FN_F4) { volume_up(); } if ((key & FN_F12)==FN_F12) { if (fork()==0) { /* that's my home made script for swsusp #!/bin/sh sync echo "disk" > /sys/power/state */ if (execv("/bin/hibernate",NULL)==-1) { perror("Cannot run hibernate"); } } } /* rest i still don't care */ } }// while xosd_destroy(disp_obj); close(fd); return 0; }