#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>

// sound stuff
#include <linux/soundcard.h>

// 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

// config hard coded :p
#define  MIXER_DEV      "/dev/mixer"

// 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);
        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;
        char buffer[2];
        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;
        char buffer[2];

        // validate values
        if (b>8) {
                b=8;
        }
        else if (b<1) {
                b=1;
        }

        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);
}

// Pool the fnkey status
int getCodes() {
        FILE* handle;
        char buffer[10];
        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(void) {
        int key;

        nice(10); // be a nice dirty code

        printf("SonyFN loaded\n");
        while(1) { // loop
                if (key=getCodes()) { // get Fn status
                        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();
                        }
                        // rest i don't care
                }
                usleep(300000);
        }
        return 0;
}


