]> Devoid-pointer.net GitWeb - omnibook.git/commitdiff
* Merge (189:HEAD) experimental branch back to trunk
authorMathieu Bérard <mathieu.berard@crans.org>
Fri, 10 Nov 2006 23:22:06 +0000 (23:22 +0000)
committerMathieu Bérard <mathieu.berard@crans.org>
Fri, 10 Nov 2006 23:22:06 +0000 (23:22 +0000)
31 files changed:
Makefile
ac.c
acpi.c
apmemu.c [deleted file]
apmemu.h [deleted file]
battery.c
blank.c
bluetooth.c
compal.c
compat.h
display.c
doc/ChangeLog
dock.c
dump.c
ec.c
fan.c
fan_policy.c
hardware.h [moved from ec.h with 78% similarity]
hotkeys.c
init.c
kbc.c [new file with mode: 0644]
lcd.c
lib.c [new file with mode: 0644]
muteled.c
nbsmi.c
omnibook.h
pio.c [new file with mode: 0644]
polling.c [new file with mode: 0644]
temperature.c
touchpad.c
wireless.c

index dc57aef3e2a9e673e3de34e857533ab76a7db7b0..71ec838c972792f9042ab23113c97b3cb03905ac 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -47,10 +47,10 @@ EXTRA_CFLAGS += -D OMNIBOOK_STANDALONE $(DEBUG)
 EXTRA_LDFLAGS +=  $(src)/sections.lds
 
 
-OBJS   = init.o ec.o compal.o acpi.o nbsmi.o \
-          ac.o apmemu.o battery.o blank.o bluetooth.o display.o dock.o dump.o \
-         fan.o fan_policy.o hotkeys.o info.o lcd.o muteled.o temperature.o \
-          touchpad.o wireless.o
+OBJS   = init.o lib.o ec.o kbc.o pio.o compal.o acpi.o nbsmi.o \
+          ac.o battery.o blank.o bluetooth.o display.o dock.o dump.o \
+         fan.o fan_policy.o hotkeys.o info.o lcd.o muteled.o polling.o \
+         temperature.o touchpad.o wireless.o
 
 obj-m         += $(MODULE_NAME).o
 omnibook-objs := $(OBJS)
diff --git a/ac.c b/ac.c
index 3b2ce968b5c45bf6d9f848aea72337853295864a..b3bebc76d7a0d60d813d5655d3f215d33fc4322c 100644 (file)
--- a/ac.c
+++ b/ac.c
  */
 
 #include "omnibook.h"
-#include "ec.h"
-
-int omnibook_get_ac(struct omnibook_operation *io_op)
-{
-       u8 ac;
-       int retval;
-
-       retval = io_op->backend->byte_read(io_op, &ac);
-       if (!retval)
-               retval = !!ac;
-       return retval;
-}
+#include "hardware.h"
 
 static int omnibook_ac_read(char *buffer, struct omnibook_operation *io_op)
 {
        int len = 0;
-       int ac;
+       u8 ac;
+       int retval;
 
-       ac = omnibook_get_ac(io_op);
-       if (ac < 0)
-               return ac;
+       retval = backend_byte_read(io_op, &ac);
+       if (retval < 0)
+               return retval;
 
-       len += sprintf(buffer + len, "AC %s\n", (ac) ? "on-line" : "off-line");
+       len += sprintf(buffer + len, "AC %s\n", (!!ac) ? "on-line" : "off-line");
 
        return len;
 }
diff --git a/acpi.c b/acpi.c
index 369e4f9a648e57d44e6e18d0bfa11642241674b7..02dd3e614695aa0345c1e50c2c8dc554a3c6fb4e 100644 (file)
--- a/acpi.c
+++ b/acpi.c
@@ -16,7 +16,7 @@
  */
 
 #include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
 
 #ifdef CONFIG_ACPI
 
@@ -79,7 +79,6 @@ static struct acpi_driver omnibook_bt_driver = {
 struct acpi_backend_data {
        acpi_handle ec_handle;  /* Handle on ACPI EC device */
        acpi_handle bt_handle;  /* Handle on ACPI BT device */
-       struct kref refcount;   /* Reference counter of this backend */
 };
 
 /*
@@ -99,16 +98,16 @@ static int omnibook_acpi_init(const struct omnibook_operation *io_op)
        }
 
        if (!priv_data) {
-               dprintk("Try to init ACPI backend\n");  
-               
+               dprintk("Try to init ACPI backend\n");
+               mutex_init(&io_op->backend->mutex);
+               mutex_lock(&io_op->backend->mutex);
+               kref_init(&io_op->backend->kref);
                priv_data = kzalloc(sizeof(struct acpi_backend_data), GFP_KERNEL);
                if (!priv_data) {
                        retval = -ENOMEM;
-                       goto out;
+                       goto error0;
                }
 
-               kref_init(&priv_data->refcount);
-
                /* Locate ACPI EC device, acpi_get_handle set dev_handle to NULL if not found */
                for (i = 0; i < ARRAY_SIZE(ec_dev_list); i++) {
                        if (acpi_get_handle(NULL, ec_dev_list[i], &dev_handle) == AE_OK) {
@@ -121,45 +120,46 @@ static int omnibook_acpi_init(const struct omnibook_operation *io_op)
                if(!dev_handle) {
                        printk(O_ERR "Can't get handle on ACPI EC device.\n");
                        retval = -ENODEV;
-                       goto err;
+                       goto error1;
                }
-               
-               io_op->backend->data = (void *) priv_data;
 
+               io_op->backend->data = (void *) priv_data;
+               
                /* attempt to register Toshiba bluetooth ACPI driver */
                acpi_bus_register_driver(&omnibook_bt_driver);
-               
+
                dprintk("ACPI backend init OK\n");
-               goto out;
+               mutex_unlock(&io_op->backend->mutex);
+               return 0;
 
        } else {
                dprintk("ACPI backend has already been initialized\n");
-               kref_get(&priv_data->refcount);
+               kref_get(&io_op->backend->kref);
                return 0;
        }
                
-       err:
+       error1:
        kfree(priv_data);
        io_op->backend->data = NULL;
-       out:
+       error0:
+       mutex_unlock(&io_op->backend->mutex);
+       mutex_destroy(&io_op->backend->mutex);
        return retval;
 }
 
 static void omnibook_acpi_free(struct kref *ref)
 {
-       struct acpi_backend_data *priv_data;
-       priv_data = container_of(ref, struct acpi_backend_data, refcount);
+       struct omnibook_backend *backend;
+       backend = container_of(ref, struct omnibook_backend, kref);
        dprintk("ACPI backend not used anymore: disposing\n");
        acpi_bus_unregister_driver(&omnibook_bt_driver);
-       kfree(priv_data);
+       kfree(backend->data);
 }
 
 static void omnibook_acpi_exit(const struct omnibook_operation *io_op)
 {
-       struct acpi_backend_data *priv_data;
        dprintk("Trying to dispose ACPI backend\n");
-       priv_data = (struct acpi_backend_data *) io_op->backend->data;
-       kref_put(&priv_data->refcount, omnibook_acpi_free);
+       kref_put(&io_op->backend->kref, omnibook_acpi_free);
 }
 
 /*
@@ -168,10 +168,11 @@ static void omnibook_acpi_exit(const struct omnibook_operation *io_op)
  */
 static int omnibook_acpi_execute(acpi_handle dev_handle, char *method, const int *param, int *result)
 {
+
        struct acpi_object_list args_list;
        struct acpi_buffer buff;
        union acpi_object arg, out_objs[1];
-
+       
        if (param) {
                args_list.count = 1;
                args_list.pointer = &arg;
@@ -210,6 +211,7 @@ static int omnibook_acpi_bt_add(struct acpi_device *device)
        dprintk("Enabling found Toshiba Bluetooth ACPI device.\n");
        strcpy(acpi_device_name(device), TOSHIBA_ACPI_DEVICE_NAME);
         strcpy(acpi_device_class(device), TOSHIBA_ACPI_BT_CLASS);
+
        /* Save handle in backend private data structure. ugly. */
        priv_data->bt_handle = device->handle;
 
diff --git a/apmemu.c b/apmemu.c
deleted file mode 100644 (file)
index 7c9a57e..0000000
--- a/apmemu.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * apmemu.c -- /proc/apm emulation
- * 
- * 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 the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- * 
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * Written by Soós Péter <sp@osb.hu>, 2002-2004
- * Modified by Mathieu Bérard <mathieu.berard@crans.org>, 2006
- */
-
-#include "omnibook.h"
-
-#ifdef CONFIG_OMNIBOOK_LEGACY
-
-#ifdef CONFIG_APM
-#include <linux/apm_bios.h>
-#endif
-
-#include <asm/system.h>
-#include <asm/io.h>
-
-#include "apmemu.h"
-
-/* Arguments, with symbols from linux/apm_bios.h.  Information is
-   from the Get Power Status (0x0a) call unless otherwise noted.
-   0) Linux driver version (this will change if format changes)
-   1) APM BIOS Version.  Usually 1.0, 1.1 or 1.2.
-   2) APM flags from APM Installation Check (0x00):
-      bit 0: APM_16_BIT_SUPPORT
-      bit 1: APM_32_BIT_SUPPORT
-      bit 2: APM_IDLE_SLOWS_CLOCK
-      bit 3: APM_BIOS_DISABLED
-      bit 4: APM_BIOS_DISENGAGED
-   3) AC line status
-      0x00: Off-line
-      0x01: On-line
-      0x02: On backup power (BIOS >= 1.1 only)
-      0xff: Unknown
-   4) Battery status
-      0x00: High
-      0x01: Low
-      0x02: Critical
-      0x03: Charging
-      0x04: Selected battery not present (BIOS >= 1.2 only)
-      0xff: Unknown
-   5) Battery flag
-      bit 0: High
-      bit 1: Low
-      bit 2: Critical
-      bit 3: Charging
-      bit 7: No system battery
-      0xff: Unknown
-   6) Remaining battery life (percentage of charge):
-      0-100: valid
-      -1: Unknown
-   7) Remaining battery life (time units):
-      Number of remaining minutes or seconds
-      -1: Unknown
-   8) min = minutes; sec = seconds */
-
-extern struct omnibook_feature ac_driver;
-
-static int omnibook_apmemu_read(char *buffer, struct omnibook_operation *io_op)
-{
-       int retval;
-       int len = 0;
-       int ac;
-
-       struct omnibook_battery_state battstat;
-
-       struct apm_features {
-               char *drvver;
-               char *apmver;
-               u8 apmflags;
-               u8 ac;
-               u8 battstat;
-               u8 battflags;
-               u8 gauge;
-               int time;
-               char *units;
-       };
-
-       struct apm_features apm = {
-               APMEMU_DRIVER_VERSION,
-               APMEMU_APM_VERSION,
-               APMEMU_32_BIT_SUPPORT | APMEMU_BIOS_DISABLED,
-               APMEMU_AC_UNKNOWN,
-               APMEMU_BATTSTAT_UNKN,
-               0x00,
-               APMEMU_BATTLIFE_UNKN,
-               APMEMU_BATTLIFE_UNKN,
-               "?"
-       };
-
-/*
- * FIXME: Broken, how do we know ac and battery are in a usable state ?
- */
-       ac = omnibook_get_ac(ac_driver.io_op);
-       apm.ac = (ac) ? APMEMU_AC_ONLINE : APMEMU_AC_OFFLINE;
-       /* Asking for Battery 0 as APM does */
-       retval = omnibook_get_battery_status(0, &battstat);
-       if (retval == 0)
-               apm.gauge = battstat.gauge;
-       if (apm.gauge >= APMEMU_BATTERY_LOW) {
-               apm.battflags = apm.battflags | APMEMU_BATTFLAG_HIGH;
-               apm.battstat = APMEMU_BATTSTAT_HIGH;
-       } else {
-               apm.battflags = apm.battflags | APMEMU_BATTFLAG_LOW;
-               apm.battstat = APMEMU_BATTSTAT_LOW;
-       }
-       if (battstat.status == OMNIBOOK_BATTSTAT_CHARGING) {
-               apm.battflags = apm.battflags | APMEMU_BATTFLAG_CHR;
-               apm.battstat = APMEMU_BATTSTAT_CHR;
-       }
-       if (battstat.status == OMNIBOOK_BATTSTAT_CRITICAL) {
-               apm.battflags = apm.battflags | APMEMU_BATTFLAG_CRIT;
-               apm.battstat = APMEMU_BATTSTAT_CRIT;
-       }
-
-       len += sprintf(buffer + len, "%s %s 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
-                      apm.drvver, apm.apmver, apm.apmflags, apm.ac, apm.battstat, apm.battflags,
-                      apm.gauge, apm.time, apm.units);
-
-       return len;
-}
-
-static int __init omnibook_apmemu_init(struct omnibook_operation *io_op)
-{
-#ifdef CONFIG_APM
-       if (!apm_info.disabled) {
-               printk(O_INFO "Real APM support is present, emulation is not necessary.\n");
-               return -ENODEV;
-       }
-#endif
-       return 0;
-}
-
-static struct omnibook_feature __declared_feature apmemu_driver = {
-       .name = "apmemu",
-       .proc_entry = "apm",    /* create /proc/apm */
-       .enabled = 0,           /* This feature is broken */
-       .read = omnibook_apmemu_read,
-       .init = omnibook_apmemu_init,
-       .ectypes = XE3GF | XE3GC | TSP10,
-};
-
-module_param_named(apmemu, apmemu_driver.enabled, int, S_IRUGO);
-MODULE_PARM_DESC(apmemu, "Use 0 to disable, 1 to enable /proc/apm emulation");
-
-#endif                         /* CONFIG_OMNIBOOK_LEGACY */
-/* End of file */
diff --git a/apmemu.h b/apmemu.h
deleted file mode 100644 (file)
index b12cab5..0000000
--- a/apmemu.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * apmemu.c -- code to emulate /proc/apm
- * 
- * 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 the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- * 
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * Written by Soós Péter <sp@osb.hu>, 2002-2004
- */
-
-
-#define APMEMU_DRIVER_VERSION  "1.16"
-#define APMEMU_APM_VERSION     "1.2"
-
-#define APMEMU_BATTERY_LOW     30      /* Battery low threshold */
-
-#define APMEMU_16_BIT_SUPPORT  0x01    /* 16 bit APM BIOS */
-#define APMEMU_32_BIT_SUPPORT  0x02    /* 32 bit APM BIOS */
-#define APMEMU_IDLE_SLOWS_CLOCK        0x04
-#define APMEMU_BIOS_DISABLED   0x08    /* APM BIOS disabled */
-#define APMEMU_BIOS_DISENGAGED 0x10    /* APM BIOS disengaged */
-
-#define APMEMU_AC_OFFLINE      0x00    /* AC offline */
-#define APMEMU_AC_ONLINE       0x01    /* AC online */
-#define APMEMU_AC_BACKUP       0x02    /* On backup power */
-#define APMEMU_AC_UNKNOWN      0xFF    /* Unkonwn status */
-
-#define APMEMU_BATTSTAT_HIGH   0x00    /* Remaining battery capacity is high */
-#define APMEMU_BATTSTAT_LOW    0x01    /* Remaining battery capacity is low */
-#define APMEMU_BATTSTAT_CRIT   0x02    /* Battery status is critical */
-#define APMEMU_BATTSTAT_CHR    0x03    /* Battery is charging */
-#define APMEMU_BATTSTAT_MISS   0x04    /* Battery is not present */
-
-#define APMEMU_BATTFLAG_HIGH   0x01    /* Remaining battery capacity is high bit */
-#define APMEMU_BATTFLAG_LOW    0x02    /* Remaining battery capacity is low bit */
-#define APMEMU_BATTFLAG_CRIT   0x04    /* Battery status is critical bit */
-#define APMEMU_BATTFLAG_CHR    0x08    /* Battery is charging bit */
-#define APMEMU_BATTFLAG_MISS   0x80    /* Battery is not present bit */
-
-#define APMEMU_BATTSTAT_UNKN   0xff    /* Status is unknown */
-
-#define APMEMU_BATTLIFE_UNKN   -1      /* Remaining battery capacity is unknown */
index 77e1e8a79a860ed6a14c77117838acaa60bacaec..189afdf141b8da08f5846ca5a6de248e1a0b049b 100644 (file)
--- a/battery.c
+++ b/battery.c
@@ -16,8 +16,7 @@
  */
 
 #include "omnibook.h"
-
-#include "ec.h"
+#include "hardware.h"
 
 static int ec_read16(u8 addr, u16 * data)
 {
@@ -25,7 +24,6 @@ static int ec_read16(u8 addr, u16 * data)
        u8 high;
        u8 low;
        u16 result;
-
        retval = legacy_ec_read(addr, &low);
        if (retval)
                return retval;
@@ -197,7 +195,7 @@ static int omnibook_get_battery_info(int num, struct omnibook_battery_info *batt
  *    1 - Battery is not present
  *    2 - Not supported
  */
-int omnibook_get_battery_status(int num, struct omnibook_battery_state *battstat)
+static int omnibook_get_battery_status(int num, struct omnibook_battery_state *battstat)
 {
        int retval;
        u8 status;
diff --git a/blank.c b/blank.c
index 7380412b0658e9f5a23d8e70ce40f2d895003265..a059d866a01b355a82a9be7cc0b21ea22b8e8301 100644 (file)
--- a/blank.c
+++ b/blank.c
 #include "omnibook.h"
 
 #include <asm/io.h>
-#include "ec.h"
+#include "hardware.h"
 
 static struct omnibook_feature blank_driver;
 
-static int omnibook_console_blank_enabled = 0;
-
+/* 
+ * console_blank_hook pointer manipulation is lock protected
+ */
 extern int (*console_blank_hook) (int);
+static DEFINE_SPINLOCK(blank_spinlock);
 
-/*
- * We would need an io_op parameter,but we are bound to the crapy
- * console_blank_hook here
- */
 
 int omnibook_lcd_blank(int blank)
 {
+       struct omnibook_feature *blank_feature = omnibook_find_feature("blank");
        int retval = 0;
 
-       if(!blank_driver.io_op)
+       if(!blank_feature)
                return -ENODEV;
 
-       if (blank_driver.io_op->backend == PIO)
-               omnibook_apply_write_mask(blank_driver.io_op, blank);
-       else if (blank_driver.io_op->backend == KBC || blank_driver.io_op->backend == CDI)
-               omnibook_toggle(blank_driver.io_op, blank);
+       if (blank_feature->io_op->backend == PIO)
+               omnibook_apply_write_mask(blank_feature->io_op, blank);
+       else if (blank_feature->io_op->backend == KBC || blank_feature->io_op->backend == CDI)
+               omnibook_toggle(blank_feature->io_op, blank);
        else {
                retval = -ENODEV;
        }
@@ -51,42 +50,46 @@ int omnibook_lcd_blank(int blank)
 
 static int console_blank_register_hook(void)
 {
-       if (omnibook_console_blank_enabled == 0) {
+       spin_lock(&blank_spinlock);
+       if (console_blank_hook != omnibook_lcd_blank) {
                if (console_blank_hook == NULL) {
                        console_blank_hook = omnibook_lcd_blank;
                        printk(O_INFO "LCD backlight turn off at console blanking is enabled.\n");
-
-                       omnibook_console_blank_enabled = 1;
-               } else {
+               } else 
                        printk(O_INFO "There is a console blanking solution already registered.\n");
-               }
        }
+       spin_unlock(&blank_spinlock);
        return 0;
 }
 
 static int console_blank_unregister_hook(void)
 {
+       int retval;
+       spin_lock(&blank_spinlock);
        if (console_blank_hook == omnibook_lcd_blank) {
                console_blank_hook = NULL;
                printk(O_INFO "LCD backlight turn off at console blanking is disabled.\n");
-               omnibook_console_blank_enabled = 0;
        } else if (console_blank_hook) {
                printk(O_WARN "You can not disable another console blanking solution.\n");
-               return -EBUSY;
+               retval = -EBUSY;
        } else {
                printk(O_INFO "Console blanking already disabled.\n");
-               return 0;
        }
-       return 0;
+       spin_unlock(&blank_spinlock);
+       return retval;
 }
 
 static int omnibook_console_blank_read(char *buffer, struct omnibook_operation *io_op)
 {
        int len = 0;
 
+       spin_lock(&blank_spinlock);
+
        len +=
            sprintf(buffer + len, "LCD console blanking hook is %s\n",
-                   (omnibook_console_blank_enabled) ? "enabled" : "disabled");
+                   (console_blank_hook == omnibook_lcd_blank) ? "enabled" : "disabled");
+
+       spin_unlock(&blank_spinlock);
 
        return len;
 }
@@ -97,17 +100,15 @@ static int omnibook_console_blank_write(char *buffer, struct omnibook_operation
 
        switch (*buffer) {
        case '0':
-               if ((retval = console_blank_unregister_hook()))
-                       return retval;
+               retval = console_blank_unregister_hook();
                break;
        case '1':
-               if ((retval = console_blank_register_hook()))
-                       return retval;
+               retval = console_blank_register_hook();
                break;
        default:
-               return -EINVAL;
+               retval = -EINVAL;
        }
-       return 0;
+       return retval;
 }
 
 static int __init omnibook_console_blank_init(struct omnibook_operation *io_op)
index 8e84afb6b08b6dfae6db502b38bc11b9752ffa2f..acb0e5be2d767056b1770e8ff7cb788b29b48559 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
 
 static int omnibook_bt_read(char *buffer, struct omnibook_operation *io_op)
 {
@@ -24,7 +24,7 @@ static int omnibook_bt_read(char *buffer, struct omnibook_operation *io_op)
        int retval;
        unsigned int state;
 
-       if ((retval = io_op->backend->aerial_get(io_op, &state)))
+       if ((retval = backend_aerial_get(io_op, &state)))
                return retval;
 
        len +=
@@ -42,23 +42,29 @@ static int omnibook_bt_write(char *buffer, struct omnibook_operation *io_op)
        int retval = 0;
        unsigned int state;
 
-       if ((retval = io_op->backend->aerial_get(io_op, &state)))
-               return retval;
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;    
+
+       if ((retval = __backend_aerial_get(io_op, &state)))
+               goto out;
 
        if (*buffer == '0')
                state &= ~BT_STA;
        else if (*buffer == '1')
                state |= BT_STA;
-       else
-               return -EINVAL;
+       else {
+               retval = -EINVAL;
+               goto out;
+       }
 
-       if ((retval = io_op->backend->aerial_set(io_op, state)))
-               return retval;
+       retval = __backend_aerial_set(io_op, state);
 
+       out:            
+       mutex_unlock(&io_op->backend->mutex);
        return retval;
 }
 
-static struct omnibook_feature bt_feature;
+static struct omnibook_feature bt_driver;
 
 static int __init omnibook_bt_init(struct omnibook_operation *io_op)
 {
@@ -69,11 +75,11 @@ static int __init omnibook_bt_init(struct omnibook_operation *io_op)
  *  Refuse enabling/disabling a non-existent device
  */
 
-       if ((retval = io_op->backend->aerial_get(io_op, &state)))
+       if ((retval = backend_aerial_get(io_op, &state)))
                return retval;
 
        if (!(state & BT_EX))
-               bt_feature.write = NULL;
+               bt_driver.write = NULL;
 
        return retval;
 }
index 277f2edb999af3bca9fd067d383a9272c8a69a4a..d91593dda7e13ea4747e22446c15710f6e1f8980 100644 (file)
--- a/compal.c
+++ b/compal.c
@@ -23,8 +23,7 @@
 #include <linux/kref.h>
 
 #include <asm/io.h>
-#include "ec.h"
-#include "compat.h"
+#include "hardware.h"
 
 /*
  * ATI's IXP PCI-LPC bridge
 #define PIO_PORT_COMMAND2      0x2
 #define PIO_PORT_DATA          0x3
 
-/* 
- * We protect access to the Command/Data/Index interface by a Mutex
- */
-static DEFINE_MUTEX(compal_lock);
-
 /*
  * Private data of this backend
  */
-static struct kref *refcount;  /* Reference counter of this backend */
 static struct pci_dev *lpc_bridge;     /* Southbridge chip ISA bridge/LPC interface PCI device */
 static u32 ioport_base;                /* PIO base adress */
 static union {
        u16 word;
        u32 dword;
 } pci_reg_state;               /* Saved state of register in PCI config spave */
-static int already_failed = 0; /* Backend init already failed at leat once */
 
 /*
  * Possible list of supported southbridges
@@ -310,26 +302,21 @@ static int omnibook_cdimode_init(const struct omnibook_operation *io_op)
        int retval = 0;
        int i;
 
-/* ectypes other than TSM30X have no business with this backend */
+       /* ectypes other than TSM30X have no business with this backend */
        if (!(omnibook_ectype & TSM30X))
                return -ENODEV;
 
-       if (already_failed) {
+       if (io_op->backend->already_failed) {
                dprintk("CDI backend init already failed, skipping.\n");
                return -ENODEV;
        }
 
-       if (!refcount) {
+       if (!lpc_bridge) {
                /* Fist use of the backend */
-               mutex_lock(&compal_lock);
                dprintk("Try to init cdimode\n");
-               refcount = kmalloc(sizeof(struct kref), GFP_KERNEL);
-               if (!refcount) {
-                       retval = -ENOMEM;
-                       goto out;
-               }
-
-               kref_init(refcount);
+               mutex_init(&io_op->backend->mutex);
+               mutex_lock(&io_op->backend->mutex);
+               kref_init(&io_op->backend->kref);
 
                /* PCI probing: find the LPC Super I/O bridge PCI device */
                for (i = 0; !lpc_bridge && lpc_bridge_table[i].vendor; ++i)
@@ -377,10 +364,11 @@ static int omnibook_cdimode_init(const struct omnibook_operation *io_op)
                clear_cdimode_pci();
 
                dprintk("Cdimode init ok\n");
-               goto out;
+               mutex_unlock(&io_op->backend->mutex);
+               return 0;
        } else {
                dprintk("Cdimode has already been initialized\n");
-               kref_get(refcount);
+               kref_get(&io_op->backend->kref);
                return 0;
        }
 
@@ -391,32 +379,34 @@ static int omnibook_cdimode_init(const struct omnibook_operation *io_op)
        pci_dev_put(lpc_bridge);
        lpc_bridge = NULL;
       error1:
-       kfree(refcount);
-       refcount = NULL;
-       already_failed = 1;
-      out:
-       mutex_unlock(&compal_lock);
+       io_op->backend->already_failed = 1;
+       mutex_unlock(&io_op->backend->mutex);
+       mutex_destroy(&io_op->backend->mutex);
        return retval;
 }
 
 static void cdimode_free(struct kref *ref)
 {
-       mutex_lock(&compal_lock);
+       struct omnibook_backend *backend;
+       
        dprintk("Cdimode not used anymore: disposing\n");
+
+       backend = container_of(ref, struct omnibook_backend, kref);
+
+       mutex_lock(&backend->mutex);
        pci_dev_put(lpc_bridge);
        release_region(ioport_base, 4);
-       kfree(refcount);
        lpc_bridge = NULL;
-       refcount = NULL;
-       mutex_unlock(&compal_lock);
+       mutex_unlock(&backend->mutex);
+       mutex_destroy(&backend->mutex);
 }
 
 static void omnibook_cdimode_exit(const struct omnibook_operation *io_op)
 {
-/* ectypes other than TSM30X have no business with this backend */
+       /* ectypes other than TSM30X have no business with this backend */
        BUG_ON(!(omnibook_ectype & TSM30X));
        dprintk("Trying to dispose cdimode\n");
-       kref_put(refcount, cdimode_free);
+       kref_put(&io_op->backend->kref, cdimode_free);
 }
 
 /* 
@@ -430,9 +420,6 @@ static int omnibook_cdimode_read(const struct omnibook_operation *io_op, u8 * va
        if (!lpc_bridge)
                return -ENODEV;
 
-       if (mutex_lock_interruptible(&compal_lock))
-               return -ERESTARTSYS;
-
        retval = enable_cdimode();
        if (retval)
                goto out;
@@ -448,7 +435,6 @@ static int omnibook_cdimode_read(const struct omnibook_operation *io_op, u8 * va
        clear_cdimode();
       out:
        clear_cdimode_pci();
-       mutex_unlock(&compal_lock);
        return retval;
 }
 
@@ -463,9 +449,6 @@ static int omnibook_cdimode_write(const struct omnibook_operation *io_op, u8 val
        if (!lpc_bridge)
                return -ENODEV;
 
-       if (mutex_lock_interruptible(&compal_lock))
-               return -ERESTARTSYS;
-
        retval = enable_cdimode();
        if (retval)
                goto out;
@@ -477,7 +460,6 @@ static int omnibook_cdimode_write(const struct omnibook_operation *io_op, u8 val
        clear_cdimode();
       out:
        clear_cdimode_pci();
-       mutex_unlock(&compal_lock);
        return retval;
 
 }
@@ -492,23 +474,17 @@ static int omnibook_cdimode_hotkeys(const struct omnibook_operation *io_op, unsi
                { CDI, 0, TSM70_FN_INDEX, 0, TSM70_FN_ENABLE, TSM70_FN_DISABLE};
 
        /* Fn+foo handling */
-       retval = omnibook_toggle(&hotkeys_op, !!(state & HKEY_FN));
+       retval = __omnibook_toggle(&hotkeys_op, !!(state & HKEY_FN));
        if (retval < 0)
                return retval;
 
        /* Multimedia keys handling */
-       if (state & HKEY_MULTIMEDIA) {
-               hotkeys_op.write_addr = TSM70_HOTKEYS_INDEX;
-               retval = omnibook_cdimode_write(&hotkeys_op, TSM70_HOTKEYS_ENABLE);
-       } else {
-               /* FIXME: quirk use kbc backend */
-               retval = kbc_backend.byte_write(NULL, OMNIBOOK_KBC_CMD_ONETOUCH_DISABLE);
-       }
+       hotkeys_op.write_addr = TSM70_HOTKEYS_INDEX;
+       hotkeys_op.on_mask = TSM70_HOTKEYS_ENABLE;
+       hotkeys_op.off_mask = TSM70_HOTKEYS_DISABLE;
+       retval = __omnibook_toggle(&hotkeys_op, !!(state & HKEY_MULTIMEDIA));
 
-       if (retval < 0)
-               return retval;
-       else
-               return HKEY_MULTIMEDIA | HKEY_FN;
+       return retval;
 }
 
 /* Scan index space, this hard locks my machine */
@@ -535,6 +511,7 @@ static int compal_scan(char *buffer)
 
 struct omnibook_backend compal_backend = {
        .name = "compal",
+       .hotkeys_write_cap = HKEY_MULTIMEDIA | HKEY_FN,
        .init = omnibook_cdimode_init,
        .exit = omnibook_cdimode_exit,
        .byte_read = omnibook_cdimode_read,
index c719127362ee2fcf3b32964a1e655ee2cdc929ea..d45605371d5bc7c444e2c2db3b62e509e24eb681 100644 (file)
--- a/compat.h
+++ b/compat.h
@@ -1,5 +1,5 @@
 /*
- * compat.h -- Older kernel (=> 2.6.9) support 
+ * compat.h -- Older kernel (=> 2.6.11) support 
  * 
  * 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 the
  * Mutex to Semaphore fallback
  */
 
-
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
 #include <asm/semaphore.h>
 #define DEFINE_MUTEX(lock)             DECLARE_MUTEX(lock)
+#define        mutex_init(lock)                init_MUTEX(lock)
 #define mutex_lock(lock)               down(lock)
 #define mutex_lock_interruptible(lock) down_interruptible(lock)
 #define mutex_unlock(lock)             up(lock)
+#define mutex_destroy(lock)            do { } while(0)
 #else
 #include <linux/mutex.h>
 #endif
index 19f40b79edcd66485c5c6b6721421aa963add272..b26af5c45caf2e4a54d2e618c5dc46458ef9eeae 100644 (file)
--- a/display.c
+++ b/display.c
@@ -16,7 +16,7 @@
  */
 
 #include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
 
 static const char display_name[][16] = {
        "Internal LCD",
@@ -31,7 +31,7 @@ static int omnibook_display_read(char *buffer, struct omnibook_operation *io_op)
        int retval;
        unsigned int sta, en_mask, det_mask;
 
-       retval = io_op->backend->display_get(io_op, &sta);
+       retval = backend_display_get(io_op, &sta);
        if (retval < 0)
                return retval;
 
@@ -64,7 +64,7 @@ static int omnibook_display_write(char *buffer, struct omnibook_operation *io_op
        if (endp == buffer)
                return -EINVAL;
        else
-               retval = io_op->backend->display_set(io_op, state);
+               retval = backend_display_set(io_op, state);
 
        return retval;
 }
index 75b1057065802c48416e56705b27ccad2e0ebf55..c29f79115f5ab8cec8335e85d533b5180845a76c 100644 (file)
@@ -6,6 +6,10 @@ Changelog file for omnibook package:
   support with a far more complete autodetection database
   (see http://www2.informatik.hu-berlin.de/~tauber/acerhk/)
 * Fix and improve bluetooth handling for TSM30X class laptops
+* Implement Volume down,up and Mute buttons polling for ectype 2
+   It was the last missing part from the "omke" module which never
+   got ported to linux 2.6
+* Implement ectype 13 Fn hotkeys handling.
 * DMI signature added:
        HP Pavilion ze4500 (ectype 7)
        Toshiba Satellite 1130 (ectype 1)
diff --git a/dock.c b/dock.c
index b7a59427e7022bebf3729c9c2d68bec048ba8412..3264f70e4c627b42b158dce18d6ad5b4ddca8522 100644 (file)
--- a/dock.c
+++ b/dock.c
@@ -16,8 +16,7 @@
  */
 
 #include "omnibook.h"
-
-#include "ec.h"
+#include "hardware.h"
 
 static int omnibook_dock_read(char *buffer, struct omnibook_operation *io_op)
 {
@@ -25,7 +24,7 @@ static int omnibook_dock_read(char *buffer, struct omnibook_operation *io_op)
        u8 dock;
        int retval;
 
-       if ((retval = io_op->backend->byte_read(io_op, &dock)))
+       if ((retval = backend_byte_read(io_op, &dock)))
                return retval;
 
        len += sprintf(buffer + len, "Laptop is %s\n", (dock) ? "docked" : "undocked");
@@ -33,6 +32,35 @@ static int omnibook_dock_read(char *buffer, struct omnibook_operation *io_op)
        return len;
 }
 
+static int omnibook_dock_write(char *buffer, struct omnibook_operation *io_op)
+{
+       int retval;
+
+       switch (*buffer) {
+       case '0':
+               retval = backend_byte_write(io_op, 0);
+               break;
+       case '1':
+               retval = backend_byte_write(io_op, 1);
+               break;
+       default:
+               retval = -EINVAL;
+       }
+
+       return retval;
+}
+
+static struct omnibook_feature dock_driver;
+
+static int __init omnibook_dock_init(struct omnibook_operation *io_op)
+{
+       /* writing is only supported on ectype 13 */
+       if(!(omnibook_ectype & TSM40))
+               dock_driver.write = NULL;
+       
+       return 0;
+}
+
 static struct omnibook_tbl dock_table[] __initdata = {
        {XE3GF, SIMPLE_BYTE(EC, XE3GF_CSPR, XE3GF_CSPR_MASK)},
        {OB500 | OB510 | OB6000 | OB6100, SIMPLE_BYTE(EC, OB500_STA1, OB500_DCKS_MASK)},
@@ -44,7 +72,9 @@ static struct omnibook_tbl dock_table[] __initdata = {
 static struct omnibook_feature __declared_feature dock_driver = {
        .name = "dock",
        .enabled = 0,
+       .init = omnibook_dock_init,
        .read = omnibook_dock_read,
+       .write = omnibook_dock_write,
        .ectypes = XE3GF | OB500 | OB510 | OB6000 | OB6100 | OB4150 | TSM40,
        .tbl = dock_table,
 };
diff --git a/dump.c b/dump.c
index 7b1a0fedc9562cc7e9fba3d7b4b462439403357c..b891bf0e56fc7bd7cd9373567b0c907b99ec4d61 100644 (file)
--- a/dump.c
+++ b/dump.c
@@ -20,7 +20,7 @@
  */
 
 #include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
 
 static u8 ecdump_regs[256];
 
diff --git a/ec.c b/ec.c
index e8e30f046f4412b86966fb4a3cecd9379f3d9493..39609661973ee7daf935815f49b033cec337467c 100644 (file)
--- a/ec.c
+++ b/ec.c
@@ -1,6 +1,5 @@
 /*
  * ec.c -- low level functions to access Embedded Controller,
- *         Keyboard Controller and system I/O ports or memory
  * 
  * 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 the
@@ -25,8 +24,7 @@
 #include <linux/ioport.h>
 
 #include <asm/io.h>
-#include "ec.h"
-#include "compat.h"
+#include "hardware.h"
 
 /*
  * Interrupt control
 
 static DEFINE_SPINLOCK(omnibook_ec_lock);
 
-/*
- * Timeout in ms for sending to controller
- */
-
-#define OMNIBOOK_TIMEOUT                250
-
 /*
  * Registers of the embedded controller
  */
@@ -104,7 +96,7 @@ static int omnibook_ec_read(const struct omnibook_operation *io_op, u8 * data)
                retval = ec_read((u8) io_op->read_addr, data);
                if (io_op->read_mask)
                        *data &= io_op->read_mask;
-               dprintk("ACPI EC read at %lx success %i.\n", io_op->read_addr, retval);
+//             dprintk("ACPI EC read at %lx success %i.\n", io_op->read_addr, retval);
                return retval;
        }
 #endif
@@ -125,7 +117,7 @@ static int omnibook_ec_read(const struct omnibook_operation *io_op, u8 * data)
                *data &= io_op->read_mask;
       end:
        spin_unlock_irq(&omnibook_ec_lock);
-       dprintk("Custom EC read at %lx success %i.\n", io_op->read_addr, retval);
+//     dprintk("Custom EC read at %lx success %i.\n", io_op->read_addr, retval);
        return retval;
 }
 
@@ -145,7 +137,7 @@ static int omnibook_ec_write(const struct omnibook_operation *io_op, u8 data)
 #ifdef CONFIG_ACPI_EC
        if (likely(!acpi_disabled)) {
                retval = ec_write((u8) io_op->write_addr, data);
-               dprintk("ACPI EC write at %lx success %i.\n", io_op->write_addr, retval);
+//             dprintk("ACPI EC write at %lx success %i.\n", io_op->write_addr, retval);
                return retval;
        }
 #endif
@@ -165,7 +157,7 @@ static int omnibook_ec_write(const struct omnibook_operation *io_op, u8 data)
        outb(data, OMNIBOOK_EC_DATA);
       end:
        spin_unlock_irq(&omnibook_ec_lock);
-       dprintk("Custom EC write at %lx success %i.\n", io_op->write_addr, retval);
+//     dprintk("Custom EC write at %lx success %i.\n", io_op->write_addr, retval);
        return retval;
 }
 
@@ -198,7 +190,7 @@ static int omnibook_ec_display(const struct omnibook_operation *io_op, unsigned
        int retval;
        u8 raw_state;
 
-       retval = io_op->backend->byte_read(io_op, &raw_state);
+       retval = __backend_byte_read(io_op, &raw_state);
        if (retval < 0)
                return retval;
 
@@ -207,268 +199,10 @@ static int omnibook_ec_display(const struct omnibook_operation *io_op, unsigned
        return DISPLAY_CRT_DET;
 }
 
-/*
- * Registers of the keyboard controller
- */
-
-#define OMNIBOOK_KBC_DATA              0x60
-#define OMNIBOOK_KBC_SC                        0x64
-
-/*
- * Keyboard controller status register bits
- */
-
-#define OMNIBOOK_KBC_STAT_OBF          0x01    /* Output buffer full */
-#define OMNIBOOK_KBC_STAT_IBF          0x02    /* Input buffer full */
-#define OMNIBOOK_KBC_STAT_CMD          0x08    /* Last write was a command write (0=data) */
-
-/*
- * Wait for keyboard buffer
- */
-
-static int omnibook_kbc_wait(u8 event)
-{
-       int timeout = OMNIBOOK_TIMEOUT;
-
-       switch (event) {
-       case OMNIBOOK_KBC_STAT_OBF:
-               while (!(inb(OMNIBOOK_KBC_SC) & event) && timeout--)
-                       mdelay(1);
-               break;
-       case OMNIBOOK_KBC_STAT_IBF:
-               while ((inb(OMNIBOOK_KBC_SC) & event) && timeout--)
-                       mdelay(1);
-               break;
-       default:
-               return -EINVAL;
-       }
-       if (timeout > 0)
-               return 0;
-       return -ETIME;
-}
-
-/*
- * Write to the keyboard command register
- */
-
-static int omnibook_kbc_write_command(u8 cmd)
-{
-       int retval;
-
-       spin_lock_irq(&omnibook_ec_lock);
-       retval = omnibook_kbc_wait(OMNIBOOK_KBC_STAT_IBF);
-       if (retval)
-               goto end;
-       outb(cmd, OMNIBOOK_KBC_SC);
-       retval = omnibook_kbc_wait(OMNIBOOK_KBC_STAT_IBF);
-      end:
-       spin_unlock_irq(&omnibook_ec_lock);
-       return retval;
-}
-
-/*
- * Write to the keyboard data register
- */
-
-static int omnibook_kbc_write_data(u8 data)
-{
-       int retval;
-
-       spin_lock_irq(&omnibook_ec_lock);
-       retval = omnibook_kbc_wait(OMNIBOOK_KBC_STAT_IBF);
-       if (retval)
-               goto end;;
-       outb(data, OMNIBOOK_KBC_DATA);
-       retval = omnibook_kbc_wait(OMNIBOOK_KBC_STAT_IBF);
-      end:
-       spin_unlock_irq(&omnibook_ec_lock);
-       return retval;
-}
-
-/*
- * Send a command to keyboard controller
- */
-
-static int omnibook_kbc_command(const struct omnibook_operation *io_op, u8 data)
-{
-       int retval;
-
-       if ((retval = omnibook_kbc_write_command(OMNIBOOK_KBC_CONTROL_CMD)))
-               return retval;
-
-       retval = omnibook_kbc_write_data(data);
-       return retval;
-}
-
-/*
- * Onetouch button hotkey handler
- */
-static int omnibook_kbc_hotkeys(const struct omnibook_operation *io_op, unsigned int state)
-{
-       int retval;
-
-       retval = omnibook_toggle(io_op, !!(state & HKEY_ONETOUCH));
-
-       if (retval < 0)
-               return retval;
-       else
-               return HKEY_ONETOUCH;
-}
-
-/*
- * IO port backend. Only support single or dual ports operations
- * private data structure: it's the linked list of requested ports
- * 
- * Race condition issue: omnibook_pio_init/exit functions are only called from
- * omnibook_backend_match and omnibook_remove from init.c, this should happen
- * only at module init/exit time so there is no need for a lock.
- */
-
-struct pio_private_data_t {
-       unsigned long addr;
-       struct kref refcount;
-       struct list_head list;
-};
-
-static struct pio_private_data_t pio_private_data = {
-       .addr = 0,
-       .list = LIST_HEAD_INIT(pio_private_data.list),
-};
-
-/*
- * Match an entry in the linked list helper function: see if we have and entry
- * whose addr field match maddr
- */
-static struct pio_private_data_t *omnibook_match_port(struct pio_private_data_t *data,
-                                                     unsigned long maddr)
-{
-       struct list_head *p;
-       struct pio_private_data_t *cursor;
-
-       list_for_each(p, &data->list) {
-               cursor = list_entry(p, struct pio_private_data_t, list);
-               if (cursor->addr == maddr) {
-                       return cursor;
-               }
-       }
-       return NULL;
-}
-
-/*
- * See if we have to request raddr
- */
-static int omnibook_claim_port(struct pio_private_data_t *data, unsigned long raddr)
-{
-       struct pio_private_data_t *match, *new;
-
-       match = omnibook_match_port(data, raddr);
-       if (match) {
-               /* Already requested by us: increment kref and quit */
-               kref_get(&match->refcount);
-               return 0;
-       }
-
-       /* there was no match: request the region and add to list */
-       if (!request_region(raddr, 1, OMNIBOOK_MODULE_NAME)) {
-               printk(O_ERR "Request I/O port error\n");
-               return -ENODEV;
-       }
-
-       new = kmalloc(sizeof(struct pio_private_data_t), GFP_KERNEL);
-       if (!new) {
-               release_region(raddr, 1);
-               return -ENOMEM;
-       }
-
-       kref_init(&new->refcount);
-       new->addr = raddr;
-       list_add(&new->list, &data->list);
-
-       return 0;
-}
-
-/*
- * Register read_addr and write_addr
- */
-static int omnibook_pio_init(const struct omnibook_operation *io_op)
-{
-       int retval = 0;
-
-       if (io_op->read_addr
-           && (retval = omnibook_claim_port(io_op->backend->data, io_op->read_addr)))
-               goto out;
-
-       if (io_op->write_addr && (io_op->write_addr != io_op->read_addr))
-               retval = omnibook_claim_port(io_op->backend->data, io_op->write_addr);
-
-      out:
-       return retval;
-}
-
-/*
- * REALLY release a port
- */
-static void omnibook_free_port(struct kref *ref)
-{
-       struct pio_private_data_t *data;
-
-       data = container_of(ref, struct pio_private_data_t, refcount);
-       release_region(data->addr, 1);
-       list_del(&data->list);
-       kfree(data);
-}
-
-/*
- * Unregister read_addr and write_addr
- */
-static void omnibook_pio_exit(const struct omnibook_operation *io_op)
-{
-       struct pio_private_data_t *match;
-
-       match = omnibook_match_port(io_op->backend->data, io_op->read_addr);
-       if (match)
-               kref_put(&match->refcount, omnibook_free_port);
-
-       match = NULL;
-       match = omnibook_match_port(io_op->backend->data, io_op->write_addr);
-       if (match)
-               kref_put(&match->refcount, omnibook_free_port);
-
-}
-
-static int omnibook_io_read(const struct omnibook_operation *io_op, u8 * value)
-{
-       *value = inb(io_op->read_addr);
-       if (io_op->read_mask)
-               *value &= io_op->read_mask;
-       return 0;
-}
-
-static int omnibook_io_write(const struct omnibook_operation *io_op, u8 value)
-{
-       outb(io_op->write_addr, value);
-       return 0;
-}
-
 /*
  * Backend interface declarations
  */
 
-struct omnibook_backend kbc_backend = {
-       .name = "i8042",
-       .byte_write = omnibook_kbc_command,
-       .hotkeys_set = omnibook_kbc_hotkeys,
-};
-
-struct omnibook_backend pio_backend = {
-       .name = "pio",
-       .data = &pio_private_data,
-       .init = omnibook_pio_init,
-       .exit = omnibook_pio_exit,
-       .byte_read = omnibook_io_read,
-       .byte_write = omnibook_io_write,
-};
-
 struct omnibook_backend ec_backend = {
        .name = "ec",
        .byte_read = omnibook_ec_read,
@@ -476,45 +210,4 @@ struct omnibook_backend ec_backend = {
        .display_get = omnibook_ec_display,
 };
 
-int omnibook_apply_write_mask(const struct omnibook_operation *io_op, int toggle)
-{
-       int retval = 0;
-       int mask;
-       u8 data;
-
-       if ((retval = io_op->backend->byte_read(io_op, &data)))
-               return retval;
-
-       if (toggle == 1)
-               mask = io_op->on_mask;
-       else if (toggle == 0)
-               mask = io_op->off_mask;
-       else
-               return -EINVAL;
-
-       if (mask > 0)
-               data |= (u8) mask;
-       else if (mask < 0)
-               data &= ~((u8) (-mask));
-       else
-               return -EINVAL;
-
-       retval = io_op->backend->byte_write(io_op, data);
-
-       return retval;
-}
-
-/*
- * Helper for toggle like operations
- */
-int omnibook_toggle(const struct omnibook_operation *io_op, int toggle)
-{
-       int retval;
-       u8 data;
-
-       data = toggle ? io_op->on_mask : io_op->off_mask;
-       retval = io_op->backend->byte_write(io_op, data);
-       return retval;
-}
-
 /* End of file */
diff --git a/fan.c b/fan.c
index ba88cbd5505735de0cfb1d6ebf17ab2cbd55b681..158722781bf0041e817038af5aaa47f953361d11 100644 (file)
--- a/fan.c
+++ b/fan.c
@@ -19,7 +19,7 @@
 
 #include <linux/delay.h>
 #include <asm/io.h>
-#include "ec.h"
+#include "hardware.h"
 
 static const struct omnibook_operation ctmp_io_op = { EC, XE3GF_CTMP, 0, 0, 0, 0 };
 static const struct omnibook_operation fot_io_op = { EC, XE3GF_FOT, XE3GF_FOT, 0, 0, 0 };
@@ -29,7 +29,7 @@ static int omnibook_get_fan(struct omnibook_operation *io_op)
        u8 fan;
        int retval;
 
-       if ((retval = io_op->backend->byte_read(io_op, &fan)))
+       if ((retval = backend_byte_read(io_op, &fan)))
                return retval;
 
        /*
@@ -57,39 +57,49 @@ static int omnibook_fan_off(struct omnibook_operation *io_op)
 {
        int i, retval = 0;
 
-/*
- * Special handling for XE3GF & TSP10
- */
-       if (omnibook_ectype & (XE3GF | TSP10)) {
-               u8 fot, temp;
-               retval = omnibook_get_fan(io_op);
+       if (!(omnibook_ectype & (XE3GF | TSP10))) {
+               retval = omnibook_apply_write_mask(io_op, 0);
+               return retval;
+       } else {
+       /*
+        * Special handling for XE3GF & TSP10
+        */
+               u8 fot, temp, fan;
+
+               if(mutex_lock_interruptible(&io_op->backend->mutex))
+                       return -ERESTARTSYS;    
+
+               retval = __backend_byte_read(io_op, &fan);
 
                /* error or fan is already off */
-               if (retval <= 0)
-                       return retval;
+               if (retval || !fan)
+                       goto out;
 
                /* now we set FOT to current temp, then reset to initial value */
-               if ((retval = fot_io_op.backend->byte_read(&fot_io_op, &fot)))
-                       return retval;
-               if ((retval = ctmp_io_op.backend->byte_read(&ctmp_io_op, &temp)))
-                       return retval;
+               if ((retval = __backend_byte_read(&fot_io_op, &fot)))
+                       goto out;
+               if ((retval = __backend_byte_read(&ctmp_io_op, &temp)))
+                       goto out;
 
-/*
- * Wait for no longer than 250ms, this is arbitrary
- */
+               /* Wait for no longer than 250ms (this is arbitrary). */
                for (i = 0; i < 250; i++) {
-                       fot_io_op.backend->byte_write(&fot_io_op, temp);
+                       __backend_byte_write(&fot_io_op, temp);
                        mdelay(1);
-                       if (omnibook_get_fan(io_op) == 0) {
-                               retval = fot_io_op.backend->byte_write(&fot_io_op, fot);
-                               return retval;
-                       }
+                       __backend_byte_read(io_op, &fan);
+                       if (!fan) /* Fan is off */
+                               break;
+               }
+               __backend_byte_write(&fot_io_op, fot);
+
+               if(i == 250 ) {
+                       printk(O_ERR "Attempt to switch off the fan failed.\n");
+                       retval = -EIO;
                }
-               fot_io_op.backend->byte_write(&fot_io_op, fot);
-               printk(O_ERR "Attempt to switch off the fan failed.\n");
-               return -EIO;
-       } else
-               retval = omnibook_apply_write_mask(io_op, 0);
+
+               out:            
+               mutex_unlock(&io_op->backend->mutex);
+       }
+               
 
        return retval;
 }
@@ -119,20 +129,18 @@ static int omnibook_fan_write(char *buffer, struct omnibook_operation *io_op)
 
        switch (*buffer) {
        case '0':
-               if ((retval = omnibook_fan_off(io_op)))
-                       return retval;
+               retval = omnibook_fan_off(io_op);
                break;
        case '1':
-               if ((retval = omnibook_fan_on(io_op)))
-                       return retval;
+               retval = omnibook_fan_on(io_op);
                break;
        default:
-               return -EINVAL;
+               retval = -EINVAL;
        }
-       return 0;
+       return retval;
 }
 
-static struct omnibook_feature fan_feature;
+static struct omnibook_feature fan_driver;
 
 static int __init omnibook_fan_init(struct omnibook_operation *io_op)
 {
@@ -143,7 +151,7 @@ static int __init omnibook_fan_init(struct omnibook_operation *io_op)
         * They only support fan reading 
         */
        if (omnibook_ectype & (OB4150 | XE2 | AMILOD))
-               fan_feature.write = NULL;
+               fan_driver.write = NULL;
        return 0;
 }
 
@@ -170,6 +178,6 @@ static struct omnibook_feature __declared_feature fan_driver = {
        .tbl = fan_table,
 };
 
-module_param_named(fan, fan_feature.enabled, int, S_IRUGO);
+module_param_named(fan, fan_driver.enabled, int, S_IRUGO);
 MODULE_PARM_DESC(fan, "Use 0 to disable, 1 to enable fan status monitor and control");
 /* End of file */
index ab86a6b65f6604598880a0c2504d222cee42f2a0..cee6bdf792a44ca67e1f62e6e01ff9a27629928d 100644 (file)
@@ -18,7 +18,7 @@
 #include "omnibook.h"
 
 #include <linux/ctype.h>
-#include "ec.h"
+#include "hardware.h"
 
 /*
  * Default temperature limits.
diff --git a/ec.h b/hardware.h
similarity index 78%
rename from ec.h
rename to hardware.h
index c80514c551cb7ece1db4b5990f11442bbb535699..5abf2fb4a8abf2278e421a989023d316f893c616 100644 (file)
--- a/ec.h
@@ -1,5 +1,5 @@
 /*
- * ec.h -- low level definitions to access Embedded Controller and co.
+ * hardware.h -- low level definitions to access Embedded Controller and co.
  * 
  * 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 the
@@ -16,6 +16,7 @@
  */
 
 #include <linux/acpi.h>
+#include "compat.h"
 
 /*
  * Quite ugly:
@@ -30,8 +31,8 @@ struct omnibook_operation {
                unsigned long read_addr; /* address for data reading */
                unsigned long write_addr; /* address for data writing */
                u8 read_mask; /* read mask */
-               int on_mask; /* mask to set (pos value) or unset (neg value) to put feature to on state */
-               int off_mask; /* mask to set (pos value) or unset (neg value) to put feature to off state */
+               int on_mask; /* mask to set (pos value) or unset (neg value) to put feature in on state */
+               int off_mask; /* mask to set (pos value) or unset (neg value) to put feature in off state */
 };
 
 #define COMMAND(backend,data_on,data_off) { backend, 0, 0, 0, data_on, data_off }
@@ -44,16 +45,19 @@ struct omnibook_tbl {
 
 /*
  * Backend interface definition
- *
- * Note:
- * display_get/set and hotkey_set/get return a positive value on success 
- * which set bits corresponds to the actual supported states 
- * (see omnibook.h for the DISPLAY_* masks)  
  */
 
 struct omnibook_backend {
        const char *name;       /* backend name */
-       void *data;             /* backend private data pointer */
+       struct mutex mutex;     /* serializes all access to backend functions */
+       const unsigned int hotkeys_read_cap; /* hotkey probing mask */
+       const unsigned int hotkeys_write_cap; /* hotkey setting mask */
+
+       /* Public data fields, access with mutex held */
+       unsigned int hotkeys_state;     /* saved hotkeys state */
+       unsigned int misc_state;        /* various status bit: touchpad and muteled */
+
+       /* Public function pointers */
        int (*init) (const struct omnibook_operation *); 
        void (*exit) (const struct omnibook_operation *);
        int (*byte_read) (const struct omnibook_operation *, u8 *); 
@@ -64,6 +68,11 @@ struct omnibook_backend {
        int (*hotkeys_set) (const struct omnibook_operation *, unsigned int); 
        int (*display_get) (const struct omnibook_operation *, unsigned int *);
        int (*display_set) (const struct omnibook_operation *, unsigned int);
+
+       /* Private fields, never to be accessed outside backend code */
+       struct kref kref;       /* Reference counter of this backend */
+       void *data;             /* private data pointer */
+       int already_failed;     /* Backend init already failed at least once */
 };
 
 extern struct omnibook_backend kbc_backend;
@@ -82,8 +91,113 @@ extern struct omnibook_backend compal_backend;
 
 int legacy_ec_read(u8 addr, u8 *data);
 int legacy_ec_write(u8 addr, u8 data);
-int omnibook_apply_write_mask(const struct omnibook_operation *io_op, int toggle);
-int omnibook_toggle(const struct omnibook_operation *io_op, int toggle);
+int __omnibook_apply_write_mask(const struct omnibook_operation *io_op, int toggle);
+int __omnibook_toggle(const struct omnibook_operation *io_op, int toggle);
+
+/*
+ * Lock helper functions. Defines locking and __prefixed non locking variants.
+ */
+
+#define helper_func(func) \
+static inline int backend_##func##_get(const struct omnibook_operation *io_op, unsigned int *data) \
+{ \
+       int retval; \
+       if(mutex_lock_interruptible(&io_op->backend->mutex)) \
+               return -ERESTARTSYS; \
+       retval = io_op->backend->func##_get(io_op, data); \
+       mutex_unlock(&io_op->backend->mutex); \
+       return retval; \
+} \
+static inline int backend_##func##_set(const struct omnibook_operation *io_op, unsigned int data) \
+{ \
+       int retval; \
+       if(mutex_lock_interruptible(&io_op->backend->mutex)) \
+               return -ERESTARTSYS; \
+       retval = io_op->backend->func##_set(io_op, data); \
+       mutex_unlock(&io_op->backend->mutex); \
+       return retval; \
+}\
+static inline int __backend_##func##_get(const struct omnibook_operation *io_op, unsigned int *data) \
+{ \
+       int retval; \
+       WARN_ON(!mutex_is_locked(&io_op->backend->mutex)); \
+       retval = io_op->backend->func##_get(io_op, data); \
+       return retval; \
+} \
+static inline int __backend_##func##_set(const struct omnibook_operation *io_op, unsigned int data) \
+{ \
+       int retval; \
+       WARN_ON(!mutex_is_locked(&io_op->backend->mutex)); \
+       retval = io_op->backend->func##_set(io_op, data); \
+       return retval; \
+}
+
+helper_func(aerial)
+helper_func(hotkeys)
+helper_func(display)
+
+static inline int backend_byte_read(const struct omnibook_operation *io_op, u8 *data)
+{
+       int retval;
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;
+       retval = io_op->backend->byte_read(io_op, data);
+       mutex_unlock(&io_op->backend->mutex);
+       return retval;
+}
+
+static inline int backend_byte_write(const struct omnibook_operation *io_op, u8 data)
+{
+       int retval;
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;
+       retval = io_op->backend->byte_write(io_op, data);
+       mutex_unlock(&io_op->backend->mutex);
+       return retval;
+}
+
+static inline int __backend_byte_read(const struct omnibook_operation *io_op, u8 *data)
+{
+       int retval;
+       WARN_ON(!mutex_is_locked(&io_op->backend->mutex));
+       retval = io_op->backend->byte_read(io_op, data);
+       return retval;
+}
+
+static inline int __backend_byte_write(const struct omnibook_operation *io_op, u8 data)
+{
+       int retval;
+       WARN_ON(!mutex_is_locked(&io_op->backend->mutex));
+       retval = io_op->backend->byte_write(io_op, data);
+       return retval;
+}
+
+static inline int omnibook_apply_write_mask(const struct omnibook_operation *io_op, int toggle)
+{
+       int retval;
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;
+       retval = __omnibook_apply_write_mask(io_op, toggle);
+       mutex_unlock(&io_op->backend->mutex);
+       return retval;
+}
+
+static inline int omnibook_toggle(const struct omnibook_operation *io_op, int toggle)
+{
+       int retval;
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;
+       retval = __omnibook_toggle(io_op, toggle);
+       mutex_unlock(&io_op->backend->mutex);
+       return retval;
+}
+
+/*
+ * Timeout in ms for sending to controller
+ */
+
+#define OMNIBOOK_TIMEOUT                250
+
 
 /*
  *     Embedded controller adresses
@@ -207,14 +321,6 @@ int omnibook_toggle(const struct omnibook_operation *io_op, int toggle);
 #define XE3GC_BRGT_MASK                0x40    /* Fn+F1/Fn+F2 - Brightness up or down pressed */
 #define XE3GC_BTVL_MASK                0x0F    /* LCD brightness */
 
-/*
- * Emulated scancodes
- */
-
-#define XE3GC_VOLD_SCAN                0x2E    /* Volume down button scancode */
-#define XE3GC_VOLU_SCAN                0x30    /* Volume up button scancode */
-#define XE3GC_MUTE_SCAN                0x20    /* Volume up button scancode */
-
 /*
  * Toshiba Satellite A105 values and mask
  */
@@ -382,6 +488,7 @@ int omnibook_toggle(const struct omnibook_operation *io_op, int toggle);
 
 /*
  * Index and values for Command/Data/Index interface
+ * Notice similitudes with commands code for kbc
  */
 
 #define TSM70_FN_INDEX         0x45
@@ -389,6 +496,7 @@ int omnibook_toggle(const struct omnibook_operation *io_op, int toggle);
 #define TSM70_FN_DISABLE       0x74
 #define TSM70_HOTKEYS_INDEX    0x59
 #define TSM70_HOTKEYS_ENABLE   0x90
+#define TSM70_HOTKEYS_DISABLE  0x91
 #define TSM70_LCD_READ         0x5C
 #define TSM70_LCD_WRITE                0x5D
 #define TSM70_TOUCHPAD_ON      0x80
@@ -397,8 +505,8 @@ int omnibook_toggle(const struct omnibook_operation *io_op, int toggle);
 #define        TSM100_LCD_ON           0xe1
 #define        TSM100_LCD_OFF          0xe2
 
-/* Toshiba SMI funtion */
-#define SMI_FN_PRESSED         0x00
+/* Toshiba SMI funtions and constants*/
+#define SMI_FN_PRESSED         0x8f
 #define SMI_SET_LCD_BRIGHTNESS 0xa2
 #define SMI_GET_LCD_BRIGHTNESS 0xa3
 #define SMI_GET_KILL_SWITCH    0xa4
@@ -417,3 +525,6 @@ int omnibook_toggle(const struct omnibook_operation *io_op, int toggle);
 #define SMI_STICK_KEYS_MASK    0x02
 #define SMI_FN_TWICE_LOCK_MASK 0x04
 #define SMI_FN_DOCK_MASK       0x08
+
+#define SMI_FN_SCAN            0x6d    /* Fn key scancode */
+#define        SMI_DOCK_SCAN           0x6e    /* Dock scancode */
index 935bcfc2ad3fae226f6d480ecc54ed781b820574..5e52a123409832fe4fd37a242949a66702e18f42 100644 (file)
--- a/hotkeys.c
+++ b/hotkeys.c
  */
 
 #include "omnibook.h"
-#include "ec.h"
-
-/*
- * Save state for suspend/resume operation
- */
-static unsigned int saved_state;
+#include "hardware.h"
 
 /* Predefined convinient on/off states */
 #define HKEY_ON  HKEY_ONETOUCH|HKEY_MULTIMEDIA|HKEY_FN|HKEY_DOCK|HKEY_FNF5
 #define HKEY_OFF 0
 
-static int omnibook_hotkeys_set(struct omnibook_operation *io_op, unsigned int state)
+/*
+ * Set hotkeys status and update recorded saved state
+ */
+static int hotkeys_set_save(struct omnibook_operation *io_op, unsigned int state)
 {
-       int write_capability;
+       int retval;
 
-       write_capability = io_op->backend->hotkeys_set(io_op, state);
-       if (write_capability < 0)
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;
+
+       retval = __backend_hotkeys_set(io_op, state);
+       if (retval < 0)
                goto out;
 
        /* Update saved state */
-       saved_state = state & write_capability;
+       io_op->backend->hotkeys_state = state & io_op->backend->hotkeys_write_cap;
 
-      out:
-       return write_capability;
+       out:
+       mutex_unlock(&io_op->backend->mutex);
+       return retval;
 }
 
-static int omnibook_hotkeys_get(struct omnibook_operation *io_op, unsigned int *state)
+/*
+ * Read hotkeys status, fallback to reading saved state if real probing is not
+ * supported.
+ */
+static int hotkeys_get_save(struct omnibook_operation *io_op, unsigned int *state)
 {
 
        unsigned int read_state = 0;
-       int read_capability = 0;
+       int retval = 0;
+
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;
 
        if (io_op->backend->hotkeys_get)
-               read_capability = io_op->backend->hotkeys_get(io_op, &read_state);
-       if (read_capability < 0)
+               retval = __backend_hotkeys_get(io_op, &read_state);
+       if (retval < 0)
                goto out;
 
        /* Return previously set state for the fields that are write only */
-       *state = (read_state & read_capability) + (saved_state & ~read_capability);
+       *state = (read_state & io_op->backend->hotkeys_read_cap) + 
+                (io_op->backend->hotkeys_state & ~io_op->backend->hotkeys_read_cap);
+
 
-      out:
-       return read_capability;
+       out:
+       mutex_unlock(&io_op->backend->mutex);
+       return 0;
 }
 
 /*
@@ -70,28 +82,20 @@ static int omnibook_hotkeys_get(struct omnibook_operation *io_op, unsigned int *
 static int omnibook_hotkeys_resume(struct omnibook_operation *io_op)
 {
        int retval;
-       retval = io_op->backend->hotkeys_set(io_op, saved_state);
-       if(retval < 0)
-               return retval;
-       return 0;
+       mutex_lock(&io_op->backend->mutex);
+       retval = __backend_hotkeys_set(io_op, io_op->backend->hotkeys_state);
+       mutex_unlock(&io_op->backend->mutex);
+       return retval;
 }
 
 /*
- * Save state and disable hotkeys upon suspend (FIXME is the disabling required ?)
+ * Disable hotkeys upon suspend (FIXME is the disabling required ?)
  */
 static int omnibook_hotkeys_suspend(struct omnibook_operation *io_op)
 {
        int retval = 0;
-
-       retval = omnibook_hotkeys_get(io_op, &saved_state);
-       if (retval < 0)
-               return retval;
-
-       retval = io_op->backend->hotkeys_set(io_op, HKEY_OFF);
-       if (retval < 0)
-               return retval;
-
-       return 0;
+       retval = backend_hotkeys_set(io_op, HKEY_OFF);
+       return retval;
 }
 
 static const char pretty_name[][27] = {
@@ -101,30 +105,31 @@ static const char pretty_name[][27] = {
        "Stick key is",
        "Press Fn twice to lock is",
        "Dock events are",
-       "Fn + F5 hotkey is"
+       "Fn + F5 hotkey is",
 };
 
 static int omnibook_hotkeys_read(char *buffer, struct omnibook_operation *io_op)
 {
        int len = 0;
-       int read_capability, write_capability;
-       unsigned int read_state, mask;
+       int retval;
+       unsigned int read_state = 0; /* buggy gcc 4.1 warning fix */
+       unsigned int shift, mask;
 
-       read_capability = omnibook_hotkeys_get(io_op, &read_state);
-       if (read_capability < 0)
-               return read_capability;
+       retval = hotkeys_get_save(io_op, &read_state);
 
-       write_capability = omnibook_hotkeys_set(io_op, read_state);
-       if (write_capability < 0)
-               return write_capability;
+       if (retval < 0)
+               return retval;
 
-       for (mask = HKEY_ONETOUCH; mask <= HKEY_FNF5; mask = mask << 1) {
+       for (shift = 0; shift <= HKEY_LAST_SHIFT ; shift++) {
+               mask = 1 << shift;
                /* we assume write capability or read capability imply support */
-               if ((read_capability | write_capability) & mask)
+               if ((io_op->backend->hotkeys_read_cap | io_op->backend->hotkeys_write_cap) & mask)
                        len +=
-                           sprintf(buffer + len, "%s %s.\n", pretty_name[ffs(mask) - 1],
+                           sprintf(buffer + len, "%s %s.\n", pretty_name[shift],
                                    (read_state & mask) ? "enabled" : "disabled");
        }
+
+
        return len;
 }
 
@@ -134,15 +139,15 @@ static int omnibook_hotkeys_write(char *buffer, struct omnibook_operation *io_op
        char *endp;
 
        if (strncmp(buffer, "off", 3) == 0)
-               omnibook_hotkeys_set(io_op, HKEY_OFF);
+               hotkeys_set_save(io_op, HKEY_OFF);
        else if (strncmp(buffer, "on", 2) == 0)
-               omnibook_hotkeys_set(io_op, HKEY_ON);
+               hotkeys_set_save(io_op, HKEY_ON);
        else {
                state = simple_strtoul(buffer, &endp, 16);
                if (endp == buffer)
                        return -EINVAL;
                else
-                       omnibook_hotkeys_set(io_op, state);
+                       hotkeys_set_save(io_op, state);
        }
        return 0;
 }
@@ -150,18 +155,19 @@ static int omnibook_hotkeys_write(char *buffer, struct omnibook_operation *io_op
 static int __init omnibook_hotkeys_init(struct omnibook_operation *io_op)
 {
        int retval;
+
        printk(O_INFO "Enabling all hotkeys.\n");
-       retval = omnibook_hotkeys_set(io_op, HKEY_ON);
+       retval = hotkeys_set_save(io_op, HKEY_ON);
        return retval < 0 ? retval : 0;
 }
 
 static void __exit omnibook_hotkeys_cleanup(struct omnibook_operation *io_op)
 {
        printk(O_INFO "Disabling all hotkeys.\n");
-       omnibook_hotkeys_set(io_op, HKEY_OFF);
+       hotkeys_set_save(io_op, HKEY_OFF);
 }
 
-static struct omnibook_tbl hotkey_table[] __initdata = {
+static struct omnibook_tbl hotkeys_table[] __initdata = {
        {XE3GF | XE3GC | OB500 | OB510 | OB6000 | OB6100 | XE4500 | AMILOD | TSP10, 
        COMMAND(KBC,OMNIBOOK_KBC_CMD_ONETOUCH_ENABLE,OMNIBOOK_KBC_CMD_ONETOUCH_DISABLE)},
        {TSM30X, {CDI,}},
@@ -181,7 +187,7 @@ static struct omnibook_feature __declared_feature hotkeys_driver = {
        .ectypes =
            XE3GF | XE3GC | OB500 | OB510 | OB6000 | OB6100 | XE4500 | AMILOD | TSP10 | TSM30X |
            TSM40,
-       .tbl = hotkey_table,
+       .tbl = hotkeys_table,
 };
 
 module_param_named(hotkeys, hotkeys_driver.enabled, int, S_IRUGO);
diff --git a/init.c b/init.c
index 9d740193724df62b1ff91d96ae53ca76b0e98254..9c9ba5f35fffcf270f5d90fb7c7beb618406fb26 100644 (file)
--- a/init.c
+++ b/init.c
@@ -22,9 +22,8 @@
 #include <linux/version.h>
 #include <asm/uaccess.h>
 
-#include "ec.h"
+#include "hardware.h"
 #include "laptop.h"
-#include "compat.h"
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
 #include <linux/platform_device.h>
@@ -87,6 +86,8 @@ static char *laptop_model __initdata;
 
 static int omnibook_userset = 0;
 
+struct input_dev *omnibook_input_dev;
+
 /*
  * The platform_driver interface was added in linux 2.6.15
  */
@@ -278,13 +279,8 @@ static int __init omnibook_init(struct omnibook_feature *feature)
                        if (omnibook_userset)
                                pmode |= S_IWUGO;
                }
-               /*
-                * FIXME: Special case for apmemu (not under /proc/omnibook)
-                */
-               if (feature->proc_entry)
-                       proc_entry = create_proc_entry(feature->proc_entry, pmode, NULL);
-               else
-                       proc_entry = create_proc_entry(feature->name, pmode, omnibook_proc_root);
+
+               proc_entry = create_proc_entry(feature->name, pmode, omnibook_proc_root);
 
                if (!proc_entry) {
                        printk(O_ERR "Unable to create proc entry %s\n", feature->name);
@@ -315,9 +311,13 @@ static int __init omnibook_init(struct omnibook_feature *feature)
 static int __init omnibook_probe(struct platform_device *dev)
 {
        int i;
-       struct list_head *p;
        struct omnibook_feature *feature;
 
+       /* temporary hack */
+       mutex_init(&kbc_backend.mutex);
+       mutex_init(&pio_backend.mutex);
+       mutex_init(&ec_backend.mutex);
+
        omnibook_available_feature = kzalloc(sizeof(struct omnibook_feature), GFP_KERNEL);
        if (!omnibook_available_feature)
                return -ENOMEM;
@@ -335,8 +335,7 @@ static int __init omnibook_probe(struct platform_device *dev)
        }
 
        printk(O_INFO "Enabled features:");
-       list_for_each(p, &omnibook_available_feature->list) {
-               feature = list_entry(p, struct omnibook_feature, list);
+       list_for_each_entry(feature, &omnibook_available_feature->list, list) {
                if (feature->name)
                        printk(" %s", feature->name);
        }
@@ -350,21 +349,17 @@ static int __init omnibook_probe(struct platform_device *dev)
  */
 static int __exit omnibook_remove(struct platform_device *dev)
 {
-       struct list_head *p, *n;
-       struct omnibook_feature *feature;
+       struct omnibook_feature *feature, *temp;
 
-       list_for_each_safe(p, n, &omnibook_available_feature->list) {
-               feature = list_entry(p, struct omnibook_feature, list);
-               list_del(p);
+       list_for_each_entry_safe(feature, temp, &omnibook_available_feature->list, list) {
+               list_del(&feature->list);
                /* Feature specific cleanup */
                if (feature->exit)
                        feature->exit(feature->io_op);
                /* Generic backend cleanup */
                if (feature->io_op && feature->io_op->backend->exit)
                        feature->io_op->backend->exit(feature->io_op);
-               if (feature->proc_entry)
-                       remove_proc_entry(feature->proc_entry, NULL);
-               else if (feature->name)
+               if (feature->name)
                        remove_proc_entry(feature->name, omnibook_proc_root);
                kfree(feature->io_op);
        }
@@ -379,11 +374,9 @@ static int __exit omnibook_remove(struct platform_device *dev)
 static int omnibook_suspend(struct platform_device *dev, pm_message_t state)
 {
        int retval;
-       struct list_head *p;
        struct omnibook_feature *feature;
 
-       list_for_each(p, &omnibook_available_feature->list) {
-               feature = list_entry(p, struct omnibook_feature, list);
+       list_for_each_entry(feature, &omnibook_available_feature->list, list) {
                if (feature->suspend) {
                        retval = feature->suspend(feature->io_op);
                        if (retval)
@@ -399,11 +392,9 @@ static int omnibook_suspend(struct platform_device *dev, pm_message_t state)
 static int omnibook_resume(struct platform_device *dev)
 {
        int retval;
-       struct list_head *p;
        struct omnibook_feature *feature;
 
-       list_for_each(p, &omnibook_available_feature->list) {
-               feature = list_entry(p, struct omnibook_feature, list);
+       list_for_each_entry(feature, &omnibook_available_feature->list, list) {
                if (feature->resume) {
                        retval = feature->resume(feature->io_op);
                        if (retval)
@@ -413,6 +404,20 @@ static int omnibook_resume(struct platform_device *dev)
        return 0;
 }
 
+/* 
+ * Find a given available feature by its name
+ */
+struct omnibook_feature *omnibook_find_feature(char *name)
+{
+       struct omnibook_feature *feature;
+
+       list_for_each_entry(feature, &omnibook_available_feature->list, list) {
+               if (!strcmp(feature->name, name))
+                       return feature;
+       }
+       return NULL;
+}
+
 /*
  * Maintain compatibility with the old ectype numbers:
  * ex: The user set/get ectype=12 for TSM30X=2^(12-1)
diff --git a/kbc.c b/kbc.c
new file mode 100644 (file)
index 0000000..7177a7c
--- /dev/null
+++ b/kbc.c
@@ -0,0 +1,155 @@
+/*
+ * kbc.c -- low level functions to access Keyboard Controller
+ * 
+ * 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 the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Written by Soós Péter <sp@osb.hu>, 2002-2004
+ * Modified by Mathieu Bérard <mathieu.berard@crans.org>, 2006
+ */
+
+#include "omnibook.h"
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include "hardware.h"
+
+extern int omnibook_key_polling_enable(void);
+extern int omnibook_key_polling_disable(void);
+
+/*
+ * Registers of the keyboard controller
+ */
+
+#define OMNIBOOK_KBC_DATA              0x60
+#define OMNIBOOK_KBC_SC                        0x64
+
+/*
+ * Keyboard controller status register bits
+ */
+
+#define OMNIBOOK_KBC_STAT_OBF          0x01    /* Output buffer full */
+#define OMNIBOOK_KBC_STAT_IBF          0x02    /* Input buffer full */
+#define OMNIBOOK_KBC_STAT_CMD          0x08    /* Last write was a command write (0=data) */
+
+/*
+ * Interrupt control
+ */
+
+static DEFINE_SPINLOCK(omnibook_kbc_lock);
+
+/*
+ * Wait for keyboard buffer
+ */
+
+static int omnibook_kbc_wait(u8 event)
+{
+       int timeout = OMNIBOOK_TIMEOUT;
+
+       switch (event) {
+       case OMNIBOOK_KBC_STAT_OBF:
+               while (!(inb(OMNIBOOK_KBC_SC) & event) && timeout--)
+                       mdelay(1);
+               break;
+       case OMNIBOOK_KBC_STAT_IBF:
+               while ((inb(OMNIBOOK_KBC_SC) & event) && timeout--)
+                       mdelay(1);
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (timeout > 0)
+               return 0;
+       return -ETIME;
+}
+
+/*
+ * Write to the keyboard command register
+ */
+
+static int omnibook_kbc_write_command(u8 cmd)
+{
+       int retval;
+
+       spin_lock_irq(&omnibook_kbc_lock);
+       retval = omnibook_kbc_wait(OMNIBOOK_KBC_STAT_IBF);
+       if (retval)
+               goto end;
+       outb(cmd, OMNIBOOK_KBC_SC);
+       retval = omnibook_kbc_wait(OMNIBOOK_KBC_STAT_IBF);
+      end:
+       spin_unlock_irq(&omnibook_kbc_lock);
+       return retval;
+}
+
+/*
+ * Write to the keyboard data register
+ */
+
+static int omnibook_kbc_write_data(u8 data)
+{
+       int retval;
+
+       spin_lock_irq(&omnibook_kbc_lock);
+       retval = omnibook_kbc_wait(OMNIBOOK_KBC_STAT_IBF);
+       if (retval)
+               goto end;;
+       outb(data, OMNIBOOK_KBC_DATA);
+       retval = omnibook_kbc_wait(OMNIBOOK_KBC_STAT_IBF);
+      end:
+       spin_unlock_irq(&omnibook_kbc_lock);
+       return retval;
+}
+
+/*
+ * Send a command to keyboard controller
+ */
+
+static int omnibook_kbc_command(const struct omnibook_operation *io_op, u8 data)
+{
+       int retval;
+
+       if ((retval = omnibook_kbc_write_command(OMNIBOOK_KBC_CONTROL_CMD)))
+               return retval;
+
+       retval = omnibook_kbc_write_data(data);
+       return retval;
+}
+
+/*
+ * Onetouch button hotkey handler
+ */
+static int omnibook_kbc_hotkeys(const struct omnibook_operation *io_op, unsigned int state)
+{
+       int retval;
+
+       retval = __omnibook_toggle(io_op, !!(state & HKEY_ONETOUCH));
+       return retval;
+}
+
+/*
+ * Backend interface declarations
+ */
+
+struct mutex kbc_mutex;
+
+struct omnibook_backend kbc_backend = {
+       .name = "i8042",
+       .hotkeys_write_cap = HKEY_ONETOUCH,
+       .byte_write = omnibook_kbc_command,
+       .hotkeys_set = omnibook_kbc_hotkeys,
+};
+
+/* End of file */
diff --git a/lcd.c b/lcd.c
index c6ddfcd811771a6d59223aefddab1220234c7c1c..df348a88f53d8b89e34c7283bb0a22074c4cd472 100644 (file)
--- a/lcd.c
+++ b/lcd.c
 #include <linux/backlight.h>
 #endif
 
-#include "ec.h"
+#include "hardware.h"
 
-static unsigned int omnibook_max_brightness;
+unsigned int omnibook_max_brightness;
 
 #ifdef CONFIG_OMNIBOOK_BACKLIGHT
-
 static struct backlight_device *omnibook_backlight_device;
 
 static int omnibook_get_backlight(struct backlight_device *bd);
@@ -40,9 +39,6 @@ static struct backlight_properties omnibookbl_data = {
        .update_status = omnibook_set_backlight,
 };
 
-#endif
-
-#ifdef CONFIG_OMNIBOOK_BACKLIGHT
 static int omnibook_get_backlight(struct backlight_device *bd)
 {
        int retval = 0;
@@ -50,7 +46,7 @@ static int omnibook_get_backlight(struct backlight_device *bd)
        u8 brgt;
 
        io_op = class_get_devdata(&bd->class_dev);
-       retval = io_op->backend->byte_read(io_op, &brgt);
+       retval = backend_byte_read(io_op, &brgt);
        if (!retval)
                retval = brgt;
 
@@ -63,16 +59,16 @@ static int omnibook_set_backlight(struct backlight_device *bd)
        struct omnibook_operation *io_op;
 
        io_op = class_get_devdata(&bd->class_dev);
-       return io_op->backend->byte_write(io_op, intensity);
+       return backend_byte_write(io_op, intensity);
 }
-#endif
+#endif /* CONFIG_OMNIBOOK_BACKLIGHT */
 
 static int omnibook_brightness_read(char *buffer, struct omnibook_operation *io_op)
 {
        int len = 0;
        u8 brgt;
 
-       io_op->backend->byte_read(io_op, &brgt);
+       backend_byte_read(io_op, &brgt);
 
        len +=
            sprintf(buffer + len, "LCD brightness: %2d (max value: %d)\n", brgt,
@@ -83,7 +79,7 @@ static int omnibook_brightness_read(char *buffer, struct omnibook_operation *io_
 
 static int omnibook_brightness_write(char *buffer, struct omnibook_operation *io_op)
 {
-       int brgt = 0;
+       unsigned int brgt = 0;
        char *endp;
 
        if (strncmp(buffer, "off", 3) == 0)
@@ -92,12 +88,12 @@ static int omnibook_brightness_write(char *buffer, struct omnibook_operation *io
                omnibook_lcd_blank(0);
        else {
                brgt = simple_strtoul(buffer, &endp, 10);
-               if ((endp == buffer) || (brgt < 0) || (brgt > omnibook_max_brightness))
+               if ((endp == buffer) || (brgt > omnibook_max_brightness))
                        return -EINVAL;
                else {
-                       io_op->backend->byte_write(io_op, brgt);
+                       backend_byte_write(io_op, brgt);
 #ifdef CONFIG_OMNIBOOK_BACKLIGHT
-                       omnibookbl_data.brightness=brgt;
+                       omnibookbl_data.brightness = brgt;
 #endif                 
                }
        }
@@ -127,7 +123,7 @@ static int __init omnibook_brightness_init(struct omnibook_operation *io_op)
        }
 
 #ifdef CONFIG_OMNIBOOK_BACKLIGHT
-       io_op->backend->byte_read(io_op, (u8*) &omnibookbl_data.brightness);
+       backend_byte_read(io_op, (u8*) &omnibookbl_data.brightness);
        omnibookbl_data.max_brightness = omnibook_max_brightness;
        omnibook_backlight_device =
            backlight_device_register(OMNIBOOK_MODULE_NAME, (void *)io_op, &omnibookbl_data);
diff --git a/lib.c b/lib.c
new file mode 100644 (file)
index 0000000..04328b8
--- /dev/null
+++ b/lib.c
@@ -0,0 +1,73 @@
+/*
+ * lib.c -- Generic helpers functions
+ * 
+ * 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 the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Written by Soós Péter <sp@osb.hu>, 2002-2004
+ * Modified by Mathieu Bérard <mathieu.berard@crans.org>, 2006
+ */
+
+#include "omnibook.h"
+
+#include "hardware.h"
+#include "compat.h"
+#include <linux/input.h>
+
+int __omnibook_apply_write_mask(const struct omnibook_operation *io_op, int toggle)
+{
+       int retval = 0;
+       int mask;
+       u8 data;
+
+       if ((retval = __backend_byte_read(io_op, &data)))
+               return retval;
+
+       if (toggle == 1)
+               mask = io_op->on_mask;
+       else if (toggle == 0)
+               mask = io_op->off_mask;
+       else
+               return -EINVAL;
+
+       if (mask > 0)
+               data |= (u8) mask;
+       else if (mask < 0)
+               data &= ~((u8) (-mask));
+       else
+               return -EINVAL;
+
+       retval = __backend_byte_write(io_op, data);
+
+       return retval;
+}
+
+/*
+ * Helper for toggle like operations
+ */
+int __omnibook_toggle(const struct omnibook_operation *io_op, int toggle)
+{
+       int retval;
+       u8 data;
+
+       data = toggle ? io_op->on_mask : io_op->off_mask;
+       retval = __backend_byte_write(io_op, data);
+       return retval;
+}
+
+void omnibook_report_key( struct input_dev *dev, unsigned int keycode)
+{
+       input_report_key(dev, keycode, 1);
+       input_sync(dev);
+       input_report_key(dev, keycode, 0);
+       input_sync(dev);
+}
+
+/* End of file */
index 78b1b96f8c3854cdfbc0328d454971f620ce67b6..751b8ef2cb629c4b88992ca17839ce50a5a455e0 100644 (file)
--- a/muteled.c
+++ b/muteled.c
  */
 
 #include "omnibook.h"
-#include "ec.h"
-
-/* There is no information about reading MUTE LED status */
-static int omnibook_muteled_enabled = 0;
+#include "hardware.h"
 
 static int omnibook_muteled_set(struct omnibook_operation *io_op, int status)
 {
-       if (omnibook_toggle(io_op, !!status)) {
+       int retval = 0;
+
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;
+
+       if((retval = __omnibook_toggle(io_op, !!status))) {
                printk(O_ERR "Failed muteled %s command.\n", status ? "on" : "off");
-               return -EIO;
+               goto out;
        }
-       return 0;
+
+       io_op->backend->misc_state = 
+               (io_op->backend->misc_state & ~MUTELED) | (MUTELED * !!status);
+
+       out:
+       mutex_unlock(&io_op->backend->mutex);
+       return retval;
 }
 
 /*
@@ -37,10 +45,13 @@ static int omnibook_muteled_read(char *buffer, struct omnibook_operation *io_op)
 {
        int len = 0;
 
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;
        len +=
            sprintf(buffer + len, "Last mute LED action was an %s command.\n",
-                   (omnibook_muteled_enabled) ? "on" : "off");
+                   (io_op->backend->misc_state & MUTELED) ? "on" : "off");
 
+       mutex_unlock(&io_op->backend->mutex);
        return len;
 }
 
@@ -51,8 +62,7 @@ static int omnibook_muteled_write(char *buffer, struct omnibook_operation *io_op
        if (*buffer == '0' || *buffer == '1') {
                cmd = *buffer - '0';
                if (!omnibook_muteled_set(io_op, cmd)) {
-                       omnibook_muteled_enabled = cmd;
-                       printk(O_INFO "Switching mute LED to %s state.\n", cmd ? "on" : "off");
+                       dprintk("Switching mute LED to %s state.\n", cmd ? "on" : "off");
                }
        } else {
                return -EINVAL;
@@ -60,9 +70,24 @@ static int omnibook_muteled_write(char *buffer, struct omnibook_operation *io_op
        return 0;
 }
 
+/*
+ * May re-enable muteled upon resume
+ */
 static int omnibook_muteled_resume(struct omnibook_operation *io_op)
+{      
+       int retval;
+       mutex_lock(&io_op->backend->mutex);
+       retval = __omnibook_toggle(io_op, !!(io_op->backend->misc_state & MUTELED));
+       mutex_unlock(&io_op->backend->mutex);
+       return retval;
+}
+
+/*
+ * Switch muteled off upon exit
+ */
+static void __exit omnibook_muteled_cleanup(struct omnibook_operation *io_op)
 {
-       return omnibook_muteled_set(io_op, omnibook_muteled_enabled);
+       omnibook_muteled_set(io_op, 0);
 }
 
 static struct omnibook_tbl muteled_table[] __initdata = {
@@ -75,6 +100,7 @@ static struct omnibook_feature __declared_feature muteled_driver = {
        .enabled = 1,
        .read = omnibook_muteled_read,
        .write = omnibook_muteled_write,
+       .exit = omnibook_muteled_cleanup,
        .resume = omnibook_muteled_resume,
        .ectypes = XE4500,
        .tbl = muteled_table,
diff --git a/nbsmi.c b/nbsmi.c
index 99c54d905cc30e71b4033a2e32e70bb8676e8820..c8da23bb2d6b12deeb50b679a4298d43d6d07f8c 100644 (file)
--- a/nbsmi.c
+++ b/nbsmi.c
  */
 
 #include "omnibook.h"
-
+#include "hardware.h"
 #include <linux/preempt.h>
 #include <linux/pci.h>
 #include <linux/kref.h>
 #include <asm/io.h>
 #include <asm/mc146818rtc.h>
-#include "ec.h"
-#include "compat.h"
+#include <linux/workqueue.h>
+
+/* copied from drivers/input/serio/i8042-io.h */
+#define I8042_KBD_PHYS_DESC "isa0060/serio0"
 
 /*
  * ATI's IXP PCI-LPC bridge
 #define BTAT_MASK      0x2
 
 /* 
- * We serialize access to this backend using a mutex
  * Crital sections around #SMI triggering are run atomically using a spinlock 
  */
-static DEFINE_MUTEX(smi_lock);
 static DEFINE_SPINLOCK(smi_spinlock);
 
 /*
  * Private data of this backend
  */
-static struct kref *refcount;
 static struct pci_dev *lpc_bridge;     /* Southbridge chip ISA bridge/LPC interface PCI device */
 static u8 start_offset;
-static int already_failed = 0; /* Backend init already failed at leat once */
+static struct input_dev *nbsmi_input_dev;
 
 /*
  * Possible list of supported southbridges
@@ -85,11 +84,7 @@ extern const struct pci_device_id lpc_bridge_table[];
  * Since we are going to trigger an SMI, all registers (I assume this does not
  * include esp and maybe ebp) and eflags may be mangled in the
  * process. 
- * So we save and restore all registers and eflags using the stack.
  * We also disable preemtion and IRQs upon SMI call.
- * FIXME: To be sorted out:
- * -> Can we reliably use spin_lock_irqsave/restore and remove the pushf/popf ?
- * -> Can we remove the pusha/popa and add eax ebx ecx edx esi edi to clobber list ?
  */
 
 static inline u32 ati_do_smi_call( u16 function)
@@ -146,6 +141,7 @@ static inline u32 intel_do_smi_call(u16 function)
        sci_en = sci_en & 0xff80; /* Keep bits 15:7 */
        sci_en += INTEL_GPE0_EN;  /* GPEO_EN offset */
        state = inl(sci_en);
+       outl(0,sci_en);
 
 /*
  * eflags, eax, ebx, ecx, edx, esi and edi are clobbered upon writing to SMI_PORT
@@ -222,9 +218,6 @@ static int nbsmi_smi_read_command(const struct omnibook_operation *io_op, u8 * d
        if (!lpc_bridge)
                return -ENODEV;
 
-       if (mutex_lock_interruptible(&smi_lock))
-               return -ERESTARTSYS;
-
        inputbuffer = kcalloc(BUFFER_SIZE, sizeof(u8), GFP_KERNEL);
        if (!inputbuffer) {
                retval = -ENOMEM;
@@ -251,7 +244,6 @@ static int nbsmi_smi_read_command(const struct omnibook_operation *io_op, u8 * d
       error2:
        kfree(inputbuffer);
       error1:
-       mutex_unlock(&smi_lock);
        return retval;
 }
 
@@ -264,9 +256,6 @@ static int nbsmi_smi_write_command(const struct omnibook_operation *io_op, u8 da
        if (!lpc_bridge)
                return -ENODEV;
 
-       if (mutex_lock_interruptible(&smi_lock))
-               return -ERESTARTSYS;
-
        inputbuffer = kcalloc(BUFFER_SIZE, sizeof(u8), GFP_KERNEL);
        if (!inputbuffer) {
                retval = -ENOMEM;
@@ -287,63 +276,218 @@ static int nbsmi_smi_write_command(const struct omnibook_operation *io_op, u8 da
       error2:
        kfree(inputbuffer);
       error1:
-       mutex_unlock(&smi_lock);
        return retval;
 }
 
 /*
  * Read/Write to INDEX/DATA interface at port 0x300 (SMSC Mailbox registers)
- * Used by Hotkeys feature under already taken mutex.
  */
-static void nbsmi_ec_read_command(u16 index, u16 * data)
+void nbsmi_ec_read_command(u8 index, u8 * data)
 {
        spin_lock_irq(&smi_spinlock);
-       outw(index, EC_INDEX_PORT);
-       *data = inw(EC_DATA_PORT);
+       outb(index, EC_INDEX_PORT);
+       *data = inb(EC_DATA_PORT);
        spin_unlock_irq(&smi_spinlock);
 }
 
-static void nbsmi_ec_write_command(u16 index, u16 data)
+#if 0
+static void nbsmi_ec_write_command(u8 index, u8 data)
 {
        spin_lock_irq(&smi_spinlock);
-       outw(index, EC_INDEX_PORT);
-       outw(data, EC_DATA_PORT);
+       outb(index, EC_INDEX_PORT);
+       outb(data, EC_DATA_PORT);
        spin_unlock_irq(&smi_spinlock);
 }
+#endif
+
+
+/*
+ * Hotkeys workflow:
+ * 1. Fn+Foo pressed
+ * 2. Scancode 0x6d generated by kbd controller
+ * 3. Scancode 0x6d caught by omnibook input handler
+ * 4. SMI Call issued -> Got keycode of last actually pressed Fn key
+ * 5. nbsmi_scan_table used to associate a detected keycode with a generated one
+ * 6. Generated keycode issued using the omnibook input device
+ */
+
+/*
+ * The input handler should only bind with the standard AT keyboard.
+ * XXX: Scancode 0x6d won't be detected if the keyboard has already been
+ * grabbed (the Xorg event input driver do that)
+ */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
+static struct input_handle *hook_connect(struct input_handler *handler,
+                                        struct input_dev *dev,
+                                        const struct input_device_id *id)
+#else
+static struct input_handle *hook_connect(struct input_handler *handler,
+                                        struct input_dev *dev,
+                                        struct input_device_id *id)
+#endif
+{
+       struct input_handle *handle;
+
+       /* the 0x0001 vendor magic number is found in atkbd.c */
+       if(!(dev->id.bustype == BUS_I8042 && dev->id.vendor == 0x0001))
+               return NULL;
+
+       if(!strstr(dev->phys, I8042_KBD_PHYS_DESC))
+               return NULL;
+
+       dprintk("hook_connect for device %s.\n", dev->name);
+
+       if(dev->grab)
+               printk(O_WARN "Input device is grabbed by %s, Fn hotkeys won't work.\n",
+                       dev->grab->name);
+
+       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+       if (!handle)
+               return NULL;
+
+       handle->dev = dev;
+       handle->handler = handler;
+       handle->name = "omnibook_scancode_hook";
+
+       input_open_device(handle);
+
+       return handle;
+}
+
+static void hook_disconnect(struct input_handle *handle)
+{
+       dprintk("hook_disconnect.\n");
+       input_close_device(handle);
+       kfree(handle);
+}
+
+/*
+ * Hook for scancode 0x6d. Actual handling is done in a workqueue as 
+ * the nbsmi backend might sleep.
+ */
+
+static void omnibook_handle_fnkey(void* data);
+DECLARE_WORK(omnibook_fnkey_work, *omnibook_handle_fnkey, NULL);
+
+static void hook_event(struct input_handle *handle, unsigned int event_type,
+                     unsigned int event_code, int value)
+{
+       if (event_type == EV_MSC && event_code == MSC_SCAN && value == SMI_FN_SCAN )
+               schedule_work(&omnibook_fnkey_work);
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
+static const struct input_device_id hook_ids[] = {
+#else
+static struct input_device_id hook_ids[] = {
+#endif
+       {
+                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+                .evbit = { BIT(EV_KEY) },
+        },
+       { },    /* Terminating entry */
+};
+
+static struct input_handler hook_handler = {
+       .event          = hook_event,
+       .connect        = hook_connect,
+       .disconnect     = hook_disconnect,
+       .name           = OMNIBOOK_MODULE_NAME,
+       .id_table       = hook_ids,
+};
+
+/*
+ * Define some KEY_ that may be missing in input.h for some kernel versions
+ */
+#ifndef KEY_WLAN
+#define KEY_WLAN 238
+#endif 
+
+/*
+ * Detected scancode to keycode table
+ */
+static struct {
+       unsigned int scancode;
+       unsigned int keycode;
+} nbsmi_scan_table[] = {
+       { KEY_ESC, KEY_MUTE},
+       { KEY_F1, KEY_FN_F1},
+       { KEY_F2, KEY_PROG1},
+       { KEY_F3, KEY_SLEEP},
+       { KEY_F4, KEY_SUSPEND},
+       { KEY_F5, KEY_SWITCHVIDEOMODE},
+       { KEY_F6, KEY_BRIGHTNESSDOWN},
+       { KEY_F7, KEY_BRIGHTNESSUP},
+       { KEY_F8, KEY_WLAN},
+       { KEY_F9, KEY_FN_F9},
+       { KEY_SPACE, KEY_ZOOM},
+       { 0,0},
+};
+
+/*
+ * Register the input handler and the input device in the input subsystem
+ */
+static int register_input_subsystem(void)
+{
+       int i, retval = 0;
+       
+       nbsmi_input_dev = input_allocate_device();
+       if (!nbsmi_input_dev) {
+               retval = -ENOMEM;
+               goto out;
+       }
+
+       nbsmi_input_dev->name = "Omnibook NbSMI scancode generator";
+       nbsmi_input_dev->phys = "omnibook/input0";
+       nbsmi_input_dev->id.bustype = BUS_HOST;
+       
+       set_bit(EV_KEY, nbsmi_input_dev->evbit);
+       
+       for(i=0 ; i < ARRAY_SIZE(nbsmi_scan_table); i++)
+               set_bit(nbsmi_scan_table[i].keycode, nbsmi_input_dev->keybit);
+
+       retval = input_register_device(nbsmi_input_dev);
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
+       retval = input_register_handler(&hook_handler);
+       
+#else
+       input_register_handler(&hook_handler);
+#endif
+
+       out:    
+       return retval;
+}
+
 
 /*
  * Try to init the backend
  * This function can be called blindly as it use a kref
  * to check if the init sequence was already done.
  */
-
 static int omnibook_nbsmi_init(const struct omnibook_operation *io_op)
 {
        int retval = 0;
        int i;
-       u16 ec_data;
+       u8 ec_data;
        u32 smi_port = 0;
 
-/* ectypes other than TSM40 have no business with this backend */
+       /* ectypes other than TSM40 have no business with this backend */
        if (!(omnibook_ectype & TSM40))
                return -ENODEV;
 
-       if (already_failed) {
+       if (io_op->backend->already_failed) {
                dprintk("NbSmi backend init already failed, skipping.\n");
                return -ENODEV;
        }
 
-       if (!refcount) {
+       if (!lpc_bridge) {
                /* Fist use of the backend */
-               mutex_lock(&smi_lock);
                dprintk("Try to init NbSmi\n");
-               refcount = kmalloc(sizeof(struct kref), GFP_KERNEL);
-               if (!refcount) {
-                       retval = -ENOMEM;
-                       goto out;
-               }
-
-               kref_init(refcount);
+               mutex_init(&io_op->backend->mutex);
+               mutex_lock(&io_op->backend->mutex);
+               kref_init(&io_op->backend->kref);
 
                /* PCI probing: find the LPC Super I/O bridge PCI device */
                for (i = 0; !lpc_bridge && lpc_bridge_table[i].vendor; ++i)
@@ -389,22 +533,24 @@ static int omnibook_nbsmi_init(const struct omnibook_operation *io_op)
 
                /*
                 * Try some heuristic tests to avoid enabling this interface on unsuported laptops:
-                * See what a port 300h read index 8f gives. Guess there is nothing if read 0xffff
+                * See what a port 300h read index 8f gives. Guess there is nothing if read 0xff
                 */
 
                nbsmi_ec_read_command(SMI_FN_PRESSED, &ec_data);
                dprintk("NbSmi test probe read: %x\n", ec_data);
-               if (ec_data == 0xffff) {
+               if (ec_data == 0xff) {
                        printk(O_ERR "Probing at SMSC Mailbox registers failed, disabling NbSmi\n");
                        retval = -ENODEV;
                        goto error4;
                }
 
+               register_input_subsystem();
                dprintk("NbSmi init ok\n");
-               goto out;
+               mutex_unlock(&io_op->backend->mutex);
+               return 0;
        } else {
                dprintk("NbSmi has already been initialized\n");
-               kref_get(refcount);
+               kref_get(&io_op->backend->kref);
                return 0;
        }
       error4:
@@ -415,21 +561,30 @@ static int omnibook_nbsmi_init(const struct omnibook_operation *io_op)
        pci_dev_put(lpc_bridge);
        lpc_bridge = NULL;
       error1:
-       kfree(refcount);
-       refcount = NULL;
-       already_failed = 1;
-      out:
-       mutex_unlock(&smi_lock);
+       io_op->backend->already_failed = 1;
+       mutex_unlock(&io_op->backend->mutex);
+       mutex_destroy(&io_op->backend->mutex);
        return retval;
 }
 
+/*
+ * Free all allocated stuff and unregister from the input subsystem
+ */
 static void nbsmi_free(struct kref *ref)
 {
        u32 smi_port = 0;
+       struct omnibook_backend *backend;
 
-       mutex_lock(&smi_lock);
        dprintk("NbSmi not used anymore: disposing\n");
 
+       flush_scheduled_work();
+       input_unregister_handler(&hook_handler);
+       input_unregister_device(nbsmi_input_dev);
+
+       backend = container_of(ref, struct omnibook_backend, kref);
+
+       mutex_lock(&backend->mutex);
+
        switch (lpc_bridge->vendor) {
        case PCI_VENDOR_ID_INTEL:
                smi_port = INTEL_SMI_PORT;
@@ -444,18 +599,85 @@ static void nbsmi_free(struct kref *ref)
        pci_dev_put(lpc_bridge);
        release_region(smi_port, 2);
        release_region(EC_INDEX_PORT, 2);
-       kfree(refcount);
        lpc_bridge = NULL;
-       refcount = NULL;
-       mutex_unlock(&smi_lock);
+       mutex_unlock(&backend->mutex);
+       mutex_destroy(&backend->mutex);
 }
 
 static void omnibook_nbsmi_exit(const struct omnibook_operation *io_op)
 {
-/* ectypes other than TSM40 have no business with this backend */
+       /* ectypes other than TSM40 have no business with this backend */
        BUG_ON(!(omnibook_ectype & TSM40));
        dprintk("Trying to dispose NbSmi\n");
-       kref_put(refcount, nbsmi_free);
+       kref_put(&io_op->backend->kref, nbsmi_free);
+}
+
+/*
+ * Adjust the lcd backlight level by delta.
+ * Used for Fn+F6/F7 keypress
+ */
+static int adjust_brighness(int delta)
+{
+       struct omnibook_feature *lcd_feature = omnibook_find_feature("lcd");
+       struct omnibook_operation *io_op;
+       int retval = 0;
+       u8 brgt;
+
+       if(!lcd_feature)
+               return -ENODEV;
+
+       io_op = lcd_feature->io_op;
+
+       mutex_lock(&io_op->backend->mutex);
+
+       if(( retval = __backend_byte_read(io_op, &brgt)))
+               goto out;       
+
+       dprintk("FnF6/F7 pressed: adjusting britghtnes.\n");
+
+       if (((int) brgt + delta) < 0)
+               brgt = 0;
+       else if ((brgt + delta) > omnibook_max_brightness)
+               brgt = omnibook_max_brightness;
+       else
+               brgt += delta;
+       
+       retval = __backend_byte_write(io_op, brgt);
+
+       out:
+       mutex_unlock(&io_op->backend->mutex);
+       return retval;
+}
+
+static const struct omnibook_operation last_scan_op = SIMPLE_BYTE(SMI,SMI_GET_FN_LAST_SCAN,0);
+
+/*
+ * Workqueue hanlder for Fn hotkeys
+ */
+static void omnibook_handle_fnkey(void* data)
+{
+       int i;
+       u8 gen_scan;
+
+       if(nbsmi_smi_read_command(&last_scan_op, &gen_scan))
+               return;
+
+       dprintk("detected scancode %x.\n", gen_scan);
+       switch(gen_scan) {
+       case KEY_F6:
+               adjust_brighness(-1);
+               break;
+       case KEY_F7:
+               adjust_brighness(+1);
+               break;
+       }
+       for(i=0 ; i < ARRAY_SIZE(nbsmi_scan_table); i++) {
+               if( gen_scan == nbsmi_scan_table[i].scancode) {
+                       dprintk("generating keycode %i.\n", nbsmi_scan_table[i].keycode);
+                       omnibook_report_key(nbsmi_input_dev, nbsmi_scan_table[i].keycode);
+                       break;
+               }
+       }
 }
 
 static int omnibook_nbsmi_get_wireless(const struct omnibook_operation *io_op, unsigned int *state)
@@ -534,7 +756,7 @@ static int omnibook_nbmsi_hotkeys_get(const struct omnibook_operation *io_op, un
        *state |= (data & SMI_FN_TWICE_LOCK_MASK) ? HKEY_TWICE_LOCK : 0;
        *state |= (data & SMI_FN_DOCK_MASK) ? HKEY_DOCK : 0;
 
-       return HKEY_FN | HKEY_STICK | HKEY_TWICE_LOCK | HKEY_DOCK;
+       return 0;
 }
 #endif
 
@@ -562,10 +784,8 @@ static int omnibook_nbmsi_hotkeys_set(const struct omnibook_operation *io_op, un
        dprintk("set_hotkeys (Fn F5) raw_state: %x\n", data);
 
        retval = nbsmi_smi_write_command(&hotkeys_op, data);
-       if (retval < 0)
-               return retval;
-       else
-               return HKEY_FN | HKEY_STICK | HKEY_TWICE_LOCK | HKEY_DOCK | HKEY_FNF5;
+       
+       return retval;
 }
 
 static const unsigned int nbsmi_display_mode_list[] = {
@@ -619,6 +839,8 @@ static int omnibook_nbmsi_display_set(const struct omnibook_operation *io_op, un
 
 struct omnibook_backend nbsmi_backend = {
        .name = "nbsmi",
+/*     .hotkey_read_cap = HKEY_FN | HKEY_STICK | HKEY_TWICE_LOCK | HKEY_DOCK, */
+       .hotkeys_write_cap = HKEY_FN | HKEY_STICK | HKEY_TWICE_LOCK | HKEY_DOCK | HKEY_FNF5,
        .init = omnibook_nbsmi_init,
        .exit = omnibook_nbsmi_exit,
        .byte_read = nbsmi_smi_read_command,
index 06ed4aff9a6fdf99dccf8f174e8f5f528f2c8479..e85e74cca881ba0416087553e8f11982ef8a03aa 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/input.h>
 #include <linux/version.h>
 
 /*
@@ -25,7 +26,7 @@
  */
 
 #define OMNIBOOK_MODULE_NAME           "omnibook"
-#define OMNIBOOK_MODULE_VERSION                "2.20060000"
+#define OMNIBOOK_MODULE_VERSION                "2.20060000-exp"
 
 /*
  * EC types
@@ -57,7 +58,6 @@ struct omnibook_operation;
 
 struct omnibook_feature {
        char *name;             /* Name */
-       char *proc_entry;       /* Specify proc entry relative to /proc (will be omnibook/name otherwise) */
        int enabled;            /* Set from module parameter */
        int (*read) (char *,struct omnibook_operation *);       /* Procfile read function */
        int (*write) (char *,struct omnibook_operation *);/* Procfile write function */
@@ -118,6 +118,16 @@ enum {
        HKEY_FNF5 = (1<<6),             /* 64 Fn + F5 (toggle display) is enabled */
 };
 
+#define HKEY_LAST_SHIFT 6
+
+/*
+ * Various status bits
+ */
+enum {
+       MUTELED = (1<<0), /* Mute LED status */
+       TOUCHPAD = (1<<1), /* Touchpad status */
+};
+
 
 /*
  * Display state backend neutral masks
@@ -136,12 +146,11 @@ enum {
        DISPLAY_DVI_DET = (1<<7),       /* 128 External DVI port */
 };
 
-
-
-int omnibook_lcd_blank(int blank);
-int omnibook_get_ac(struct omnibook_operation *io_op);
-int omnibook_get_battery_status(int num, struct omnibook_battery_state *battstat);
+extern unsigned int omnibook_max_brightness;
 int set_omnibook_param(const char *val, struct kernel_param *kp);
+int omnibook_lcd_blank(int blank);
+struct omnibook_feature *omnibook_find_feature(char *name);
+void omnibook_report_key(struct input_dev *dev, unsigned int keycode);
 
 
 #define __declared_feature __attribute__ (( __section__(".features"),  __aligned__(__alignof__ (struct omnibook_feature)))) __attribute_used__
@@ -161,14 +170,17 @@ int set_omnibook_param(const char *val, struct kernel_param *kp);
 #define dprintk_simple(fmt, args...) do { } while(0)
 #endif
 
+
+
+
 /* 
  * Configuration for standalone compilation: 
  * -Register as backlight depends on kernel config (requires 2.6.17+ interface)
- * -APM emulation is disabled by default
+ * -Legacy features disbled by default
  */
 
 #ifdef  OMNIBOOK_STANDALONE
-#if     (defined (CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE)) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16))
+#if     (defined (CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE)) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
 #define CONFIG_OMNIBOOK_BACKLIGHT
 #else
 #undef  CONFIG_OMNIBOOK_BACKLIGHT
diff --git a/pio.c b/pio.c
new file mode 100644 (file)
index 0000000..e3d3a93
--- /dev/null
+++ b/pio.c
@@ -0,0 +1,174 @@
+/*
+ * pio.c -- low level functions I/O ports
+ * 
+ * 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 the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Written by Soós Péter <sp@osb.hu>, 2002-2004
+ * Modified by Mathieu Bérard <mathieu.berard@crans.org>, 2006
+ */
+
+#include "omnibook.h"
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include "hardware.h"
+
+/*
+ * IO port backend. Only support single or dual ports operations
+ * private data structure: it's the linked list of requested ports
+ * 
+ * Race condition issue: omnibook_pio_init/exit functions are only called from
+ * omnibook_backend_match and omnibook_remove from init.c, this should happen
+ * only at module init/exit time so there is no need for a lock.
+ */
+
+struct pio_private_data_t {
+       unsigned long addr;
+       struct kref refcount;
+       struct list_head list;
+};
+
+static struct pio_private_data_t pio_private_data = {
+       .addr = 0,
+       .list = LIST_HEAD_INIT(pio_private_data.list),
+};
+
+/*
+ * Match an entry in the linked list helper function: see if we have and entry
+ * whose addr field match maddr
+ */
+static struct pio_private_data_t *omnibook_match_port(struct pio_private_data_t *data,
+                                                     unsigned long maddr)
+{
+       struct pio_private_data_t *cursor;
+
+       list_for_each_entry(cursor, &data->list, list) {
+               if (cursor->addr == maddr) {
+                       return cursor;
+               }
+       }
+       return NULL;
+}
+
+/*
+ * See if we have to request raddr
+ */
+static int omnibook_claim_port(struct pio_private_data_t *data, unsigned long raddr)
+{
+       struct pio_private_data_t *match, *new;
+
+       match = omnibook_match_port(data, raddr);
+       if (match) {
+               /* Already requested by us: increment kref and quit */
+               kref_get(&match->refcount);
+               return 0;
+       }
+
+       /* there was no match: request the region and add to list */
+       if (!request_region(raddr, 1, OMNIBOOK_MODULE_NAME)) {
+               printk(O_ERR "Request I/O port error\n");
+               return -ENODEV;
+       }
+
+       new = kmalloc(sizeof(struct pio_private_data_t), GFP_KERNEL);
+       if (!new) {
+               release_region(raddr, 1);
+               return -ENOMEM;
+       }
+
+       kref_init(&new->refcount);
+       new->addr = raddr;
+       list_add(&new->list, &data->list);
+
+       return 0;
+}
+
+/*
+ * Register read_addr and write_addr
+ */
+static int omnibook_pio_init(const struct omnibook_operation *io_op)
+{
+       int retval = 0;
+
+       if (io_op->read_addr
+           && (retval = omnibook_claim_port(io_op->backend->data, io_op->read_addr)))
+               goto out;
+
+       if (io_op->write_addr && (io_op->write_addr != io_op->read_addr))
+               retval = omnibook_claim_port(io_op->backend->data, io_op->write_addr);
+
+      out:
+       return retval;
+}
+
+/*
+ * REALLY release a port
+ */
+static void omnibook_free_port(struct kref *ref)
+{
+       struct pio_private_data_t *data;
+
+       data = container_of(ref, struct pio_private_data_t, refcount);
+       release_region(data->addr, 1);
+       list_del(&data->list);
+       kfree(data);
+}
+
+/*
+ * Unregister read_addr and write_addr
+ */
+static void omnibook_pio_exit(const struct omnibook_operation *io_op)
+{
+       struct pio_private_data_t *match;
+
+       match = omnibook_match_port(io_op->backend->data, io_op->read_addr);
+       if (match)
+               kref_put(&match->refcount, omnibook_free_port);
+
+       match = NULL;
+       match = omnibook_match_port(io_op->backend->data, io_op->write_addr);
+       if (match)
+               kref_put(&match->refcount, omnibook_free_port);
+
+}
+
+static int omnibook_io_read(const struct omnibook_operation *io_op, u8 * value)
+{
+       *value = inb(io_op->read_addr);
+       if (io_op->read_mask)
+               *value &= io_op->read_mask;
+       return 0;
+}
+
+static int omnibook_io_write(const struct omnibook_operation *io_op, u8 value)
+{
+       outb(io_op->write_addr, value);
+       return 0;
+}
+
+/*
+ * Backend interface declarations
+ */
+struct omnibook_backend pio_backend = {
+       .name = "pio",
+       .data = &pio_private_data,
+       .init = omnibook_pio_init,
+       .exit = omnibook_pio_exit,
+       .byte_read = omnibook_io_read,
+       .byte_write = omnibook_io_write,
+};
+
+/* End of file */
diff --git a/polling.c b/polling.c
new file mode 100644 (file)
index 0000000..3befba9
--- /dev/null
+++ b/polling.c
@@ -0,0 +1,256 @@
+/*
+ * polling.c -- scancode emulation for volume buttons
+ * 
+ * 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 the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Written by Soós Péter <sp@osb.hu>, 2002-2004
+ * Modified by Mathieu Bérard <mathieu.berard@crans.org>, 2006
+ */
+
+#include "omnibook.h"
+#include "hardware.h"
+#include <linux/workqueue.h>
+
+/* Predefined convinient on/off states */
+#define HKEY_ON  HKEY_ONETOUCH|HKEY_MULTIMEDIA|HKEY_FN|HKEY_DOCK|HKEY_FNF5|HKEY_VOL
+#define HKEY_OFF 0
+
+/*
+ * XE3GC type key_polling polling:
+ *
+ * Polling interval for keys (100 ms)
+ */
+
+#define OMNIBOOK_POLL  msecs_to_jiffies(100)
+
+/*
+ * workqueue manipulations are mutex protected and thus kept in sync with key_polling_enabled
+ */
+static struct workqueue_struct *omnibook_wq;  
+static int key_polling_enabled;
+DEFINE_MUTEX(poll_mutex);
+
+static void omnibook_key_poller(void *data);
+static struct omnibook_feature key_polling_driver;
+DECLARE_WORK(omnibook_poll_work, *omnibook_key_poller, &key_polling_driver.io_op);
+
+static struct input_dev *poll_input_dev;
+
+static void omnibook_key_poller(void *data)
+{
+       u8 q0a;
+       int retval;
+       struct omnibook_operation *io_op;
+
+       io_op = *( (struct omnibook_operation **) data);
+
+       mutex_lock(&io_op->backend->mutex);
+       __backend_byte_read(io_op, &q0a);
+       __backend_byte_write(io_op, 0);
+       mutex_unlock(&io_op->backend->mutex);
+
+#ifdef OMNIBOOK_DEBUG
+       if (unlikely(q0a & XE3GC_SLPB_MASK))
+               dprintk("Sleep button pressed.\n");
+       if (unlikely(q0a & XE3GC_F5_MASK))
+               dprintk("Fn-F5 - LCD/CRT switch pressed.\n");
+       if (unlikely(q0a & XE3GC_CNTR_MASK))
+               dprintk("Fn+F3/Fn+F4 - Contrast up or down pressed.\n");
+       if (unlikely(q0a & XE3GC_BRGT_MASK))
+               dprintk("Fn+F1/Fn+F2 - Brightness up or down pressed.\n");
+#endif
+
+       /*
+        * Volume button scancode emulaton
+        * It emulates a key press and a release without repeat as other OneTouch buttons do.
+        */
+
+       if (unlikely(q0a & XE3GC_VOLD_MASK)) {
+               dprintk("Fn-down arrow or Volume down pressed.\n");
+               omnibook_report_key(poll_input_dev, KEY_VOLUMEDOWN);
+       }
+       if (unlikely(q0a & XE3GC_VOLU_MASK)) {
+               dprintk("Fn-up arrow or Volume up pressed.\n");
+               omnibook_report_key(poll_input_dev, KEY_VOLUMEUP);
+       }
+       if (unlikely(q0a & XE3GC_MUTE_MASK)) {
+               dprintk("Fn+F7 - Volume mute pressed.\n");
+               omnibook_report_key(poll_input_dev, KEY_MUTE);
+       }
+
+       retval = queue_delayed_work(omnibook_wq, &omnibook_poll_work, OMNIBOOK_POLL);
+       if(unlikely(!retval)) /* here non-zero on success */
+               printk(O_ERR "Key_poller failed to rearm.\n");
+}
+
+static int omnibook_key_polling_enable(void)
+{
+       int retval = 0;
+
+       if(mutex_lock_interruptible(&poll_mutex))
+               return -ERESTARTSYS;
+
+       if(key_polling_enabled)
+               goto out;
+
+       retval = !queue_delayed_work(omnibook_wq, &omnibook_poll_work, OMNIBOOK_POLL);
+       if(retval)
+               printk(O_ERR "Key_poller enabling failed.\n");
+       else {  
+               dprintk("Scancode emulation for volume buttons enabled.\n");
+               key_polling_enabled = 1;
+       }
+
+       out:
+       mutex_unlock(&poll_mutex);
+       return retval;
+}
+       
+static int omnibook_key_polling_disable(void)
+{
+       if(mutex_lock_interruptible(&poll_mutex))
+               return -ERESTARTSYS;
+
+       if(!key_polling_enabled)
+               goto out;
+
+       cancel_rearming_delayed_workqueue(omnibook_wq, &omnibook_poll_work);
+       dprintk("Scancode emulation for volume buttons disabled.\n");
+       key_polling_enabled = 0;
+
+       out:
+       mutex_unlock(&poll_mutex);
+       return 0;
+}
+
+
+static int omnibook_key_polling_read(char *buffer, struct omnibook_operation *io_op)
+{
+       int len = 0;
+       
+       if(mutex_lock_interruptible(&poll_mutex))
+               return -ERESTARTSYS;
+
+       len += sprintf(buffer + len, "Volume buttons polling is %s.\n",
+               (key_polling_enabled) ? "enabled" : "disabled");
+#ifdef OMNIBOOK_DEBUG
+       if(key_polling_enabled) 
+               len += sprintf(buffer + len, "Will poll in %i msec.\n",
+               jiffies_to_msecs(omnibook_poll_work.timer.expires - jiffies));
+#endif
+       mutex_unlock(&poll_mutex);
+       return len;
+}
+
+static int omnibook_key_polling_write(char *buffer, struct omnibook_operation *io_op)
+{
+       int retval;
+       switch (*buffer) {
+       case '0':
+               retval = omnibook_key_polling_disable();
+               break;
+       case '1':
+               retval = omnibook_key_polling_enable();
+               break;
+       default:
+               retval = -EINVAL;
+       }
+       return retval;
+}
+
+
+/*
+ * Stop polling upon suspend an restore it upon resume
+ */
+static int omnibook_key_polling_resume(struct omnibook_operation *io_op)
+{
+       int retval = 0;
+
+       mutex_lock(&poll_mutex);
+       if(key_polling_enabled)
+               retval = !queue_delayed_work(omnibook_wq, &omnibook_poll_work, OMNIBOOK_POLL);
+       mutex_unlock(&poll_mutex);
+       return retval;  
+}
+
+static int omnibook_key_polling_suspend(struct omnibook_operation *io_op)
+{
+       mutex_lock(&poll_mutex);
+       if(key_polling_enabled)
+               cancel_rearming_delayed_workqueue(omnibook_wq, &omnibook_poll_work);
+       mutex_unlock(&poll_mutex);
+       return 0;
+}
+
+static int __init omnibook_key_polling_init(struct omnibook_operation *io_op)
+{
+       int retval = 0; 
+       
+       poll_input_dev = input_allocate_device();
+       if (!poll_input_dev) {
+               retval = -ENOMEM;
+               goto out;
+       }
+
+       poll_input_dev->name = "Omnibook legacy laptop scancode generator";
+       poll_input_dev->phys = "omnibook/input0";
+       poll_input_dev->id.bustype = BUS_HOST;
+       
+       /* this device has three keys */
+       set_bit(EV_KEY, poll_input_dev->evbit);
+       set_bit(KEY_VOLUMEDOWN, poll_input_dev->keybit);
+       set_bit(KEY_VOLUMEUP, poll_input_dev->keybit);
+       set_bit(KEY_MUTE, poll_input_dev->keybit);
+
+       retval = input_register_device(poll_input_dev);
+       if (retval) {
+               input_free_device(poll_input_dev);
+               goto out;
+       }
+
+       omnibook_wq = create_singlethread_workqueue("omnibook");
+       if(!omnibook_wq)
+               retval = -ENOMEM;
+       else
+               retval = omnibook_key_polling_enable();
+
+out:
+       return retval;
+}
+
+static void __exit omnibook_key_polling_cleanup(struct omnibook_operation *io_op)
+{
+       omnibook_key_polling_disable(); 
+       destroy_workqueue(omnibook_wq);
+       input_unregister_device(poll_input_dev);
+}
+
+static struct omnibook_tbl key_polling_table[] __initdata = {
+       {XE3GC, SIMPLE_BYTE(EC, XE3GC_Q0A, 0)},
+       {0,}
+};
+
+static struct omnibook_feature __declared_feature key_polling_driver = {
+       .name = "key_polling",
+       .enabled = 0, /* dangerous */
+       .read = omnibook_key_polling_read,
+       .write = omnibook_key_polling_write,
+       .init = omnibook_key_polling_init,
+       .exit = omnibook_key_polling_cleanup,
+       .suspend = omnibook_key_polling_suspend,
+       .resume = omnibook_key_polling_resume,
+       .ectypes = XE3GC,
+       .tbl = key_polling_table,
+};
+
+module_param_named(key_polling, key_polling_driver.enabled, int, S_IRUGO);
+MODULE_PARM_DESC(key_polling, "Use 0 to disable, 1 to enable key polling");
+/* End of file */
index 61bc6c33b6e64bd5bd04b62979caffc7a9b765f7..d5c109e50c10e8e9e0797962314bbba397c4ab4a 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
 
 static int omnibook_temperature_read(char *buffer, struct omnibook_operation *io_op)
 {
@@ -24,7 +24,7 @@ static int omnibook_temperature_read(char *buffer, struct omnibook_operation *io
        int retval;
        u8 temp;
 
-       if ((retval = io_op->backend->byte_read(io_op, &temp)))
+       if ((retval = backend_byte_read(io_op, &temp)))
                return retval;
 
        len += sprintf(buffer + len, "CPU temperature:            %2d C\n", temp);
index 93035af9c2a6df0aba4773462e4889bb52e5ff67..679d2d3f07bb6afbb2a5eac95ce2a3eefabe461c 100644 (file)
  */
 
 #include "omnibook.h"
-#include "ec.h"
-
-/* Touchpad is assumed to be enabled by default */
-static int omnibook_touchpad_enabled = 1;
+#include "hardware.h"
 
 static int omnibook_touchpad_set(struct omnibook_operation *io_op, int status)
 {
        int retval = 0;
-       if ((retval = omnibook_toggle(io_op, !!status))) {
+
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;
+
+       if ((retval = __omnibook_toggle(io_op, !!status))) {
                printk(O_ERR "Failed touchpad %sable command.\n", status ? "en" : "dis");
+               goto out;
        }
+
+       io_op->backend->misc_state = 
+               (io_op->backend->misc_state & ~TOUCHPAD) | (TOUCHPAD * !!status);
+
+       out:
+       mutex_unlock(&io_op->backend->mutex);
        return retval;
 }
 
 /*
- * Power management handlers: redisable touchpad on resume (if requested)
+ * Power management handlers: redisable touchpad on resume (if necessary)
  */
 static int omnibook_touchpad_resume(struct omnibook_operation *io_op)
 {
        int retval;
-       retval = (omnibook_touchpad_enabled ? 0 : omnibook_touchpad_set(io_op, 0));
+       mutex_lock(&io_op->backend->mutex);
+       retval = __omnibook_toggle(io_op, !!(io_op->backend->misc_state & TOUCHPAD));
+       mutex_unlock(&io_op->backend->mutex);
        return retval;
 }
 
@@ -47,10 +57,14 @@ static int omnibook_touchpad_read(char *buffer, struct omnibook_operation *io_op
 {
        int len = 0;
 
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;
+
        len +=
            sprintf(buffer + len, "Last touchpad action was an %s command.\n",
-                   (omnibook_touchpad_enabled) ? "enable" : "disable");
+                   (io_op->backend->misc_state & TOUCHPAD) ? "enable" : "disable");
 
+       mutex_unlock(&io_op->backend->mutex);
        return len;
 }
 
@@ -61,8 +75,7 @@ static int omnibook_touchpad_write(char *buffer, struct omnibook_operation *io_o
        if (*buffer == '0' || *buffer == '1') {
                cmd = *buffer - '0';
                if (!omnibook_touchpad_set(io_op, cmd)) {
-                       omnibook_touchpad_enabled = cmd;
-                       printk(O_INFO "%sabling touchpad.\n", cmd ? "En" : "Dis");
+                       dprintk("%sabling touchpad.\n", cmd ? "En" : "Dis");
                }
        } else {
                return -EINVAL;
@@ -70,6 +83,16 @@ static int omnibook_touchpad_write(char *buffer, struct omnibook_operation *io_o
        return 0;
 }
 
+
+static int __init omnibook_touchpad_init(struct omnibook_operation *io_op)
+{
+       mutex_lock(&io_op->backend->mutex);
+       /* Touchpad is assumed to be enabled by default */
+       io_op->backend->misc_state |= TOUCHPAD;
+       mutex_unlock(&io_op->backend->mutex);
+       return 0;
+}
+
 /*
  * Reenable touchpad upon exit
  */
@@ -91,6 +114,7 @@ static struct omnibook_feature __declared_feature touchpad_driver = {
        .enabled = 1,
        .read = omnibook_touchpad_read,
        .write = omnibook_touchpad_write,
+       .init = omnibook_touchpad_init,
        .exit = omnibook_touchpad_cleanup,
        .resume = omnibook_touchpad_resume,
        .ectypes = XE3GF | XE3GC | TSP10 | TSM30X,
index 045cd1da1344b0c0cb3fadab508626e9914a5a4e..aad5ca9b9b99ed7707944c6dbdc23fd15fcdd440 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
 
 static int omnibook_wifi_read(char *buffer, struct omnibook_operation *io_op)
 {
@@ -24,7 +24,7 @@ static int omnibook_wifi_read(char *buffer, struct omnibook_operation *io_op)
        int retval;
        unsigned int state;
 
-       if ((retval = io_op->backend->aerial_get(io_op, &state)))
+       if ((retval = backend_aerial_get(io_op, &state)))
                return retval;
 
        len +=
@@ -45,23 +45,30 @@ static int omnibook_wifi_write(char *buffer, struct omnibook_operation *io_op)
        int retval = 0;
        unsigned int state;
 
-       if ((retval = io_op->backend->aerial_get(io_op, &state)))
-               return retval;
+       if(mutex_lock_interruptible(&io_op->backend->mutex))
+               return -ERESTARTSYS;    
+
+       if ((retval = __backend_aerial_get(io_op, &state)))
+               goto out;
 
        if (*buffer == '0')
                state &= ~WIFI_STA;
        else if (*buffer == '1')
                state |= WIFI_STA;
-       else
-               return -EINVAL;
+       else {
+               retval = -EINVAL;
+               goto out;
+       }
 
-       if ((retval = io_op->backend->aerial_set(io_op, state)))
+       if ((retval = __backend_aerial_set(io_op, state)))
                return retval;
 
+       out:            
+       mutex_unlock(&io_op->backend->mutex);
        return retval;
 }
 
-static struct omnibook_feature wifi_feature;
+static struct omnibook_feature wifi_driver;
 
 static int __init omnibook_wifi_init(struct omnibook_operation *io_op)
 {
@@ -72,11 +79,11 @@ static int __init omnibook_wifi_init(struct omnibook_operation *io_op)
  *  Refuse enabling/disabling a non-existent device
  */
 
-       if ((retval = io_op->backend->aerial_get(io_op, &state)))
+       if ((retval = backend_aerial_get(io_op, &state)))
                return retval;
 
        if (!(state & WIFI_EX))
-               wifi_feature.write = NULL;
+               wifi_driver.write = NULL;
 
        return retval;
 }