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)
*/
#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;
}
*/
#include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
#ifdef CONFIG_ACPI
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 */
};
/*
}
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) {
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);
}
/*
*/
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;
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;
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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 */
*/
#include "omnibook.h"
-
-#include "ec.h"
+#include "hardware.h"
static int ec_read16(u8 addr, u16 * data)
{
u8 high;
u8 low;
u16 result;
-
retval = legacy_ec_read(addr, &low);
if (retval)
return retval;
* 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;
#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;
}
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;
}
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)
*/
#include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
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 +=
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)
{
* 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;
}
#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
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)
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;
}
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);
}
/*
if (!lpc_bridge)
return -ENODEV;
- if (mutex_lock_interruptible(&compal_lock))
- return -ERESTARTSYS;
-
retval = enable_cdimode();
if (retval)
goto out;
clear_cdimode();
out:
clear_cdimode_pci();
- mutex_unlock(&compal_lock);
return retval;
}
if (!lpc_bridge)
return -ENODEV;
- if (mutex_lock_interruptible(&compal_lock))
- return -ERESTARTSYS;
-
retval = enable_cdimode();
if (retval)
goto out;
clear_cdimode();
out:
clear_cdimode_pci();
- mutex_unlock(&compal_lock);
return retval;
}
{ 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 */
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,
/*
- * 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
*/
#include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
static const char display_name[][16] = {
"Internal LCD",
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;
if (endp == buffer)
return -EINVAL;
else
- retval = io_op->backend->display_set(io_op, state);
+ retval = backend_display_set(io_op, state);
return retval;
}
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)
*/
#include "omnibook.h"
-
-#include "ec.h"
+#include "hardware.h"
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");
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)},
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,
};
*/
#include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
static u8 ecdump_regs[256];
/*
* 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
#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
*/
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
*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;
}
#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
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;
}
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;
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,
.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 */
#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 };
u8 fan;
int retval;
- if ((retval = io_op->backend->byte_read(io_op, &fan)))
+ if ((retval = backend_byte_read(io_op, &fan)))
return retval;
/*
{
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;
}
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)
{
* They only support fan reading
*/
if (omnibook_ectype & (OB4150 | XE2 | AMILOD))
- fan_feature.write = NULL;
+ fan_driver.write = NULL;
return 0;
}
.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 */
#include "omnibook.h"
#include <linux/ctype.h>
-#include "ec.h"
+#include "hardware.h"
/*
* Default temperature limits.
/*
- * 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
*/
#include <linux/acpi.h>
+#include "compat.h"
/*
* Quite ugly:
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 }
/*
* 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 *);
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;
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
#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
*/
/*
* Index and values for Command/Data/Index interface
+ * Notice similitudes with commands code for kbc
*/
#define TSM70_FN_INDEX 0x45
#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
#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
#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 */
*/
#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;
}
/*
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] = {
"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;
}
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;
}
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,}},
.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);
#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>
static int omnibook_userset = 0;
+struct input_dev *omnibook_input_dev;
+
/*
* The platform_driver interface was added in linux 2.6.15
*/
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);
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;
}
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);
}
*/
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);
}
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)
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)
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)
--- /dev/null
+/*
+ * 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 */
#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);
.update_status = omnibook_set_backlight,
};
-#endif
-
-#ifdef CONFIG_OMNIBOOK_BACKLIGHT
static int omnibook_get_backlight(struct backlight_device *bd)
{
int retval = 0;
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;
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,
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)
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
}
}
}
#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);
--- /dev/null
+/*
+ * 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 */
*/
#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;
}
/*
{
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;
}
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;
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 = {
.enabled = 1,
.read = omnibook_muteled_read,
.write = omnibook_muteled_write,
+ .exit = omnibook_muteled_cleanup,
.resume = omnibook_muteled_resume,
.ectypes = XE4500,
.tbl = muteled_table,
*/
#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
* 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)
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
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;
error2:
kfree(inputbuffer);
error1:
- mutex_unlock(&smi_lock);
return retval;
}
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;
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)
/*
* 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:
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;
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)
*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
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[] = {
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,
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/input.h>
#include <linux/version.h>
/*
*/
#define OMNIBOOK_MODULE_NAME "omnibook"
-#define OMNIBOOK_MODULE_VERSION "2.20060000"
+#define OMNIBOOK_MODULE_VERSION "2.20060000-exp"
/*
* EC types
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 */
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
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__
#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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
*/
#include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
static int omnibook_temperature_read(char *buffer, struct omnibook_operation *io_op)
{
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);
*/
#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;
}
{
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;
}
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;
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
*/
.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,
*/
#include "omnibook.h"
-#include "ec.h"
+#include "hardware.h"
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 +=
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)
{
* 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;
}