#include #include #include #include #include #include #include #include #include #include #include #include #include #define DEBUG gchar *mixername = NULL; gchar *fbname = NULL; gboolean use_alsa = FALSE; gboolean show_help = FALSE; enum actions { VOLUME_UP, VOLUME_DOWN, VOLUME_MUTE, BACKLIGHT_UP, BACKLIGHT_DOWN, EJECT_CD }; struct poptOption options[] = { { "alsa", 'a', POPT_ARG_NONE, &use_alsa, 0, "Use ALSA mixer instead of OSS mixer", NULL}, { "mixer", 'm', POPT_ARG_STRING, &mixername, 0, "Use a device other than /dev/mixer for the volume control", "MIXER"}, { "fb", 'f', POPT_ARG_STRING, &fbname, 0, "Use a device other than /dev/fb for the backlight control", "FB"}, POPT_AUTOHELP {NULL, 0, 0, NULL, 0} }; static void quit(gint i, gchar * msg) { g_print("%s\n", msg); exit(i); } static void do_signal(gint signum) { gchar *msg = 0; /* There's a leak here, but we don't care since we're * quitting the app */ g_strdup_printf("Caught signal %d", signum); quit(signum == SIGTERM ? 0 : -1, msg); } #define open_action_dev(x) open(x,O_RDONLY) static void volume_actions_oss(int action) { #ifdef SINGLE_CHANNEL #define CHANNEL SOUND_MIXER_VOLUME static int mute = 0; #else #define CHANNELS 2 static int channel[CHANNELS] = { SOUND_MIXER_VOLUME, SOUND_MIXER_SPEAKER }; static int channelidx = 0; #define CHANNEL channel[channelidx] #endif int actionfd; static int vol = 0; int parm; actionfd = open_action_dev(mixername); switch (action) { #ifdef SINGLE_CHANNEL case VOLUME_UP: if (!mute) { ioctl(actionfd, MIXER_READ(CHANNEL), &vol); vol = (vol & 0xff) + 8; if (vol > 100) vol = 100; vol |= vol << 8; } //dont increment if unmute from press mute = 0; parm = vol; break; case VOLUME_DOWN: ioctl(actionfd, MIXER_READ(CHANNEL), &parm); if (parm || mute) { //if we aren't muted anymore or we think we are muted mute = 0; //not muted now if (parm) { //weren't anyway vol = parm; vol = (vol & 0xff) - 8; if (vol < 0) vol = 0; vol |= vol << 8; } //dont decrement if unmuting due to press parm = vol; } else { //no vol and no mute... we're mute now.. mute = 1; parm = 0; } break; case VOLUME_MUTE: if (!mute) { ioctl(actionfd, MIXER_READ(CHANNEL), &parm); if (!parm) { //already muted and we didn't know it parm = vol; //if vol==0, it was deliberate. mute = 0; } else { //have volume. mute vol = parm; parm = 0; mute = 1; } } else { parm = vol; mute = 0; } break; #else case VOLUME_UP: vol = (vol & 0xff) + 8; if (vol > 100) vol = 100; vol |= vol << 8; break; case VOLUME_DOWN: vol = (vol & 0xff) - 8; if (vol < 0) vol = 0; vol |= vol << 8; break; case VOLUME_MUTE: ioctl(actionfd, MIXER_READ(CHANNEL), &vol); parm = 0; ioctl(actionfd, MIXER_WRITE(CHANNEL), &parm); channelidx = (channelidx + 1) % CHANNELS; parm = vol; break; #endif } ioctl(actionfd, MIXER_WRITE(CHANNEL), &parm); close(actionfd); } static void backlight_actions(int action) { int actionfd; __u32 bklight; int foo; actionfd = open_action_dev(fbname); ioctl(actionfd, FBIOGET_BACKLIGHT, &bklight); switch (action) { case BACKLIGHT_UP: bklight++; if (bklight > FBBACKLIGHT_MAX) bklight = FBBACKLIGHT_MAX; break; case BACKLIGHT_DOWN: if (bklight > FBBACKLIGHT_OFF) bklight--; break; } foo = ioctl(actionfd, FBIOSET_BACKLIGHT, &bklight); if (foo <0) perror("keyevd"); close(actionfd); } int main(int argc, const char **argv) { poptContext pctx; int eventfd = -1; struct input_event inp; struct sigaction sigpipe = { {SIG_IGN}, {{0}}, SA_RESTART, 0 }; struct sigaction sigterm = { {do_signal}, {{0}}, SA_RESTART, 0 }; short ids[4]; char *filename; int i; pctx = poptGetContext(NULL, argc, argv, options, 0); while ((i = poptGetNextOpt(pctx)) != -1) { //everything should be handled poptStrerror(i); printf("%s: %s (-? for help)\n", poptStrerror(i), poptBadOption(pctx, 0)); exit(0); } if (mixername == NULL) { if (use_alsa == FALSE) mixername = g_strdup("/dev/mixer"); else g_print("somebody please fix this ;)\n"); } if (fbname == NULL) fbname = g_strdup("/dev/fb0"); if (sigaction(SIGTERM, &sigterm, 0)) quit(-1, "could not install SIGTERM handler"); if (sigaction(SIGPIPE, &sigpipe, 0)) quit(-1, "could not install SIGPIPE handler"); for (i = 0; i < 32; i++) { filename = g_strdup_printf("/dev/input/event%i", i); eventfd = open(filename, O_RDONLY); if (eventfd >= 0) { ioctl(eventfd, EVIOCGID, ids); if ((ids[2] & 0xfff) == 0x71f) { printf("Powerbook Button device found at event%i.\n", i); syslog(LOG_INFO, "Powerbook Button device found at event%i.\n", i); break; } #ifdef DEBUG fprintf(stderr, "[%x] ids - %x %x %x %x\n", i, ids[0], ids[1], ids[2], ids[3]); #endif close(eventfd); eventfd = -1; } #ifdef DEBUG else { fprintf(stderr, "[%x] nil\n", i); } #endif } if (eventfd < 0) { printf("Powerbook Button event device not found.\n"); exit(-1); } #ifndef DEBUG { int pid = fork(); if (pid < 0) { printf("Couldn't fork\n"); exit(-1); } if (pid > 0) quit(0, "parent exiting [note PID]"); chdir("/"); setsid(); close(0); close(1); close(2); } #endif while (read(eventfd, &inp, sizeof(inp))) { if (inp.value) { g_print("Event %0x caught\n", inp.code); switch (inp.code) { case KEY_MUTE: if (inp.value == 2) continue; if (!use_alsa) volume_actions_oss(VOLUME_MUTE); else g_print("fixme\n"); break; case KEY_VOLUMEDOWN: if (!use_alsa) volume_actions_oss(VOLUME_DOWN); else g_print("fixme\n"); break; case KEY_VOLUMEUP: if (!use_alsa) volume_actions_oss(VOLUME_UP); else g_print("fixme\n"); break; case KEY_BRIGHTNESSDOWN: backlight_actions(BACKLIGHT_DOWN); break; case KEY_BRIGHTNESSUP: backlight_actions(BACKLIGHT_UP); break; case KEY_EJECTCD: system("eject"); break; } } } close(eventfd); return 0; }