Add a sysfs interface to allow userspace to modify the mapping between
ThinkPad hotkeys and the keycode input events they generate.

Signed-off-by: Henrique de Moraes Holschuh <[EMAIL PROTECTED]>
---
 drivers/misc/thinkpad_acpi.c |  109 +++++++++++++++++++++++++++++++++++++++--
 1 files changed, 103 insertions(+), 6 deletions(-)

diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index fad3bd0..5690247 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -809,6 +809,84 @@ static ssize_t hotkey_bios_mask_show(struct device *dev,
 static struct device_attribute dev_attr_hotkey_bios_mask =
        __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
 
+/* sysfs hotkey event_map ---------------------------------------------- */
+static ssize_t hotkey_event_map_read(struct kobject *kobj, char *buffer,
+                                       loff_t off, size_t count)
+{
+       int res;
+
+       BUG_ON(off < 0);
+
+       /* sanitize */
+       if (off > sizeof(hotkey_event_map))
+               return 0;
+       if (off + count > sizeof(hotkey_event_map))
+               count = sizeof(hotkey_event_map) - off;
+
+       if (count > 0) {
+               res = mutex_lock_interruptible(&hotkey_mutex);
+               if (res < 0)
+                       return res;
+
+               /* Attribute is little-endian.  Since this driver is for 
+                * ia32 and amd-64 only, conversion is not required */
+               memcpy(buffer, (char *)hotkey_event_map + off, count);
+
+               mutex_unlock(&hotkey_mutex);
+       }
+
+       return count;
+}
+
+static ssize_t hotkey_event_map_write(struct kobject *kobj, char *buffer,
+                                       loff_t off, size_t count)
+{
+       unsigned int i;
+       u16 *p;
+       int res;
+
+       /*
+        * Due to weirdness in the sysfs bin attribute support,
+        * for fixed-size attributes, we accept only full writes
+        * of the entire buffer.
+        *
+        * Too bad we can't force a fixed size for the inode,
+        * that would allow proper support.  On 2.6.20, a short
+        * write can truncate the file(!) and break subsequent
+        * reads of the binary attribute.
+        */
+       if (off != 0 || count != sizeof(hotkey_event_map))
+               return -EINVAL;
+
+       /* validate buffer */
+       for (i = 0, p = (u16 *)buffer; i < count; i += 2, p++)
+               if (*p > KEY_MAX)
+                       return -EINVAL;
+
+       res = mutex_lock_interruptible(&hotkey_mutex);
+       if (res < 0)
+               return res;
+
+       /* Attribute is little-endian.  Since this driver is for 
+        * ia32 and amd-64 only, conversion is not required */
+       memcpy((char *)hotkey_event_map + off, buffer, count);
+
+       mutex_unlock(&hotkey_mutex);
+
+       return count;
+}
+
+static struct bin_attribute bin_attr_hotkey_event_map = {
+       .attr = {
+               .name = "hotkey_event_map",
+               .mode = S_IWUSR | S_IRUGO,
+               .owner = THIS_MODULE,
+               },
+       .size = sizeof(hotkey_event_map),
+       .read = hotkey_event_map_read,
+       .write = hotkey_event_map_write,
+};
+
 /* --------------------------------------------------------------------- */
 
 static struct attribute *hotkey_mask_attributes[] = {
@@ -862,6 +940,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                                        hotkey_dev_attributes,
                                        &tpacpi_pdev->dev.kobj);
 
+               if (!res) {
+                       res = sysfs_create_bin_file(
+                               &tpacpi_pdev->dev.kobj,
+                               &bin_attr_hotkey_event_map);
+               }
+
                if (res)
                        return res;
 
@@ -885,6 +969,9 @@ static void hotkey_exit(void)
        }
 
        if (hotkey_dev_attributes) {
+               sysfs_remove_bin_file(&tpacpi_pdev->dev.kobj,
+                                     &bin_attr_hotkey_event_map);
+
                delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
                hotkey_dev_attributes = NULL;
        }
@@ -900,18 +987,28 @@ static void tpacpi_input_send_key(unsigned int keycode)
        }
 }
 
+static void hotkey_send_input_event(int hkey)
+{
+       unsigned int keycode;
+
+       if (hkey > 0x1000 && hkey < 0x1011) {
+               mutex_lock(&hotkey_mutex);
+               keycode = hotkey_event_map[(hkey - 1) & 0x0f];
+               mutex_unlock(&hotkey_mutex);
+
+               tpacpi_input_send_key(keycode);
+       } else {
+               printk(IBM_ERR "unknown hotkey 0x%04x\n", hkey);
+       }
+}
+
 static void hotkey_notify(struct ibm_struct *ibm, u32 event)
 {
        int hkey;
 
        if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
                acpi_bus_generate_event(ibm->acpi->device, event, hkey);
-               if (hkey > 0x1000 && hkey < 0x1011) {
-                       tpacpi_input_send_key(
-                                       hotkey_event_map[(hkey - 1) & 0x0f]);
-               } else {
-                       printk(IBM_ERR "unknown hotkey 0x%04x\n", hkey);
-               }
+               hotkey_send_input_event(hkey);
        } else {
                printk(IBM_ERR "unknown hotkey event %d\n", event);
                acpi_bus_generate_event(ibm->acpi->device, event, 0);
-- 
1.5.1.6


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
ibm-acpi-devel mailing list
ibm-acpi-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ibm-acpi-devel

Reply via email to