Index: hald/linux2/addons/addon-acpi.c =================================================================== RCS file: /cvs/hal/hal/hald/linux2/addons/addon-acpi.c,v retrieving revision 1.13 diff -u -r1.13 addon-acpi.c --- hald/linux2/addons/addon-acpi.c 9 Nov 2005 21:13:30 -0000 1.13 +++ hald/linux2/addons/addon-acpi.c 9 Jan 2006 00:38:27 -0000 @@ -5,6 +5,7 @@ * * Copyright (C) 2005 David Zeuthen, * Copyright (C) 2005 Ryan Lortie + * Copyright (C) 2006 Richard Hughes * * 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 @@ -26,6 +27,8 @@ # include #endif +#define ACPI_UINPUT + #include #include #include @@ -37,10 +40,22 @@ #include #include +#ifdef ACPI_UINPUT +#include +#include +#endif + #include "libhal/libhal.h" #include "../probing/shared.h" +#ifdef ACPI_UINPUT +static int out_fd = -1; +static int uinput_open (void); +static int uinput_event (unsigned int key); +static int uinput_close (void); +#endif + #ifdef ACPI_PROC static FILE * acpi_get_event_fp_kernel (void) @@ -91,6 +106,142 @@ } #endif +#ifdef ACPI_UINPUT +/** Opens the kernel uinput device + * @return Success + */ +static int +uinput_open (void) +{ + int j, i; + struct uinput_user_dev udev_spec = { .name = "Virtual ACPI Keyboard" }; + + /* try to open uinput from all the different places it could be */ + out_fd = open ("/dev/uinput", O_WRONLY | O_NDELAY); + if (out_fd < 0) /* try harder */ + out_fd = open ("/dev/input/uinput", O_WRONLY | O_NDELAY); + if (out_fd < 0) /* try harder */ + out_fd = open ("/dev/misc/uinput", O_WRONLY | O_NDELAY); + if (out_fd < 0) { /* try harder */ + printf ("Cannot open uinput (maybe not root?)\n"); + return FALSE; + } + + /* inform that we'll generate key events */ + j = ioctl (out_fd, UI_SET_EVBIT, EV_KEY) < 0; + j |= ioctl (out_fd, UI_SET_EVBIT, EV_REP) < 0; + + /* set key events we can generate (in this case, all) */ + for (i = KEY_RESERVED; i < BTN_MISC; i++) + j |= ioctl (out_fd, UI_SET_KEYBIT, i) < 0; + if (j) { + printf ("error setting up keyboard input device (maybe not root?)\n"); + return FALSE; + } + /* write down information for creating a new device */ + if (write (out_fd, &udev_spec, sizeof udev_spec) != sizeof udev_spec) { + printf ("error writing input device spec\n"); + return FALSE; + } + /* create, and check */ + if (ioctl (out_fd, UI_DEV_CREATE, 0) < 0) { + printf ("error creating input device\n"); + return FALSE; + } + return TRUE; +} +#endif + +/** Writes to the /dev/uinput device a keypress, i.e. down then up + * + * @param key The event, e.g KEY_BRIGHTNESSUP + * @return Success + */ +static int +uinput_event (unsigned int key) +{ +#ifdef ACPI_UINPUT + struct input_event event; + event.type = EV_KEY; + event.code = key; + event.value = 1; + if (write (out_fd, &event, sizeof event) != sizeof event) { + printf ("error writing down %d/%d/%d to device", EV_KEY, event.value, 1); + return FALSE; + } + event.value = 0; + if (write (out_fd, &event, sizeof event) != sizeof event) { + printf ("error writing up %d/%d/%d to device", EV_KEY, event.value, 0); + return FALSE; + } + return TRUE; +#endif +} + +#ifdef ACPI_UINPUT +/** Closes the /dev/uinput device + * + * @return Success + */ +static int +uinput_close (void) +{ + static struct input_event event = { + .type = EV_SYN, + .code = SYN_REPORT + }; + if (!out_fd) + return FALSE; + write (out_fd, &event, sizeof event); + return TRUE; +} +#endif + +/** If found, does a uinput event and returns the condition name + * + * @param event The acpi event + * @return The ButtonPressed condition + */ +static char * +do_hkey_event (unsigned int event) +{ + /* Toshiba FnESC */ + if (event == 0x101) { + uinput_event (KEY_MUTE); + return "Mute"; + } + /* Toshiba FnF1 */ + if (event == 0x13b) { + uinput_event (KEY_EXIT); /* need KEY_LOCK */ + return "Lock"; + } + /* Toshiba FnF2 */ + if (event == 0x13c) { + uinput_event (KEY_SEARCH); + return "Search"; + } + /* Toshiba FnF3 */ + if (event == 0x13d) { + uinput_event (KEY_SUSPEND); + return "Suspend"; + } + /* Toshiba FnF4 */ + if (event == 0x13e) { + uinput_event (KEY_SLEEP); + return "Hibernate"; + } + /* Toshiba FnF6 */ + if (event == 0x140) { + uinput_event (KEY_BRIGHTNESSDOWN); + return "BrightnessDown"; + } + /* Toshiba FnF7 */ + if (event == 0x141) { + uinput_event (KEY_BRIGHTNESSUP); + return "BrightnessUp"; + } + return NULL; +} static void main_loop (LibHalContext *ctx, FILE *eventfp) @@ -127,8 +278,18 @@ } else if (strncmp (acpi_path, "battery", sizeof ("battery") - 1) == 0) { dbg ("battery event"); libhal_device_rescan (ctx, udi, &error); + } else if (strncmp (acpi_path, "hkey", sizeof ("hkey") - 1) == 0) { + dbg ("hotkey event; acpi_name=%s, acpi_num1=%i, acpi_num2=%i", acpi_name, acpi_num1, acpi_num2); + /* we only do events when the button is pressed, not released */ + if (acpi_num1 == 1) { + char *desc; + const char *uinput_udi = "/org/freedesktop/Hal/devices/acpi_uinput"; + desc = do_hkey_event (acpi_num2); + if (desc) + libhal_device_emit_condition (ctx, + uinput_udi, "ButtonPressed", desc, &error); + } } - } else { dbg ("cannot parse event"); } @@ -156,6 +317,10 @@ return 1; } +#ifdef ACPI_UINPUT + uinput_open (); +#endif + while (1) { #ifdef ACPI_PROC @@ -178,6 +343,10 @@ sleep (5); } +#ifdef ACPI_UINPUT + uinput_close (); +#endif + return 1; }