FritzNet

FritzNet is a blog of my path to freedom from Micro$oft. I'm embarking on trip into the Open Source movement. In this blog, I will be documenting my plans, successes and failures.

Monday, June 19, 2006

Function keys are now working

In a previous post, I mentioned that didn't have any function keys working. Well, since I got out of this semester, I fixed this problem. Long ago, I found instructions for making the function keys work on the Gentoo forums. I had to read through them and took out the parts that I didn't need. After paring down all that discussion, I ended up with a much quicker and easier procedure that works.

First, I put the following code into a file called sonyfn.c This code was submitted to the Gentoo forums by Pijalu. If this code is helpful to you, please let him know.


#include
#include
#include
#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"

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

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

close(fd);
return 0;
}


Then I had to compile this by doing a:


$ gcc sonyfn.c -o sonyfn
$ mv sonyfn /usr/bin
$ sudo chown root /usr/bin/sonyfn
$ sudo chmod 4755 /usr/bin/sonyfn


Then to manually run this, you call the program and provide the path to the keyboard. In my case, the keyboard is /dev/input/event0.

So now I need it to launch at boot time, so I'm using the Session GUI to add it to the start up programs.

sonyfn /dev/input/event0 &


I rebooted and it launches just fine.

0 Comments:

Post a Comment

<< Home