code:
 3rdparty/acerhk/AUTHORS         |    1
 3rdparty/acerhk/COPYING         |  340 ++++
 3rdparty/acerhk/INSTALL         |  109 +
 3rdparty/acerhk/Makefile        |   65
 3rdparty/acerhk/NEWS            |   16
 3rdparty/acerhk/README          |  215 ++
 3rdparty/acerhk/acerhk.c        | 2999 ++++++++++++++++++++++++++++++++++++++++
 3rdparty/acerhk/acerhk.h        |   91 +
 3rdparty/acerhk/doc/FAQ         |  150 ++
 3rdparty/acerhk/doc/IOCTL       |   61
 3rdparty/acerhk/doc/acertm.def  |   56
 3rdparty/acerhk/doc/keycodes    |   26
 3rdparty/acerhk/doc/md95400.def |   14
 13 files changed, 4143 insertions(+)
diff -Nurp linux-2.6.37/3rdparty/acerhk/acerhk.c linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.c
--- linux-2.6.37/3rdparty/acerhk/acerhk.c	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.c	2007-02-10 17:46:23.000000000 +0200
@@ -0,0 +1,2999 @@
+/*********************************************************************
+ * Filename:      acerhk.c
+ * Version:       0.5
+ *
+ * Copyright (C) 2002-2006, Olaf Tauber (olaf-tauber@versanet.de)
+ *
+ * Description:   kernel driver for Acer Travelmate and similar
+ *                laptops special keys
+ * Author:        Olaf Tauber <olaf-tauber@versanet.de>
+ * Created at:    Mon Apr 29 22:16:42 2002
+ * Modified at:   Mon Oct 16 21:36:44 2006
+ * Modified by:   Olaf Tauber <olaf-tauber@versanet.de>
+ * Modified at:   Thu Nov 24 13:03:01 2005
+ * Modified by:   Antonio Cuni <cuni@programmazione.it>
+ * Modified at:   Wed Oct 27 19:47:11 CEST 2004
+ * Modified by:   Joachim Fenkes <acerhk@dojoe.net>
+ *
+ * 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 of the License, 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ */
+
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+
+/* This driver is heavily dependent on the architecture, don't let
+ * anyone without an X86 machine use it. On laptops with AMD64
+ * architecture this driver is only useable in 32 bit mode.
+ */
+#ifdef CONFIG_X86
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define KERNEL26
+#include <linux/moduleparam.h>
+#else
+#include <linux/modversions.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+#define STATIC_INPUT_DEV
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/miscdevice.h>
+#include <linux/mc146818rtc.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+
+#include "acerhk.h"
+
+/* #define ACERDEBUG */
+/* #define DUMMYHW */
+
+#define ACERHK_VERSION "0.5.35"
+#define MODULE_NAME "acerhk"
+
+/* maximum number of polling loops, adjust it if needed to values between
+ * 1 and 32
+ */
+#define MAX_POLLING_LOOPS 16U
+
+/* maximum length for model string */
+#define ACERHK_MODEL_STRLEN 16
+/* size of mapped areas */
+#define AREA_SIZE 0xffff
+/* needed for colussi algorithm */
+#define XSIZE     20
+
+/* Module parameters */
+static int poll=1;
+static int autowlan;
+static int usedritek=1;
+static int wlan_state=-1;
+static int bluetooth_state=-1;
+static int verbose;
+static unsigned int force_series;
+#ifdef KERNEL26
+module_param(poll, int, 0444);
+module_param(autowlan, int, 0444);
+module_param(usedritek, int, 0444);
+module_param(verbose, int, 0444);
+module_param(wlan_state, int, 0444);
+module_param(bluetooth_state, int, 0444);
+module_param(force_series, uint, 0444);
+#else
+MODULE_PARM(poll, "i");
+MODULE_PARM(autowlan, "i");
+MODULE_PARM(wlan_state, "i");
+MODULE_PARM(bluetooth_state, "i");
+MODULE_PARM(usedritek, "i");
+MODULE_PARM(verbose, "i");
+MODULE_PARM(force_series, "i");
+#endif
+MODULE_PARM_DESC(poll, "start polling timer");
+MODULE_PARM_DESC(autowlan, "automatic switching of wlan hardware");
+MODULE_PARM_DESC(wlan_state, "(assumed) initial state of WLAN LED/hardware");
+MODULE_PARM_DESC(bluetooth_state, "(assumed) initial state of Bluetooth LED/hardware");
+MODULE_PARM_DESC(usedritek, "enable dritek keyboard extension");
+MODULE_PARM_DESC(verbose, "output additional information");
+MODULE_PARM_DESC(force_series, "force laptop series, skip autodetection");
+
+/* input device */
+static struct input_dev *acerhk_input_dev_ptr;
+#ifdef STATIC_INPUT_DEV
+static struct input_dev acerhk_input_dev;
+#endif
+
+/* mapped IO area from 0xf0000 */
+static void *reg1;
+/* mapped IO area from 0xe0000 */
+static void *reg2;
+/* Pointer to mapped area at 0x400 on 520 series */
+static void *preg400;
+/* location of IO routine in mapped area */
+static unsigned int bios_routine;
+/* index of CMOS port to get key event */
+static unsigned int cmos_index;
+/* function for bios call */
+static bios_call call_bios;
+/* address of model string */
+static char *acerhk_model_addr;
+/* copied string, maximum length 16 ('TravelMate xxx') */
+static char acerhk_model_string[ACERHK_MODEL_STRLEN];
+/* type of hardware access  */
+static t_acer_type acerhk_type;
+/* travelmate series  */
+static unsigned int acerhk_series;
+/* supported features for this model */
+static unsigned int acerhk_model_features;
+/* map of acer key codes to acer key names */
+static unsigned char acerhk_key2name[0xff];
+/* map of acer key names to key events */
+static t_map_name2event acerhk_name2event;
+/* timer for polling key presses */
+static struct timer_list acerhk_timer_poll;
+/* polling active */
+static int acerhk_polling_state;
+/* polling delay */
+static unsigned acerhk_polling_delay = HZ/5;
+/* wlan hardware toggle */
+static int acerhk_wlan_state;
+/* bluetooth hardware toggle */
+static int acerhk_bluetooth_state;
+
+/* bluetooth blinking state; added by Antonio Cuni
+   possible values:
+      -1: blinking disabled (default)
+       0: blinking enabled, led currently off
+       1: blinking enabled, led currently on
+*/
+static int acerhk_blueled_blinking = -1;
+/* delay between two changes of state, in jiffies */
+static unsigned acerhk_blueled_blinking_delay;
+/* timer for blinking */
+static struct timer_list acerhk_timer_blinking;
+
+/* function prototypes */
+static void start_polling(void);
+static void stop_polling(void);
+
+/* Added by Antonio Cuni */
+static void start_blinking(void);
+static void stop_blinking(void);
+
+/* {{{ Experimental use of dritek keyboard extension */
+
+#define EC_STATUS_REG		0x66	/* Status register of EC (R) */
+#define EC_CNTL_REG		    0x66	/* Controller command register of EC (W) */
+#define EC_DATA_REG		    0x62	/* EC data register (R/W) */
+
+#ifdef KERNEL26
+
+#include <linux/preempt.h>
+
+#define KBD_STATUS_REG		0x64	/* Status register (R) */
+#define KBD_CNTL_REG		0x64	/* Controller command register (W) */
+#define KBD_DATA_REG		0x60	/* Keyboard data register (R/W) */
+
+#else
+
+#ifndef KEY_MEDIA
+#define KEY_MEDIA		226
+#endif
+
+#define preempt_disable()		do { } while (0)
+#define preempt_enable_no_resched()	do { } while (0)
+#define preempt_enable()		do { } while (0)
+#define preempt_check_resched()		do { } while (0)
+#include <linux/pc_keyb.h>
+
+#endif
+
+static inline int my_i8042_read_status(void)
+{
+  return inb(KBD_STATUS_REG);
+}
+static int my_i8042_wait_write(void)
+{
+	int i = 0;
+	while ((my_i8042_read_status() & 0x02) && (i < 10000)) {
+		udelay(50);
+		i++;
+	}
+	return -(i == 10000);
+}
+static void send_kbd_cmd(unsigned char cmd, unsigned char val)
+{
+  if (usedritek) {
+    preempt_disable();
+    if (!my_i8042_wait_write())
+      outb(cmd, KBD_CNTL_REG);
+    if (!my_i8042_wait_write())
+      outb(val, KBD_DATA_REG);
+    preempt_enable_no_resched();
+  } else {
+    printk(KERN_INFO"acerhk: request for accessing EC ignored\n"
+           KERN_INFO"acerhk: Use of dritek keyboard extension not enabled, use module\n"
+           KERN_INFO"acerhk: parameter usedritek=1 to do that (possibly dangerous)\n");
+  }
+}
+#ifdef ACERDEBUG
+static inline int my_i8042_read_ecstatus(void)
+{
+  return inb(EC_STATUS_REG);
+}
+static int my_i8042_wait_ecwrite(void)
+{
+	int i = 0;
+	while ((my_i8042_read_ecstatus() & 0x02) && (i < 10000)) {
+		udelay(50);
+		i++;
+	}
+	return -(i == 10000);
+}
+static void send_ec_cmd(unsigned char cmd, unsigned char val)
+{
+  if (usedritek) {
+    preempt_disable();
+    if (!my_i8042_wait_ecwrite())
+      outb(cmd, EC_CNTL_REG);
+    if (!my_i8042_wait_ecwrite())
+      outb(val, EC_DATA_REG);
+    preempt_enable_no_resched();
+  } else {
+    printk(KERN_INFO"acerhk: request for accessing EC ignored\n"
+           KERN_INFO"acerhk: Use of dritek keyboard extension not enabled, use module\n"
+           KERN_INFO"acerhk: parameter usedritek=1 to do that (possibly dangerous)\n");
+  }
+}
+#endif
+#ifdef ACERDEBUG
+static void enable_mute_led_ec(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: enabling mute led via EC\n");
+  send_kbd_cmd(0x59, 0x94);
+}
+static void disable_mute_led_ec(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: disabling mute led via EC\n");
+  send_kbd_cmd(0x59, 0x95);
+}
+static void enable_dmm_function(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: enabling WLAN via EC variant 2\n");
+  send_kbd_cmd(0x45, 0xd3);
+}
+#endif
+static void enable_wlan_ec_1(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: enabling WLAN via EC variant 1\n");
+  send_kbd_cmd(0xe7, 0x01);
+  acerhk_wlan_state = 1;
+}
+static void disable_wlan_ec_1(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: disabling WLAN via EC variant 1\n");
+  send_kbd_cmd(0xe7, 0x00);
+  acerhk_wlan_state = 0;
+}
+static void enable_bluetooth_ec_1(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: enabling Bluetooth via EC variant 1\n");
+  send_kbd_cmd(0xe7, 0x03);
+  acerhk_bluetooth_state = 1;
+}
+static void disable_bluetooth_ec_1(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: disabling Bluetooth via EC variant 1\n");
+  send_kbd_cmd(0xe7, 0x02);
+  acerhk_bluetooth_state = 0;
+}
+static void enable_wlan_ec_2(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: enabling WLAN via EC variant 2\n");
+  send_kbd_cmd(0x45, acerhk_bluetooth_state ? 0xa2 : 0xa0);
+  acerhk_wlan_state = 1;
+}
+static void disable_wlan_ec_2(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: disabling WLAN via EC variant 2\n");
+  send_kbd_cmd(0x45, acerhk_bluetooth_state ? 0xa1 : 0xa3);
+  acerhk_wlan_state = 0;
+}
+static void enable_bluetooth_ec_2(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: enabling Bluetooth via EC variant 2\n");
+  send_kbd_cmd(0x45, acerhk_wlan_state ? 0xa2 : 0xa1);
+  acerhk_bluetooth_state = 1;
+}
+static void disable_bluetooth_ec_2(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: disabling Bluetooth via EC variant 2\n");
+  send_kbd_cmd(0x45, acerhk_wlan_state ? 0xa0 : 0xa3);
+  acerhk_bluetooth_state = 0;
+}
+#ifdef ACERDEBUG
+static void enable_wireless_ec(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: enabling wireless hardware\n");
+  if (usedritek) {
+    preempt_disable();
+    if (!my_i8042_wait_ecwrite())
+      outb(0x4d, EC_CNTL_REG);
+    if (!my_i8042_wait_ecwrite())
+      outb(0xd2, EC_DATA_REG);
+    if (!my_i8042_wait_ecwrite())
+      outb(0x01, EC_DATA_REG);
+    preempt_enable_no_resched();
+  }
+  acerhk_wlan_state = 1;
+}
+static void disable_wireless_ec(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: disabling wireless hardware\n");
+  if (usedritek) {
+    preempt_disable();
+    if (!my_i8042_wait_ecwrite())
+      outb(0x4d, EC_CNTL_REG);
+    if (!my_i8042_wait_ecwrite())
+      outb(0xd2, EC_DATA_REG);
+    if (!my_i8042_wait_ecwrite())
+      outb(0x00, EC_DATA_REG);
+    preempt_enable_no_resched();
+  }
+  acerhk_wlan_state = 0;
+}
+#endif
+static void enable_dritek_keyboard(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: enabling dritek keyboard extension\n");
+  send_kbd_cmd(0x59, 0x90);
+}
+static void disable_dritek_keyboard(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: disabling dritek keyboard extension\n");
+  send_kbd_cmd(0x59, 0x91);
+}
+static void enable_mail_led_ec_1(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: enabling mail led via EC variant 1\n");
+  send_kbd_cmd(0xe8, 0x01);
+}
+static void disable_mail_led_ec_1(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: disabling mail led via EC variant 1\n");
+  send_kbd_cmd(0xe8, 0x00);
+}
+
+static void enable_mail_led_ec_2(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: enabling mail led via EC variant 2\n");
+  send_kbd_cmd(0x59, 0x92);
+}
+static void disable_mail_led_ec_2(void)
+{
+  if (verbose)
+    printk(KERN_INFO "acerhk: disabling mail led via EC variant 2\n");
+  send_kbd_cmd(0x59, 0x93);
+}
+static void enable_mail_led_ec_3(void)
+{
+ if (verbose)
+    printk(KERN_INFO "acerhk:  enabling mail led via EC variant 3\n");
+  if (usedritek) {
+    preempt_disable();
+    if (!my_i8042_wait_write())
+      outl(0x80008894, 0xCF8);
+    if (!my_i8042_wait_write())
+      outw(0xC061, 0xCFC);
+    preempt_enable_no_resched();
+  }
+}
+static void disable_mail_led_ec_3(void)
+{
+ if (verbose)
+    printk(KERN_INFO "acerhk:  disabling mail led via EC variant 3\n");
+  if (usedritek) {
+    preempt_disable();
+    if (!my_i8042_wait_write())
+      outl(0x80008894, 0xCF8);
+    if (!my_i8042_wait_write())
+      outw(0xC060, 0xCFC);
+    preempt_enable_no_resched();
+  }
+}
+
+/* }}} */
+
+/* {{{ string search functions */
+
+/* This is the Colussi algorithm, the code is taken from
+   http://www-igm.univ-mlv.fr/~lecroq/string
+*/
+int preColussi(char *x, int m, int *h, int *next, int *shift)
+{
+  int i, k, nd, q, r, s;
+  int hmax[XSIZE], kmin[XSIZE], nhd0[XSIZE], rmin[XSIZE];
+  /* Computation of hmax */
+  i = k = 1;
+  do {
+    while (x[i] == x[i - k])
+      i++;
+    hmax[k] = i;
+    q = k + 1;
+    while (hmax[q - k] + k < i) {
+      hmax[q] = hmax[q - k] + k;
+      q++;
+    }
+    k = q;
+    if (k == i + 1)
+      i = k;
+  } while (k <= m);    /* Computation of kmin */
+  memset(kmin, 0, m*sizeof(int));
+  r = 0;
+  for (i = m; i >= 1; --i)
+    if (hmax[i] < m)
+      kmin[hmax[i]] = i;    /* Computation of rmin */
+  for (i = m - 1; i >= 0; --i) {
+    if (hmax[i + 1] == m)
+      r = i + 1;
+    if (kmin[i] == 0)
+      rmin[i] = r;
+    else
+      rmin[i] = 0;
+  }    /* Computation of h */
+  s = -1;
+  r = m;
+  for (i = 0; i < m; ++i)
+    if (kmin[i] == 0)
+      h[--r] = i;
+    else
+      h[++s] = i;
+  nd = s;    /* Computation of shift */
+  for (i = 0; i <= nd; ++i)
+    shift[i] = kmin[h[i]];
+  for (i = nd + 1; i < m; ++i)
+    shift[i] = rmin[h[i]];
+  shift[m] = rmin[0];    /* Computation of nhd0 */
+  s = 0;
+  for (i = 0; i < m; ++i) {
+    nhd0[i] = s;
+    if (kmin[i] > 0)
+      ++s;
+  }    /* Computation of next */
+  for (i = 0; i <= nd; ++i)
+    next[i] = nhd0[h[i] - kmin[h[i]]];
+  for (i = nd + 1; i < m; ++i)
+    next[i] = nhd0[m - rmin[h[i]]];
+  next[m] = nhd0[m - rmin[h[m - 1]]];    return(nd);
+}
+
+int COLUSSI(char *x, int m, char *y, int n) {
+  int i, j, last, nd,
+    h[XSIZE], next[XSIZE], shift[XSIZE];    /* Processing */
+  int match_pos; /* position of first match */
+  nd = preColussi(x, m, h, next, shift);    /* Searching */
+  i = j = 0;
+  last = -1;
+  match_pos = -1;
+  while ( (match_pos == -1)
+          && (j <= n - m) ) {
+    while (i < m && last < j + h[i] &&
+           x[h[i]] == y[j + h[i]])
+      i++;
+    if (i >= m || last >= j + h[i]) {
+      /* Match found, bail out */
+      match_pos = j;
+      i = m;
+    }
+    if (i > nd)
+      last = j + m - 1;
+    j += shift[i];
+    i = next[i];
+  }
+  return match_pos;
+}
+
+/* }}} */
+
+/* {{{ hardware access functions */
+
+/* call_bios_<model family>
+ *
+ * call request handler in mapped system rom
+ *
+ * the request is handed over via all 6 general purpose registers, results are
+ * taken from them and copied back to buf
+ */
+static asmlinkage void call_bios_6xx(struct register_buffer *buf)
+{
+  if (bios_routine) {
+      local_irq_disable();
+	__asm__ __volatile__(
+						 "movl %1,%%edx\n\t"
+						 "pusha\n\t"
+						 "movl %%edx,%%ebp\n\t"
+						 "movl (%%ebp),%%eax\n\t"
+						 "movl 4(%%ebp),%%ebx\n\t"
+						 "movl 8(%%ebp),%%ecx\n\t"
+						 "movl 12(%%ebp),%%edx\n\t"
+						 "movl 16(%%ebp),%%edi\n\t"
+						 "movl 20(%%ebp),%%esi\n\t"
+						 "pushl %%ebp\n\t"
+						 "call *%0\n\t"
+						 "popl %%ebp\n\t"
+						 "movl %%eax, (%%ebp)\n\t"
+						 "movl %%ebx, 4(%%ebp)\n\t"
+						 "movl %%ecx, 8(%%ebp)\n\t"
+						 "movl %%edx, 12(%%ebp)\n\t"
+						 "movl %%edi, 16(%%ebp)\n\t"
+						 "movl %%esi, 20(%%ebp)\n\t"
+						 "popa\n\t"
+						 :
+						 :"m" (bios_routine), "m" (buf)
+						 :"%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi", "%ebp"
+						 );
+      local_irq_enable();
+  }
+}
+
+static asmlinkage void call_bios_52x(struct register_buffer *buf)
+{
+  if (bios_routine) {
+      local_irq_disable();
+	__asm__ __volatile__(
+						 "movl %2,%%edx\n\t"
+						 "pusha\n\t"
+ 						 "movl %%edx,%%ebp\n\t"
+						 "movl (%%ebp),%%eax\n\t"
+						 "movl 4(%%ebp),%%ebx\n\t"
+						 "movl 8(%%ebp),%%ecx\n\t"
+						 "movl 12(%%ebp),%%edx\n\t"
+						 "movl 16(%%ebp),%%edi\n\t"
+						 "movl 20(%%ebp),%%esi\n\t"
+						 "pushl %%ebp\n\t"
+						 "movl %1, %%ebp\n\t"
+						 "call *%0\n\t"
+						 "popl %%ebp\n\t"
+						 "movl %%eax, (%%ebp)\n\t"
+						 "movl %%ebx, 4(%%ebp)\n\t"
+						 "movl %%ecx, 8(%%ebp)\n\t"
+						 "movl %%edx, 12(%%ebp)\n\t"
+						 "movl %%edi, 16(%%ebp)\n\t"
+						 "movl %%esi, 20(%%ebp)\n\t"
+						 "popa\n\t"
+						 :
+						 :"m" (bios_routine), "m" (preg400), "m" (buf)
+						 :"%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi", "%ebp"
+						 );
+      local_irq_enable();
+  }
+}
+
+#define PRINT_BUFFER(x) \
+  printk(KERN_INFO"acerhk: eax=0x%x ebx=0x%x ecx=0x%x edx=0x%x\n" \
+		 "acerhk: edi=0x%x esi=0x%x ebp=0x%x\n", \
+		 x.eax, x.ebx, x.ecx, x.edx, x.edi, x.esi, x.ebp);
+
+/* get_fnkey_event
+ *
+ * gets the first (oldest) key id from the queue of events
+ *
+ * return value: id of key
+ */
+static int get_fnkey_event(void)
+{
+  struct register_buffer regs;
+  regs.eax = 0x9610;
+  regs.ebx = 0x61C;
+  /* clear other registers, some models need this */
+  regs.ecx = 0;
+  regs.edx = 0;
+  preempt_disable();
+  call_bios(&regs);
+  preempt_enable_no_resched();
+  return regs.eax & 0xffff;
+}
+
+/* get_thermal_event
+ *
+ * does what?
+ *
+ * return value: event ?
+ */
+static int get_thermal_event(void)
+{
+  struct register_buffer regs;
+  if (acerhk_model_features & TM_F_THERMAL) {
+    regs.eax = 0x9612;
+    regs.ebx = 0x12e;
+    preempt_disable();
+    call_bios(&regs);
+    preempt_enable_no_resched();
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: thermal event = 0x%x\n", regs.eax);
+  } else {
+    regs.eax = 0x00;
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: thermal event not supported\n");
+  }
+  return regs.eax & 0xffff;
+}
+
+#ifdef ACERDEBUG
+/* pbutton_fct
+ *
+ * does what?
+ *
+ * return value: ?
+ */
+static int pbutton_fct(void)
+{
+  struct register_buffer regs;
+  if (acerhk_model_features & TM_F_PBUTTON) {
+    regs.eax = 0x9612;
+    regs.ebx = 0x10b;
+    regs.ecx = 0x2;
+    preempt_disable();
+    call_bios(&regs);
+    preempt_enable_no_resched();
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: pbutton = 0x%x\n", regs.eax);
+  } else {
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: pbutton function not supported\n");
+    regs.eax = 0x00;
+  }
+  return regs.eax & 0xffff;
+}
+#endif
+
+/* wbutton_fct_1
+ *
+ * turn on installed Bluetooth hardware together with the corresponding LED
+ *
+ * val: 0       turns off the LED
+ *      1       turns the LED to green/blue
+ *
+ * return value: ?
+ */
+static int wbutton_fct_1(int val)
+{
+  struct register_buffer regs;
+  if (acerhk_model_features & TM_F_WBUTTON) {
+    acerhk_bluetooth_state = val;
+    regs.eax = 0x9610;
+    regs.ebx = ((val & 0xff) << 8) | 0x34;
+    preempt_disable();
+    call_bios(&regs);
+    preempt_enable_no_resched();
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: wbutton1 = 0x%x\n", regs.eax);
+  } else {
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: wbutton function 1 not supported\n");
+    regs.eax = 0x00;
+  }
+  return regs.eax & 0xffff;
+}
+
+/* wbutton_fct_2
+ *
+ * turn on installed WLAN hardware together with the corresponding LED
+ *
+ * val: 0       turns off the LED
+ *      1       turns the LED to orange
+ *
+ * return value: ?
+ */
+static int wbutton_fct_2(int val)
+{
+  struct register_buffer regs;
+  if (acerhk_model_features & TM_F_WBUTTON) {
+    acerhk_wlan_state = val;
+    regs.eax = 0x9610;
+    regs.ebx = ((val & 0xff) << 8) | 0x35;
+    preempt_disable();
+    call_bios(&regs);
+    preempt_enable_no_resched();
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: wbutton2 = 0x%x\n", regs.eax);
+  } else {
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: wbutton function 2 not supported\n");
+    regs.eax = 0x00;
+  }
+  return regs.eax & 0xffff;
+}
+
+/* get_cmos_index
+ *
+ * gets index of CMOS port from ROM. The number of events is monitored
+ * in this port.
+ *
+ * return value: index of CMOS port
+ */
+static int get_cmos_index(void)
+{
+  struct register_buffer regs;
+  regs.eax = 0x9610;
+  regs.ebx = 0x51C;
+  preempt_disable();
+  call_bios(&regs);
+  preempt_enable_no_resched();
+  cmos_index = regs.ecx & 0xff;
+  if (verbose)
+    printk(KERN_INFO"acerhk: cmos index set to 0x%x\n", cmos_index);
+  return cmos_index;
+}
+
+/* get_nr_events
+ *
+ * gets the number of cached events (keys pressed) in queue. Up to 31 events
+ * are cached.
+ *
+ * return value: number of events in queue
+ */
+static int get_nr_events(void)
+{
+  unsigned long flags;
+  unsigned char c = 0;
+
+  spin_lock_irqsave (&rtc_lock, flags);
+#ifndef DUMMYHW
+  if (cmos_index)
+    c = CMOS_READ(cmos_index);
+  else if (verbose > 3)
+    printk(KERN_INFO"acerhk: get_nr_events - no valid cmos index set\n");
+#endif
+  spin_unlock_irqrestore (&rtc_lock, flags);
+  return c;
+}
+
+/* set_mail_led
+ *
+ * change state of mail led
+ *
+ * val: 0 - switch led off
+ *		1 - switch led on (blinking)
+ *
+ * return value: 1 - action succesfull (val valid)
+ *				 0 - no action taken (val invalid)
+ */
+static int set_mail_led(int val)
+{
+  struct register_buffer regs;
+  if (acerhk_model_features & TM_F_MAIL_LED) {
+    regs.eax = 0x9610;
+    regs.ebx = ((val & 0xff) << 8) | 0x31;
+    preempt_disable();
+    call_bios(&regs);
+    preempt_enable_no_resched();
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: mail led set to = 0x%x\n", val);
+  } else if (acerhk_model_features & TM_F_MAIL_LED_EC) {
+    if (val == 1)
+      enable_mail_led_ec_1();
+    else  if (val == 0)
+      disable_mail_led_ec_1();
+  } else if (acerhk_model_features & TM_F_MAIL_LED_EC2) {
+    if (val == 1)
+      enable_mail_led_ec_2();
+    else  if (val == 0)
+      disable_mail_led_ec_2();
+  } else if (acerhk_model_features & TM_F_MAIL_LED_EC3) {
+    if (val == 1)
+      enable_mail_led_ec_3();
+    else  if (val == 0)
+      disable_mail_led_ec_3();
+  } else {
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: mail led not supported\n");
+    regs.eax = 0x00;
+  }
+  return regs.eax & 0xffff;
+}
+
+/* launch_connect
+ *
+ * does what?
+ * val: 1 - only known value from windows driver
+ */
+static int launch_connect(int val)
+{
+  struct register_buffer regs;
+  if (acerhk_model_features & TM_F_CONNECT) {
+    regs.eax = 0x9610;
+    regs.ebx = ((val & 0xff) << 8) | 0x2e;
+    preempt_disable();
+    call_bios(&regs);
+    preempt_enable_no_resched();
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: connect(%d) = 0x%x\n", val, regs.eax);
+  } else {
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: connect not supported\n");
+    regs.eax = 0x00;
+  }
+  return regs.eax & 0xffff;
+}
+
+/* }}} */
+
+/* {{{ hardware probing */
+
+static struct proc_dir_entry *proc_acer_dir;
+
+static unsigned int __init find_hk_area(void)
+{
+  int offset, sig;
+  unsigned int fkt;
+  fkt = 0;
+  sig = -1; /* offset to signature in io area */
+  /* Look for signature, start at 0xf0000, search until 0xffff0 */
+  for (offset = 0;offset < 0xfffd; offset += 16) {
+    if (readl(reg1 + offset) == 0x30552142) {
+      sig = offset;
+      offset = 0xffff;
+    }
+  }
+  if (sig < 0)
+    printk(KERN_WARNING"acerhk: could not find request handler, possibly not all functions available\n");
+  else {
+    /* compute location of bios routine */
+    fkt = readl(reg1 + sig + 5);
+    /* adjust fkt to address of mapped IO area */
+    if (fkt >= 0xf0000)
+      fkt = (unsigned int)reg1 + fkt - 0xf0000;
+    else if (fkt >= 0xe0000)
+      fkt = (unsigned int)reg1 + fkt - 0xe0000;
+    else
+      fkt = 0;
+  }
+  return fkt;
+}
+
+static void print_features(void)
+{
+  int i;
+  printk(KERN_INFO"acerhk: supported keys:");
+  for (i = 0; i < 255; i++) {
+    switch (acerhk_key2name[i]) {
+    case k_help: printk(" help"); break;
+    case k_setup: printk(" setup"); break;
+    case k_p1: printk(" p1"); break;
+    case k_p2: printk(" p2"); break;
+    case k_p3: printk(" p3"); break;
+    case k_www: printk(" www"); break;
+    case k_mail: printk(" mail"); break;
+    case k_wireless: printk(" wireless"); break;
+    case k_power: printk(" power"); break;
+    case k_mute: printk(" mute"); break;
+    case k_volup: printk(" volup"); break;
+    case k_voldn: printk(" voldn"); break;
+    case k_res: printk(" res"); break;
+    case k_close: printk(" close"); break;
+    case k_open: printk(" open"); break;
+    case k_wireless2: printk(" wireless2"); break;
+    case k_play: printk(" play"); break;
+    case k_stop: printk(" stop"); break;
+    case k_prev: printk(" prev"); break;
+    case k_next: printk(" next"); break;
+    case k_display: printk(" display"); break;
+    default: break;
+    }
+  }
+  printk("\n");
+  if (acerhk_model_features & TM_F_MUTE_LED_EC)
+    printk(KERN_INFO"acerhk: mute led is supported\n");
+  if (acerhk_model_features & TM_F_MAIL_LED)
+    printk(KERN_INFO"acerhk: mail led is supported\n");
+  else if (acerhk_model_features & TM_F_MAIL_LED_EC)
+    printk(KERN_INFO"acerhk: mail led (EC) is supported\n");
+  else if (acerhk_model_features & TM_F_MAIL_LED_EC2)
+    printk(KERN_INFO"acerhk: mail led (EC2) is supported\n");
+  else if (acerhk_model_features & TM_F_MAIL_LED_EC3)
+    printk(KERN_INFO"acerhk: mail led (EC3) is supported\n");
+  if (acerhk_model_features & TM_F_WLAN_EC1)
+    printk(KERN_INFO"acerhk: wlan control (EC1) is supported\n");
+  else if (acerhk_model_features & TM_F_WLAN_EC2)
+    printk(KERN_INFO"acerhk: wlan control (EC2) is supported\n");
+  if (acerhk_model_features & TM_F_BLUE_EC1)
+    printk(KERN_INFO"acerhk: bluetooth control (EC1) is supported\n");
+  else if (acerhk_model_features & TM_F_BLUE_EC2)
+    printk(KERN_INFO"acerhk: bluetooth control (EC2) is supported\n");
+  printk(KERN_INFO"acerhk: supported functions:");
+  if (acerhk_model_features & TM_F_CONNECT)
+    printk(" connect");
+  if (acerhk_model_features & TM_F_THERMAL)
+    printk(" thermal");
+  if (acerhk_model_features & TM_F_PBUTTON)
+    printk(" pbutton");
+  if (acerhk_model_features & TM_F_WBUTTON)
+    printk(" wbutton");
+  printk("\n");
+}
+
+static void __init setup_keymap_model(unsigned int series)
+{
+  /* clear mapping keycode -> keyname, */
+  memset(&acerhk_key2name[0], k_none, sizeof(acerhk_key2name));
+  /* first set the common keys, namely FnF1 and FnF2, */
+  acerhk_key2name[1] = k_help;
+  acerhk_key2name[2] = k_setup;
+  /* then set known keycodes according to model */
+  switch (series) {
+   case 110:
+    acerhk_key2name[48] = k_wireless;
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[54] = k_www;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[3]  = k_power;
+    acerhk_key2name[8]  = k_mute;
+    acerhk_key2name[32] = k_volup;
+    acerhk_key2name[33] = k_voldn;
+    /* C110 generates 2 extra codes when opening/closing the lid */
+    acerhk_key2name[74] = k_close;
+    acerhk_key2name[75] = k_open;
+    break;
+  case 300: /* treat C300 like C100 with Bluetooth button */
+    acerhk_key2name[68] = k_wireless2;
+  case 100:
+    acerhk_key2name[48] = k_wireless;
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[49] = k_www;
+    acerhk_key2name[54] = k_mail;
+    acerhk_key2name[3]  = k_power;
+    acerhk_key2name[8]  = k_mute;
+    acerhk_key2name[32] = k_volup;
+    acerhk_key2name[33] = k_voldn;
+    break;
+  default:
+    /* only the two common keys are supported */
+    break;
+  case 210:
+    acerhk_key2name[19] = k_p1;
+    acerhk_key2name[20] = k_p2;
+    acerhk_key2name[17] = k_www;
+    acerhk_key2name[18] = k_mail;
+    break;
+  case 220:
+  case 260: /* 260 with same keys? */
+    acerhk_key2name[49] = k_p1;
+    acerhk_key2name[19] = k_p2;
+    acerhk_key2name[18] = k_www;
+    acerhk_key2name[17] = k_mail;
+    break;
+  case 230:
+  case 280: /* 280 with same keys? */
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[54] = k_www;
+    break;
+  case 1500:
+    acerhk_key2name[0x49] = k_setup;
+    acerhk_key2name[0x36] = k_www;
+    acerhk_key2name[0x31] = k_mail;
+    acerhk_key2name[0x11] = k_p1;
+    acerhk_key2name[0x12] = k_p2;
+    acerhk_key2name[0x30] = k_wireless;
+    acerhk_key2name[0x44] = k_wireless2;
+    acerhk_key2name[0x03] = k_power;
+    break;
+  case 240:
+    acerhk_key2name[0x31] = k_www;
+    acerhk_key2name[0x36] = k_mail;
+    acerhk_key2name[0x11] = k_p1;
+    acerhk_key2name[0x12] = k_p2;
+    acerhk_key2name[0x44] = k_wireless;
+    acerhk_key2name[0x30] = k_wireless2;
+    acerhk_key2name[0x03] = k_power;
+    acerhk_key2name[0x08] = k_mute;
+    //  acerhk_key2name[] = k_volup;
+    //  acerhk_key2name[] = k_voldn;
+    break;
+  case 2900:
+    acerhk_key2name[0x31] = k_mail; /* with led */
+    acerhk_key2name[0x36] = k_www;
+    acerhk_key2name[0x11] = k_p1;
+    acerhk_key2name[0x12] = k_p2;
+    acerhk_key2name[0x30] = k_wireless; /* wireless, with led, related with autowlan=1 */
+    break;
+  case 250: /* enriqueg@altern.org */
+    /* TravelMate 254LMi_DT manual common for 240/250 series, but key order
+       differ from 240 already present on acerhk driver */
+    /* TravelMate 254LMi_DT: 6 buttons: left to right: mail, www, p1, p2, bluetooth, wireless */
+    acerhk_key2name[0x31] = k_mail; /* with led */
+    acerhk_key2name[0x36] = k_www;
+    acerhk_key2name[0x11] = k_p1;
+    acerhk_key2name[0x12] = k_p2;
+    acerhk_key2name[0x44] = k_wireless2; /* bluetooth, hw optional */
+    acerhk_key2name[0x30] = k_wireless; /* wireless, with led, related with autowlan=1 */
+    acerhk_key2name[0x03] = k_power; /* Fn+F3 */
+    acerhk_key2name[0x08] = k_mute; /* Fn+F8 */
+    break;
+  case 380:
+    /* TM 380 has same codes as TM 370, with an additional one */
+    acerhk_key2name[0x03] = k_power;
+  case 370:
+    acerhk_key2name[0x30] = k_wireless;
+    acerhk_key2name[0x11] = k_p1;
+    acerhk_key2name[0x12] = k_p2;
+    acerhk_key2name[0x13] = k_p3;
+    acerhk_key2name[0x36] = k_www;
+    acerhk_key2name[0x31] = k_mail;
+    break;
+  case 360:
+    /* 360 series has the same layout as 350, with an
+       additional wireless key */
+    acerhk_key2name[64] = k_wireless;
+  case 350:
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[20] = k_p3;
+    acerhk_key2name[21] = k_www;
+    acerhk_key2name[19] = k_mail;
+    break;
+  case 520:
+    acerhk_key2name[19] = k_p1;
+    acerhk_key2name[20] = k_p2;
+    acerhk_key2name[17] = k_www;
+    acerhk_key2name[18] = k_mail;
+    break;
+  case 610:
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[19] = k_p3;
+    acerhk_key2name[21] = k_www;
+    acerhk_key2name[20] = k_mail;
+    acerhk_key2name[64] = k_wireless;
+    break;
+  case 630:
+    /* 630 has all keys of 620 plus one */
+    acerhk_key2name[8] = k_mute;
+  case 620:
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[19] = k_p3;
+    acerhk_key2name[54] = k_www;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[48] = k_wireless;
+    acerhk_key2name[3] = k_power;
+    acerhk_key2name[32] = k_volup;
+    acerhk_key2name[33] = k_voldn;
+    break;
+  case 290:
+  case 420:
+  case 430:
+  case 530:
+  case 540:
+  case 650:
+  case 660:
+  case 800:
+  case 1450:
+  case 2300:
+  case 2350:
+  case 4000:
+  case 4050:
+  case 6000:
+  case 8000:
+  case 4100:
+  case 4150:
+  case 4500:
+  case 4600:
+  case 4650:
+  case 1680:
+  case 1690:
+    /* keys are handled by dritek EC */
+    acerhk_key2name[1] = k_none;
+    acerhk_key2name[2] = k_none;
+    break;
+  case 1300:
+  case 1310:
+  case 1350:
+  case 1360:
+  case 1400:
+  case 1700:
+  case 1800:
+  case 2000:
+  case 2010:
+  case 2020:
+    /* Aspire 13xx series laptops use dritek hardware, no
+       acerhk-mapping needed
+       VolUp and VolDown are managed as normal keys
+       1300/1310 series should have P1, P2, Mail, WWW, Mute buttons
+       1353 has bluetooth, wifi, p1, p2, www, mail, help, setup, power
+       and mute
+       Aspire 1400/1450/Ferrari use dritek EC, too
+       1450 should have bluetooth, wifi, p1, p2, www, mail, help,
+       setup, power and mute
+       Aspire 1700 uses dritek EC, too
+       1700 should have bluetooth, wifi, p1, p2, www, mail, help,
+       setup, power and mute
+       need the MM-buttons Activation? (forward, shuffle, ...)
+       2000 hast lots of MM buttons
+       2010 should have bluetooth, wifi, p1, p2, www, mail, help,
+       setup, power and mute
+    */
+    acerhk_key2name[1] = k_none;
+    acerhk_key2name[2] = k_none;
+    break;
+  case 1600:
+    /* Aspire 1600 has acer keycode 0x49 for FnF2 */
+    acerhk_key2name[73] = k_setup;
+    acerhk_key2name[48] = k_wireless;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[54] = k_www;
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[19] = k_p3;
+    acerhk_key2name[3] = k_power;
+    acerhk_key2name[8] = k_mute;
+    /* VolUp and VolDown keys doesn't seem to be managed as special keys
+       but as normal keys ! */
+    break;
+  case 5020: /* Aspire 5020 has 0x6a for Fn+F2 */
+    acerhk_key2name[2] = k_none;
+    acerhk_key2name[106] = k_setup;
+    acerhk_key2name[3] = k_power;
+    acerhk_key2name[5] = k_display;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[54] = k_www;
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[48] = k_wireless;
+    acerhk_key2name[68] = k_wireless2;
+    break;
+  case 2410: /* TM 2410 is very similar to Aspire 5020, but has 0x6s for Fn-F3 */
+    acerhk_key2name[2] = k_none;
+    acerhk_key2name[106] = k_setup;
+    acerhk_key2name[109] = k_power;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[54] = k_www;
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[48] = k_wireless;
+    acerhk_key2name[68] = k_wireless2;
+    break;
+  case 40100:
+    /* Medion MD40100, 4 keys */
+    acerhk_key2name[54] = k_www;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[48] = k_wireless;
+    acerhk_key2name[55] = k_res;
+    break;
+  case 96500:
+  case 95400:
+    /* Medion MD95400, many keys */
+    acerhk_key2name[49] = k_mail;       /*  1 */
+    acerhk_key2name[54] = k_www;        /*  2 */
+    acerhk_key2name[48] = k_wireless;   /*  3 */
+    acerhk_key2name[68] = k_wireless2;  /*  4 (Bluetooth) */
+
+    acerhk_key2name[17] = k_p1;         /*  5 */
+    acerhk_key2name[18] = k_p2;         /*  6 */
+    acerhk_key2name[36] = k_play;       /*  7 */
+    acerhk_key2name[37] = k_stop;       /*  8 */
+    acerhk_key2name[34] = k_prev;       /*  9 */
+    acerhk_key2name[35] = k_next;       /* 10 */
+    acerhk_key2name[33] = k_voldn;      /* 11 */
+    acerhk_key2name[32] = k_volup;      /* 12 */
+    acerhk_key2name[38] = k_p3;         /* 13 */
+    acerhk_key2name[8]  = k_mute;       /* 14 */
+
+    acerhk_key2name[1]  = k_help;       /* FN+F1 (Help) */
+    acerhk_key2name[5]  = k_display;    /* FN+F3 (Display switch) */
+    acerhk_key2name[6]  = k_res;        /* FN+F4 (Display ein/ausschalten) */
+    break;
+  case 42200:
+    /* Medion MD42200, 7 keys, no setup */
+    acerhk_key2name[2] = k_none;
+    acerhk_key2name[5] = k_display;
+    acerhk_key2name[54] = k_www;
+    acerhk_key2name[48] = k_wireless;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    break;
+  case 9783:
+    /* Medion MD9783, 6 keys + info, no setup */
+    acerhk_key2name[2] = k_none;
+    acerhk_key2name[54] = k_www;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[19] = k_p3;
+    acerhk_key2name[8] = k_mute;
+    break;
+  case 7400:
+    /* Amilo Pro V2000 does not have Help and Setup key (?)
+       Amilo M 7400 has Help key, disabling only setup
+     */
+    acerhk_key2name[2] = k_none;
+    acerhk_key2name[48] = k_wireless;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[54] = k_www;
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    break;
+  case 1559:
+    acerhk_key2name[6] = k_display; /* FN+F4 (Display ein/ausschalten) */
+  case 1555:
+    /* AOpen (Ahtec Signal 1555M) is similar to FS Amilo M */
+    acerhk_key2name[2] = k_none;
+    acerhk_key2name[48] = k_wireless;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[54] = k_www;
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[34] = k_prev;
+    acerhk_key2name[35] = k_next;
+    acerhk_key2name[36] = k_play;
+    acerhk_key2name[37] = k_stop;
+    break;
+  case 6800:
+  case 7820:
+    /* Amilo D does not have Setup key */
+    acerhk_key2name[2] = k_none;
+    acerhk_key2name[49] = k_mail;
+    acerhk_key2name[54] = k_www;
+    acerhk_key2name[17] = k_p1;
+    acerhk_key2name[18] = k_p2;
+    acerhk_key2name[19] = k_p3;
+    acerhk_key2name[8] = k_mute;
+    break;
+  }
+}
+
+static void __init setup_model_features(unsigned int series)
+{
+  switch (series) {
+  case 200:
+  case 210:
+  case 520:
+    /* nothing special */
+    acerhk_model_features = 0;
+    acerhk_type = TM_old;
+    break;
+  case 220:
+  case 230:
+  case 260:
+  case 280:
+  case 360:
+  case 40100: /* Medion MD40100 */
+  case 95400: /* Medion MD95400 */
+  case 96500: /* Medion MD96500 */
+    /* all special functions, no mail led */
+    acerhk_model_features = 0x00f00000;
+    acerhk_type = TM_new;
+    break;
+  case 42200: /* Medion MD42200 */
+    /* has WLAN button, should call connect() */
+    acerhk_model_features = TM_F_WBUTTON | TM_F_CONNECT;
+    acerhk_type = TM_old;
+    break;
+  case 9783: /* Medion MD9783 */
+    /* only email led */
+    acerhk_model_features = TM_F_MAIL_LED;
+    acerhk_type = TM_new;
+    break;
+  case 1600:
+    acerhk_type = TM_new;
+    /* Do Aspire 1600 series have special functions or not ? I enable
+       them, perhaps it helps with problems Francois Valenduc has */
+    acerhk_model_features = 0x00f00000;
+    break;
+  case 300:
+  case 100:
+  case 110:
+  case 240:
+  case 350:
+  case 610:
+  case 620:
+  case 630:
+    /* all special functions, mail led */
+    acerhk_model_features = TM_F_MAIL_LED | 0x00f00000;
+    acerhk_type = TM_new;
+    break;
+  case 370:
+  case 380:
+  case 2410:
+  case 2900: /* Medion MD2900 */
+  case 2100: /* TM 2100 uses same driver as 5020 */
+  case 5020: /* Aspire 5020 is still old hardware */
+    acerhk_model_features = TM_F_MAIL_LED | TM_F_CONNECT| TM_F_WBUTTON;
+    acerhk_type = TM_new;
+    break;
+  case 7400:
+  case 1555:
+  case 1559:
+    /* all special functions for Fujitsu-Siemens Amilo M7400, Pro V2000; AOpen */
+    acerhk_model_features = 0x00f00000;
+    acerhk_type = TM_new;
+    break;
+  case 6800:
+  case 7820:
+    /* mail led and all special functions for FS Amilo D */
+    acerhk_model_features = TM_F_MAIL_LED | 0x00f00000;
+    acerhk_type = TM_new;
+    break;
+  case 2350:
+  case 4050:
+    acerhk_wlan_state = 1;	// Default state is on
+  case 290:
+    /* no special functions, wireless hardware controlled by EC */
+    acerhk_model_features = TM_F_WLAN_EC2 | TM_F_BLUE_EC2;
+    acerhk_type = TM_dritek;
+    break;
+  case 650:
+  case 1300:
+  case 1310:
+  case 1400:
+  case 1700:
+    /* all special functions, wireless hardware can be controlled */
+    acerhk_model_features = 0x00f00000;
+    acerhk_type = TM_dritek;
+    break;
+  case 4100:
+  case 4600:
+  case 1680:
+  case 1690: /* Aspire 1680/1690 should be similar to TM 4100/4600 */
+    /* mail led, wireless and bluetooth controlled the old way, but keys are
+       controlled by normal keyboard controller, so mark as dritek and
+       deactivate dritek use */
+    acerhk_model_features = TM_F_MAIL_LED | TM_F_WBUTTON;
+    acerhk_type = TM_dritek;
+    usedritek=0;
+    break;
+  case 660:
+  case 800:
+    /* all special functions, mail led */
+    acerhk_model_features = TM_F_MAIL_LED | 0x00f00000;
+    acerhk_type = TM_dritek;
+    break;
+  case 1350:
+  case 1360:
+    /* mail led, handled by EC, wireless HW is not (yet) controllable ? */
+    acerhk_model_features = TM_F_MAIL_LED_EC|TM_F_WLAN_EC1;
+    acerhk_type = TM_dritek;
+    break;
+  case 1450:
+    /* Bluetooth/Wlan led, Mail led handled by EC (variant 3) */
+    acerhk_model_features = TM_F_MAIL_LED_EC3|TM_F_WBUTTON;
+    acerhk_type = TM_dritek;
+    break;
+  case 1500:
+    /* Bluetooth/Wlan led */
+    acerhk_model_features = TM_F_WBUTTON;
+    acerhk_type = TM_new;
+    break;
+  case 420:
+  case 430:
+    /* all functions and dritek EC, mail LED is handled by EC, second
+       variant. An additional led is available, mute. (really?)
+       */
+    acerhk_type = TM_dritek;
+    acerhk_model_features = TM_F_MUTE_LED_EC|TM_F_MAIL_LED_EC2;
+    break;
+  case 2300:
+  case 4000:
+  case 4500:
+    /* wireless hardware, hopefully under control of my driver */
+    acerhk_type = TM_dritek;
+    acerhk_model_features = TM_F_BLUE_EC1|TM_F_WLAN_EC1;
+    break;
+  case 3200:
+    /* test, if this model uses old style wlan control */
+    acerhk_model_features = TM_F_WBUTTON;
+    acerhk_type = TM_dritek;
+    break;
+  case 6000:
+  case 8000:
+    /* 6000 and 8000 have wireless hardware, but I don't know how to handle,
+       so I choose no features */
+    acerhk_type = TM_dritek;
+    break;
+  case 530:
+  case 540:
+  case 2000:
+    /* No features (?) dritek EC, mail LED is handled by EC but
+       different from other Aspire series */
+    acerhk_type = TM_dritek;
+    acerhk_model_features = TM_F_MAIL_LED_EC2;
+    break;
+  case 4150:
+  case 4650:
+    /* Dritek EC, bluetooth, wifi, mail */
+    /* According to Andreas Stumpfl his TM 4652LMi does also work as series
+       3200, which might mean that the BIOS function accesses the EC */
+    acerhk_type = TM_dritek;
+    acerhk_model_features = TM_F_MAIL_LED_EC2 | TM_F_WLAN_EC2 | TM_F_BLUE_EC2;
+    break;
+  case 1800:
+  case 2010:
+  case 2020:
+    /* Dritek EC, bluetooth, wifi, mail */
+    acerhk_type = TM_dritek;
+    acerhk_model_features = TM_F_MAIL_LED_EC2 | TM_F_WLAN_EC2 | TM_F_BLUE_EC2;
+    acerhk_wlan_state = 1;	// Default state is on
+    break;
+  case 250: /* enriqueg@altern.org */
+    /* TravelMate254LMi_DT : mail led, bluetooth (button present, hw optional), wifi (with led) */
+    acerhk_model_features = TM_F_MAIL_LED|
+                            TM_F_WBUTTON ;
+    acerhk_type = TM_new;
+    acerhk_wlan_state = 0;	//Initial state is off on 254LMi_DT
+    break;
+  default:
+    /* nothing special */
+    acerhk_model_features = 0;
+    acerhk_type = TM_unknown;
+    break;
+  }
+  /* set the correct bios call function according to type */
+  if ((acerhk_type == TM_new) || (acerhk_type == TM_dritek)) {
+    call_bios = call_bios_6xx;
+    if (verbose > 2)
+      printk(KERN_INFO"acerhk: using call_bios_6xx mode\n");
+  } else {
+    call_bios = call_bios_52x;
+    if (verbose > 2)
+      printk(KERN_INFO"acerhk: using call_bios_52x mode\n");
+  }
+  /* remove key file on dritek hardware */
+  if (acerhk_type == TM_dritek) {
+    remove_proc_entry("key", proc_acer_dir);
+  }
+  /* setup available keys */
+  setup_keymap_model(acerhk_series);
+  if (verbose > 1)
+    print_features();
+}
+
+static unsigned int __init determine_laptop_series(char * str)
+{
+  /* 0 means unknown series, handled like TM 200 */
+  unsigned int series = 0;
+  if (strncmp(str, "TravelMate ", 11) == 0) {
+    switch (str[11]) {
+    case 'C':
+      if (str[12] == '1') {
+        if (str[13] == '0') {
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates TM C100 series\n");
+          series = 100;
+        } else if (str[13] == '1') {
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates TM C110 series\n");
+          series = 110;
+        }
+      } else if (str[12] == '3') {
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates TM C300 series\n");
+        series = 300;
+      }
+      break;
+    case 'F':
+      if (str[12] == '4') {
+        series = 230;
+      }
+      break;
+    case '2':
+      if (str[14] == '0') {
+        /* newer Travelmate 2xxx series */
+        switch (str[12]) {
+        case '0':
+        case '5':
+          series = 2000; // 2000 and 2500 are the same
+          break;
+        case '1':
+          if (str[13] == '0')
+            series = 2100;
+          break;
+        case '2':
+        case '7':
+          series = 2200; // 2200 and 2700 are the same
+          break;
+        case '3':
+          if (str[13] == '0')
+            series = 4000; // 2300 is the same as 4000
+          else if (str[13] == '5')
+            series = 4050; // 2350 is the same as 4050
+          break;
+        case '4':
+          if (str[13] == '1')
+            series = 2410;
+          break;
+        default:
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates unknown TM 2xxx series\n");
+          break;
+        }
+      } else {
+        /* older Travelmate 2xx series */
+        switch (str[12]) {
+        case '0': series = 200; break;
+        case '1': series = 210; break;
+        case '2': series = 220; break;
+        case '4': series = 240; break;
+        case '5': series = 250; break; /* enriqueg@altern.org */
+        case '6': series = 260; break;
+        default:
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates unknown TM 2xx series\n");
+          break;
+        }
+      }
+      break;
+    case '3':
+      switch (str[12]) {
+      case '0': series = 3200; break; /* TM 3000 works like TM 3200 */
+        /* Travelmate 3xx series */
+      case '5': series = 350; break;
+      case '6': series = 360; break;
+      case '7': series = 370; break;
+      case '8': series = 380; break;
+      default:
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown TM 3xx series\n");
+        break;
+      }
+      break;
+    case '4':
+      if ( (strnlen(str, ACERHK_MODEL_STRLEN-1) == 15) &&
+           (str[14] == '0') ) { /* Travelmate 4xxx series */
+        switch (str[12]) {
+        case '0': /* 4000 and 4500 are the same */
+        case '5':
+          series = 4000;
+          break;
+        case '1':
+        case '6': /* 4100 and 4600 are the same */
+          series = 4100;
+          break;
+        default:
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates unknown TM 4xxx series\n");
+          break;
+        }
+      } else { /* Travelmate 4xx series */
+        switch (str[12]) {
+        case '2': series = 420; break;
+        case '3': series = 430; break;
+        default:
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates unknown TM 4xx series\n");
+          break;
+        }
+      }
+      break;
+    case '5': /* Travelmate 5xx series */
+      if (str[12] == '2')
+        series = 520;
+      else if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates unknown TM 5xx series\n");
+      break;
+    case '6': /* older Travelmate 6xx series */
+      switch (str[12]) {
+      case '1': series = 610; break;
+      case '2': series = 620; break;
+      case '3': series = 630; break;
+      default:
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown TM 6xx series\n");
+        break;
+      }
+      break;
+    default:
+      printk(KERN_INFO"acerhk: model string indicates unknown TM xxx series\n");
+      break;
+    }
+    if (series && verbose > 1)
+      printk(KERN_INFO"acerhk: model string indicates TM %d series\n", series);
+  }
+  /* newer Travelmate series do not have a space after 'TravelMate' */
+  else if (strncmp(str, "TravelMate", 10) == 0) {
+    switch (str[10]) {
+    case '2':
+      if (str[11] == '9') {
+        series = 290;
+      } else {
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown TM2xx series\n");
+      }
+      break;
+    case '3':
+      if (str[11] == '2' && str[14] == '3') {
+        // TM 3200 uses "TravelMate32003"
+        series = 3200;
+      } else {
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown TM3xxx series\n");
+      }
+      break;
+    case '4':
+      switch (str[11]) {
+      case '3': series = 430; break;
+      default:
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown TM4xx series\n");
+        break;
+      }
+      break;
+    case '5':
+      switch (str[11]) {
+      case '3': series = 530; break;
+      case '4': series = 540; break;
+      default:
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown TM5xx series\n");
+        break;
+      }
+      break;
+    case '6':
+      switch (str[11]) {
+      case '5': series = 650; break;
+      case '6': series = 660; break;
+      case '0':
+        if (strncmp(str, "TravelMate60003", 15) == 0) {
+          series = 6000; break;
+        }
+      default:
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown TM6xx series\n");
+        break;
+      }
+      break;
+    case '8':
+      if (strncmp(str, "TravelMate80003", 15) == 0) {
+        series = 8000;
+      } else if (str[11] == '0') {
+        series = 800;
+      } else {
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown TM8xx series\n");
+      }
+      break;
+    default:
+      printk(KERN_INFO"acerhk: model string indicates unknown TMxxx series\n");
+      break;
+    }
+    if (series && verbose > 1)
+      printk(KERN_INFO"acerhk: model string indicates TM%d series\n", series);
+  }
+  else if (strncmp(str, "Aspire ", 7) == 0) {
+    switch(str[7]) {
+    case '1': /* Aspire 1xxx series */
+      switch(str[8]) {
+      case '3': /* Aspire 13xx series */
+        switch (str[9]) {
+        case '0': series = 1300; break;
+        case '1': series = 1310; break;
+        case '5': series = 1350; break;
+        case '6': series = 1360; break;
+        default:
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates unknown Aspire 13xx series\n");
+          break;
+        }
+        break;
+      case '4': /* Aspire 14xx series */
+        switch (str[9]) {
+        case '0': series = 1400; break;
+        case '5': series = 1450; break;
+        default:
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates unknown Aspire 14xx series\n");
+          break;
+        }
+        break;
+      case '5': series = 1500; break;
+      case '6': /* Aspire 14xx series */
+        switch (str[9]) {
+        case '0': series = 1600; break;
+        case '8':
+        case '9': series = 1680; break;
+        default:
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates unknown Aspire 16xx series\n");
+          break;
+        }
+        break;
+      case '7': series = 1700; break;
+      case '8': series = 1800; break;
+      default:
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown Aspire 1xxx series\n");
+        break;
+      }
+      break;
+    case '2': /* Aspire 2xxx series */
+      if (str[8] == '0') {
+        switch (str[9]) {
+        default:
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates unknown Aspire 20xx series\n");
+          break;
+        case '0': series = 2000; break;
+        case '1': series = 2010; break;
+        case '2': series = 2020; break;
+        }
+      } else {
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown Aspire 2xxx series\n");
+      }
+      break;
+    case '3': /* Aspire 3xxx series */
+      if (str[8] == '0') {
+        switch (str[9]) {
+        default:
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates unknown Aspire 30xx series\n");
+          break;
+        case '2': series = 5020; break; /* Aspire 3020/5020 are identical */
+        }
+      } else {
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown Aspire 3xxx series\n");
+      }
+      break;
+    case '5': /* Aspire 5xxx series */
+      if (str[8] == '0') {
+        switch (str[9]) {
+        default:
+          if (verbose > 1)
+            printk(KERN_INFO"acerhk: model string indicates unknown Aspire 50xx series\n");
+          break;
+        case '2': series = 5020; break;
+        }
+      } else {
+        if (verbose > 1)
+          printk(KERN_INFO"acerhk: model string indicates unknown Aspire 5xxx series\n");
+      }
+      break;
+    default:
+      if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates unknown Aspire series\n");
+      break;
+    }
+    if (series && verbose > 1)
+      printk(KERN_INFO"acerhk: model string indicates Aspire %d series\n", series);
+  }
+  else if (strncmp(str, "Extensa ", 8) == 0) {
+    /* Extensa series */
+    switch (str[8]) {
+    case '3':
+      switch (str[9]) {
+      case '0':
+        series = 3000; break;
+      default: break;
+      }
+      break;
+    default: break;
+    }
+    if (series && verbose > 1)
+      printk(KERN_INFO"acerhk: model string indicates Extensa %d series\n", series);
+    else if (verbose > 1)
+      printk(KERN_INFO"acerhk: model string indicates unknown Extensa series\n");
+  }
+  else if (strncmp(str, "Amilo ", 6) == 0) {
+    switch (str[6]) {
+    case 'D':   /* complete string is "Amilo D-Series", there seems to be no model number */
+      if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates FS Amilo D series\n");
+      /* this is the model number of my Amilo */
+      series = 7820;
+      break;
+    default:
+      if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates unknown FS Amilo XX series\n");
+      series = 7820;
+    }
+  }
+  else if (strncmp(str, "AMILO ", 6) == 0) {
+    switch (str[6]) {
+    case 'D':   /* AMILO D 6800 P4-2000 */
+      if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates FS AMILO D series\n");
+      series = 6800;
+      break;
+    case 'M':
+      if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates FS AMILO M(7400) series\n");
+      series = 7400;
+      break;
+    case 'P':
+      /* it is assumed, that 'AMILO P' appears only on Amilo Pro Series */
+      if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates FS AMILO Pro (V2000) series\n");
+      series = 7400;
+      break;
+    default:
+      if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates unknown FS AMILO XX series\n");
+      series = 6800;
+    }
+  }
+  else if (strncmp(str, "MEDIONPC", 8) == 0) {
+    uint medionmodel;
+    if ((medionmodel = COLUSSI("WIM 2040", 4, reg1, AREA_SIZE)) >= 0) {
+      printk(KERN_INFO"acerhk: found Medion model string:'%s'\n", (char*)reg1+medionmodel);
+      series = 96500;
+    } else {
+      if ((medionmodel = COLUSSI("MD 9", 4, reg1, AREA_SIZE)) >= 0) {
+        printk(KERN_INFO"acerhk: found Medion model string:'%s'\n", (char*)reg1+medionmodel);
+      }
+      series = 95400;
+    }
+    if (verbose > 1)
+      printk(KERN_INFO"acerhk: model string indicates a medion MD %d\n", series);
+  }
+  else if (strncmp(str, "MEDIONNB", 8) == 0) {
+    /* Search for the Product string of the MD9783. */
+    if (COLUSSI("MD 42200", 8, reg1, AREA_SIZE) >= 0) {
+      if (verbose>1)
+        printk(KERN_INFO"acerhk: model string indicates a Medion MD 42200\n");
+      series = 42200;
+    } else if (COLUSSI("MD 9783", 7, reg1, AREA_SIZE) >= 0){
+      if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates a medion MD 9783\n");
+      series = 9783;
+    } else if (COLUSSI("WIM 2000", 7, reg1, AREA_SIZE) >= 0){
+      if (verbose>1)
+        printk(KERN_INFO"acerhk: model string indicates a Medion MD 2900\n");
+      series = 2900;
+    } else {
+      if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates a medion MD40100\n");
+      series = 40100;
+    }
+  } else if (strncmp(str, "AOpen", 5) == 0) {
+    if (strncmp(str, "AOpen*EzRestore", 15) == 0) {
+      if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates a AOpen 1559\n");
+      series = 1559;
+    } else {
+      /* Unless I know of other models no further differentiation,
+         although there is a second part of the model string */
+      if (verbose > 1)
+        printk(KERN_INFO"acerhk: model string indicates a AOpen\n");
+      series = 1555;
+    }
+  } else if (strncmp(str, "CL56", 4) == 0) {
+    /* Unless I know of other models no further differentiation,
+       although there are strings with more numbers ("CL561" on a Compal
+       CL56/Zepto 4200, reported by Stian B. Barmen)
+       It has the same functions as Acer Aspire 2010
+    */
+    if (verbose > 1)
+      printk(KERN_INFO"acerhk: model string indicates a Compal CL56 (or similar)\n");
+    series = 2010;
+  } else if (strncmp(str, "Geneva2", 7) == 0) {
+    /* This might be an Aspire 9110 which is very similar to 4650 */
+    if (verbose > 1)
+      printk(KERN_INFO"acerhk: model string indicates an Aspire 9110\n");
+    series = 4650;
+  } else {
+    if (verbose > 1)
+      printk(KERN_INFO"acerhk: model string indicates no supported hardware\n");
+  }
+  return (series);
+}
+
+static void __init probe_model(void) {
+  int offset; /* offset from beginning of reg1 to Model string */
+  if (verbose)
+    printk(KERN_INFO"acerhk: start search for model string at %p\n", reg1);
+  /* first we look for Travelmate, if it isn't one we try to identify other
+     laptops, such as Medion or Aspire */
+  offset = COLUSSI("Travel", 6, reg1, AREA_SIZE);
+  /* Try to detect Aspire laptops */
+  if (offset < 0)
+    offset = COLUSSI("Aspire", 6, reg1, AREA_SIZE);
+  /* Try to detect Extensa laptops */
+  if (offset < 0)
+    offset = COLUSSI("Extensa", 7, reg1, AREA_SIZE);
+  /* Try to detect Medion laptops */
+  if (offset < 0)
+    offset = COLUSSI("MEDION", 6, reg1, AREA_SIZE);
+  /* Try to detect AOpen laptops */
+  if (offset < 0)
+    offset = COLUSSI("AOpen", 5, reg1, AREA_SIZE);
+  /* Try to detect Fujitsu Siemens Amilo laptops */
+  if (offset < 0)
+    offset = COLUSSI("Amilo", 5, reg1, AREA_SIZE);
+  if (offset < 0)
+    offset = COLUSSI("AMILO", 5, reg1, AREA_SIZE);
+  /* Try to detect Compal */
+  if (offset < 0)
+    offset = COLUSSI("CL56", 4, reg1, AREA_SIZE);
+  /* That might be an Aspire 9110 */
+  if (offset < 0)
+    offset = COLUSSI("Geneva2", 7, reg1, AREA_SIZE);
+  if (offset >= 0) {
+    acerhk_model_addr = reg1 + offset;
+    /* copy the string, but not more than 15 characters */
+    strncpy(acerhk_model_string, acerhk_model_addr, ACERHK_MODEL_STRLEN-1);
+    if (verbose)
+      printk(KERN_INFO"acerhk: found model string '%s' at %p\n",
+             acerhk_model_string, acerhk_model_addr);
+    if (bios_routine && verbose > 2)
+      printk(KERN_INFO"acerhk: offset from model string to function address: 0x%lx\n",
+             bios_routine - (unsigned long)acerhk_model_addr);
+    acerhk_series = determine_laptop_series(acerhk_model_string);
+  } else {
+    printk(KERN_WARNING"acerhk: Could not find model string, will assume type 200 series\n");
+    acerhk_series = 200;
+  }
+}
+
+/* }}} */
+
+/* {{{ key polling and translation */
+
+static void print_mapping(void)
+{
+  printk(KERN_INFO"acerhk: key mapping:\n");
+  printk("acerhk: help     0x%x\n", acerhk_name2event[k_help]);
+  printk("acerhk: setup    0x%x\n", acerhk_name2event[k_setup]);
+  printk("acerhk: p1       0x%x\n", acerhk_name2event[k_p1]);
+  printk("acerhk: p2       0x%x\n", acerhk_name2event[k_p2]);
+  printk("acerhk: p3       0x%x\n", acerhk_name2event[k_p3]);
+  printk("acerhk: www      0x%x\n", acerhk_name2event[k_www]);
+  printk("acerhk: mail     0x%x\n", acerhk_name2event[k_mail]);
+  printk("acerhk: wireless 0x%x\n", acerhk_name2event[k_wireless]);
+  printk("acerhk: power    0x%x\n", acerhk_name2event[k_power]);
+  printk("acerhk: mute     0x%x\n", acerhk_name2event[k_mute]);
+  printk("acerhk: volup    0x%x\n", acerhk_name2event[k_volup]);
+  printk("acerhk: voldn    0x%x\n", acerhk_name2event[k_voldn]);
+  printk("acerhk: res      0x%x\n", acerhk_name2event[k_res]);
+  printk("acerhk: close    0x%x\n", acerhk_name2event[k_close]);
+  printk("acerhk: open     0x%x\n", acerhk_name2event[k_open]);
+  printk("acerhk: wireless2 0x%x\n", acerhk_name2event[k_wireless2]);
+  printk("acerhk: play     0x%x\n", acerhk_name2event[k_play]);
+  printk("acerhk: stop     0x%x\n", acerhk_name2event[k_stop]);
+  printk("acerhk: prev     0x%x\n", acerhk_name2event[k_prev]);
+  printk("acerhk: next     0x%x\n", acerhk_name2event[k_next]);
+  printk("acerhk: display  0x%x\n", acerhk_name2event[k_display]);
+}
+
+static void set_keymap_name(t_key_names name, unsigned int key)
+{
+  acerhk_name2event[name] = key;
+}
+
+static void init_keymap_input(void)
+{
+  /* these values for input keys are chosen to match the key names on the
+     actual Acer laptop */
+  set_keymap_name(k_none, KEY_RESERVED);
+  set_keymap_name(k_help, KEY_HELP);
+  set_keymap_name(k_setup, KEY_CONFIG);
+  set_keymap_name(k_p1, KEY_PROG1);
+  set_keymap_name(k_p2, KEY_PROG2);
+  set_keymap_name(k_p3, KEY_PROG3);
+  set_keymap_name(k_www, KEY_WWW);
+  set_keymap_name(k_mail, KEY_MAIL);
+  set_keymap_name(k_wireless, KEY_XFER);
+  set_keymap_name(k_power, KEY_POWER);
+  set_keymap_name(k_mute, KEY_MUTE);
+  set_keymap_name(k_volup, KEY_VOLUMEUP);
+  set_keymap_name(k_voldn, KEY_VOLUMEDOWN);
+  set_keymap_name(k_res, KEY_CONFIG);
+  set_keymap_name(k_close, KEY_CLOSE);
+  set_keymap_name(k_open, KEY_OPEN);
+  /* I am not really happy with the selections for wireless and wireless2,
+     but coffee looks good. Michal Veselenyi proposed this value */
+  set_keymap_name(k_wireless2, KEY_COFFEE);
+  set_keymap_name(k_play, KEY_PLAYPAUSE);
+  set_keymap_name(k_stop, KEY_STOPCD);
+  set_keymap_name(k_prev, KEY_PREVIOUSSONG);
+  set_keymap_name(k_next, KEY_NEXTSONG);
+  set_keymap_name(k_display, KEY_MEDIA); /* also not happy with this */
+  if (verbose > 1)
+    print_mapping();
+}
+
+static int filter_idle_value(int keycode)
+{
+  int validkey = 0;
+  if (keycode != 0x0 &&
+      keycode != 0x9610 &&
+      keycode != 0xc100 && /* Francois Valenduc, Aspire 1601 LC */
+      keycode != 0x8610 &&
+      keycode != 0x861 &&
+      keycode != 0x8650 &&
+      keycode != 0x865)
+    validkey = keycode;
+  if (verbose > 4 && !validkey)
+    printk(KERN_INFO"acerhk: throw away idle value 0x%x\n", keycode);
+  return validkey;
+}
+
+static void send_key_event(t_key_names key)
+{
+  unsigned int input_key;
+  if (key != k_none) {
+    /* convert key name to kernel keycode */
+    input_key = acerhk_name2event[key];
+    if (verbose > 2)
+      printk(KERN_INFO"acerhk: translated acer key name 0x%x to input key 0x%x\n",
+             key, input_key);
+    /* send press and release together, as there is no such event from acer as 'release' */
+    input_report_key(acerhk_input_dev_ptr, input_key, 1);
+    input_report_key(acerhk_input_dev_ptr, input_key, 0);
+  }
+}
+
+static t_key_names transl8_key_code(int keycode)
+{
+  t_key_names keyname = k_none;
+  /* first filter out idle values */
+  if ( (keycode = filter_idle_value(keycode)) ) {
+    if (verbose > 3)
+      printk(KERN_INFO"acerhk: received key code 0x%x\n", keycode);
+    /* translate keycode to key name */
+    if (keycode >= 0 && keycode <= 255)
+      keyname = acerhk_key2name[keycode];
+    else {
+      if (verbose > 3)
+        printk(KERN_INFO"acerhk: keycode 0x%x too big, will use only 8 bits\n", keycode);
+      /* use only lower 8 bits of value to distinguish keys */
+      keyname = acerhk_key2name[keycode&0xff];
+    }
+    /* produce some log information for higher verbosity levels */
+    if (keyname != k_none && verbose > 2)
+      printk(KERN_INFO"acerhk: translated acer key code 0x%x to key name 0x%x\n",
+             keycode, keyname);
+    else if (keyname == k_none && verbose > 3)
+      printk(KERN_INFO"acerhk: translated acer key code 0x%x to no key\n",
+             keycode);
+    if (autowlan) {
+      /* if automatic switching of wlan hardware is enabled, do it here
+         on wireless key press */
+      if (keyname == k_wireless2) {
+        if (acerhk_bluetooth_state)
+          wbutton_fct_1(0);
+        else
+          wbutton_fct_1(1);
+      }
+      if (keyname == k_wireless) {
+        if (acerhk_wlan_state)
+          wbutton_fct_2(0);
+        else
+          wbutton_fct_2(1);
+      }
+    }
+  }
+  return keyname;
+}
+
+/* polling timer handler */
+static void acerhk_poll_event(unsigned long save_size)
+{
+#ifndef DUMMYHW
+  unsigned int max = MAX_POLLING_LOOPS;
+  /* make sure not to loop more then 32 times */
+  if (!max || max > 32)
+    max = 32;
+  if (acerhk_type != TM_dritek) {
+    while (get_nr_events() && max--) {
+      send_key_event(transl8_key_code(get_fnkey_event()));
+    }
+  } else {
+    send_key_event(transl8_key_code(get_fnkey_event()));
+  }
+#endif
+  acerhk_timer_poll.expires = jiffies + acerhk_polling_delay;
+  add_timer(&acerhk_timer_poll);
+}
+
+/* blinking timer handler; added by Antonio Cuni */
+static void acerhk_blink_event(unsigned long not_used)
+{
+  if (acerhk_blueled_blinking != -1) {
+    acerhk_blueled_blinking = !acerhk_blueled_blinking;
+#ifndef DUMMYHW
+    wbutton_fct_1(acerhk_blueled_blinking);
+#endif
+    acerhk_timer_blinking.expires = jiffies + acerhk_blueled_blinking_delay;
+    add_timer(&acerhk_timer_blinking);
+  }
+  else
+    printk(KERN_WARNING "acerhk: blinking event called, but blinking not active\n");
+}
+
+static void init_input(void)
+{
+  int i;
+
+#ifndef KERNEL26
+  /* request keyboard input module */
+  request_module("keybdev");
+  if (verbose > 3)
+    printk(KERN_INFO"requested keyboard input driver\n");
+#endif
+
+#ifndef STATIC_INPUT_DEV
+  /* allocate acerhk input device */
+  acerhk_input_dev_ptr=input_allocate_device();
+  /* enter some name */
+  acerhk_input_dev_ptr->name = "Acer hotkey driver";
+#else
+  acerhk_input_dev_ptr=&acerhk_input_dev;
+#endif
+
+  /* some laptops have a mail led, should I announce it here? */
+  acerhk_input_dev_ptr->evbit[0] = BIT(EV_KEY);
+  /* announce keys to input system
+   * the generated keys can be changed on runtime,
+   * but to publish those changes the device needs to
+   * get reconnected (I dont't know any other way)
+   * Therefore I enable all possible keys */
+  for (i = KEY_RESERVED; i < BTN_MISC; i++)
+    set_bit(i, acerhk_input_dev_ptr->keybit);
+  /* set mapping keyname -> input event */
+  init_keymap_input();
+  if (verbose)
+    printk(KERN_INFO"acerhk: registered input device\n");
+  input_register_device(acerhk_input_dev_ptr);
+  init_timer(&acerhk_timer_poll);
+  acerhk_polling_state = 0;
+}
+
+static void stop_polling(void)
+{
+  if (acerhk_polling_state == 1) {
+    del_timer(&acerhk_timer_poll);
+    if (verbose)
+      printk(KERN_INFO"acerhk: key polling stopped\n");
+    acerhk_polling_state = 0;
+  } else
+    if (verbose)
+      printk(KERN_INFO"acerhk: key polling not active\n");
+}
+
+static void start_polling(void)
+{
+  if (acerhk_polling_state != 1) {
+    acerhk_timer_poll.function = acerhk_poll_event;
+    acerhk_timer_poll.expires = jiffies + acerhk_polling_delay;
+    acerhk_timer_poll.data = get_nr_events();
+    add_timer(&acerhk_timer_poll);
+    acerhk_polling_state = 1;
+    if (acerhk_type == TM_dritek) {
+      printk(KERN_INFO"acerhk: Your hardware does not need polling enabled for hotkeys to work, "
+             "you can safely disable polling by using the module parameter poll=0 (unless you "
+             "want to play around with the driver and see if there are buttons which need polling).\n");
+    }
+    if (verbose)
+      printk(KERN_INFO"acerhk: starting key polling, every %d ms\n", acerhk_polling_delay);
+  } else
+    if (verbose)
+      printk(KERN_INFO"acerhk: key polling already active\n");
+}
+
+/* addedd by Antonio Cuni */
+static void start_blinking(void)
+{
+  if (acerhk_blueled_blinking == -1) {
+    // blinking was disabled... enable it!
+    acerhk_timer_blinking.function = acerhk_blink_event;
+    acerhk_timer_blinking.expires = jiffies + acerhk_blueled_blinking_delay;
+    acerhk_timer_blinking.data = 0; // not used
+    add_timer(&acerhk_timer_blinking);
+    acerhk_blueled_blinking = 0;
+    if (verbose)
+      printk(KERN_INFO "acerhk: starting blueled blinking\n");
+  } else
+    if (verbose)
+      printk(KERN_INFO "acerhk: blueled already blinking\n");
+}
+
+/* Added by Antonio Cuni */
+static void stop_blinking(void)
+{
+  if (acerhk_blueled_blinking != -1) {
+    del_timer(&acerhk_timer_blinking);
+    if (verbose)
+      printk(KERN_INFO "acerhk: blueled blinking stopped\n");
+    acerhk_blueled_blinking = -1;
+  }
+}
+
+static void release_input(void)
+{
+  stop_polling();
+  input_unregister_device(acerhk_input_dev_ptr);
+}
+
+/* }}} */
+
+/* {{{ procfs functions */
+
+#ifndef CONFIG_PROC_FS
+
+static int acerhk_proc_init(void)
+{
+  return 1;
+}
+#else
+
+/* This macro frees the machine specific function from bounds checking and
+ * things like that... */
+#define	PRINT_PROC(fmt,args...)                     \
+  do {												\
+    *len += sprintf( buffer+*len, fmt, ##args );	\
+    if (*begin + *len > offset + size)				\
+      return( 0 );                                  \
+    if (*begin + *len < offset) {					\
+      *begin += *len;								\
+      *len = 0;                                     \
+    }												\
+  } while(0)
+
+static int pc_proc_infos( char *buffer, int *len,
+                          off_t *begin, off_t offset, int size )
+{
+  PRINT_PROC( "Acer hotkeys version %s\n", ACERHK_VERSION);
+  PRINT_PROC( "Model(Type)\t: %s(", acerhk_model_string);
+  switch(acerhk_type) {
+  default:
+    PRINT_PROC( "unknown)\n");
+    break;
+  case TM_old:
+    PRINT_PROC( "old)\n");
+    break;
+  case TM_new:
+    PRINT_PROC( "new)\n");
+    break;
+  case TM_dritek:
+    PRINT_PROC( "Dritek)\n");
+    break;
+  }
+  if (bios_routine != 0) {
+    PRINT_PROC( "request handler\t: 0x%x\n", bios_routine);
+    if (cmos_index) {
+      PRINT_PROC( "CMOS index\t: 0x%x\n", cmos_index);
+      PRINT_PROC( "events pending\t: %u\n", get_nr_events());
+    } else {
+      PRINT_PROC( "CMOS index\t: not available\n");
+    }
+    if (acerhk_polling_state == 1)
+      PRINT_PROC( "kernel polling\t: active\n");
+    else
+      PRINT_PROC( "kernel polling\t: inactive\n");
+    PRINT_PROC( "autoswitch wlan\t: ");
+    if (autowlan == 1)
+      PRINT_PROC( "enabled\n");
+    else
+      PRINT_PROC( "disabled\n");
+  } else {
+    PRINT_PROC( "request handler\t: not found\n");
+    PRINT_PROC( "kernel polling\t: not possible\n");
+  }
+  /* model specific infos */
+  if (acerhk_type == TM_dritek) {
+    PRINT_PROC( "use of Dritek EC: ");
+    if (usedritek)
+      PRINT_PROC( "enabled\n");
+    else
+      PRINT_PROC( "disabled\n");
+  }
+  if (acerhk_type == TM_old)
+    PRINT_PROC( "preg400\t\t: 0x%p\n", preg400);
+  return (1);
+}
+
+static int acerhk_proc_info( char *buffer, char **start, off_t offset,
+                             int size, int *eof, void *data )
+{
+  int len = 0;
+  off_t begin = 0;
+
+  *eof = pc_proc_infos( buffer, &len, &begin, offset, size );
+
+  if (offset >= begin + len)
+    return( 0 );
+  *start = buffer + (offset - begin);
+  return( size < begin + len - offset ? size : begin + len - offset );
+
+}
+
+static int acerhk_proc_key( char *buffer, char **start, off_t offset,
+                            int size, int *eof, void *data )
+{
+  if (size >= 5 && offset == 0) {
+    if (acerhk_type == TM_dritek || acerhk_polling_state == 1) {
+      snprintf(buffer+offset, size, "n/a\n");
+    } else {
+      snprintf(buffer+offset, size, "0x%02x\n", filter_idle_value(get_fnkey_event()));
+    }
+    *eof = 1;
+    return 5;
+  }
+  *eof = 1;
+  return 0;
+}
+
+static int acerhk_proc_led(struct file* file, const char* buffer,
+                           unsigned long count, void* data)
+{
+  char str[4];
+  int len;
+  if (count > 4)
+    len = 4;
+  else
+    len = count;
+  if (copy_from_user(str, buffer, len))
+    return -EFAULT;
+  str[3] = '\0';
+  if ( ( (len >= 2) && (!strncmp(str, "on", 2) || !strncmp(str, "an", 2)) )
+       || str[0] == '1')
+    set_mail_led(1);
+  else
+    set_mail_led(0);
+  return len;
+}
+
+static int acerhk_proc_wirelessled(struct file* file, const char* buffer,
+                                   unsigned long count, void* data)
+{
+  char str[4];
+  int len;
+  if (count > 4)
+    len = 4;
+  else
+    len = count;
+  if (copy_from_user(str, buffer, len))
+    return -EFAULT;
+  str[3] = '\0';
+  if ( ( (len >= 2) && (!strncmp(str, "on", 2) || !strncmp(str, "an", 2)) )
+       || str[0] == '1') {
+    if (acerhk_model_features & TM_F_WLAN_EC1)
+      enable_wlan_ec_1();
+    else if (acerhk_model_features & TM_F_WLAN_EC2)
+      enable_wlan_ec_2();
+    else
+      wbutton_fct_2(1);
+  }
+  else {
+    if (acerhk_model_features & TM_F_WLAN_EC1)
+      disable_wlan_ec_1();
+    else if (acerhk_model_features & TM_F_WLAN_EC2)
+      disable_wlan_ec_2();
+    else
+      wbutton_fct_2(0);
+  }
+  return len;
+}
+
+
+/* Modified by Antonio Cuni: added support for blinking
+   possible values:
+   - off, 0:       led always off
+   - on, an,  1:   led alway on
+   - n (a number): led blinking; n is the delay between
+   two changes of state, in jiffies; n must
+   be > 50, to prevent the user from overloading
+   the kernel.
+
+ */
+static int acerhk_proc_blueled(struct file* file, const char* buffer,
+                               unsigned long count, void* data)
+{
+  const int MAXLEN=11;
+  char str[MAXLEN];
+  int len;
+  int isNumber;
+
+  if (count > MAXLEN)
+    len = MAXLEN;
+  else
+    len = count;
+  if (copy_from_user(str, buffer, len))
+    return -EFAULT;
+  str[MAXLEN - 1] = '\0';
+
+  /* try to parse a number */
+  isNumber = sscanf(str, "%u", &acerhk_blueled_blinking_delay);
+  /* if the delay is 0, turn off the led */
+  if (isNumber && acerhk_blueled_blinking_delay != 0 && acerhk_blueled_blinking_delay != 1) {
+    if (acerhk_blueled_blinking_delay < 50)
+      printk(KERN_INFO"acerhk: blinking request rejected. The delay must be > 50.\n");
+    else {
+      if (verbose)
+        printk(KERN_INFO"acerhk: blinking delay set to %u.\n", acerhk_blueled_blinking_delay);
+      start_blinking();
+    }
+  } else if (acerhk_blueled_blinking_delay == 1 || !strncmp(str, "on", 2) || !strncmp(str, "an", 2)) {
+    stop_blinking();
+    if (acerhk_model_features & TM_F_BLUE_EC1)
+      enable_bluetooth_ec_1();
+    else if (acerhk_model_features & TM_F_BLUE_EC2)
+      enable_bluetooth_ec_2();
+    else
+      wbutton_fct_1(1);
+  } else {
+    /* it's 0 or everything else */
+    stop_blinking();
+    if (acerhk_model_features & TM_F_BLUE_EC1)
+      disable_bluetooth_ec_1();
+    else if (acerhk_model_features & TM_F_BLUE_EC2)
+      disable_bluetooth_ec_2();
+    else
+      wbutton_fct_1(0);
+  }
+  return len;
+}
+
+#ifdef ACERDEBUG
+static void do_debug(const char* buffer, unsigned long len)
+{
+  unsigned int h, i;
+  switch (buffer[0]) {
+  case 'b':
+    /* test WLAN on TM 4001 */
+    switch (buffer[1]) {
+    case '0':
+      disable_wlan_ec_1();
+      break;
+    case '1':
+    default:
+      enable_wlan_ec_1();
+    }
+    break;
+  case 'B':
+    /* test BLUETOOTH on TM 4001 */
+    switch (buffer[1]) {
+    case '0':
+      disable_bluetooth_ec_1();
+      break;
+    case '1':
+    default:
+      enable_bluetooth_ec_1();
+    }
+    break;
+  case 'D':
+    /* test "DMM Function Enabled" entry of TM 4150/4650 */
+    enable_dmm_function();
+    break;
+  case 'i':
+  case '1':
+#ifndef KERNEL26
+    MOD_INC_USE_COUNT;
+#endif
+    break;
+  case 'e':
+    switch (buffer[1]) {
+    case '1':
+      start_polling();
+      break;
+    default:
+      stop_polling();
+    }
+    break;
+  case 'k':
+    for (i = 0; i <= 255;i++) {
+      input_report_key(acerhk_input_dev_ptr, i, 1);
+      input_report_key(acerhk_input_dev_ptr, i, 0);
+    }
+    break;
+  case 'm':
+    /* set mapping key names -> input events */
+    sscanf(&buffer[2],"%x", &i);
+    h = buffer[1] - '0' + 1;
+    printk("acerhk: key name %x maps to %x\n", h, i);
+    acerhk_name2event[h] = i;
+    break;
+  case 'M':
+    /* test mute LED on dritek hardware */
+    switch (buffer[1]) {
+    case '0':
+      disable_mute_led_ec();
+      break;
+    case '1':
+    default:
+      enable_mute_led_ec();
+    }
+    break;
+  case 'p':
+    printk("acerhk: pbutton = 0x%x\n", pbutton_fct());
+    break;
+  case 's':
+    /* send key event to test the key translation in input system */
+    sscanf(&buffer[1],"%x", &h);
+    printk("acerhk: sending key event 0x%x\n", h);
+    input_report_key(acerhk_input_dev_ptr, h, 1);
+    input_report_key(acerhk_input_dev_ptr, h, 0);
+    break;
+  case 'S':
+    /* simulate key codes to test the key translation in acerhk */
+    sscanf(&buffer[1],"%x", &h);
+    send_key_event(transl8_key_code(h));
+    break;
+  case 't':
+    printk("acerhk: thermal event = 0x%x\n", get_thermal_event());
+    break;
+  case 'w':
+    /* test the wbutton functions, someone really needs to have another look
+       at the windows driver */
+    switch (buffer[1]) {
+    case '2':
+      printk("acerhk: wbutton_2(%d) = 0x%x\n", buffer[2]-'0', wbutton_fct_2(buffer[2]-'0'));
+      break;
+    case '1':
+    default:
+      printk("acerhk: wbutton_1(%d) = 0x%x\n", buffer[2]-'0', wbutton_fct_1(buffer[2]-'0'));
+    }
+    break;
+  case 'W':
+    /* test wireless HW/LED on some models using dritek hardware */
+    switch (buffer[1]) {
+    case '0':
+      disable_wireless_ec();
+      break;
+    case '1':
+    default:
+      enable_wireless_ec();
+    }
+    break;
+  case 'v':
+    verbose = buffer[1]-'0';
+    printk("acerhk: verbosity level changed to %d\n", verbose);
+    break;
+  case 'd':
+  case '0':
+  default:
+#ifndef KERNEL26
+    MOD_DEC_USE_COUNT;
+#endif
+    break;
+  }
+}
+
+static int acerhk_proc_debug(struct file* file, const char* buffer,
+                             unsigned long count, void* data)
+{
+  char str[5];
+  int len;
+  if (count > 5)
+    len = 5;
+  else
+    len = count;
+  if (copy_from_user(str, buffer, len))
+    return -EFAULT;
+  str[4] = '\0';
+  do_debug(str, len);
+  return len;
+}
+#endif
+
+static int acerhk_proc_init(void)
+{
+  int retval;
+  struct proc_dir_entry *entry;
+  /* create own directory */
+  proc_acer_dir = proc_mkdir("driver/acerhk", NULL);
+  if (proc_acer_dir == NULL) {
+    retval = 0;
+    printk(KERN_INFO"acerhk: could not create /proc/driver/acerhk\n");
+  }
+  else {
+    proc_acer_dir->owner = THIS_MODULE;
+    /* now create several files, first general info ... */
+    entry = create_proc_read_entry("info",
+                                   0444, proc_acer_dir, acerhk_proc_info, NULL);
+    if (entry == NULL) {
+      printk(KERN_INFO"acerhk: cannot create info file\n");
+      remove_proc_entry("driver/acerhk", NULL);
+      retval = 0;
+    } else {
+      entry->owner = THIS_MODULE;
+      /* ... last pressed key ... */
+      entry = create_proc_read_entry("key",
+                                     0444, proc_acer_dir, acerhk_proc_key, NULL);
+      if (entry == NULL) {
+        printk(KERN_INFO"acerhk: cannot create key file\n");
+        remove_proc_entry("info", proc_acer_dir);
+        remove_proc_entry("driver/acerhk", NULL);
+        retval = 0;
+      } else {
+        entry->owner = THIS_MODULE;
+        /* ... and led control file */
+        entry = create_proc_entry("led", 0222, proc_acer_dir);
+        if (entry == NULL) {
+          printk(KERN_INFO"acerhk: cannot create LED file\n");
+          remove_proc_entry("info", proc_acer_dir);
+          remove_proc_entry("key", proc_acer_dir);
+          remove_proc_entry("driver/acerhk", NULL);
+          retval = 0;
+        }
+        else {
+          entry->write_proc = acerhk_proc_led;
+          entry->owner = THIS_MODULE;
+          /* ... and wireless led controll file */
+          entry = create_proc_entry("wirelessled", 0222, proc_acer_dir);
+          if (entry == NULL) {
+            printk(KERN_INFO"acerhk: cannot create wirelessled file\n");
+            remove_proc_entry("info", proc_acer_dir);
+            remove_proc_entry("key", proc_acer_dir);
+            remove_proc_entry("led", proc_acer_dir);
+            remove_proc_entry("driver/acerhk", NULL);
+            retval = 0;
+          }
+          else {
+            entry->write_proc = acerhk_proc_wirelessled;
+            entry->owner = THIS_MODULE;
+            /* ... and bluetooth led controll file */
+            entry = create_proc_entry("blueled", 0222, proc_acer_dir);
+            if (entry == NULL) {
+              printk(KERN_INFO"acerhk: cannot create blueled file\n");
+              remove_proc_entry("info", proc_acer_dir);
+              remove_proc_entry("key", proc_acer_dir);
+              remove_proc_entry("led", proc_acer_dir);
+              remove_proc_entry("wirelessled", proc_acer_dir);
+              remove_proc_entry("driver/acerhk", NULL);
+              retval = 0;
+            } else {
+              entry->write_proc = acerhk_proc_blueled;
+              entry->owner = THIS_MODULE;
+              retval = 1;
+#ifdef ACERDEBUG
+              /* add extra file for debugging purposes */
+              entry = create_proc_entry("debug", 0222, proc_acer_dir);
+              if (entry == NULL) {
+                printk(KERN_INFO"acerhk: cannot create debug file\n");
+                remove_proc_entry("info", proc_acer_dir);
+                remove_proc_entry("key", proc_acer_dir);
+                remove_proc_entry("led", proc_acer_dir);
+                remove_proc_entry("wirelessled", proc_acer_dir);
+                remove_proc_entry("blueled", proc_acer_dir);
+                remove_proc_entry("driver/acerhk", NULL);
+                retval = 0;
+              }
+              else {
+                entry->write_proc = acerhk_proc_debug;
+                entry->owner = THIS_MODULE;
+                retval = 1;
+              }
+#endif
+            }
+          }
+        }
+      }
+    }
+  }
+  return retval;
+}
+
+static void acerhk_proc_cleanup(void)
+{
+  if (proc_acer_dir) {
+    remove_proc_entry("info", proc_acer_dir);
+    /* On dritek type hardware key file is already removed */
+    if (acerhk_type != TM_dritek)
+      remove_proc_entry("key", proc_acer_dir);
+    remove_proc_entry("led", proc_acer_dir);
+    remove_proc_entry("wirelessled", proc_acer_dir);
+    remove_proc_entry("blueled", proc_acer_dir);
+#ifdef ACERDEBUG
+    remove_proc_entry("debug", proc_acer_dir);
+#endif
+    remove_proc_entry("driver/acerhk", NULL);
+    proc_acer_dir = NULL;
+  }
+}
+
+#endif /* CONFIG_PROC_FS */
+
+/* }}} */
+
+/* {{{ file operations */
+
+static int acerhk_ioctl( struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long arg )
+{
+  int retval;
+  switch( cmd ) {
+  case ACERHK_GET_KEYCOUNT:
+    {
+      char nr;
+      nr = get_nr_events();
+      put_user(nr, (char*)arg);
+      retval = 0;
+      break;
+    }
+  case ACERHK_GET_KEYID:
+    {
+      char id;
+      id = get_fnkey_event();
+      put_user(id, (char*)arg);
+      retval = 0;
+      break;
+    }
+  case ACERHK_CONNECT:
+    launch_connect(1);
+    retval = 0;
+    break;
+  case ACERHK_START_POLLING:
+    start_polling();
+    retval = 0;
+    break;
+  case ACERHK_STOP_POLLING:
+    stop_polling();
+    retval = 0;
+    break;
+  case ACERHK_DISCONNECT:
+    launch_connect(0);
+    retval = 0;
+    break;
+  case ACERHK_GET_THERMAL_EVENT:
+    {
+      short event;
+      event = get_thermal_event();
+      put_user(event, (short*)arg);
+      retval = 0;
+      break;
+    }
+  case ACERHK_MAIL_LED_OFF:
+    set_mail_led(0);
+    retval = 0;
+    break;
+  case ACERHK_MAIL_LED_ON:
+    set_mail_led(1);
+    retval = 0;
+    break;
+  case ACERHK_GET_KEY_MAP:
+    if (copy_to_user((t_map_name2event*)arg, &acerhk_name2event, sizeof(acerhk_name2event)))
+      retval = -EFAULT;
+    else
+      retval = 0;
+    break;
+  case ACERHK_SET_KEY_MAP:
+    if (copy_from_user(&acerhk_name2event, (t_map_name2event*)arg, sizeof(acerhk_name2event)))
+      retval = -EFAULT;
+    else {
+      if (verbose) {
+        printk(KERN_INFO"acerhk: changed key mapping\n");
+        print_mapping();
+      }
+      retval = 0;
+    }
+    break;
+  default:
+    retval = -EINVAL;
+  }
+  return retval;
+}
+
+#ifdef ACERDEBUG
+static ssize_t acerhk_write (struct file* file, const char* buffer, size_t length, loff_t* offset)
+{
+  if (length)
+    do_debug(buffer, length);
+  return length;
+}
+#endif
+
+static int acerhk_open( struct inode *inode, struct file *file )
+{
+  return 0;
+}
+
+static int acerhk_release( struct inode *inode, struct file *file )
+{
+  return 0;
+}
+
+static struct file_operations acerhk_fops = {
+  owner:        THIS_MODULE,
+  ioctl:        acerhk_ioctl,
+  open:         acerhk_open,
+#ifdef ACERDEBUG
+  write:        acerhk_write,
+#endif
+  release:      acerhk_release,
+};
+
+static struct miscdevice acerhk_dev = {
+  MISC_DYNAMIC_MINOR,
+  "acerhk",
+  &acerhk_fops
+};
+
+/* }}} */
+
+static void __init model_init(void)
+{
+  /* set callroutine, features and keymap for model */
+  setup_model_features(acerhk_series);
+  /* override initial state of wireless hardware if specified by module options */
+  if (wlan_state >= 0) acerhk_wlan_state = wlan_state;
+  if (bluetooth_state >= 0) acerhk_bluetooth_state = bluetooth_state;
+  /* Launch connect only if available */
+  if (acerhk_model_features & TM_F_CONNECT) {
+    if (verbose)
+      printk(KERN_INFO"acerhk: Model type %d, calling launch_connect(1)\n",
+             acerhk_type);
+    launch_connect(1);
+  }
+  if ( acerhk_type != TM_dritek ) {
+    get_cmos_index();
+  }
+  if ( acerhk_type == TM_dritek ) {
+    enable_dritek_keyboard();
+  }
+  /* added by Antonio Cuni */
+  init_timer(&acerhk_timer_blinking);
+}
+
+
+static void __exit acerhk_cleanup_module (void);
+static int __init acerhk_init(void)
+{
+  int ret;
+
+  ret = misc_register( &acerhk_dev );
+  if (ret) {
+    printk(KERN_ERR "acerhk: can't misc_register on minor=%d\n", ACERHK_MINOR);
+    ret = -EAGAIN;
+  }
+  else if (!acerhk_proc_init()) {
+    printk(KERN_ERR "acerhk: can't create procfs entries\n");
+    ret = -ENOMEM;
+    misc_deregister( &acerhk_dev );
+  }
+  else {
+    reg1 = ioremap(0xf0000, 0xffff);
+    if (verbose > 1)
+      printk(KERN_INFO"acerhk: area from 0xf000 to 0xffff mapped to %p\n", reg1);
+    reg2 = ioremap(0xe0000, 0xffff);
+    if (verbose > 1)
+      printk(KERN_INFO"acerhk: area from 0xe000 to 0xffff mapped to %p\n", reg2);
+    /* the area 0x400 is used as data area by earlier (520) series  */
+    preg400 = ioremap(0x400, 0xfff);
+    if (verbose > 1)
+      printk(KERN_INFO"acerhk: area from 0x400 to 0x13ff mapped to %p\n", preg400);
+    /* attach to input system */
+    init_input();
+    memset(acerhk_model_string, 0x00, ACERHK_MODEL_STRLEN);
+#ifdef DUMMYHW
+    acerhk_model_addr = (void*)0x12345678;
+    /* copy the string, but not more than 15 characters */
+    strncpy(acerhk_model_string, "TravelmateDummy", ACERHK_MODEL_STRLEN-1);
+    /* set callroutine for model */
+    if (force_series)
+      acerhk_series = force_series;
+    else
+      acerhk_series = 2000;
+    setup_model_features(acerhk_series);
+    printk(KERN_INFO "Acer Travelmate hotkey driver v" ACERHK_VERSION " dummy\n");
+    if ( acerhk_type == TM_dritek )
+      enable_dritek_keyboard();
+    if (poll)
+      start_polling();
+    init_timer(&acerhk_timer_blinking);
+#else
+    bios_routine = find_hk_area();
+    if (!force_series)
+      probe_model();
+    else {
+      if (verbose)
+        printk(KERN_INFO"acerhk: forced laptop series to %d\n", force_series);
+      acerhk_series = force_series;
+    }
+    /* do model specific initialization */
+    model_init();
+    /* Without a bios routine we cannot do anything except on dritek
+       type HW, unload on other types */
+    if (bios_routine || (acerhk_type == TM_dritek)) {
+      ret = 0;
+      if (verbose && bios_routine)
+        printk(KERN_INFO"acerhk: bios routine found at 0x%x\n", bios_routine);
+      printk(KERN_INFO "Acer Travelmate hotkey driver v" ACERHK_VERSION "\n");
+      /* If automatic switching of wlan is wanted but polling is disabled,
+         automatically enable it */
+      if (!poll && autowlan) {
+        printk(KERN_INFO "Automatic switching of wireless hardware needs polling, enabling it\n");
+        poll = 1;
+      }
+      /* start automatic polling of key presses if wanted and bios routine found */
+      if (poll && bios_routine)
+        start_polling();
+    } else {
+      printk(KERN_ERR "acerhk: can't find bios routine, cannot do anything for you, sorry!\n");
+      ret = -ENOMEM;
+      acerhk_cleanup_module();
+    }
+#endif
+  }
+  return ret;
+}
+
+static void __exit acerhk_cleanup_module (void)
+{
+  acerhk_proc_cleanup();
+  stop_blinking();
+  if (reg1)
+    iounmap(reg1);
+  if (reg2)
+    iounmap(reg2);
+  if (preg400)
+    iounmap(preg400);
+  release_input();
+  misc_deregister( &acerhk_dev );
+  if ( acerhk_type == TM_dritek ) {
+    disable_dritek_keyboard();
+  }
+  if (verbose > 2)
+    printk(KERN_INFO "acerhk: unloaded\n");
+}
+
+module_init(acerhk_init);
+module_exit(acerhk_cleanup_module);
+
+MODULE_AUTHOR("Olaf Tauber");
+MODULE_DESCRIPTION("AcerHotkeys extra buttons keyboard driver");
+MODULE_LICENSE("GPL");
+
+#ifndef KERNEL26
+EXPORT_NO_SYMBOLS;
+#endif
+
+#else
+#error This driver is only available for X86 architecture
+#endif
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
+
diff -Nurp linux-2.6.37/3rdparty/acerhk/acerhk.h linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.h
--- linux-2.6.37/3rdparty/acerhk/acerhk.h	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.h	2005-06-17 00:10:12.000000000 +0300
@@ -0,0 +1,91 @@
+#ifndef __ACERHK_H__
+#define __ACERHK_H__
+
+#include <linux/ioctl.h>
+
+#define ACERHK_MINOR   MISC_DYNAMIC_MINOR
+
+#define ACERHK_GET_KEYCOUNT      _IOR('p', 0x01, char)  /* Get number of cached key presses */
+#define ACERHK_GET_KEYID         _IOR('p', 0x02, char)  /* Get first key in queue */
+#define ACERHK_CONNECT           _IO('p', 0x03)         /* ? */
+#define ACERHK_DISCONNECT        _IO('p', 0x04)         /* ? */
+#define ACERHK_GET_THERMAL_EVENT _IOR('p', 0x05, short) /* ? */
+#define ACERHK_MAIL_LED_OFF      _IO('p', 0x10)         /* switch mail LED off */
+#define ACERHK_MAIL_LED_ON       _IO('p', 0x11)         /* switch mail LED on (blinking) */
+#define ACERHK_START_POLLING     _IO('p', 0x12)         /* poll keys in kernel, send real key events */
+#define ACERHK_STOP_POLLING      _IO('p', 0x13)         /* stop key polling in kernel */
+#define ACERHK_GET_KEY_MAP       _IOR('p', 0x20, int)  /* Get mapping of key names to key events, */
+#define ACERHK_SET_KEY_MAP       _IOW('p', 0x21, int)  /* Set mapping of key names to key events */
+
+/* all possible keys (known to me) */
+typedef enum e_key_names {
+  k_none      =  0,
+  k_help      =  1, /* Fn+F1 */
+  k_setup     =  2, /* Fn+F2 */
+  k_p1        =  3,
+  k_p2        =  4,
+  k_p3        =  5,
+  k_www       =  6,
+  k_mail      =  7,
+  k_wireless  =  8,
+  k_power     =  9, /* Fn+F3 */
+  k_mute      = 10, /* Fn+F8 */
+  k_volup     = 11, /* Fn+Up */
+  k_voldn     = 12, /* Fn+Down */
+  k_res       = 13, /* resolution change on Medion MD 40100 */
+  k_close     = 14, /* if lid is closed in tablet mode */
+  k_open      = 15, /* if lid is opend in tablet mode */
+  k_wireless2 = 16, /* second wireless button on TM 243LC */
+  k_play      = 17, /* Play/Pause found on AOpen */
+  k_stop      = 18, /* Stop/Eject found on AOpen */
+  k_prev      = 19, /* Prev found on AOpen */
+  k_next      = 20, /* Next found on AOpen */
+  k_display   = 21  /* Change internal/external display on MD 42200 */
+} t_key_names;
+#define NR_KEY_NAMES 22
+typedef unsigned int t_map_name2event[NR_KEY_NAMES];
+
+#ifdef __KERNEL__
+
+/* available features */
+#define TM_F_WLAN_EC1     0x00000010
+#define TM_F_BLUE_EC1     0x00000020
+#define TM_F_WLAN_EC2     0x00000040
+#define TM_F_BLUE_EC2     0x00000080
+#define TM_F_MUTE_LED_EC  0x00001000
+#define TM_F_MAIL_LED     0x00010000
+#define TM_F_MAIL_LED_EC  0x00020000
+#define TM_F_MAIL_LED_EC2 0x00040000
+#define TM_F_MAIL_LED_EC3 0x00080000
+
+#define TM_F_CONNECT      0x00100000
+#define TM_F_THERMAL      0x00200000
+#define TM_F_PBUTTON      0x00400000
+#define TM_F_WBUTTON      0x00800000
+
+typedef enum acer_type {
+  TM_unknown,
+  /* 200, 210, 520, 600 and 730 series, Medion MD42200 */
+  TM_old,
+  /* C100, C110, 220, 230, 240, 260, 350, 360, 610, 620, 630, 740 series
+     Medion MD40100, Aspire 1600, FS Amilo */
+  TM_new,
+  /* Aspire 13xx, 14xx, 1700, TM 290, 650, 660, 800 */
+  TM_dritek
+} t_acer_type;
+
+struct register_buffer {
+  unsigned int eax;
+  unsigned int ebx;
+  unsigned int ecx;
+  unsigned int edx;
+  unsigned int edi;
+  unsigned int esi;
+  unsigned int ebp;
+};
+
+typedef asmlinkage void (*bios_call) (struct register_buffer *);
+
+#endif
+
+#endif
diff -Nurp linux-2.6.37/3rdparty/acerhk/AUTHORS linux-2.6.37.3rdparty/3rdparty/acerhk/AUTHORS
--- linux-2.6.37/3rdparty/acerhk/AUTHORS	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/AUTHORS	2006-11-10 00:02:55.000000000 +0200
@@ -0,0 +1 @@
+Olaf Tauber <otauber@web.de>
\ Ingen nyrad vid filslut
diff -Nurp linux-2.6.37/3rdparty/acerhk/COPYING linux-2.6.37.3rdparty/3rdparty/acerhk/COPYING
--- linux-2.6.37/3rdparty/acerhk/COPYING	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/COPYING	2002-05-08 22:01:52.000000000 +0300
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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 of the License, 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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/acertm.def linux-2.6.37.3rdparty/3rdparty/acerhk/doc/acertm.def
--- linux-2.6.37/3rdparty/acerhk/doc/acertm.def	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/acertm.def	2003-08-24 19:46:37.000000000 +0300
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<CONFIG model="Acer Travelmate 610 series">
+
+<!--
+Possible tags are (not all are implemented) :
+
+    PrevTrack
+    Play
+    Eject
+    Stop
+    Pause
+    NextTrack
+    VolUp
+    VolDown
+    Mute
+    WebBrowser
+    Email
+    Help
+    WakeUp
+    PowerDown
+    Communities
+    Search
+    Idea
+    Shopping
+    Print
+    Go
+    Record
+    Shell
+    Transfer
+    MyDocuments
+    MyComputer
+    Calculator
+    iNews
+    Sleep
+    Suspend
+    Rewind
+    Rotate
+-->
+
+
+  <!-- User define functions -->
+
+  <userdef keycode="129" command="gnomecc">Konfiguration</userdef>
+
+  <userdef keycode="93" command="/home/ole/bin/audiotoggle.sh">Mute/Unmute</userdef>
+  <userdef keycode="176" command="aumix -v+5">Lauter</userdef>
+  <userdef keycode="174" command="aumix -v-5">Leiser</userdef>
+  <Help keycode="226"/>
+  <userdef keycode="153" command="multi-gnome-terminal --use-factory --start-factory-server --tclass=ole --geometry=80x49">Terminal</userdef>
+  <userdef keycode="144" command="xemacs">XEmacs</userdef>
+  <userdef keycode="171" command="xmms --play-pause">Play/Pause</userdef>
+  <userdef keycode="147" command="xmms --play-pause">Play/Pause</userdef>
+  <Email keycode="236"/>
+  <Webbrowser keycode="178"/>
+
+</CONFIG>
diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/FAQ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/FAQ
--- linux-2.6.37/3rdparty/acerhk/doc/FAQ	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/FAQ	2005-11-10 19:45:33.000000000 +0200
@@ -0,0 +1,150 @@
+******************************************************************************
+
+Q: I have a (non Acer) notebook which is not recognized by your driver but I
+think it should. What information do you need?
+
+A: If it is a non-Acer laptop I would like to know, what makes you think that
+your laptop would work with my driver. A windows driver/utility package of the
+name "LaunchManager" or "EasyButton" is a good hint. If it is clear that your
+hardware is okay, I need the string with your model name from BIOS. Please
+don't ask me how to do it. To find out which functions of your laptop the
+driver will support, it is best, if you can tell me where to get this
+"LaunchManager" or "EasyButton" package.
+If it is a model from 2003 or newer then chances are good that it's a dritek
+type one. In this case try the option "force_series=6000" to at least enable
+the keys.
+
+******************************************************************************
+
+Q: Why can't I activate my wireless hardware on Acer TM 420/430/6000/8000 ...?
+
+A: On many newer laptops (Dritek type) I do not now how to do this,
+sorry. Someone would need to find out how windows does it. Volunteers?
+
+******************************************************************************
+
+Q: I know that wireless hardware is supported on my Aspire 1690/TravelMate4600,
+but I cannot get it to work, why?
+
+A: On these model (and similar) the wireless hardware is controlled on two
+different levels. One is controlled by acerhk's xxxled file, the other level
+is controlled by the key itself. To actually activate the hardware you need to
+write '1' to the xxled file and you need to press the corresponding button.
+Example:
+echo 1 > /proc/driver/acerhk/wirelessled
+<if still not working, press Wlan button>
+
+******************************************************************************
+
+Q: Why do I always get 0x00 from /proc/driver/acerhk/key?
+
+A1: Check the type of your laptop if /proc/driver/acerhk/info. If it is
+"Dritek", you cannot read the keys from the driver. Starting from version
+0.5.17 you get "n/a" out of the key file in this case.
+A2: If you have polling enabled (default) you will almost always read 0x00
+from this file. This is because in every polling cycle it is checked for key
+events and if there is one, it is instantly translated and sent to the kernel
+input system. Starting with version 0.5.20 you get "n/a" out of the key file
+in this case.
+
+******************************************************************************
+
+Q: When I press a key, nothing happens. Why are they not working?
+
+A: Most keys won't do anything by themself. If nothing happens, that is
+because no programm knows what to do with the new keys. You need to assign
+actions to them, use the hotkey manager of your desktop to do that. If
+using Gnome, you find it under desktop settings - keyboard shortcuts.
+
+******************************************************************************
+
+Q: The driver works for my laptop, but not all of the keys are working. What
+can I do?
+
+A: There are some keys/key combinations which generate an ACPI event,
+e.g. Fn+F4 on some models or the lid button.
+If you have a different laptop than the one which got detected (or you used
+"force_series=xxx" anyway), then it is possible that the mapping acerhk uses
+to translate the codes from the buttons to key events is wrong.
+In this case, load the driver with "verbose=4" and press the buttons which do
+not work. Then look for messages from acerhk of the form "translated acer key
+code xxx to no key". Note these codes together with the button they belong to
+and send me this list along with the model name of your laptop.
+If you do not see a usable name in /proc/driver/acerhk/info please try the
+tools dmidecode/biosdecode/vpddecode to find this name.
+
+******************************************************************************
+Q: I press the wireless key but the hardware doesn't get activated, what's wrong?
+
+A: The driver is only on older models (non-Dritek type) able to read
+keypresses by itself and toggle the hardware/LED automatically (with option
+autowlan=1). On Dritek type models this must be done by writing the desired
+value to one of the wireless files in the proc filesystem. In most
+cases this would be /proc/drivers/acerhk/wirelessled to control wlan
+hardware (blueled for Bluetooth hardware):
+
+echo 1 > /proc/driver/acerhk/wirelessled
+
+But you could use a hotkey manager to do that automatically when you press the
+button. In this case be aware that on some models the button generates
+different key events according to the actual state of the wireless hardware.
+
+******************************************************************************
+
+Q: My keys do not work, I only get kernel messages of the form:
+atkbd.c: Unknown key pressed (translated set 2, code 0xf4 on isa0060/serio0).
+atkbd.c: Use 'setkeycodes e074 <keycode>' to make it known.
+
+A: Press each of the buttons and note the mentioned
+code for it (e074 in this example). You should get a list like this:
+P1	e074
+P2	e075
+...
+If you are finished with it, look into /usr/include/linux/input.h, using
+your favourite text viewer/editor. Search for "KEY_STOP". You should see
+the following line in the file:
+
+#define KEY_STOP                128
+
+After it many more lines with equal #defines should be visible. Look for
+key names which best match the names of your buttons, e.g. KEY_PROG1,
+KEY_WWW and so on. Note the numbers assigned to the names, for KEY_STOP
+this would be 128, for KEY_PROG1 148.
+Now you have a list with three items per entry, your button, a code
+from the kernel messages and a corresponding number from the file
+linux.h:
+P1	e074	148
+P2	e075	149
+...
+For each line in this list, issue the setkeycodes command as mentioned
+in the kernel message:
+setkeycodes e074 148
+setkeycodes e075 149
+...
+After doing that, the keys should be available for your hotkey manager.
+
+******************************************************************************
+
+Q: My WLAN hardware gets activated through /proc/driver/acerhk/wirelessled,
+but the LED is not working. Why not?
+
+A: Try if adding the option "led=1" to your wireless module helps. For the
+ipw2200 driver it works, as Didier CLERC <didier@linuxbourg.ch> found out:
+
+	I have to load the module "ipw2200" with the option "led=1", then
+	the wifi button blinks until a network is detected.
+
+******************************************************************************
+
+Q: I have an unsupported laptop, but the driver works when I force the series
+to a type like 610 or 2100. Only my buttons doesn't get recognized, why?
+
+A: On models of the type TM_new (like TravelMate 600, 2100 and many other, see
+acerhk.c, function setup_model_features for details) the buttons use different
+codes on different models. Therefore the driver needs to know these codes. You
+can get them if you load the driver with verbose=4, press the buttons and key
+combinations (Fn+xx) you are interested in and look for kernel messages of the
+form "acerhk: translated acer key code 0xnn to ...". Write down the key code
+for each button/key combination and send them to me so I can patch the
+driver. I also need your model string to make autodetection work, so include
+/proc/driver/acerk/info.
\ Ingen nyrad vid filslut
diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/IOCTL linux-2.6.37.3rdparty/3rdparty/acerhk/doc/IOCTL
--- linux-2.6.37/3rdparty/acerhk/doc/IOCTL	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/IOCTL	2004-01-31 22:38:17.000000000 +0200
@@ -0,0 +1,61 @@
+Documentation of possible IOCTLs used by acerhk
++++++++++++++++++++++++++++++++++++++++++++++++
+
+ACERHK_GET_KEYCOUNT
+	Read the number of unread key presses in queue
+	Parameter: pointer to char
+
+ACERHK_GET_KEYID
+	Read the code of the first key press (oldest) in queue
+	Parameter: pointer to char
+
+ACERHK_CONNECT
+	Don't know what it does, used in windows driver
+
+ACERHK_DISCONNECT
+	Don't know what it does, used in windows driver
+
+ACERHK_GET_THERMAL_EVENT
+	Don't know what it does, used in windows driver
+	Parameter: pointer to short
+
+ACERHK_MAIL_LED_OFF
+	Switch off the LED of the mail button(if available)
+
+ACERHK_MAIL_LED_ON
+	Switch on the LED of the mail button (if available)
+
+ACERHK_START_POLLING
+	Start polling (and translation to key events) in kernel
+
+ACERHK_STOP_POLLING
+	Stop polling in kernel
+
+ACERHK_GET_KEY_MAP
+       	Get mapping of key names to key events
+	Parameter: pointer to t_map_name2event
+
+ACERHK_SET_KEY_MAP
+       	Set mapping of key names to key events
+	Parameter: pointer to t_map_name2event
+
+IOCTLs used by windows driver
++++++++++++++++++++++++++++++
+device name:
+\DosDevices\HOTKEY
+\Device\HOTKEY
+
+
+630 series:
+0x222404
+	Get CMOS index
+0x222408
+	ACERHK_GET_KEYCOUNT
+0x22240C
+	ACERHK_GET_KEYID
+0x222410
+	ACERHK_MAIL_LED_OFF/ACERHK_MAIL_LED_ON
+0x222414
+	ACERHK_CONNECT/ACERHK_DISCONNECT
+0x222418
+	ACERHK_GET_THERMAL_EVENT
diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/keycodes linux-2.6.37.3rdparty/3rdparty/acerhk/doc/keycodes
--- linux-2.6.37/3rdparty/acerhk/doc/keycodes	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/keycodes	2004-04-18 20:42:59.000000000 +0300
@@ -0,0 +1,26 @@
+standard X keycodes with older (acerhk controlled) hardware from Acer
+*********************************************************************
+help    (Fn+F1)		226
+setup   (Fn+F2)		129
+p1			153
+p2			144
+p3			171
+www			178
+mail			236
+wireless		147
+power   (Fn+F3)		222
+mute    (Fn+F8)		166
+volup   (Fn+Up)		158
+voldn   (Fn+Down)	165
+
+standard X keycodes with newer (acerhk activated) hardware from Dritek
+**********************************************************************
+help    (Fn+F1)		226
+setup   (Fn+F2)		129
+p1			153
+p2			144
+www			178
+mail			236
+volup   (Fn+Up)		176
+voldn   (Fn+Down)	174
+mute    (Fn+F8)		160
diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/md95400.def linux-2.6.37.3rdparty/3rdparty/acerhk/doc/md95400.def
--- linux-2.6.37/3rdparty/acerhk/doc/md95400.def	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/md95400.def	2005-03-01 22:46:53.000000000 +0200
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<CONFIG model="Medion MD 95400 series">
+
+<userdef keycode="236" command="/usr/bin/thunderbird">Mail</userdef>
+<userdef keycode="178" command="/usr/bin/firefox">Web</userdef>
+<userdef keycode="162" command="/usr/bin/xmms --play-pause">Play/Pause</userdef>
+<userdef keycode="164" command="/usr/bin/xmms --stop">Stop</userdef>
+<userdef keycode="144" command="/usr/bin/xmms --rew">Previous</userdef>
+<userdef keycode="153" command="/usr/bin/xmms --fwd">Next</userdef>
+<userdef keycode="174" command="/usr/bin/aumix -v -5">Leiser</userdef>
+<userdef keycode="176" command="/usr/bin/aumix -v +5">Lauter</userdef>
+<userdef keycode="160" command="/usr/bin/aumix -v 0"></userdef>
+
+</CONFIG>
diff -Nurp linux-2.6.37/3rdparty/acerhk/INSTALL linux-2.6.37.3rdparty/3rdparty/acerhk/INSTALL
--- linux-2.6.37/3rdparty/acerhk/INSTALL	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/INSTALL	2005-12-07 14:27:16.000000000 +0200
@@ -0,0 +1,109 @@
+Installation
+************
+
+1. You need the kernel sources (or kernel headers for your kernel)
+installed to compile the driver.
+
+2. Your kernel needs loadable module support with version information for
+modules enabled. Usage of procfs is highly recommended.
+If you want the driver to generate regular keyboard events using
+kernel version 2.4 you need the input system of the kernel enabled
+(Input core support AND keyboard support). In kernel version 2.6 all
+needed functionality should be available by default.
+
+In most cases you can skip the next step, the Makefile tries do determine
+the correct directory on its own. Change KERNELSRC only if the autodetection
+does not work for you. Otherwise proceed directly with step 4.
+
+3. Before you compile the driver, change KERNELSRC in the makefile to your
+path to the kernel build environment. If you are using a self compiled kernel,
+point it to the root of your sources. If you are using a packaged kernel of
+your distribution, install the package with kernel headers
+(Debian:kernel-headers) and point KERNELSRC to where the headers and config
+files are located. If you are using Debian, this
+would be "/lib/modules/<kernelversion>/build".
+
+4. Do:
+	make
+to compile the driver. If you run into problems because of the makefile not
+recognizing your kernel version correctly, try this:
+	make acerhk.o		- kernel version 2.4
+	make acerhk.ko		- kernel version 2.6
+
+5. Do:
+	make install
+to automatically copy the driver into the kernel module library. If you've
+done so, proceed directly with step 8. If you want to install the module
+binary yourself (because you want a different location), use steps 6 and 7
+instead.
+
+6. Copy the created file "acerhk.o" ("acerhk.ko" with version 2.6) to your
+kernel modules path. In Debian this could be
+"/lib/modules/<kernelversion>/kernel/drivers/extra/".
+
+7. Update module dependencies: depmod -a
+
+8. Try loading the module with:
+	insmod/modprobe acerhk
+If it succeeds - congratulations! If you have procfs enabled, you can try the
+following to test the driver:
+
+Non-Dritek models:
+Press one of the special keys and after that:
+	cat /proc/driver/acerhk/key
+to read the (hexadezimal) code of the key pressed. It should
+be different from 0x00.
+(Note: You mustn't have the polling feature enabled for this to work, so load
+ the module with poll=0)
+
+Dritek-models:
+Press one of the special keys and look for the generated key with "xev". If
+there is none, then you should see at least kernel messages about using
+setkeycodes.
+
+If your notebook has a mail led you can try this:
+	echo on > /proc/driver/acerhk/led
+This should sete the mail led to blinking mode.
+	echo off > /proc/driver/acerhk/led
+turns it off again.
+See README for further usage information.
+
+If the module didn't load look into your kernel messages what went wrong. If
+you see something like the following lines:
+	acerhk: could not find request handler
+	acerhk: can't find ROM area
+	acerhk: unloaded
+then your hardware is not recognized. See README for supported models. If it
+won't work on your notebook, please contact me and I will see if I can fix
+that.
+
+Integrating the driver into kernel tree version 2.6
+***************************************************
+
+If you want the driver to fully integrate into the kernel tree of version 2.6
+proceed as follows:
+1. Copy the acerhk directory into the source tree, for instance
+	/usr/src/linux/drivers/misc/acerhk
+2. Include the driver directory in the config files. Add to the Kconfig
+file of the parent directory(/usr/src/linux/drivers/misc/Kconfig):
+
+config ACERHK
+       tristate "Acerhk driver"
+       depends on EXPERIMENTAL
+       ---help---
+               This is an experimental acer keyboard driver for
+               acer laptops
+
+3. Include the acer directory in it's parents
+Makefile(/usr/src/linux/drivers/misc/Makefile):
+
+obj-$(CONFIG_ACERHK)   +=      acerhk/
+
+4. In this case you also need to activate the misc drivers first
+(/usr/src/linux/drivers/Kconfig):
+
+source "drivers/misc/Kconfig"
+
+If that's done, you should be able to select the driver from the configuration
+programm and build the module.
+
diff -Nurp linux-2.6.37/3rdparty/acerhk/Makefile linux-2.6.37.3rdparty/3rdparty/acerhk/Makefile
--- linux-2.6.37/3rdparty/acerhk/Makefile	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/Makefile	2006-08-16 19:11:08.000000000 +0300
@@ -0,0 +1,65 @@
+# change KERNELSRC to the location of your kernel build tree only if
+# autodetection does not work
+#KERNELSRC=/usr/src/linux
+KERNELSRC?=/lib/modules/`uname -r`/build
+# Starting with 2.6.18, the kernel version is in utsrelease.h instead of version.h, accomodate both cases
+KERNELVERSION=$(shell awk -F\" '/REL/ {print $$2}' $(shell grep -s -l REL $(KERNELSRC)/include/linux/version.h $(KERNELSRC)/include/linux/utsrelease.h))
+KERNELMAJOR=$(shell echo $(KERNELVERSION)|head -c3)
+
+# next line is for kernel 2.6, if you integrate the driver in the kernel tree
+# /usr/src/linux/drivers/acerhk - or something similar
+# don't forget to add the following line to the parent dir's Makefile:
+# (/usr/src/linux/drivers/Makefile)
+# obj-m                           += acerhk/
+CONFIG_ACERHK?=m
+obj-$(CONFIG_ACERHK) += acerhk.o
+
+CFLAGS+=-c -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe
+INCLUDE=-I$(KERNELSRC)/include
+
+ifeq ($(KERNELMAJOR), 2.6)
+TARGET := acerhk.ko
+else
+TARGET := acerhk.o
+endif
+
+SOURCE := acerhk.c
+
+all: $(TARGET)
+
+help:
+	@echo Possible targets:
+	@echo -e all\\t- default target, builds kernel module
+	@echo -e install\\t- copies module binary to /lib/modules/$(KERNELVERSION)/extra/
+	@echo -e clean\\t- removes all binaries and temporary files
+
+# this target is only for me, don't use it yourself (Olaf)
+export:
+	sh export.sh
+
+acerhk.ko: $(SOURCE) acerhk.h
+	$(MAKE) -C $(KERNELSRC) SUBDIRS=$(PWD) modules
+
+acerhk.o: $(SOURCE) acerhk.h
+	$(CC) $(INCLUDE) $(CFLAGS) -DMODVERSIONS -DMODULE -D__KERNEL__ -o $(TARGET) $(SOURCE)
+
+asm:	$(SOURCE)
+ifeq ($(KERNELMAJOR), 2.6)
+	$(CC) $(INCLUDE) $(INCLUDE)/asm-i386/mach-default $(CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE)
+else
+	$(CC) $(INCLUDE) $(CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE)
+endif
+
+clean:
+	rm -f *~ *.o *.s *.ko .acerhk* *.mod.c
+
+load:	$(TARGET)
+	insmod $(TARGET)
+
+unload:
+	rmmod acerhk
+
+install: $(TARGET)
+	mkdir -p /lib/modules/$(KERNELVERSION)/extra
+	cp -v $(TARGET) /lib/modules/$(KERNELVERSION)/extra/
+	depmod -a
diff -Nurp linux-2.6.37/3rdparty/acerhk/NEWS linux-2.6.37.3rdparty/3rdparty/acerhk/NEWS
--- linux-2.6.37/3rdparty/acerhk/NEWS	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/NEWS	2003-02-28 02:47:18.000000000 +0200
@@ -0,0 +1,16 @@
+2003-02-28 Version 0.5.0
+	completely changed key polling/translation
+	support for more series
+2002-07-06 Version 0.4.2
+	added debug functionality
+	bugfix with 520/210
+2002-06-24 Version 0.4.1
+	added support for TM 210 series
+	removed nvram dependency
+2002-06-15 Version 0.4
+	added model recognition
+	added kernel polling an key event generation
+	added support for 520 series
+
+2002-04-29 Version 0.3
+	Initial release
\ Ingen nyrad vid filslut
diff -Nurp linux-2.6.37/3rdparty/acerhk/README linux-2.6.37.3rdparty/3rdparty/acerhk/README
--- linux-2.6.37/3rdparty/acerhk/README	1970-01-01 02:00:00.000000000 +0200
+++ linux-2.6.37.3rdparty/3rdparty/acerhk/README	2006-11-10 00:01:46.000000000 +0200
@@ -0,0 +1,215 @@
+
+What is this driver good for?
+*****************************
+
+This driver will give access to the special keys on notebooks of the
+Acer Travelmate series, which are not handled by the keyboard
+driver.
+It also works on notebooks from other manufacturers (some Medion,
+Fujitsu-Siemens, ...).
+
+It also has some other related functionality (depending on the model):
+- controlling LEDs (Mail, Wireless)
+- enable/disable wireless hardware
+
+Usage
+*****
+
+The driver provides a device /dev/misc/acerhk where you can access all
+functions through IOCTL's, look into acerhk.h for their definitions.
+I use devfs and don't care about the minor number. You may want to change
+ACERHK_MINOR in acerhk.h.
+If you don't use devfs you need to create the device node. The device uses
+major 10 (misc character devices), the minor is chosen by the kernel (if
+ACERHK_MINOR equals MISC_DYNAMIC_MINOR) or by yourself (any other value).
+Use something like
+	mknod /dev/acerhk c 10 123
+to create the device node.
+You can also use most functions through procfs. You will find some files in
+/proc/driver/acerhk:
+	led  - write "on" or "off" to set the mail led state
+	key  - read it to get a key press, only useful on non-dritek models
+	       and only if polling is disabled
+	       This file exists only on non-dritek models
+	info - some information about the driver, including the number of
+	       pending keys
+	wirelessled - write "on" or "off" to set the led state and enable
+		      wlan hardware
+		      On some laptops you need to load the ipw2200 (others
+		      too?) with option "led=1" to make the led work.
+	blueled - write "on" or "off" to set the led state and enable
+		  bluetooth hardware
+		  write a value n >= 50 to let the led blink every n jiffies
+		  Do not use blinking mode where not only the led but also the
+                  bluetooth hardware is controlled!
+
+Probably the best way to use the driver is to let it poll for the keys itself
+and generate real key events. this is the normal case when loading the module
+without an additional parameter :
+
+	modprobe acerhk
+
+or you can use the ioctl as specified in acerhk.h to control the polling. If
+your kernel has keyboard input support you will get real key events when
+pressing the special keys.
+You can then use whatever software you like to make use of those keys,
+i.e. 'hotkeys' or Linux Easy Access Keyboard 'lineakd'. I prefer hotkeys, just
+in case anyone is interested, you can find a sample configuration for this
+programm in doc/acertm.def.
+Gnome >= 2.4 has built in support for multimedia keys (acme), that's
+what I use now.
+
+Have a look at
+ http://mmkc.sourceforge.net/
+
+Note: If you have one of the newer models using dritek hardware you don't need
+polling (nor the file /proc/driver/acerhk/key) to use your buttons. On this
+hardware the driver only needs to send a special command to the keyboard
+controller to make them work. The actual key presses are then handled by the
+normal keyboard driver of the kernel. You can switch of polling by
+loading the module with poll=0. It saves you precious cpu time.
+
+
+Module parameters
+*****************
+name	 values	meaning
+autowlan 0,1	disable(default)/enable automatic switching of wlan hardware
+		on wireless keypress, only useful for older (no
+		dritek-hardware) models, works only will poll=1
+poll	 0,1	disable/enable(default) kernel polling of key events
+verbose  0-4	verbosity level, see below
+usedritek 0,1	disable/enable(default) use of dritek hardware on newer
+		series, needed to activate the keys on such models
+force_series 	set this to the laptop series number you want the driver to
+		assume, skip autodetection (look at function
+		setup_model_features() for possible values)
+
+Debugging
+*********
+
+You can make the the driver be more verbose. To do this, add the following
+parameter when loading the module:
+
+	verbose=<n>
+
+n is an integer, 0 (default) means no additional information while increasing
+values provide an increasing amount of information. Currently 3 is maximum,
+bigger values will have the same effect as 3. The existing verbosity levels
+will generate information about:
+	Level	Information
+	1	state changes and variable initialization
+	2	model probing
+	3	key translation, only known keys
+	4	key translation, also unknown keys
+	5	misc. information (idle values)
+
+If you have rather serious problems you can activate debugging functionality
+in the driver. To do this, uncomment the '#define ACERDEBUG' in acerhk.c. You
+will find a new file in /proc/driver/acerhk, named 'debug'. You cannot read
+from this file, but you can write commands consisting of up to 4 digits. The
+first one specifies the action, while the latter can give additional
+parameters. Implemented are:
+	'd'	decrement module usage counter
+	'i'	increment module usage counter
+
+	'p'	call function pbutton_fct()
+	't'	call function get_thermal_event()
+	'w1x'	call function wbutton_fct_1() with parameter x (0-9)
+	'w2x'	call function wbutton_fct_2() with parameter x (0-9)
+
+	'vx'	change verbosity level to x (0-9)
+
+	'mxyy'	set mapping of key name x to key event yy (hex)
+	'sxx'	send key event xx (hex) to input system
+	'Sxx'	simulate acer key press with code xx (hex)
+
+	'e0'	stop kernel polling
+	'e1'	start kernel polling
+
+Example:
+
+1)	echo d > /proc/driver/acerhk/debug
+
+will decrement the usage counter, very useful if a program using the driver
+segfaulted. This way you can still unload the driver.
+
+2)	echo v4 > /proc/driver/acerhk/debug
+
+will set the verbosity level to maximum.
+
+Keycodes
+********
+
+see doc/keycodes
+Also see http://bernd-wurst.de/linux/tm800.php#mmkeys (only in german)
+
+If you have one of the newer models with the dritek hardware, use kernel 2.6
+and get (after enabling it) kernel messages of the form:
+
+	atkbd.c: Unknown key pressed (translated set 2, code 0xf4 on
+	isa0060/serio0).
+	atkbd.c: Use 'setkeycodes e074 <keycode>' to make it known.
+
+then you should do exactly what your told. In this case you could do
+
+	setkeycodes e074 158
+
+to map the button with scancode e074 (hex) to keycode 158 (decimal). To find
+out the scancodes of the buttons either look into the kernel log or into the
+file MMKEYBD.CFG of the windows launch manager package. There you should find
+lines like this:
+
+Key 1 = 1,E0,74,E0,F4,F500,P1
+          ** **            **
+
+The important information is marked in the example above. The numbers give the
+scancode produced by the button which's name is given last.
+The keycode you give as parameter to setkeycodes is one out of the header file
+linux/input.h, in the example above the one for KEY_BACK.
+Important note: I received mails from a number of people where setkeycodes
+rejected keycodes above a certain value. This is caused by an outdated version
+of setkeycodes, use a more recent one.
+To ease the setup of keymappings for the newer series I will try to include
+setup scripts for the different notebook series. If I have enough time to
+spare I will perhaps expand the driver itself do to that.
+
+How does it work?
+*****************
+
+The driver is based on the windows Me for series 610 driver and
+resembles its structure and functionality.
+Key presses are events, which are stored in a FIFO queue with 31
+entries. You can access the event count via CMOS nvram, but the access to
+the actual queue (and other functionality like switching the mail led) is
+done through calling a system ROM function.
+Upon loading the driver looks for this function, if it cannot find it,
+loading aborts.
+Newer Dritek Hardware:
+Button handling is done entirely by the EC (embbedded/environment
+controller) which behaves like an extended keyboard controller. My
+driver only enables/disables this extension.
+
+
+Credits
+*******
+
+Leif Jensen, whose driver inspired me to do the probing stuff
+http://www.math.columbia.edu/~jensen/linux/acertm/
+
+Thanks to all who contributed patches to this driver or who just tried it out
+on their laptops, without them it wouldn't support anything else but my
+TM 613.
+
+Contact
+*******
+
+If you have problems with the driver, please include the following information:
+1. name of your laptop (e.g. Acer TM 4001)
+2. content of /proc/driver/acerhk/info, if available
+3. kernel output after loading the module with verbose=2
+
+Email: Olaf Tauber <otauber@web.de>
+
+The latest version can be found here:
+
+http://www.informatik.hu-berlin.de/~tauber/acerhk