Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (32 commits)
  Input: wm97xx - update email address for Liam Girdwood
  Input: i8042 - add Thinkpad R31 to nomux list
  Input: move map_to_7segment.h to include/linux
  Input: ads7846 - fix cache line sharing issue
  Input: cm109 - add missing newlines to messages
  Input: document i8042.debug in kernel-parameters.txt
  Input: keyboard - fix potential out of bound access to key_map
  Input: psmouse - add OLPC touchpad driver
  Input: psmouse - tweak PSMOUSE_DEFINE_ATTR to support raw set callbacks
  Input: psmouse - add psmouse_queue_work() for ps/2 extension to make use of
  Input: psmouse - export psmouse_set_state for ps/2 extensions to use
  Input: ads7846 - introduce .gpio_pendown to get pendown state
  Input: ALPS - add signature for DualPoint found in Dell Latitude E6500
  Input: serio_raw - allow attaching to translated (SERIO_I8042XL) ports
  Input: cm109 - don't use obsolete logging macros
  Input: atkbd - expand Latitude's force release quirk to other Dells
  Input: bf54x-keys - add power management support
  Input: atmel_tsadcc - improve accuracy
  Input: convert drivers to use strict_strtoul()
  Input: appletouch - handle geyser 3/4 status bits
  ...
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 2443f5b..82c561f 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -796,6 +796,7 @@
 			Defaults to the default architecture's huge page size
 			if not specified.
 
+	i8042.debug	[HW] Toggle i8042 debug mode
 	i8042.direct	[HW] Put keyboard port into non-translated mode
 	i8042.dumbkbd	[HW] Pretend that controller can only read data from
 			     keyboard and cannot control its state
diff --git a/MAINTAINERS b/MAINTAINERS
index df20e29c..57975bd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4618,7 +4618,7 @@
 P:	Mark Brown
 M:	broonie@opensource.wolfsonmicro.com
 P:	Liam Girdwood
-M:	liam.girdwood@wolfsonmicro.com
+M:	lrg@slimlogic.co.uk
 L:	linux-input@vger.kernel.org
 T:	git git://opensource.wolfsonmicro.com/linux-2.6-touch
 W:	http://opensource.wolfsonmicro.com/node/7
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 7b3a212..de26a97 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1249,7 +1249,7 @@
 		return;
 	}
 
-	if (keycode > NR_KEYS)
+	if (keycode >= NR_KEYS)
 		if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
 			keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1);
 		else
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 078e4ee..2880eaa 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -231,6 +231,7 @@
 enum gameport_event_type {
 	GAMEPORT_REGISTER_PORT,
 	GAMEPORT_REGISTER_DRIVER,
+	GAMEPORT_ATTACH_DRIVER,
 };
 
 struct gameport_event {
@@ -245,11 +246,12 @@
 static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
 static struct task_struct *gameport_task;
 
-static void gameport_queue_event(void *object, struct module *owner,
-			      enum gameport_event_type event_type)
+static int gameport_queue_event(void *object, struct module *owner,
+				enum gameport_event_type event_type)
 {
 	unsigned long flags;
 	struct gameport_event *event;
+	int retval = 0;
 
 	spin_lock_irqsave(&gameport_event_lock, flags);
 
@@ -268,24 +270,34 @@
 		}
 	}
 
-	if ((event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC))) {
-		if (!try_module_get(owner)) {
-			printk(KERN_WARNING "gameport: Can't get module reference, dropping event %d\n", event_type);
-			kfree(event);
-			goto out;
-		}
-
-		event->type = event_type;
-		event->object = object;
-		event->owner = owner;
-
-		list_add_tail(&event->node, &gameport_event_list);
-		wake_up(&gameport_wait);
-	} else {
-		printk(KERN_ERR "gameport: Not enough memory to queue event %d\n", event_type);
+	event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
+	if (!event) {
+		printk(KERN_ERR
+			"gameport: Not enough memory to queue event %d\n",
+			event_type);
+		retval = -ENOMEM;
+		goto out;
 	}
+
+	if (!try_module_get(owner)) {
+		printk(KERN_WARNING
+			"gameport: Can't get module reference, dropping event %d\n",
+			event_type);
+		kfree(event);
+		retval = -EINVAL;
+		goto out;
+	}
+
+	event->type = event_type;
+	event->object = object;
+	event->owner = owner;
+
+	list_add_tail(&event->node, &gameport_event_list);
+	wake_up(&gameport_wait);
+
 out:
 	spin_unlock_irqrestore(&gameport_event_lock, flags);
+	return retval;
 }
 
 static void gameport_free_event(struct gameport_event *event)
@@ -378,9 +390,10 @@
 }
 
 /*
- * Remove all events that have been submitted for a given gameport port.
+ * Remove all events that have been submitted for a given object,
+ * be it a gameport port or a driver.
  */
-static void gameport_remove_pending_events(struct gameport *gameport)
+static void gameport_remove_pending_events(void *object)
 {
 	struct list_head *node, *next;
 	struct gameport_event *event;
@@ -390,7 +403,7 @@
 
 	list_for_each_safe(node, next, &gameport_event_list) {
 		event = list_entry(node, struct gameport_event, node);
-		if (event->object == gameport) {
+		if (event->object == object) {
 			list_del_init(node);
 			gameport_free_event(event);
 		}
@@ -705,10 +718,40 @@
 			drv->driver.name, error);
 }
 
-void __gameport_register_driver(struct gameport_driver *drv, struct module *owner)
+int __gameport_register_driver(struct gameport_driver *drv, struct module *owner,
+				const char *mod_name)
 {
+	int error;
+
 	drv->driver.bus = &gameport_bus;
-	gameport_queue_event(drv, owner, GAMEPORT_REGISTER_DRIVER);
+	drv->driver.owner = owner;
+	drv->driver.mod_name = mod_name;
+
+	/*
+	 * Temporarily disable automatic binding because probing
+	 * takes long time and we are better off doing it in kgameportd
+	 */
+	drv->ignore = 1;
+
+	error = driver_register(&drv->driver);
+	if (error) {
+		printk(KERN_ERR
+			"gameport: driver_register() failed for %s, error: %d\n",
+			drv->driver.name, error);
+		return error;
+	}
+
+	/*
+	 * Reset ignore flag and let kgameportd bind the driver to free ports
+	 */
+	drv->ignore = 0;
+	error = gameport_queue_event(drv, NULL, GAMEPORT_ATTACH_DRIVER);
+	if (error) {
+		driver_unregister(&drv->driver);
+		return error;
+	}
+
+	return 0;
 }
 
 void gameport_unregister_driver(struct gameport_driver *drv)
@@ -716,7 +759,9 @@
 	struct gameport *gameport;
 
 	mutex_lock(&gameport_mutex);
+
 	drv->ignore = 1;	/* so gameport_find_driver ignores it */
+	gameport_remove_pending_events(drv);
 
 start_over:
 	list_for_each_entry(gameport, &gameport_list, node) {
@@ -729,6 +774,7 @@
 	}
 
 	driver_unregister(&drv->driver);
+
 	mutex_unlock(&gameport_mutex);
 }
 
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index 92498d4..6489f40 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -414,8 +414,7 @@
 
 static int __init a3d_init(void)
 {
-	gameport_register_driver(&a3d_drv);
-	return 0;
+	return gameport_register_driver(&a3d_drv);
 }
 
 static void __exit a3d_exit(void)
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index d1ca8a1..89c4c08 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -572,8 +572,7 @@
 
 static int __init adi_init(void)
 {
-	gameport_register_driver(&adi_drv);
-	return 0;
+	return gameport_register_driver(&adi_drv);
 }
 
 static void __exit adi_exit(void)
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 708c5ae..356b3a2 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -761,9 +761,7 @@
 static int __init analog_init(void)
 {
 	analog_parse_options();
-	gameport_register_driver(&analog_drv);
-
-	return 0;
+	return gameport_register_driver(&analog_drv);
 }
 
 static void __exit analog_exit(void)
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index 639b975..3497b87 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -263,8 +263,7 @@
 
 static int __init cobra_init(void)
 {
-	gameport_register_driver(&cobra_drv);
-	return 0;
+	return gameport_register_driver(&cobra_drv);
 }
 
 static void __exit cobra_exit(void)
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index cb6eef1..67c207f 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -375,8 +375,7 @@
 
 static int __init gf2k_init(void)
 {
-	gameport_register_driver(&gf2k_drv);
-	return 0;
+	return gameport_register_driver(&gf2k_drv);
 }
 
 static void __exit gf2k_exit(void)
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index 684e07c..fc55899 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -426,8 +426,7 @@
 
 static int __init grip_init(void)
 {
-	gameport_register_driver(&grip_drv);
-	return 0;
+	return gameport_register_driver(&grip_drv);
 }
 
 static void __exit grip_exit(void)
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 8279481..2d47baf 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -689,8 +689,7 @@
 
 static int __init grip_init(void)
 {
-	gameport_register_driver(&grip_drv);
-	return 0;
+	return gameport_register_driver(&grip_drv);
 }
 
 static void __exit grip_exit(void)
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index 25ec3fa..4058d4b 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -283,8 +283,7 @@
 
 static int __init guillemot_init(void)
 {
-	gameport_register_driver(&guillemot_drv);
-	return 0;
+	return gameport_register_driver(&guillemot_drv);
 }
 
 static void __exit guillemot_exit(void)
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index 8c3290b..2478289 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -317,8 +317,7 @@
 
 static int __init interact_init(void)
 {
-	gameport_register_driver(&interact_drv);
-	return 0;
+	return gameport_register_driver(&interact_drv);
 }
 
 static void __exit interact_exit(void)
diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c
index 2a1b82c..cd894a0 100644
--- a/drivers/input/joystick/joydump.c
+++ b/drivers/input/joystick/joydump.c
@@ -161,8 +161,7 @@
 
 static int __init joydump_init(void)
 {
-	gameport_register_driver(&joydump_drv);
-	return 0;
+	return gameport_register_driver(&joydump_drv);
 }
 
 static void __exit joydump_exit(void)
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index 7b4865f..ca13a6b 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -818,8 +818,7 @@
 
 static int __init sw_init(void)
 {
-	gameport_register_driver(&sw_drv);
-	return 0;
+	return gameport_register_driver(&sw_drv);
 }
 
 static void __exit sw_exit(void)
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index 60c37bc..d6c6098 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -438,8 +438,7 @@
 
 static int __init tmdc_init(void)
 {
-	gameport_register_driver(&tmdc_drv);
-	return 0;
+	return gameport_register_driver(&tmdc_drv);
 }
 
 static void __exit tmdc_exit(void)
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index b1ce10f..22016ca 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -834,10 +834,10 @@
 }
 
 /*
- * Most special keys (Fn+F?) on Dell Latitudes do not generate release
+ * Most special keys (Fn+F?) on Dell laptops do not generate release
  * events so we have to do it ourselves.
  */
-static void atkbd_latitude_keymap_fixup(struct atkbd *atkbd)
+static void atkbd_dell_laptop_keymap_fixup(struct atkbd *atkbd)
 {
 	const unsigned int forced_release_keys[] = {
 		0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93,
@@ -1207,15 +1207,13 @@
 {
 	struct input_dev *old_dev, *new_dev;
 	unsigned long value;
-	char *rest;
 	int err;
 	unsigned char old_extra, old_set;
 
 	if (!atkbd->write)
 		return -EIO;
 
-	value = simple_strtoul(buf, &rest, 10);
-	if (*rest || value > 1)
+	if (strict_strtoul(buf, 10, &value) || value > 1)
 		return -EINVAL;
 
 	if (atkbd->extra != value) {
@@ -1264,12 +1262,10 @@
 {
 	struct input_dev *old_dev, *new_dev;
 	unsigned long value;
-	char *rest;
 	int err;
 	unsigned char old_scroll;
 
-	value = simple_strtoul(buf, &rest, 10);
-	if (*rest || value > 1)
+	if (strict_strtoul(buf, 10, &value) || value > 1)
 		return -EINVAL;
 
 	if (atkbd->scroll != value) {
@@ -1310,15 +1306,13 @@
 {
 	struct input_dev *old_dev, *new_dev;
 	unsigned long value;
-	char *rest;
 	int err;
 	unsigned char old_set, old_extra;
 
 	if (!atkbd->write)
 		return -EIO;
 
-	value = simple_strtoul(buf, &rest, 10);
-	if (*rest || (value != 2 && value != 3))
+	if (strict_strtoul(buf, 10, &value) || (value != 2 && value != 3))
 		return -EINVAL;
 
 	if (atkbd->set != value) {
@@ -1361,15 +1355,13 @@
 {
 	struct input_dev *old_dev, *new_dev;
 	unsigned long value;
-	char *rest;
 	int err;
 	unsigned char old_softrepeat, old_softraw;
 
 	if (!atkbd->write)
 		return -EIO;
 
-	value = simple_strtoul(buf, &rest, 10);
-	if (*rest || value > 1)
+	if (strict_strtoul(buf, 10, &value) || value > 1)
 		return -EINVAL;
 
 	if (atkbd->softrepeat != value) {
@@ -1413,12 +1405,10 @@
 {
 	struct input_dev *old_dev, *new_dev;
 	unsigned long value;
-	char *rest;
 	int err;
 	unsigned char old_softraw;
 
-	value = simple_strtoul(buf, &rest, 10);
-	if (*rest || value > 1)
+	if (strict_strtoul(buf, 10, &value) || value > 1)
 		return -EINVAL;
 
 	if (atkbd->softraw != value) {
@@ -1461,13 +1451,13 @@
 
 static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
 	{
-		.ident = "Dell Latitude series",
+		.ident = "Dell Laptop",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
+			DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
 		},
 		.callback = atkbd_setup_fixup,
-		.driver_data = atkbd_latitude_keymap_fixup,
+		.driver_data = atkbd_dell_laptop_keymap_fixup,
 	},
 	{
 		.ident = "HP 2133",
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
index e348cfc..1928401 100644
--- a/drivers/input/keyboard/bf54x-keys.c
+++ b/drivers/input/keyboard/bf54x-keys.c
@@ -8,7 +8,7 @@
  *
  *
  * Modified:
- *               Copyright 2007 Analog Devices Inc.
+ *               Copyright 2007-2008 Analog Devices Inc.
  *
  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  *
@@ -81,6 +81,9 @@
 	unsigned short *keycode;
 	struct timer_list timer;
 	unsigned int keyup_test_jiffies;
+	unsigned short kpad_msel;
+	unsigned short kpad_prescale;
+	unsigned short kpad_ctl;
 };
 
 static inline int bfin_kpad_find_key(struct bf54x_kpad *bf54x_kpad,
@@ -360,6 +363,10 @@
 {
 	struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
 
+	bf54x_kpad->kpad_msel = bfin_read_KPAD_MSEL();
+	bf54x_kpad->kpad_prescale = bfin_read_KPAD_PRESCALE();
+	bf54x_kpad->kpad_ctl = bfin_read_KPAD_CTL();
+
 	if (device_may_wakeup(&pdev->dev))
 		enable_irq_wake(bf54x_kpad->irq);
 
@@ -370,6 +377,10 @@
 {
 	struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
 
+	bfin_write_KPAD_MSEL(bf54x_kpad->kpad_msel);
+	bfin_write_KPAD_PRESCALE(bf54x_kpad->kpad_prescale);
+	bfin_write_KPAD_CTL(bf54x_kpad->kpad_ctl);
+
 	if (device_may_wakeup(&pdev->dev))
 		disable_irq_wake(bf54x_kpad->irq);
 
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index ec96b36..05f3f43 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -36,9 +36,10 @@
 	struct gpio_button_data data[0];
 };
 
-static void gpio_keys_report_event(struct gpio_keys_button *button,
-				   struct input_dev *input)
+static void gpio_keys_report_event(struct gpio_button_data *bdata)
 {
+	struct gpio_keys_button *button = bdata->button;
+	struct input_dev *input = bdata->input;
 	unsigned int type = button->type ?: EV_KEY;
 	int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
 
@@ -50,34 +51,23 @@
 {
 	struct gpio_button_data *data = (struct gpio_button_data *)_data;
 
-	gpio_keys_report_event(data->button, data->input);
+	gpio_keys_report_event(data);
 }
 
 static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
 {
-	struct platform_device *pdev = dev_id;
-	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
-	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
-	int i;
+	struct gpio_button_data *bdata = dev_id;
+	struct gpio_keys_button *button = bdata->button;
 
-	for (i = 0; i < pdata->nbuttons; i++) {
-		struct gpio_keys_button *button = &pdata->buttons[i];
+	BUG_ON(irq != gpio_to_irq(button->gpio));
 
-		if (irq == gpio_to_irq(button->gpio)) {
-			struct gpio_button_data *bdata = &ddata->data[i];
+	if (button->debounce_interval)
+		mod_timer(&bdata->timer,
+			jiffies + msecs_to_jiffies(button->debounce_interval));
+	else
+		gpio_keys_report_event(bdata);
 
-			if (button->debounce_interval)
-				mod_timer(&bdata->timer,
-					  jiffies +
-					  msecs_to_jiffies(button->debounce_interval));
-			else
-				gpio_keys_report_event(button, bdata->input);
-
-			return IRQ_HANDLED;
-		}
-	}
-
-	return IRQ_NONE;
+	return IRQ_HANDLED;
 }
 
 static int __devinit gpio_keys_probe(struct platform_device *pdev)
@@ -151,7 +141,7 @@
 				    IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |
 					IRQF_TRIGGER_FALLING,
 				    button->desc ? button->desc : "gpio_keys",
-				    pdev);
+				    bdata);
 		if (error) {
 			pr_err("gpio-keys: Unable to claim irq %d; error %d\n",
 				irq, error);
@@ -178,7 +168,7 @@
 
  fail2:
 	while (--i >= 0) {
-		free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
+		free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
 		if (pdata->buttons[i].debounce_interval)
 			del_timer_sync(&ddata->data[i].timer);
 		gpio_free(pdata->buttons[i].gpio);
@@ -203,7 +193,7 @@
 
 	for (i = 0; i < pdata->nbuttons; i++) {
 		int irq = gpio_to_irq(pdata->buttons[i].gpio);
-		free_irq(irq, pdev);
+		free_irq(irq, &ddata->data[i]);
 		if (pdata->buttons[i].debounce_interval)
 			del_timer_sync(&ddata->data[i].timer);
 		gpio_free(pdata->buttons[i].gpio);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index e99b788..199055d 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -180,6 +180,19 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called yealink.
 
+config INPUT_CM109
+	tristate "C-Media CM109 USB I/O Controller"
+	depends on EXPERIMENTAL
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  Say Y here if you want to enable keyboard and buzzer functions of the
+	  C-Media CM109 usb phones. The audio part is enabled by the generic
+	  usb sound driver, so you might want to enable that as well.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called cm109.
+
 config INPUT_UINPUT
 	tristate "User level driver support"
 	help
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index f48009b..d7db2ae 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -16,6 +16,7 @@
 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
 obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
 obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
+obj-$(CONFIG_INPUT_CM109)		+= cm109.o
 obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index a7fabaf..3c9988d 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -1,8 +1,8 @@
 /*
  * ati_remote2 - ATI/Philips USB RF remote driver
  *
- * Copyright (C) 2005 Ville Syrjala <syrjala@sci.fi>
- * Copyright (C) 2007 Peter Stokes <linux@dadeos.freeserve.co.uk>
+ * Copyright (C) 2005-2008 Ville Syrjala <syrjala@sci.fi>
+ * Copyright (C) 2007-2008 Peter Stokes <linux@dadeos.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2
@@ -12,7 +12,7 @@
 #include <linux/usb/input.h>
 
 #define DRIVER_DESC    "ATI/Philips USB RF remote driver"
-#define DRIVER_VERSION "0.2"
+#define DRIVER_VERSION "0.3"
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
@@ -27,7 +27,7 @@
  * A remote's "channel" may be altered by pressing and holding the "PC" button for
  * approximately 3 seconds, after which the button will slowly flash the count of the
  * currently configured "channel", using the numeric keypad enter a number between 1 and
- * 16 and then the "PC" button again, the button will slowly flash the count of the
+ * 16 and then press the "PC" button again, the button will slowly flash the count of the
  * newly configured "channel".
  */
 
@@ -45,9 +45,25 @@
 };
 MODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
 
-static struct {
-	int hw_code;
-	int key_code;
+static DEFINE_MUTEX(ati_remote2_mutex);
+
+enum {
+	ATI_REMOTE2_OPENED = 0x1,
+	ATI_REMOTE2_SUSPENDED = 0x2,
+};
+
+enum {
+	ATI_REMOTE2_AUX1,
+	ATI_REMOTE2_AUX2,
+	ATI_REMOTE2_AUX3,
+	ATI_REMOTE2_AUX4,
+	ATI_REMOTE2_PC,
+	ATI_REMOTE2_MODES,
+};
+
+static const struct {
+	u8  hw_code;
+	u16 keycode;
 } ati_remote2_key_table[] = {
 	{ 0x00, KEY_0 },
 	{ 0x01, KEY_1 },
@@ -73,6 +89,7 @@
 	{ 0x37, KEY_RECORD },
 	{ 0x38, KEY_DVD },
 	{ 0x39, KEY_TV },
+	{ 0x3f, KEY_PROG1 }, /* AUX1-AUX4 and PC */
 	{ 0x54, KEY_MENU },
 	{ 0x58, KEY_UP },
 	{ 0x59, KEY_DOWN },
@@ -91,15 +108,9 @@
 	{ 0xa9, BTN_LEFT },
 	{ 0xaa, BTN_RIGHT },
 	{ 0xbe, KEY_QUESTION },
-	{ 0xd5, KEY_FRONT },
 	{ 0xd0, KEY_EDIT },
+	{ 0xd5, KEY_FRONT },
 	{ 0xf9, KEY_INFO },
-	{ (0x00 << 8) | 0x3f, KEY_PROG1 },
-	{ (0x01 << 8) | 0x3f, KEY_PROG2 },
-	{ (0x02 << 8) | 0x3f, KEY_PROG3 },
-	{ (0x03 << 8) | 0x3f, KEY_PROG4 },
-	{ (0x04 << 8) | 0x3f, KEY_PC },
-	{ 0, KEY_RESERVED }
 };
 
 struct ati_remote2 {
@@ -117,46 +128,106 @@
 
 	char name[64];
 	char phys[64];
+
+	/* Each mode (AUX1-AUX4 and PC) can have an independent keymap. */
+	u16 keycode[ATI_REMOTE2_MODES][ARRAY_SIZE(ati_remote2_key_table)];
+
+	unsigned int flags;
 };
 
 static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
 static void ati_remote2_disconnect(struct usb_interface *interface);
+static int ati_remote2_suspend(struct usb_interface *interface, pm_message_t message);
+static int ati_remote2_resume(struct usb_interface *interface);
 
 static struct usb_driver ati_remote2_driver = {
 	.name       = "ati_remote2",
 	.probe      = ati_remote2_probe,
 	.disconnect = ati_remote2_disconnect,
 	.id_table   = ati_remote2_id_table,
+	.suspend    = ati_remote2_suspend,
+	.resume     = ati_remote2_resume,
+	.supports_autosuspend = 1,
 };
 
-static int ati_remote2_open(struct input_dev *idev)
+static int ati_remote2_submit_urbs(struct ati_remote2 *ar2)
 {
-	struct ati_remote2 *ar2 = input_get_drvdata(idev);
 	int r;
 
 	r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
 	if (r) {
 		dev_err(&ar2->intf[0]->dev,
-			"%s: usb_submit_urb() = %d\n", __func__, r);
+			"%s(): usb_submit_urb() = %d\n", __func__, r);
 		return r;
 	}
 	r = usb_submit_urb(ar2->urb[1], GFP_KERNEL);
 	if (r) {
 		usb_kill_urb(ar2->urb[0]);
 		dev_err(&ar2->intf[1]->dev,
-			"%s: usb_submit_urb() = %d\n", __func__, r);
+			"%s(): usb_submit_urb() = %d\n", __func__, r);
 		return r;
 	}
 
 	return 0;
 }
 
+static void ati_remote2_kill_urbs(struct ati_remote2 *ar2)
+{
+	usb_kill_urb(ar2->urb[1]);
+	usb_kill_urb(ar2->urb[0]);
+}
+
+static int ati_remote2_open(struct input_dev *idev)
+{
+	struct ati_remote2 *ar2 = input_get_drvdata(idev);
+	int r;
+
+	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
+
+	r = usb_autopm_get_interface(ar2->intf[0]);
+	if (r) {
+		dev_err(&ar2->intf[0]->dev,
+			"%s(): usb_autopm_get_interface() = %d\n", __func__, r);
+		goto fail1;
+	}
+
+	mutex_lock(&ati_remote2_mutex);
+
+	if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) {
+		r = ati_remote2_submit_urbs(ar2);
+		if (r)
+			goto fail2;
+	}
+
+	ar2->flags |= ATI_REMOTE2_OPENED;
+
+	mutex_unlock(&ati_remote2_mutex);
+
+	usb_autopm_put_interface(ar2->intf[0]);
+
+	return 0;
+
+ fail2:
+	mutex_unlock(&ati_remote2_mutex);
+	usb_autopm_put_interface(ar2->intf[0]);
+ fail1:
+	return r;
+}
+
 static void ati_remote2_close(struct input_dev *idev)
 {
 	struct ati_remote2 *ar2 = input_get_drvdata(idev);
 
-	usb_kill_urb(ar2->urb[0]);
-	usb_kill_urb(ar2->urb[1]);
+	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
+
+	mutex_lock(&ati_remote2_mutex);
+
+	if (!(ar2->flags & ATI_REMOTE2_SUSPENDED))
+		ati_remote2_kill_urbs(ar2);
+
+	ar2->flags &= ~ATI_REMOTE2_OPENED;
+
+	mutex_unlock(&ati_remote2_mutex);
 }
 
 static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
@@ -172,7 +243,7 @@
 
 	mode = data[0] & 0x0F;
 
-	if (mode > 4) {
+	if (mode > ATI_REMOTE2_PC) {
 		dev_err(&ar2->intf[0]->dev,
 			"Unknown mode byte (%02x %02x %02x %02x)\n",
 			data[3], data[2], data[1], data[0]);
@@ -191,7 +262,7 @@
 {
 	int i;
 
-	for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
+	for (i = 0; i < ARRAY_SIZE(ati_remote2_key_table); i++)
 		if (ati_remote2_key_table[i].hw_code == hw_code)
 			return i;
 
@@ -211,7 +282,7 @@
 
 	mode = data[0] & 0x0F;
 
-	if (mode > 4) {
+	if (mode > ATI_REMOTE2_PC) {
 		dev_err(&ar2->intf[1]->dev,
 			"Unknown mode byte (%02x %02x %02x %02x)\n",
 			data[3], data[2], data[1], data[0]);
@@ -219,10 +290,6 @@
 	}
 
 	hw_code = data[2];
-	/*
-	 * Mode keys (AUX1-AUX4, PC) all generate the same code byte.
-	 * Use the mode byte to figure out which one was pressed.
-	 */
 	if (hw_code == 0x3f) {
 		/*
 		 * For some incomprehensible reason the mouse pad generates
@@ -236,8 +303,6 @@
 
 		if (data[1] == 0)
 			ar2->mode = mode;
-
-		hw_code |= mode << 8;
 	}
 
 	if (!((1 << mode) & mode_mask))
@@ -260,8 +325,8 @@
 	case 2:	/* repeat */
 
 		/* No repeat for mouse buttons. */
-		if (ati_remote2_key_table[index].key_code == BTN_LEFT ||
-		    ati_remote2_key_table[index].key_code == BTN_RIGHT)
+		if (ar2->keycode[mode][index] == BTN_LEFT ||
+		    ar2->keycode[mode][index] == BTN_RIGHT)
 			return;
 
 		if (!time_after_eq(jiffies, ar2->jiffies))
@@ -276,7 +341,7 @@
 		return;
 	}
 
-	input_event(idev, EV_KEY, ati_remote2_key_table[index].key_code, data[1]);
+	input_event(idev, EV_KEY, ar2->keycode[mode][index], data[1]);
 	input_sync(idev);
 }
 
@@ -287,6 +352,7 @@
 
 	switch (urb->status) {
 	case 0:
+		usb_mark_last_busy(ar2->udev);
 		ati_remote2_input_mouse(ar2);
 		break;
 	case -ENOENT:
@@ -297,6 +363,7 @@
 			"%s(): urb status = %d\n", __func__, urb->status);
 		return;
 	default:
+		usb_mark_last_busy(ar2->udev);
 		dev_err(&ar2->intf[0]->dev,
 			"%s(): urb status = %d\n", __func__, urb->status);
 	}
@@ -314,6 +381,7 @@
 
 	switch (urb->status) {
 	case 0:
+		usb_mark_last_busy(ar2->udev);
 		ati_remote2_input_key(ar2);
 		break;
 	case -ENOENT:
@@ -324,6 +392,7 @@
 			"%s(): urb status = %d\n", __func__, urb->status);
 		return;
 	default:
+		usb_mark_last_busy(ar2->udev);
 		dev_err(&ar2->intf[1]->dev,
 			"%s(): urb status = %d\n", __func__, urb->status);
 	}
@@ -334,10 +403,60 @@
 			"%s(): usb_submit_urb() = %d\n", __func__, r);
 }
 
+static int ati_remote2_getkeycode(struct input_dev *idev,
+				  int scancode, int *keycode)
+{
+	struct ati_remote2 *ar2 = input_get_drvdata(idev);
+	int index, mode;
+
+	mode = scancode >> 8;
+	if (mode > ATI_REMOTE2_PC || !((1 << mode) & mode_mask))
+		return -EINVAL;
+
+	index = ati_remote2_lookup(scancode & 0xFF);
+	if (index < 0)
+		return -EINVAL;
+
+	*keycode = ar2->keycode[mode][index];
+	return 0;
+}
+
+static int ati_remote2_setkeycode(struct input_dev *idev, int scancode, int keycode)
+{
+	struct ati_remote2 *ar2 = input_get_drvdata(idev);
+	int index, mode, old_keycode;
+
+	mode = scancode >> 8;
+	if (mode > ATI_REMOTE2_PC || !((1 << mode) & mode_mask))
+		return -EINVAL;
+
+	index = ati_remote2_lookup(scancode & 0xFF);
+	if (index < 0)
+		return -EINVAL;
+
+	if (keycode < KEY_RESERVED || keycode > KEY_MAX)
+		return -EINVAL;
+
+	old_keycode = ar2->keycode[mode][index];
+	ar2->keycode[mode][index] = keycode;
+	set_bit(keycode, idev->keybit);
+
+	for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
+		for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
+			if (ar2->keycode[mode][index] == old_keycode)
+				return 0;
+		}
+	}
+
+	clear_bit(old_keycode, idev->keybit);
+
+	return 0;
+}
+
 static int ati_remote2_input_init(struct ati_remote2 *ar2)
 {
 	struct input_dev *idev;
-	int i, retval;
+	int index, mode, retval;
 
 	idev = input_allocate_device();
 	if (!idev)
@@ -350,8 +469,26 @@
 	idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
 		BIT_MASK(BTN_RIGHT);
 	idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
-	for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
-		set_bit(ati_remote2_key_table[i].key_code, idev->keybit);
+
+	for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
+		for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
+			ar2->keycode[mode][index] = ati_remote2_key_table[index].keycode;
+			set_bit(ar2->keycode[mode][index], idev->keybit);
+		}
+	}
+
+	/* AUX1-AUX4 and PC generate the same scancode. */
+	index = ati_remote2_lookup(0x3f);
+	ar2->keycode[ATI_REMOTE2_AUX1][index] = KEY_PROG1;
+	ar2->keycode[ATI_REMOTE2_AUX2][index] = KEY_PROG2;
+	ar2->keycode[ATI_REMOTE2_AUX3][index] = KEY_PROG3;
+	ar2->keycode[ATI_REMOTE2_AUX4][index] = KEY_PROG4;
+	ar2->keycode[ATI_REMOTE2_PC][index] = KEY_PC;
+	set_bit(KEY_PROG1, idev->keybit);
+	set_bit(KEY_PROG2, idev->keybit);
+	set_bit(KEY_PROG3, idev->keybit);
+	set_bit(KEY_PROG4, idev->keybit);
+	set_bit(KEY_PC, idev->keybit);
 
 	idev->rep[REP_DELAY]  = 250;
 	idev->rep[REP_PERIOD] = 33;
@@ -359,6 +496,9 @@
 	idev->open = ati_remote2_open;
 	idev->close = ati_remote2_close;
 
+	idev->getkeycode = ati_remote2_getkeycode;
+	idev->setkeycode = ati_remote2_setkeycode;
+
 	idev->name = ar2->name;
 	idev->phys = ar2->phys;
 
@@ -490,6 +630,8 @@
 
 	usb_set_intfdata(interface, ar2);
 
+	interface->needs_remote_wakeup = 1;
+
 	return 0;
 
  fail2:
@@ -522,6 +664,57 @@
 	kfree(ar2);
 }
 
+static int ati_remote2_suspend(struct usb_interface *interface,
+			       pm_message_t message)
+{
+	struct ati_remote2 *ar2;
+	struct usb_host_interface *alt = interface->cur_altsetting;
+
+	if (alt->desc.bInterfaceNumber)
+		return 0;
+
+	ar2 = usb_get_intfdata(interface);
+
+	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
+
+	mutex_lock(&ati_remote2_mutex);
+
+	if (ar2->flags & ATI_REMOTE2_OPENED)
+		ati_remote2_kill_urbs(ar2);
+
+	ar2->flags |= ATI_REMOTE2_SUSPENDED;
+
+	mutex_unlock(&ati_remote2_mutex);
+
+	return 0;
+}
+
+static int ati_remote2_resume(struct usb_interface *interface)
+{
+	struct ati_remote2 *ar2;
+	struct usb_host_interface *alt = interface->cur_altsetting;
+	int r = 0;
+
+	if (alt->desc.bInterfaceNumber)
+		return 0;
+
+	ar2 = usb_get_intfdata(interface);
+
+	dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
+
+	mutex_lock(&ati_remote2_mutex);
+
+	if (ar2->flags & ATI_REMOTE2_OPENED)
+		r = ati_remote2_submit_urbs(ar2);
+
+	if (!r)
+		ar2->flags &= ~ATI_REMOTE2_SUSPENDED;
+
+	mutex_unlock(&ati_remote2_mutex);
+
+	return r;
+}
+
 static int __init ati_remote2_init(void)
 {
 	int r;
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
new file mode 100644
index 0000000..bce160f
--- /dev/null
+++ b/drivers/input/misc/cm109.c
@@ -0,0 +1,882 @@
+/*
+ * Driver for the VoIP USB phones with CM109 chipsets.
+ *
+ * Copyright (C) 2007 - 2008 Alfred E. Heggestad <aeh@db.org>
+ *
+ *	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, version 2.
+ */
+
+/*
+ *   Tested devices:
+ *	- Komunikate KIP1000
+ *	- Genius G-talk
+ *	- Allied-Telesis Corega USBPH01
+ *	- ...
+ *
+ * This driver is based on the yealink.c driver
+ *
+ * Thanks to:
+ *   - Authors of yealink.c
+ *   - Thomas Reitmayr
+ *   - Oliver Neukum for good review comments and code
+ *   - Shaun Jackman <sjackman@gmail.com> for Genius G-talk keymap
+ *   - Dmitry Torokhov for valuable input and review
+ *
+ * Todo:
+ *   - Read/write EEPROM
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/rwsem.h>
+#include <linux/usb/input.h>
+
+#define DRIVER_VERSION "20080805"
+#define DRIVER_AUTHOR  "Alfred E. Heggestad"
+#define DRIVER_DESC    "CM109 phone driver"
+
+static char *phone = "kip1000";
+module_param(phone, charp, S_IRUSR);
+MODULE_PARM_DESC(phone, "Phone name {kip1000, gtalk, usbph01}");
+
+enum {
+	/* HID Registers */
+	HID_IR0 = 0x00, /* Record/Playback-mute button, Volume up/down  */
+	HID_IR1 = 0x01, /* GPI, generic registers or EEPROM_DATA0       */
+	HID_IR2 = 0x02, /* Generic registers or EEPROM_DATA1            */
+	HID_IR3 = 0x03, /* Generic registers or EEPROM_CTRL             */
+	HID_OR0 = 0x00, /* Mapping control, buzzer, SPDIF (offset 0x04) */
+	HID_OR1 = 0x01, /* GPO - General Purpose Output                 */
+	HID_OR2 = 0x02, /* Set GPIO to input/output mode                */
+	HID_OR3 = 0x03, /* SPDIF status channel or EEPROM_CTRL          */
+
+	/* HID_IR0 */
+	RECORD_MUTE   = 1 << 3,
+	PLAYBACK_MUTE = 1 << 2,
+	VOLUME_DOWN   = 1 << 1,
+	VOLUME_UP     = 1 << 0,
+
+	/* HID_OR0 */
+	/* bits 7-6
+	   0: HID_OR1-2 are used for GPO; HID_OR0, 3 are used for buzzer
+	      and SPDIF
+	   1: HID_OR0-3 are used as generic HID registers
+	   2: Values written to HID_OR0-3 are also mapped to MCU_CTRL,
+	      EEPROM_DATA0-1, EEPROM_CTRL (see Note)
+	   3: Reserved
+	 */
+	HID_OR_GPO_BUZ_SPDIF   = 0 << 6,
+	HID_OR_GENERIC_HID_REG = 1 << 6,
+	HID_OR_MAP_MCU_EEPROM  = 2 << 6,
+
+	BUZZER_ON = 1 << 5,
+
+	/* up to 256 normal keys, up to 16 special keys */
+	KEYMAP_SIZE = 256 + 16,
+};
+
+/* CM109 protocol packet */
+struct cm109_ctl_packet {
+	u8 byte[4];
+} __attribute__ ((packed));
+
+enum { USB_PKT_LEN = sizeof(struct cm109_ctl_packet) };
+
+/* CM109 device structure */
+struct cm109_dev {
+	struct input_dev *idev;	 /* input device */
+	struct usb_device *udev; /* usb device */
+	struct usb_interface *intf;
+
+	/* irq input channel */
+	struct cm109_ctl_packet *irq_data;
+	dma_addr_t irq_dma;
+	struct urb *urb_irq;
+
+	/* control output channel */
+	struct cm109_ctl_packet *ctl_data;
+	dma_addr_t ctl_dma;
+	struct usb_ctrlrequest *ctl_req;
+	dma_addr_t ctl_req_dma;
+	struct urb *urb_ctl;
+	/*
+	 * The 3 bitfields below are protected by ctl_submit_lock.
+	 * They have to be separate since they are accessed from IRQ
+	 * context.
+	 */
+	unsigned irq_urb_pending:1;	/* irq_urb is in flight */
+	unsigned ctl_urb_pending:1;	/* ctl_urb is in flight */
+	unsigned buzzer_pending:1;	/* need to issue buzz command */
+	spinlock_t ctl_submit_lock;
+
+	unsigned char buzzer_state;	/* on/off */
+
+	/* flags */
+	unsigned open:1;
+	unsigned resetting:1;
+	unsigned shutdown:1;
+
+	/* This mutex protects writes to the above flags */
+	struct mutex pm_mutex;
+
+	unsigned short keymap[KEYMAP_SIZE];
+
+	char phys[64];		/* physical device path */
+	int key_code;		/* last reported key */
+	int keybit;		/* 0=new scan  1,2,4,8=scan columns  */
+	u8 gpi;			/* Cached value of GPI (high nibble) */
+};
+
+/******************************************************************************
+ * CM109 key interface
+ *****************************************************************************/
+
+static unsigned short special_keymap(int code)
+{
+	if (code > 0xff) {
+		switch (code - 0xff) {
+		case RECORD_MUTE:	return KEY_MUTE;
+		case PLAYBACK_MUTE:	return KEY_MUTE;
+		case VOLUME_DOWN:	return KEY_VOLUMEDOWN;
+		case VOLUME_UP:		return KEY_VOLUMEUP;
+		}
+	}
+	return KEY_RESERVED;
+}
+
+/* Map device buttons to internal key events.
+ *
+ * The "up" and "down" keys, are symbolised by arrows on the button.
+ * The "pickup" and "hangup" keys are symbolised by a green and red phone
+ * on the button.
+
+ Komunikate KIP1000 Keyboard Matrix
+
+     -> -- 1 -- 2 -- 3  --> GPI pin 4 (0x10)
+      |    |    |    |
+     <- -- 4 -- 5 -- 6  --> GPI pin 5 (0x20)
+      |    |    |    |
+     END - 7 -- 8 -- 9  --> GPI pin 6 (0x40)
+      |    |    |    |
+     OK -- * -- 0 -- #  --> GPI pin 7 (0x80)
+      |    |    |    |
+
+     /|\  /|\  /|\  /|\
+      |    |    |    |
+GPO
+pin:  3    2    1    0
+     0x8  0x4  0x2  0x1
+
+ */
+static unsigned short keymap_kip1000(int scancode)
+{
+	switch (scancode) {				/* phone key:   */
+	case 0x82: return KEY_NUMERIC_0;		/*   0          */
+	case 0x14: return KEY_NUMERIC_1;		/*   1          */
+	case 0x12: return KEY_NUMERIC_2;		/*   2          */
+	case 0x11: return KEY_NUMERIC_3;		/*   3          */
+	case 0x24: return KEY_NUMERIC_4;		/*   4          */
+	case 0x22: return KEY_NUMERIC_5;		/*   5          */
+	case 0x21: return KEY_NUMERIC_6;		/*   6          */
+	case 0x44: return KEY_NUMERIC_7;		/*   7          */
+	case 0x42: return KEY_NUMERIC_8;		/*   8          */
+	case 0x41: return KEY_NUMERIC_9;		/*   9          */
+	case 0x81: return KEY_NUMERIC_POUND;		/*   #          */
+	case 0x84: return KEY_NUMERIC_STAR;		/*   *          */
+	case 0x88: return KEY_ENTER;			/*   pickup     */
+	case 0x48: return KEY_ESC;			/*   hangup     */
+	case 0x28: return KEY_LEFT;			/*   IN         */
+	case 0x18: return KEY_RIGHT;			/*   OUT        */
+	default:   return special_keymap(scancode);
+	}
+}
+
+/*
+  Contributed by Shaun Jackman <sjackman@gmail.com>
+
+  Genius G-Talk keyboard matrix
+     0 1 2 3
+  4: 0 4 8 Talk
+  5: 1 5 9 End
+  6: 2 6 # Up
+  7: 3 7 * Down
+*/
+static unsigned short keymap_gtalk(int scancode)
+{
+	switch (scancode) {
+	case 0x11: return KEY_NUMERIC_0;
+	case 0x21: return KEY_NUMERIC_1;
+	case 0x41: return KEY_NUMERIC_2;
+	case 0x81: return KEY_NUMERIC_3;
+	case 0x12: return KEY_NUMERIC_4;
+	case 0x22: return KEY_NUMERIC_5;
+	case 0x42: return KEY_NUMERIC_6;
+	case 0x82: return KEY_NUMERIC_7;
+	case 0x14: return KEY_NUMERIC_8;
+	case 0x24: return KEY_NUMERIC_9;
+	case 0x44: return KEY_NUMERIC_POUND;	/* # */
+	case 0x84: return KEY_NUMERIC_STAR;	/* * */
+	case 0x18: return KEY_ENTER;		/* Talk (green handset) */
+	case 0x28: return KEY_ESC;		/* End (red handset) */
+	case 0x48: return KEY_UP;		/* Menu up (rocker switch) */
+	case 0x88: return KEY_DOWN;		/* Menu down (rocker switch) */
+	default:   return special_keymap(scancode);
+	}
+}
+
+/*
+ * Keymap for Allied-Telesis Corega USBPH01
+ * http://www.alliedtelesis-corega.com/2/1344/1437/1360/chprd.html
+ *
+ * Contributed by july@nat.bg
+ */
+static unsigned short keymap_usbph01(int scancode)
+{
+	switch (scancode) {
+	case 0x11: return KEY_NUMERIC_0;		/*   0          */
+	case 0x21: return KEY_NUMERIC_1;		/*   1          */
+	case 0x41: return KEY_NUMERIC_2;		/*   2          */
+	case 0x81: return KEY_NUMERIC_3;		/*   3          */
+	case 0x12: return KEY_NUMERIC_4;		/*   4          */
+	case 0x22: return KEY_NUMERIC_5;		/*   5          */
+	case 0x42: return KEY_NUMERIC_6;		/*   6          */
+	case 0x82: return KEY_NUMERIC_7;		/*   7          */
+	case 0x14: return KEY_NUMERIC_8;		/*   8          */
+	case 0x24: return KEY_NUMERIC_9;		/*   9          */
+	case 0x44: return KEY_NUMERIC_POUND;		/*   #          */
+	case 0x84: return KEY_NUMERIC_STAR;		/*   *          */
+	case 0x18: return KEY_ENTER;			/*   pickup     */
+	case 0x28: return KEY_ESC;			/*   hangup     */
+	case 0x48: return KEY_LEFT;			/*   IN         */
+	case 0x88: return KEY_RIGHT;			/*   OUT        */
+	default:   return special_keymap(scancode);
+	}
+}
+
+static unsigned short (*keymap)(int) = keymap_kip1000;
+
+/*
+ * Completes a request by converting the data into events for the
+ * input subsystem.
+ */
+static void report_key(struct cm109_dev *dev, int key)
+{
+	struct input_dev *idev = dev->idev;
+
+	if (dev->key_code >= 0) {
+		/* old key up */
+		input_report_key(idev, dev->key_code, 0);
+	}
+
+	dev->key_code = key;
+	if (key >= 0) {
+		/* new valid key */
+		input_report_key(idev, key, 1);
+	}
+
+	input_sync(idev);
+}
+
+/******************************************************************************
+ * CM109 usb communication interface
+ *****************************************************************************/
+
+static void cm109_submit_buzz_toggle(struct cm109_dev *dev)
+{
+	int error;
+
+	if (dev->buzzer_state)
+		dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
+	else
+		dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
+
+	error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
+	if (error)
+		err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
+}
+
+/*
+ * IRQ handler
+ */
+static void cm109_urb_irq_callback(struct urb *urb)
+{
+	struct cm109_dev *dev = urb->context;
+	const int status = urb->status;
+	int error;
+
+	dev_dbg(&urb->dev->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
+	     dev->irq_data->byte[0],
+	     dev->irq_data->byte[1],
+	     dev->irq_data->byte[2],
+	     dev->irq_data->byte[3],
+	     dev->keybit);
+
+	if (status) {
+		if (status == -ESHUTDOWN)
+			return;
+		err("%s: urb status %d", __func__, status);
+	}
+
+	/* Special keys */
+	if (dev->irq_data->byte[HID_IR0] & 0x0f) {
+		const int code = (dev->irq_data->byte[HID_IR0] & 0x0f);
+		report_key(dev, dev->keymap[0xff + code]);
+	}
+
+	/* Scan key column */
+	if (dev->keybit == 0xf) {
+
+		/* Any changes ? */
+		if ((dev->gpi & 0xf0) == (dev->irq_data->byte[HID_IR1] & 0xf0))
+			goto out;
+
+		dev->gpi = dev->irq_data->byte[HID_IR1] & 0xf0;
+		dev->keybit = 0x1;
+	} else {
+		report_key(dev, dev->keymap[dev->irq_data->byte[HID_IR1]]);
+
+		dev->keybit <<= 1;
+		if (dev->keybit > 0x8)
+			dev->keybit = 0xf;
+	}
+
+ out:
+
+	spin_lock(&dev->ctl_submit_lock);
+
+	dev->irq_urb_pending = 0;
+
+	if (likely(!dev->shutdown)) {
+
+		if (dev->buzzer_state)
+			dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
+		else
+			dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
+
+		dev->ctl_data->byte[HID_OR1] = dev->keybit;
+		dev->ctl_data->byte[HID_OR2] = dev->keybit;
+
+		dev->buzzer_pending = 0;
+		dev->ctl_urb_pending = 1;
+
+		error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
+		if (error)
+			err("%s: usb_submit_urb (urb_ctl) failed %d",
+				__func__, error);
+	}
+
+	spin_unlock(&dev->ctl_submit_lock);
+}
+
+static void cm109_urb_ctl_callback(struct urb *urb)
+{
+	struct cm109_dev *dev = urb->context;
+	const int status = urb->status;
+	int error;
+
+	dev_dbg(&urb->dev->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
+	     dev->ctl_data->byte[0],
+	     dev->ctl_data->byte[1],
+	     dev->ctl_data->byte[2],
+	     dev->ctl_data->byte[3]);
+
+	if (status)
+		err("%s: urb status %d", __func__, status);
+
+	spin_lock(&dev->ctl_submit_lock);
+
+	dev->ctl_urb_pending = 0;
+
+	if (likely(!dev->shutdown)) {
+
+		if (dev->buzzer_pending) {
+			dev->buzzer_pending = 0;
+			dev->ctl_urb_pending = 1;
+			cm109_submit_buzz_toggle(dev);
+		} else if (likely(!dev->irq_urb_pending)) {
+			/* ask for key data */
+			dev->irq_urb_pending = 1;
+			error = usb_submit_urb(dev->urb_irq, GFP_ATOMIC);
+			if (error)
+				err("%s: usb_submit_urb (urb_irq) failed %d",
+					__func__, error);
+		}
+	}
+
+	spin_unlock(&dev->ctl_submit_lock);
+}
+
+static void cm109_toggle_buzzer_async(struct cm109_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->ctl_submit_lock, flags);
+
+	if (dev->ctl_urb_pending) {
+		/* URB completion will resubmit */
+		dev->buzzer_pending = 1;
+	} else {
+		dev->ctl_urb_pending = 1;
+		cm109_submit_buzz_toggle(dev);
+	}
+
+	spin_unlock_irqrestore(&dev->ctl_submit_lock, flags);
+}
+
+static void cm109_toggle_buzzer_sync(struct cm109_dev *dev, int on)
+{
+	int error;
+
+	if (on)
+		dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
+	else
+		dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
+
+	error = usb_control_msg(dev->udev,
+				usb_sndctrlpipe(dev->udev, 0),
+				dev->ctl_req->bRequest,
+				dev->ctl_req->bRequestType,
+				le16_to_cpu(dev->ctl_req->wValue),
+				le16_to_cpu(dev->ctl_req->wIndex),
+				dev->ctl_data,
+				USB_PKT_LEN, USB_CTRL_SET_TIMEOUT);
+	if (error && error != EINTR)
+		err("%s: usb_control_msg() failed %d", __func__, error);
+}
+
+static void cm109_stop_traffic(struct cm109_dev *dev)
+{
+	dev->shutdown = 1;
+	/*
+	 * Make sure other CPUs see this
+	 */
+	smp_wmb();
+
+	usb_kill_urb(dev->urb_ctl);
+	usb_kill_urb(dev->urb_irq);
+
+	cm109_toggle_buzzer_sync(dev, 0);
+
+	dev->shutdown = 0;
+	smp_wmb();
+}
+
+static void cm109_restore_state(struct cm109_dev *dev)
+{
+	if (dev->open) {
+		/*
+		 * Restore buzzer state.
+		 * This will also kick regular URB submission
+		 */
+		cm109_toggle_buzzer_async(dev);
+	}
+}
+
+/******************************************************************************
+ * input event interface
+ *****************************************************************************/
+
+static int cm109_input_open(struct input_dev *idev)
+{
+	struct cm109_dev *dev = input_get_drvdata(idev);
+	int error;
+
+	error = usb_autopm_get_interface(dev->intf);
+	if (error < 0) {
+		err("%s - cannot autoresume, result %d",
+		    __func__, error);
+		return error;
+	}
+
+	mutex_lock(&dev->pm_mutex);
+
+	dev->buzzer_state = 0;
+	dev->key_code = -1;	/* no keys pressed */
+	dev->keybit = 0xf;
+
+	/* issue INIT */
+	dev->ctl_data->byte[HID_OR0] = HID_OR_GPO_BUZ_SPDIF;
+	dev->ctl_data->byte[HID_OR1] = dev->keybit;
+	dev->ctl_data->byte[HID_OR2] = dev->keybit;
+	dev->ctl_data->byte[HID_OR3] = 0x00;
+
+	error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL);
+	if (error)
+		err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
+	else
+		dev->open = 1;
+
+	mutex_unlock(&dev->pm_mutex);
+
+	if (error)
+		usb_autopm_put_interface(dev->intf);
+
+	return error;
+}
+
+static void cm109_input_close(struct input_dev *idev)
+{
+	struct cm109_dev *dev = input_get_drvdata(idev);
+
+	mutex_lock(&dev->pm_mutex);
+
+	/*
+	 * Once we are here event delivery is stopped so we
+	 * don't need to worry about someone starting buzzer
+	 * again
+	 */
+	cm109_stop_traffic(dev);
+	dev->open = 0;
+
+	mutex_unlock(&dev->pm_mutex);
+
+	usb_autopm_put_interface(dev->intf);
+}
+
+static int cm109_input_ev(struct input_dev *idev, unsigned int type,
+			  unsigned int code, int value)
+{
+	struct cm109_dev *dev = input_get_drvdata(idev);
+
+	dev_dbg(&dev->udev->dev,
+		"input_ev: type=%u code=%u value=%d\n", type, code, value);
+
+	if (type != EV_SND)
+		return -EINVAL;
+
+	switch (code) {
+	case SND_TONE:
+	case SND_BELL:
+		dev->buzzer_state = !!value;
+		if (!dev->resetting)
+			cm109_toggle_buzzer_async(dev);
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+
+/******************************************************************************
+ * Linux interface and usb initialisation
+ *****************************************************************************/
+
+struct driver_info {
+	char *name;
+};
+
+static const struct driver_info info_cm109 = {
+	.name = "CM109 USB driver",
+};
+
+enum {
+	VENDOR_ID        = 0x0d8c, /* C-Media Electronics */
+	PRODUCT_ID_CM109 = 0x000e, /* CM109 defines range 0x0008 - 0x000f */
+};
+
+/* table of devices that work with this driver */
+static const struct usb_device_id cm109_usb_table[] = {
+	{
+		.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+				USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor = VENDOR_ID,
+		.idProduct = PRODUCT_ID_CM109,
+		.bInterfaceClass = USB_CLASS_HID,
+		.bInterfaceSubClass = 0,
+		.bInterfaceProtocol = 0,
+		.driver_info = (kernel_ulong_t) &info_cm109
+	},
+	/* you can add more devices here with product ID 0x0008 - 0x000f */
+	{ }
+};
+
+static void cm109_usb_cleanup(struct cm109_dev *dev)
+{
+	if (dev->ctl_req)
+		usb_buffer_free(dev->udev, sizeof(*(dev->ctl_req)),
+				dev->ctl_req, dev->ctl_req_dma);
+	if (dev->ctl_data)
+		usb_buffer_free(dev->udev, USB_PKT_LEN,
+				dev->ctl_data, dev->ctl_dma);
+	if (dev->irq_data)
+		usb_buffer_free(dev->udev, USB_PKT_LEN,
+				dev->irq_data, dev->irq_dma);
+
+	usb_free_urb(dev->urb_irq);	/* parameter validation in core/urb */
+	usb_free_urb(dev->urb_ctl);	/* parameter validation in core/urb */
+	kfree(dev);
+}
+
+static void cm109_usb_disconnect(struct usb_interface *interface)
+{
+	struct cm109_dev *dev = usb_get_intfdata(interface);
+
+	usb_set_intfdata(interface, NULL);
+	input_unregister_device(dev->idev);
+	cm109_usb_cleanup(dev);
+}
+
+static int cm109_usb_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct driver_info *nfo = (struct driver_info *)id->driver_info;
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct cm109_dev *dev;
+	struct input_dev *input_dev = NULL;
+	int ret, pipe, i;
+	int error = -ENOMEM;
+
+	interface = intf->cur_altsetting;
+	endpoint = &interface->endpoint[0].desc;
+
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	spin_lock_init(&dev->ctl_submit_lock);
+	mutex_init(&dev->pm_mutex);
+
+	dev->udev = udev;
+	dev->intf = intf;
+
+	dev->idev = input_dev = input_allocate_device();
+	if (!input_dev)
+		goto err_out;
+
+	/* allocate usb buffers */
+	dev->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
+					 GFP_KERNEL, &dev->irq_dma);
+	if (!dev->irq_data)
+		goto err_out;
+
+	dev->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
+					 GFP_KERNEL, &dev->ctl_dma);
+	if (!dev->ctl_data)
+		goto err_out;
+
+	dev->ctl_req = usb_buffer_alloc(udev, sizeof(*(dev->ctl_req)),
+					GFP_KERNEL, &dev->ctl_req_dma);
+	if (!dev->ctl_req)
+		goto err_out;
+
+	/* allocate urb structures */
+	dev->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->urb_irq)
+		goto err_out;
+
+	dev->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->urb_ctl)
+		goto err_out;
+
+	/* get a handle to the interrupt data pipe */
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	if (ret != USB_PKT_LEN)
+		err("invalid payload size %d, expected %d", ret, USB_PKT_LEN);
+
+	/* initialise irq urb */
+	usb_fill_int_urb(dev->urb_irq, udev, pipe, dev->irq_data,
+			 USB_PKT_LEN,
+			 cm109_urb_irq_callback, dev, endpoint->bInterval);
+	dev->urb_irq->transfer_dma = dev->irq_dma;
+	dev->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	dev->urb_irq->dev = udev;
+
+	/* initialise ctl urb */
+	dev->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+					USB_DIR_OUT;
+	dev->ctl_req->bRequest = USB_REQ_SET_CONFIGURATION;
+	dev->ctl_req->wValue = cpu_to_le16(0x200);
+	dev->ctl_req->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
+	dev->ctl_req->wLength = cpu_to_le16(USB_PKT_LEN);
+
+	usb_fill_control_urb(dev->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
+			     (void *)dev->ctl_req, dev->ctl_data, USB_PKT_LEN,
+			     cm109_urb_ctl_callback, dev);
+	dev->urb_ctl->setup_dma = dev->ctl_req_dma;
+	dev->urb_ctl->transfer_dma = dev->ctl_dma;
+	dev->urb_ctl->transfer_flags |= URB_NO_SETUP_DMA_MAP |
+					URB_NO_TRANSFER_DMA_MAP;
+	dev->urb_ctl->dev = udev;
+
+	/* find out the physical bus location */
+	usb_make_path(udev, dev->phys, sizeof(dev->phys));
+	strlcat(dev->phys, "/input0", sizeof(dev->phys));
+
+	/* register settings for the input device */
+	input_dev->name = nfo->name;
+	input_dev->phys = dev->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, dev);
+	input_dev->open = cm109_input_open;
+	input_dev->close = cm109_input_close;
+	input_dev->event = cm109_input_ev;
+
+	input_dev->keycode = dev->keymap;
+	input_dev->keycodesize = sizeof(unsigned char);
+	input_dev->keycodemax = ARRAY_SIZE(dev->keymap);
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_SND);
+	input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+
+	/* register available key events */
+	for (i = 0; i < KEYMAP_SIZE; i++) {
+		unsigned short k = keymap(i);
+		dev->keymap[i] = k;
+		__set_bit(k, input_dev->keybit);
+	}
+	__clear_bit(KEY_RESERVED, input_dev->keybit);
+
+	error = input_register_device(dev->idev);
+	if (error)
+		goto err_out;
+
+	usb_set_intfdata(intf, dev);
+
+	return 0;
+
+ err_out:
+	input_free_device(input_dev);
+	cm109_usb_cleanup(dev);
+	return error;
+}
+
+static int cm109_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct cm109_dev *dev = usb_get_intfdata(intf);
+
+	dev_info(&intf->dev, "cm109: usb_suspend (event=%d)\n", message.event);
+
+	mutex_lock(&dev->pm_mutex);
+	cm109_stop_traffic(dev);
+	mutex_unlock(&dev->pm_mutex);
+
+	return 0;
+}
+
+static int cm109_usb_resume(struct usb_interface *intf)
+{
+	struct cm109_dev *dev = usb_get_intfdata(intf);
+
+	dev_info(&intf->dev, "cm109: usb_resume\n");
+
+	mutex_lock(&dev->pm_mutex);
+	cm109_restore_state(dev);
+	mutex_unlock(&dev->pm_mutex);
+
+	return 0;
+}
+
+static int cm109_usb_pre_reset(struct usb_interface *intf)
+{
+	struct cm109_dev *dev = usb_get_intfdata(intf);
+
+	mutex_lock(&dev->pm_mutex);
+
+	/*
+	 * Make sure input events don't try to toggle buzzer
+	 * while we are resetting
+	 */
+	dev->resetting = 1;
+	smp_wmb();
+
+	cm109_stop_traffic(dev);
+
+	return 0;
+}
+
+static int cm109_usb_post_reset(struct usb_interface *intf)
+{
+	struct cm109_dev *dev = usb_get_intfdata(intf);
+
+	dev->resetting = 0;
+	smp_wmb();
+
+	cm109_restore_state(dev);
+
+	mutex_unlock(&dev->pm_mutex);
+
+	return 0;
+}
+
+static struct usb_driver cm109_driver = {
+	.name		= "cm109",
+	.probe		= cm109_usb_probe,
+	.disconnect	= cm109_usb_disconnect,
+	.suspend	= cm109_usb_suspend,
+	.resume		= cm109_usb_resume,
+	.reset_resume	= cm109_usb_resume,
+	.pre_reset	= cm109_usb_pre_reset,
+	.post_reset	= cm109_usb_post_reset,
+	.id_table	= cm109_usb_table,
+	.supports_autosuspend = 1,
+};
+
+static int __init cm109_select_keymap(void)
+{
+	/* Load the phone keymap */
+	if (!strcasecmp(phone, "kip1000")) {
+		keymap = keymap_kip1000;
+		printk(KERN_INFO KBUILD_MODNAME ": "
+			"Keymap for Komunikate KIP1000 phone loaded\n");
+	} else if (!strcasecmp(phone, "gtalk")) {
+		keymap = keymap_gtalk;
+		printk(KERN_INFO KBUILD_MODNAME ": "
+			"Keymap for Genius G-talk phone loaded\n");
+	} else if (!strcasecmp(phone, "usbph01")) {
+		keymap = keymap_usbph01;
+		printk(KERN_INFO KBUILD_MODNAME ": "
+			"Keymap for Allied-Telesis Corega USBPH01 phone loaded\n");
+	} else {
+		printk(KERN_ERR KBUILD_MODNAME ": "
+			"Unsupported phone: %s\n", phone);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __init cm109_init(void)
+{
+	int err;
+
+	err = cm109_select_keymap();
+	if (err)
+		return err;
+
+	err = usb_register(&cm109_driver);
+	if (err)
+		return err;
+
+	printk(KERN_INFO KBUILD_MODNAME ": "
+		DRIVER_DESC ": " DRIVER_VERSION " (C) " DRIVER_AUTHOR "\n");
+
+	return 0;
+}
+
+static void __exit cm109_exit(void)
+{
+	usb_deregister(&cm109_driver);
+}
+
+module_init(cm109_init);
+module_exit(cm109_exit);
+
+MODULE_DEVICE_TABLE(usb, cm109_usb_table);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index fe268be..7c8957d 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -277,6 +277,16 @@
 	{ KE_END,  0 }
 };
 
+static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = {
+	{ KE_KEY,       0x01, {KEY_HELP} },          /* Fn+F1 */
+	{ KE_KEY,       0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */
+	{ KE_BLUETOOTH, 0x30 },                      /* Fn+F10 */
+	{ KE_KEY,       0x31, {KEY_MAIL} },          /* mail button */
+	{ KE_KEY,       0x36, {KEY_WWW} },           /* www button */
+	{ KE_WIFI,      0x78 },                      /* satelite dish button */
+	{ KE_END,       0 }
+};
+
 static struct key_entry keymap_fujitsu_n3510[] __initdata = {
 	{ KE_KEY, 0x11, {KEY_PROG1} },
 	{ KE_KEY, 0x12, {KEY_PROG2} },
@@ -618,6 +628,15 @@
 	},
 	{
 		.callback = dmi_matched,
+		.ident = "Fujitsu-Siemens Amilo Pro Edition V3505",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"),
+		},
+		.driver_data = keymap_fs_amilo_pro_v3505
+	},
+	{
+		.callback = dmi_matched,
 		.ident = "Fujitsu-Siemens Amilo M7400",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index facefd3..11b5c7e 100644
--- a/drivers/input/misc/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -52,8 +52,8 @@
 #include <linux/module.h>
 #include <linux/rwsem.h>
 #include <linux/usb/input.h>
+#include <linux/map_to_7segment.h>
 
-#include "map_to_7segment.h"
 #include "yealink.h"
 
 #define DRIVER_VERSION "yld-20051230"
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index f996546..f488b68 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -96,6 +96,16 @@
 
 	  If unsure, say N.
 
+config MOUSE_PS2_OLPC
+	bool "OLPC PS/2 mouse protocol extension"
+	depends on MOUSE_PS2 && OLPC
+	help
+	  Say Y here if you have an OLPC XO-1 laptop (with built-in
+	  PS/2 touchpad/tablet device).  The manufacturer calls the
+	  touchpad an HGPK.
+
+	  If unsure, say N.
+
 config MOUSE_SERIAL
 	tristate "Serial mouse"
 	select SERIO
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index d4d2025..8e6e690 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -21,6 +21,7 @@
 psmouse-objs := psmouse-base.o synaptics.o
 
 psmouse-$(CONFIG_MOUSE_PS2_ALPS)	+= alps.o
+psmouse-$(CONFIG_MOUSE_PS2_OLPC)	+= hgpk.o
 psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP)	+= logips2pp.o
 psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK)	+= lifebook.o
 psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT)	+= trackpoint.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 385e32b..cbedf95 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -54,6 +54,7 @@
 	{ { 0x20, 0x02, 0x0e },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
 	{ { 0x22, 0x02, 0x0a },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
 	{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
+	{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */
 	{ { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 } /* Dell Vostro 1400 */
 };
 
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 1f41ae9..079816e 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -136,12 +136,28 @@
 #define ATP_GEYSER_MODE_REQUEST_INDEX		0
 #define ATP_GEYSER_MODE_VENDOR_VALUE		0x04
 
+/**
+ * enum atp_status_bits - status bit meanings
+ *
+ * These constants represent the meaning of the status bits.
+ * (only Geyser 3/4)
+ *
+ * @ATP_STATUS_BUTTON: The button was pressed
+ * @ATP_STATUS_BASE_UPDATE: Update of the base values (untouched pad)
+ * @ATP_STATUS_FROM_RESET: Reset previously performed
+ */
+enum atp_status_bits {
+	ATP_STATUS_BUTTON	= BIT(0),
+	ATP_STATUS_BASE_UPDATE	= BIT(2),
+	ATP_STATUS_FROM_RESET	= BIT(4),
+};
+
 /* Structure to hold all of our device specific stuff */
 struct atp {
 	char			phys[64];
 	struct usb_device	*udev;		/* usb device */
 	struct urb		*urb;		/* usb request block */
-	signed char		*data;		/* transferred data */
+	u8			*data;		/* transferred data */
 	struct input_dev	*input;		/* input dev */
 	enum atp_touchpad_type	type;		/* type of touchpad */
 	bool			open;
@@ -251,8 +267,6 @@
 	int retval;
 
 	dprintk("appletouch: putting appletouch to sleep (reinit)\n");
-	dev->idlecount = 0;
-
 	atp_geyser_init(udev);
 
 	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
@@ -327,11 +341,14 @@
 	input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2);
 }
 
-static void atp_complete(struct urb *urb)
+/* Check URB status and for correct length of data package */
+
+#define ATP_URB_STATUS_SUCCESS		0
+#define ATP_URB_STATUS_ERROR		1
+#define ATP_URB_STATUS_ERROR_FATAL	2
+
+static int atp_status_check(struct urb *urb)
 {
-	int x, y, x_z, y_z, x_f, y_f;
-	int retval, i, j;
-	int key;
 	struct atp *dev = urb->context;
 
 	switch (urb->status) {
@@ -351,11 +368,12 @@
 		/* This urb is terminated, clean up */
 		dbg("atp_complete: urb shutting down with status: %d",
 		    urb->status);
-		return;
+		return ATP_URB_STATUS_ERROR_FATAL;
+
 	default:
 		dbg("atp_complete: nonzero urb status received: %d",
 		    urb->status);
-		goto exit;
+		return ATP_URB_STATUS_ERROR;
 	}
 
 	/* drop incomplete datasets */
@@ -363,30 +381,33 @@
 		dprintk("appletouch: incomplete data package"
 			" (first byte: %d, length: %d).\n",
 			dev->data[0], dev->urb->actual_length);
-		goto exit;
+		return ATP_URB_STATUS_ERROR;
 	}
 
+	return ATP_URB_STATUS_SUCCESS;
+}
+
+/*
+ * USB interrupt callback functions
+ */
+
+/* Interrupt function for older touchpads: FOUNTAIN/GEYSER1/GEYSER2 */
+
+static void atp_complete_geyser_1_2(struct urb *urb)
+{
+	int x, y, x_z, y_z, x_f, y_f;
+	int retval, i, j;
+	int key;
+	struct atp *dev = urb->context;
+	int status = atp_status_check(urb);
+
+	if (status == ATP_URB_STATUS_ERROR_FATAL)
+		return;
+	else if (status == ATP_URB_STATUS_ERROR)
+		goto exit;
+
 	/* reorder the sensors values */
-	if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) {
-		memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
-
-		/*
-		 * The values are laid out like this:
-		 * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ...
-		 * '-' is an unused value.
-		 */
-
-		/* read X values */
-		for (i = 0, j = 19; i < 20; i += 2, j += 3) {
-			dev->xy_cur[i] = dev->data[j + 1];
-			dev->xy_cur[i + 1] = dev->data[j + 2];
-		}
-		/* read Y values */
-		for (i = 0, j = 1; i < 9; i += 2, j += 3) {
-			dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1];
-			dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2];
-		}
-	} else if (dev->type == ATP_GEYSER2) {
+	if (dev->type == ATP_GEYSER2) {
 		memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
 
 		/*
@@ -427,34 +448,40 @@
 		/* first sample */
 		dev->valid = true;
 		dev->x_old = dev->y_old = -1;
+
+		/* Store first sample */
 		memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
 
-		if (dev->size_detect_done ||
-		    dev->type == ATP_GEYSER3) /* No 17" Macbooks (yet) */
+		/* Perform size detection, if not done already */
+		if (!dev->size_detect_done) {
+
+			/* 17" Powerbooks have extra X sensors */
+			for (i = (dev->type == ATP_GEYSER2 ? 15 : 16);
+			     i < ATP_XSENSORS; i++) {
+				if (!dev->xy_cur[i])
+					continue;
+
+				printk(KERN_INFO
+					"appletouch: 17\" model detected.\n");
+
+				if (dev->type == ATP_GEYSER2)
+					input_set_abs_params(dev->input, ABS_X,
+							     0,
+							     (20 - 1) *
+							     ATP_XFACT - 1,
+							     ATP_FUZZ, 0);
+				else
+					input_set_abs_params(dev->input, ABS_X,
+							     0,
+							     (26 - 1) *
+							     ATP_XFACT - 1,
+							     ATP_FUZZ, 0);
+				break;
+			}
+
+			dev->size_detect_done = 1;
 			goto exit;
-
-		/* 17" Powerbooks have extra X sensors */
-		for (i = (dev->type == ATP_GEYSER2 ? 15 : 16);
-		     i < ATP_XSENSORS; i++) {
-			if (!dev->xy_cur[i])
-				continue;
-
-			printk(KERN_INFO "appletouch: 17\" model detected.\n");
-			if (dev->type == ATP_GEYSER2)
-				input_set_abs_params(dev->input, ABS_X, 0,
-						     (20 - 1) *
-						     ATP_XFACT - 1,
-						     ATP_FUZZ, 0);
-			else
-				input_set_abs_params(dev->input, ABS_X, 0,
-						     (ATP_XSENSORS - 1) *
-						     ATP_XFACT - 1,
-						     ATP_FUZZ, 0);
-			break;
 		}
-
-		dev->size_detect_done = 1;
-		goto exit;
 	}
 
 	for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
@@ -475,7 +502,118 @@
 			      ATP_XFACT, &x_z, &x_f);
 	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
 			      ATP_YFACT, &y_z, &y_f);
-	key = dev->data[dev->datalen - 1] & 1;
+	key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON;
+
+	if (x && y) {
+		if (dev->x_old != -1) {
+			x = (dev->x_old * 3 + x) >> 2;
+			y = (dev->y_old * 3 + y) >> 2;
+			dev->x_old = x;
+			dev->y_old = y;
+
+			if (debug > 1)
+				printk(KERN_DEBUG "appletouch: "
+					"X: %3d Y: %3d Xz: %3d Yz: %3d\n",
+					x, y, x_z, y_z);
+
+			input_report_key(dev->input, BTN_TOUCH, 1);
+			input_report_abs(dev->input, ABS_X, x);
+			input_report_abs(dev->input, ABS_Y, y);
+			input_report_abs(dev->input, ABS_PRESSURE,
+					 min(ATP_PRESSURE, x_z + y_z));
+			atp_report_fingers(dev->input, max(x_f, y_f));
+		}
+		dev->x_old = x;
+		dev->y_old = y;
+
+	} else if (!x && !y) {
+
+		dev->x_old = dev->y_old = -1;
+		input_report_key(dev->input, BTN_TOUCH, 0);
+		input_report_abs(dev->input, ABS_PRESSURE, 0);
+		atp_report_fingers(dev->input, 0);
+
+		/* reset the accumulator on release */
+		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
+	}
+
+	input_report_key(dev->input, BTN_LEFT, key);
+	input_sync(dev->input);
+
+ exit:
+	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
+	if (retval)
+		err("atp_complete: usb_submit_urb failed with result %d",
+		    retval);
+}
+
+/* Interrupt function for older touchpads: GEYSER3/GEYSER4 */
+
+static void atp_complete_geyser_3_4(struct urb *urb)
+{
+	int x, y, x_z, y_z, x_f, y_f;
+	int retval, i, j;
+	int key;
+	struct atp *dev = urb->context;
+	int status = atp_status_check(urb);
+
+	if (status == ATP_URB_STATUS_ERROR_FATAL)
+		return;
+	else if (status == ATP_URB_STATUS_ERROR)
+		goto exit;
+
+	/* Reorder the sensors values:
+	 *
+	 * The values are laid out like this:
+	 * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ...
+	 * '-' is an unused value.
+	 */
+
+	/* read X values */
+	for (i = 0, j = 19; i < 20; i += 2, j += 3) {
+		dev->xy_cur[i] = dev->data[j + 1];
+		dev->xy_cur[i + 1] = dev->data[j + 2];
+	}
+	/* read Y values */
+	for (i = 0, j = 1; i < 9; i += 2, j += 3) {
+		dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1];
+		dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2];
+	}
+
+	dbg_dump("sample", dev->xy_cur);
+
+	/* Just update the base values (i.e. touchpad in untouched state) */
+	if (dev->data[dev->datalen - 1] & ATP_STATUS_BASE_UPDATE) {
+
+		dprintk(KERN_DEBUG "appletouch: updated base values\n");
+
+		memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
+		goto exit;
+	}
+
+	for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
+		/* calculate the change */
+		dev->xy_acc[i] = dev->xy_cur[i] - dev->xy_old[i];
+
+		/* this is a round-robin value, so couple with that */
+		if (dev->xy_acc[i] > 127)
+			dev->xy_acc[i] -= 256;
+
+		if (dev->xy_acc[i] < -127)
+			dev->xy_acc[i] += 256;
+
+		/* prevent down drifting */
+		if (dev->xy_acc[i] < 0)
+			dev->xy_acc[i] = 0;
+	}
+
+	dbg_dump("accumulator", dev->xy_acc);
+
+	x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
+			      ATP_XFACT, &x_z, &x_f);
+	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
+			      ATP_YFACT, &y_z, &y_f);
+	key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON;
 
 	if (x && y) {
 		if (dev->x_old != -1) {
@@ -514,28 +652,27 @@
 	input_sync(dev->input);
 
 	/*
-	 * Many Geysers will continue to send packets continually after
+	 * Geysers 3/4 will continue to send packets continually after
 	 * the first touch unless reinitialised. Do so if it's been
 	 * idle for a while in order to avoid waking the kernel up
-	 * several hundred times a second. Re-initialization does not
-	 * work on Fountain touchpads.
+	 * several hundred times a second.
 	 */
-	if (dev->type != ATP_FOUNTAIN) {
-		/*
-		 * Button must not be pressed when entering suspend,
-		 * otherwise we will never release the button.
-		 */
-		if (!x && !y && !key) {
-			dev->idlecount++;
-			if (dev->idlecount == 10) {
-				dev->valid = false;
-				schedule_work(&dev->work);
-				/* Don't resubmit urb here, wait for reinit */
-				return;
-			}
-		} else
+
+	/*
+	 * Button must not be pressed when entering suspend,
+	 * otherwise we will never release the button.
+	 */
+	if (!x && !y && !key) {
+		dev->idlecount++;
+		if (dev->idlecount == 10) {
+			dev->x_old = dev->y_old = -1;
 			dev->idlecount = 0;
-	}
+			schedule_work(&dev->work);
+			/* Don't resubmit urb here, wait for reinit */
+			return;
+		}
+	} else
+		dev->idlecount = 0;
 
  exit:
 	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
@@ -632,9 +769,19 @@
 	if (!dev->data)
 		goto err_free_urb;
 
-	usb_fill_int_urb(dev->urb, udev,
-			 usb_rcvintpipe(udev, int_in_endpointAddr),
-			 dev->data, dev->datalen, atp_complete, dev, 1);
+	/* Select the USB complete (callback) function */
+	if (dev->type == ATP_FOUNTAIN ||
+	    dev->type == ATP_GEYSER1 ||
+	    dev->type == ATP_GEYSER2)
+		usb_fill_int_urb(dev->urb, udev,
+				 usb_rcvintpipe(udev, int_in_endpointAddr),
+				 dev->data, dev->datalen,
+				 atp_complete_geyser_1_2, dev, 1);
+	else
+		usb_fill_int_urb(dev->urb, udev,
+				 usb_rcvintpipe(udev, int_in_endpointAddr),
+				 dev->data, dev->datalen,
+				 atp_complete_geyser_3_4, dev, 1);
 
 	error = atp_handle_geyser(dev);
 	if (error)
@@ -751,8 +898,6 @@
 	struct atp *dev = usb_get_intfdata(iface);
 
 	usb_kill_urb(dev->urb);
-	dev->valid = false;
-
 	return 0;
 }
 
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
new file mode 100644
index 0000000..e82d342
--- /dev/null
+++ b/drivers/input/mouse/hgpk.c
@@ -0,0 +1,477 @@
+/*
+ * OLPC HGPK (XO-1) touchpad PS/2 mouse driver
+ *
+ * Copyright (c) 2006-2008 One Laptop Per Child
+ * Authors:
+ *   Zephaniah E. Hull
+ *   Andres Salomon <dilinger@debian.org>
+ *
+ * This driver is partly based on the ALPS driver, which is:
+ *
+ * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
+ * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * The spec from ALPS is available from
+ * <http://wiki.laptop.org/go/Touch_Pad/Tablet>.  It refers to this
+ * device as HGPK (Hybrid GS, PT, and Keymatrix).
+ *
+ * The earliest versions of the device had simultaneous reporting; that
+ * was removed.  After that, the device used the Advanced Mode GS/PT streaming
+ * stuff.  That turned out to be too buggy to support, so we've finally
+ * switched to Mouse Mode (which utilizes only the center 1/3 of the touchpad).
+ */
+
+#define DEBUG
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+#include <linux/delay.h>
+#include <asm/olpc.h>
+
+#include "psmouse.h"
+#include "hgpk.h"
+
+static int tpdebug;
+module_param(tpdebug, int, 0644);
+MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
+
+static int recalib_delta = 100;
+module_param(recalib_delta, int, 0644);
+MODULE_PARM_DESC(recalib_delta,
+	"packets containing a delta this large will cause a recalibration.");
+
+/*
+ * When the touchpad gets ultra-sensitive, one can keep their finger 1/2"
+ * above the pad and still have it send packets.  This causes a jump cursor
+ * when one places their finger on the pad.  We can probably detect the
+ * jump as we see a large deltas (>= 100px).  In mouse mode, I've been
+ * unable to even come close to 100px deltas during normal usage, so I think
+ * this threshold is safe.  If a large delta occurs, trigger a recalibration.
+ */
+static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y)
+{
+	struct hgpk_data *priv = psmouse->private;
+
+	if (abs(x) > recalib_delta || abs(y) > recalib_delta) {
+		hgpk_err(psmouse, ">%dpx jump detected (%d,%d)\n",
+				recalib_delta, x, y);
+		/* My car gets forty rods to the hogshead and that's the
+		 * way I likes it! */
+		psmouse_queue_work(psmouse, &priv->recalib_wq,
+				msecs_to_jiffies(1000));
+	}
+}
+
+/*
+ * We have no idea why this particular hardware bug occurs.  The touchpad
+ * will randomly start spewing packets without anything touching the
+ * pad.  This wouldn't necessarily be bad, but it's indicative of a
+ * severely miscalibrated pad; attempting to use the touchpad while it's
+ * spewing means the cursor will jump all over the place, and act "drunk".
+ *
+ * The packets that are spewed tend to all have deltas between -2 and 2, and
+ * the cursor will move around without really going very far.  It will
+ * tend to end up in the same location; if we tally up the changes over
+ * 100 packets, we end up w/ a final delta of close to 0.  This happens
+ * pretty regularly when the touchpad is spewing, and is pretty hard to
+ * manually trigger (at least for *my* fingers).  So, it makes a perfect
+ * scheme for detecting spews.
+ */
+static void hgpk_spewing_hack(struct psmouse *psmouse,
+			      int l, int r, int x, int y)
+{
+	struct hgpk_data *priv = psmouse->private;
+
+	/* ignore button press packets; many in a row could trigger
+	 * a false-positive! */
+	if (l || r)
+		return;
+
+	priv->x_tally += x;
+	priv->y_tally += y;
+
+	if (++priv->count > 100) {
+		if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) {
+			hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n",
+				 priv->x_tally, priv->y_tally);
+			psmouse_queue_work(psmouse, &priv->recalib_wq,
+					   msecs_to_jiffies(1000));
+		}
+		/* reset every 100 packets */
+		priv->count = 0;
+		priv->x_tally = 0;
+		priv->y_tally = 0;
+	}
+}
+
+/*
+ * HGPK Mouse Mode format (standard mouse format, sans middle button)
+ *
+ * byte 0:	y-over	x-over	y-neg	x-neg	1	0	swr	swl
+ * byte 1:	x7	x6	x5	x4	x3	x2	x1	x0
+ * byte 2:	y7	y6	y5	y4	y3	y2	y1	y0
+ *
+ * swr/swl are the left/right buttons.
+ * x-neg/y-neg are the x and y delta negative bits
+ * x-over/y-over are the x and y overflow bits
+ */
+static int hgpk_validate_byte(unsigned char *packet)
+{
+	return (packet[0] & 0x0C) == 0x08;
+}
+
+static void hgpk_process_packet(struct psmouse *psmouse)
+{
+	struct input_dev *dev = psmouse->dev;
+	unsigned char *packet = psmouse->packet;
+	int x, y, left, right;
+
+	left = packet[0] & 1;
+	right = (packet[0] >> 1) & 1;
+
+	x = packet[1] - ((packet[0] << 4) & 0x100);
+	y = ((packet[0] << 3) & 0x100) - packet[2];
+
+	hgpk_jumpy_hack(psmouse, x, y);
+	hgpk_spewing_hack(psmouse, left, right, x, y);
+
+	if (tpdebug)
+		hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y);
+
+	input_report_key(dev, BTN_LEFT, left);
+	input_report_key(dev, BTN_RIGHT, right);
+
+	input_report_rel(dev, REL_X, x);
+	input_report_rel(dev, REL_Y, y);
+
+	input_sync(dev);
+}
+
+static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
+{
+	struct hgpk_data *priv = psmouse->private;
+
+	if (hgpk_validate_byte(psmouse->packet)) {
+		hgpk_dbg(psmouse, "%s: (%d) %02x %02x %02x\n",
+				__func__, psmouse->pktcnt, psmouse->packet[0],
+				psmouse->packet[1], psmouse->packet[2]);
+		return PSMOUSE_BAD_DATA;
+	}
+
+	if (psmouse->pktcnt >= psmouse->pktsize) {
+		hgpk_process_packet(psmouse);
+		return PSMOUSE_FULL_PACKET;
+	}
+
+	if (priv->recalib_window) {
+		if (time_before(jiffies, priv->recalib_window)) {
+			/*
+			 * ugh, got a packet inside our recalibration
+			 * window, schedule another recalibration.
+			 */
+			hgpk_dbg(psmouse,
+				 "packet inside calibration window, "
+				 "queueing another recalibration\n");
+			psmouse_queue_work(psmouse, &priv->recalib_wq,
+					msecs_to_jiffies(1000));
+		}
+		priv->recalib_window = 0;
+	}
+
+	return PSMOUSE_GOOD_DATA;
+}
+
+static int hgpk_force_recalibrate(struct psmouse *psmouse)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	struct hgpk_data *priv = psmouse->private;
+
+	/* C-series touchpads added the recalibrate command */
+	if (psmouse->model < HGPK_MODEL_C)
+		return 0;
+
+	/* we don't want to race with the irq handler, nor with resyncs */
+	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+
+	/* start by resetting the device */
+	psmouse_reset(psmouse);
+
+	/* send the recalibrate request */
+	if (ps2_command(ps2dev, NULL, 0xf5) ||
+	    ps2_command(ps2dev, NULL, 0xf5) ||
+	    ps2_command(ps2dev, NULL, 0xe6) ||
+	    ps2_command(ps2dev, NULL, 0xf5)) {
+		return -1;
+	}
+
+	/* according to ALPS, 150mS is required for recalibration */
+	msleep(150);
+
+	/* XXX: If a finger is down during this delay, recalibration will
+	 * detect capacitance incorrectly.  This is a hardware bug, and
+	 * we don't have a good way to deal with it.  The 2s window stuff
+	 * (below) is our best option for now.
+	 */
+
+	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
+		return -1;
+
+	psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+
+	/* After we recalibrate, we shouldn't get any packets for 2s.  If
+	 * we do, it's likely that someone's finger was on the touchpad.
+	 * If someone's finger *was* on the touchpad, it's probably
+	 * miscalibrated.  So, we should schedule another recalibration
+	 */
+	priv->recalib_window = jiffies +  msecs_to_jiffies(2000);
+
+	return 0;
+}
+
+/*
+ * This kills power to the touchpad; according to ALPS, current consumption
+ * goes down to 50uA after running this.  To turn power back on, we drive
+ * MS-DAT low.
+ */
+static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	int timeo;
+
+	/* Added on D-series touchpads */
+	if (psmouse->model < HGPK_MODEL_D)
+		return 0;
+
+	if (enable) {
+		psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+
+		/*
+		 * Sending a byte will drive MS-DAT low; this will wake up
+		 * the controller.  Once we get an ACK back from it, it
+		 * means we can continue with the touchpad re-init.  ALPS
+		 * tells us that 1s should be long enough, so set that as
+		 * the upper bound.
+		 */
+		for (timeo = 20; timeo > 0; timeo--) {
+			if (!ps2_sendbyte(&psmouse->ps2dev,
+					PSMOUSE_CMD_DISABLE, 20))
+				break;
+			msleep(50);
+		}
+
+		psmouse_reset(psmouse);
+
+		/* should be all set, enable the touchpad */
+		ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+		psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+
+	} else {
+		hgpk_dbg(psmouse, "Powering off touchpad.\n");
+		psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+
+		if (ps2_command(ps2dev, NULL, 0xec) ||
+		    ps2_command(ps2dev, NULL, 0xec) ||
+		    ps2_command(ps2dev, NULL, 0xea)) {
+			return -1;
+		}
+
+		/* probably won't see an ACK, the touchpad will be off */
+		ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
+	}
+
+	return 0;
+}
+
+static int hgpk_poll(struct psmouse *psmouse)
+{
+	/* We can't poll, so always return failure. */
+	return -1;
+}
+
+static int hgpk_reconnect(struct psmouse *psmouse)
+{
+	/* During suspend/resume the ps2 rails remain powered.  We don't want
+	 * to do a reset because it's flush data out of buffers; however,
+	 * earlier prototypes (B1) had some brokenness that required a reset. */
+	if (olpc_board_at_least(olpc_board(0xb2)))
+		if (psmouse->ps2dev.serio->dev.power.power_state.event !=
+				PM_EVENT_ON)
+			return 0;
+
+	psmouse_reset(psmouse);
+
+	return 0;
+}
+
+static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf)
+{
+	struct hgpk_data *priv = psmouse->private;
+
+	return sprintf(buf, "%d\n", priv->powered);
+}
+
+static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
+				const char *buf, size_t count)
+{
+	struct hgpk_data *priv = psmouse->private;
+	unsigned long value;
+	int err;
+
+	err = strict_strtoul(buf, 10, &value);
+	if (err || value > 1)
+		return -EINVAL;
+
+	if (value != priv->powered) {
+		/*
+		 * hgpk_toggle_power will deal w/ state so
+		 * we're not racing w/ irq
+		 */
+		err = hgpk_toggle_power(psmouse, value);
+		if (!err)
+			priv->powered = value;
+	}
+
+	return err ? err : count;
+}
+
+__PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL,
+		      hgpk_show_powered, hgpk_set_powered, 0);
+
+static void hgpk_disconnect(struct psmouse *psmouse)
+{
+	struct hgpk_data *priv = psmouse->private;
+
+	device_remove_file(&psmouse->ps2dev.serio->dev,
+			   &psmouse_attr_powered.dattr);
+	psmouse_reset(psmouse);
+	kfree(priv);
+}
+
+static void hgpk_recalib_work(struct work_struct *work)
+{
+	struct delayed_work *w = container_of(work, struct delayed_work, work);
+	struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
+	struct psmouse *psmouse = priv->psmouse;
+
+	hgpk_dbg(psmouse, "recalibrating touchpad..\n");
+
+	if (hgpk_force_recalibrate(psmouse))
+		hgpk_err(psmouse, "recalibration failed!\n");
+}
+
+static int hgpk_register(struct psmouse *psmouse)
+{
+	struct input_dev *dev = psmouse->dev;
+	int err;
+
+	/* unset the things that psmouse-base sets which we don't have */
+	__clear_bit(BTN_MIDDLE, dev->keybit);
+
+	/* set the things we do have */
+	__set_bit(EV_KEY, dev->evbit);
+	__set_bit(EV_REL, dev->evbit);
+
+	__set_bit(REL_X, dev->relbit);
+	__set_bit(REL_Y, dev->relbit);
+
+	__set_bit(BTN_LEFT, dev->keybit);
+	__set_bit(BTN_RIGHT, dev->keybit);
+
+	/* register handlers */
+	psmouse->protocol_handler = hgpk_process_byte;
+	psmouse->poll = hgpk_poll;
+	psmouse->disconnect = hgpk_disconnect;
+	psmouse->reconnect = hgpk_reconnect;
+	psmouse->pktsize = 3;
+
+	/* Disable the idle resync. */
+	psmouse->resync_time = 0;
+	/* Reset after a lot of bad bytes. */
+	psmouse->resetafter = 1024;
+
+	err = device_create_file(&psmouse->ps2dev.serio->dev,
+				 &psmouse_attr_powered.dattr);
+	if (err)
+		hgpk_err(psmouse, "Failed to create sysfs attribute\n");
+
+	return err;
+}
+
+int hgpk_init(struct psmouse *psmouse)
+{
+	struct hgpk_data *priv;
+	int err = -ENOMEM;
+
+	priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
+	if (!priv)
+		goto alloc_fail;
+
+	psmouse->private = priv;
+	priv->psmouse = psmouse;
+	priv->powered = 1;
+	INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
+
+	err = psmouse_reset(psmouse);
+	if (err)
+		goto init_fail;
+
+	err = hgpk_register(psmouse);
+	if (err)
+		goto init_fail;
+
+	return 0;
+
+init_fail:
+	kfree(priv);
+alloc_fail:
+	return err;
+}
+
+static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	unsigned char param[3];
+
+	/* E7, E7, E7, E9 gets us a 3 byte identifier */
+	if (ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21) ||
+	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21) ||
+	    ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE21) ||
+	    ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
+		return -EIO;
+	}
+
+	hgpk_dbg(psmouse, "ID: %02x %02x %02x", param[0], param[1], param[2]);
+
+	/* HGPK signature: 0x67, 0x00, 0x<model> */
+	if (param[0] != 0x67 || param[1] != 0x00)
+		return -ENODEV;
+
+	hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
+
+	return param[2];
+}
+
+int hgpk_detect(struct psmouse *psmouse, int set_properties)
+{
+	int version;
+
+	version = hgpk_get_model(psmouse);
+	if (version < 0)
+		return version;
+
+	if (set_properties) {
+		psmouse->vendor = "ALPS";
+		psmouse->name = "HGPK";
+		psmouse->model = version;
+	}
+
+	return 0;
+}
diff --git a/drivers/input/mouse/hgpk.h b/drivers/input/mouse/hgpk.h
new file mode 100644
index 0000000..a4b2a96
--- /dev/null
+++ b/drivers/input/mouse/hgpk.h
@@ -0,0 +1,49 @@
+/*
+ * OLPC HGPK (XO-1) touchpad PS/2 mouse driver
+ */
+
+#ifndef _HGPK_H
+#define _HGPK_H
+
+enum hgpk_model_t {
+	HGPK_MODEL_PREA = 0x0a,	/* pre-B1s */
+	HGPK_MODEL_A = 0x14,	/* found on B1s, PT disabled in hardware */
+	HGPK_MODEL_B = 0x28,	/* B2s, has capacitance issues */
+	HGPK_MODEL_C = 0x3c,
+	HGPK_MODEL_D = 0x50,	/* C1, mass production */
+};
+
+struct hgpk_data {
+	struct psmouse *psmouse;
+	int powered;
+	int count, x_tally, y_tally;	/* hardware workaround stuff */
+	unsigned long recalib_window;
+	struct delayed_work recalib_wq;
+};
+
+#define hgpk_dbg(psmouse, format, arg...)		\
+	dev_dbg(&(psmouse)->ps2dev.serio->dev, format, ## arg)
+#define hgpk_err(psmouse, format, arg...)		\
+	dev_err(&(psmouse)->ps2dev.serio->dev, format, ## arg)
+#define hgpk_info(psmouse, format, arg...)		\
+	dev_info(&(psmouse)->ps2dev.serio->dev, format, ## arg)
+#define hgpk_warn(psmouse, format, arg...)		\
+	dev_warn(&(psmouse)->ps2dev.serio->dev, format, ## arg)
+#define hgpk_notice(psmouse, format, arg...)		\
+	dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
+
+#ifdef CONFIG_MOUSE_PS2_OLPC
+int hgpk_detect(struct psmouse *psmouse, int set_properties);
+int hgpk_init(struct psmouse *psmouse);
+#else
+static inline int hgpk_detect(struct psmouse *psmouse, int set_properties)
+{
+	return -ENODEV;
+}
+static inline int hgpk_init(struct psmouse *psmouse)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 0c5660d..390f1db 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -157,10 +157,8 @@
 static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, const char *buf, size_t count)
 {
 	unsigned long value;
-	char *rest;
 
-	value = simple_strtoul(buf, &rest, 10);
-	if (*rest || value > 1)
+	if (strict_strtoul(buf, 10, &value) || value > 1)
 		return -EINVAL;
 
 	ps2pp_set_smartscroll(psmouse, value);
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index f5a6be1..126e977 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -25,6 +25,7 @@
 #include "synaptics.h"
 #include "logips2pp.h"
 #include "alps.h"
+#include "hgpk.h"
 #include "lifebook.h"
 #include "trackpoint.h"
 #include "touchkit_ps2.h"
@@ -201,6 +202,12 @@
 	return PSMOUSE_FULL_PACKET;
 }
 
+void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
+		unsigned long delay)
+{
+	queue_delayed_work(kpsmoused_wq, work, delay);
+}
+
 /*
  * __psmouse_set_state() sets new psmouse state and resets all flags.
  */
@@ -220,7 +227,7 @@
  * is not a concern.
  */
 
-static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
+void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
 {
 	serio_pause_rx(psmouse->ps2dev.serio);
 	__psmouse_set_state(psmouse, new_state);
@@ -305,7 +312,7 @@
 		       psmouse->name, psmouse->phys, psmouse->pktcnt);
 		psmouse->badbyte = psmouse->packet[0];
 		__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
-		queue_work(kpsmoused_wq, &psmouse->resync_work);
+		psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
 		goto out;
 	}
 
@@ -342,7 +349,7 @@
 	    time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) {
 		psmouse->badbyte = psmouse->packet[0];
 		__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
-		queue_work(kpsmoused_wq, &psmouse->resync_work);
+		psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
 		goto out;
 	}
 
@@ -630,8 +637,20 @@
 		}
 	}
 
-	if (max_proto > PSMOUSE_IMEX) {
+/*
+ * Try OLPC HGPK touchpad.
+ */
+	if (max_proto > PSMOUSE_IMEX &&
+			hgpk_detect(psmouse, set_properties) == 0) {
+		if (!set_properties || hgpk_init(psmouse) == 0)
+			return PSMOUSE_HGPK;
+/*
+ * Init failed, try basic relative protocols
+ */
+		max_proto = PSMOUSE_IMEX;
+	}
 
+	if (max_proto > PSMOUSE_IMEX) {
 		if (genius_detect(psmouse, set_properties) == 0)
 			return PSMOUSE_GENPS;
 
@@ -762,6 +781,14 @@
 		.detect		= touchkit_ps2_detect,
 	},
 #endif
+#ifdef CONFIG_MOUSE_PS2_OLPC
+	{
+		.type		= PSMOUSE_HGPK,
+		.name		= "OLPC HGPK",
+		.alias		= "hgpk",
+		.detect		= hgpk_detect,
+	},
+#endif
 	{
 		.type		= PSMOUSE_CORTRON,
 		.name		= "CortronPS/2",
@@ -935,7 +962,7 @@
 static void psmouse_resync(struct work_struct *work)
 {
 	struct psmouse *parent = NULL, *psmouse =
-		container_of(work, struct psmouse, resync_work);
+		container_of(work, struct psmouse, resync_work.work);
 	struct serio *serio = psmouse->ps2dev.serio;
 	psmouse_ret_t rc = PSMOUSE_GOOD_DATA;
 	int failed = 0, enabled = 0;
@@ -1194,7 +1221,7 @@
 		goto err_free;
 
 	ps2_init(&psmouse->ps2dev, serio);
-	INIT_WORK(&psmouse->resync_work, psmouse_resync);
+	INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync);
 	psmouse->dev = input_dev;
 	snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);
 
@@ -1395,25 +1422,29 @@
 
 	psmouse = serio_get_drvdata(serio);
 
-	if (psmouse->state == PSMOUSE_IGNORE) {
-		retval = -ENODEV;
-		goto out_unlock;
-	}
+	if (attr->protect) {
+		if (psmouse->state == PSMOUSE_IGNORE) {
+			retval = -ENODEV;
+			goto out_unlock;
+		}
 
-	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
-		parent = serio_get_drvdata(serio->parent);
-		psmouse_deactivate(parent);
-	}
+		if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+			parent = serio_get_drvdata(serio->parent);
+			psmouse_deactivate(parent);
+		}
 
-	psmouse_deactivate(psmouse);
+		psmouse_deactivate(psmouse);
+	}
 
 	retval = attr->set(psmouse, attr->data, buf, count);
 
-	if (retval != -ENODEV)
-		psmouse_activate(psmouse);
+	if (attr->protect) {
+		if (retval != -ENODEV)
+			psmouse_activate(psmouse);
 
-	if (parent)
-		psmouse_activate(parent);
+		if (parent)
+			psmouse_activate(parent);
+	}
 
  out_unlock:
 	mutex_unlock(&psmouse_mutex);
@@ -1433,10 +1464,8 @@
 {
 	unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset);
 	unsigned long value;
-	char *rest;
 
-	value = simple_strtoul(buf, &rest, 10);
-	if (*rest)
+	if (strict_strtoul(buf, 10, &value))
 		return -EINVAL;
 
 	if ((unsigned int)value != value)
@@ -1549,10 +1578,8 @@
 static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count)
 {
 	unsigned long value;
-	char *rest;
 
-	value = simple_strtoul(buf, &rest, 10);
-	if (*rest)
+	if (strict_strtoul(buf, 10, &value))
 		return -EINVAL;
 
 	psmouse->set_rate(psmouse, value);
@@ -1562,10 +1589,8 @@
 static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count)
 {
 	unsigned long value;
-	char *rest;
 
-	value = simple_strtoul(buf, &rest, 10);
-	if (*rest)
+	if (strict_strtoul(buf, 10, &value))
 		return -EINVAL;
 
 	psmouse->set_resolution(psmouse, value);
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 1317bdd..8b608a1 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -39,7 +39,7 @@
 	void *private;
 	struct input_dev *dev;
 	struct ps2dev ps2dev;
-	struct work_struct resync_work;
+	struct delayed_work resync_work;
 	char *vendor;
 	char *name;
 	unsigned char packet[8];
@@ -89,20 +89,24 @@
 	PSMOUSE_TRACKPOINT,
 	PSMOUSE_TOUCHKIT_PS2,
 	PSMOUSE_CORTRON,
+	PSMOUSE_HGPK,
 	PSMOUSE_AUTO		/* This one should always be last */
 };
 
+void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
+		unsigned long delay);
 int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
 int psmouse_reset(struct psmouse *psmouse);
+void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
 void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
 
-
 struct psmouse_attribute {
 	struct device_attribute dattr;
 	void *data;
 	ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf);
 	ssize_t (*set)(struct psmouse *psmouse, void *data,
 			const char *buf, size_t count);
+	int protect;
 };
 #define to_psmouse_attr(a)	container_of((a), struct psmouse_attribute, dattr)
 
@@ -111,7 +115,7 @@
 ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr,
 				const char *buf, size_t count);
 
-#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set)			\
+#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect)	\
 static ssize_t _show(struct psmouse *, void *data, char *);			\
 static ssize_t _set(struct psmouse *, void *data, const char *, size_t);	\
 static struct psmouse_attribute psmouse_attr_##_name = {			\
@@ -126,6 +130,10 @@
 	.data	= _data,							\
 	.show	= _show,							\
 	.set	= _set,								\
+	.protect = _protect,							\
 }
 
+#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set)	\
+		__PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, 1)
+
 #endif /* _PSMOUSE_H */
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 26b845f..e68c814 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -89,10 +89,8 @@
 	struct trackpoint_attr_data *attr = data;
 	unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
 	unsigned long value;
-	char *rest;
 
-	value = simple_strtoul(buf, &rest, 10);
-	if (*rest || value > 255)
+	if (strict_strtoul(buf, 10, &value) || value > 255)
 		return -EINVAL;
 
 	*field = value;
@@ -117,10 +115,8 @@
 	struct trackpoint_attr_data *attr = data;
 	unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
 	unsigned long value;
-	char *rest;
 
-	value = simple_strtoul(buf, &rest, 10);
-	if (*rest || value > 1)
+	if (strict_strtoul(buf, 10, &value) || value > 1)
 		return -EINVAL;
 
 	if (attr->inverted)
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 5aafe24..a321aea 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -322,6 +322,13 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"),
 		},
 	},
+	{
+		.ident = "IBM 2656",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "2656"),
+		},
+	},
 	{ }
 };
 
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index c9397c8..470770c 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -373,6 +373,12 @@
 		.id	= SERIO_ANY,
 		.extra	= SERIO_ANY,
 	},
+	{
+		.type	= SERIO_8042_XL,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
 	{ 0 }
 };
 
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index 8f037a1..e53c838 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -1202,16 +1202,22 @@
 store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct aiptek *aiptek = dev_get_drvdata(dev);
-	int x;
+	long x;
 
-	if (strcmp(buf, "disable") == 0) {
+	if (strict_strtol(buf, 10, &x)) {
+		size_t len = buf[count - 1] == '\n' ? count - 1 : count;
+
+		if (strncmp(buf, "disable", len))
+			return -EINVAL;
+
 		aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE;
 	} else {
-		x = (int)simple_strtol(buf, NULL, 10);
-		if (x >= AIPTEK_TILT_MIN && x <= AIPTEK_TILT_MAX) {
-			aiptek->newSetting.xTilt = x;
-		}
+		if (x < AIPTEK_TILT_MIN || x > AIPTEK_TILT_MAX)
+			return -EINVAL;
+
+		aiptek->newSetting.xTilt = x;
 	}
+
 	return count;
 }
 
@@ -1238,16 +1244,22 @@
 store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct aiptek *aiptek = dev_get_drvdata(dev);
-	int y;
+	long y;
 
-	if (strcmp(buf, "disable") == 0) {
+	if (strict_strtol(buf, 10, &y)) {
+		size_t len = buf[count - 1] == '\n' ? count - 1 : count;
+
+		if (strncmp(buf, "disable", len))
+			return -EINVAL;
+
 		aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE;
 	} else {
-		y = (int)simple_strtol(buf, NULL, 10);
-		if (y >= AIPTEK_TILT_MIN && y <= AIPTEK_TILT_MAX) {
-			aiptek->newSetting.yTilt = y;
-		}
+		if (y < AIPTEK_TILT_MIN || y > AIPTEK_TILT_MAX)
+			return -EINVAL;
+
+		aiptek->newSetting.yTilt = y;
 	}
+
 	return count;
 }
 
@@ -1269,8 +1281,12 @@
 store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct aiptek *aiptek = dev_get_drvdata(dev);
+	long j;
 
-	aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10);
+	if (strict_strtol(buf, 10, &j))
+		return -EINVAL;
+
+	aiptek->newSetting.jitterDelay = (int)j;
 	return count;
 }
 
@@ -1294,8 +1310,12 @@
 store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct aiptek *aiptek = dev_get_drvdata(dev);
+	long d;
 
-	aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10);
+	if (strict_strtol(buf, 10, &d))
+		return -EINVAL;
+
+	aiptek->newSetting.programmableDelay = (int)d;
 	return count;
 }
 
@@ -1541,8 +1561,11 @@
 store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct aiptek *aiptek = dev_get_drvdata(dev);
+	long w;
 
-	aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10);
+	if (strict_strtol(buf, 10, &w)) return -EINVAL;
+
+	aiptek->newSetting.wheel = (int)w;
 	return count;
 }
 
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 8583c76..b9b7fc6 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -69,6 +69,17 @@
 	int	ignore;
 };
 
+/*
+ * We allocate this separately to avoid cache line sharing issues when
+ * driver is used with DMA-based SPI controllers (like atmel_spi) on
+ * systems where main memory is not DMA-coherent (most non-x86 boards).
+ */
+struct ads7846_packet {
+	u8			read_x, read_y, read_z1, read_z2, pwrdown;
+	u16			dummy;		/* for the pwrdown read */
+	struct ts_event		tc;
+};
+
 struct ads7846 {
 	struct input_dev	*input;
 	char			phys[32];
@@ -86,9 +97,7 @@
 	u16			x_plate_ohms;
 	u16			pressure_max;
 
-	u8			read_x, read_y, read_z1, read_z2, pwrdown;
-	u16			dummy;		/* for the pwrdown read */
-	struct ts_event		tc;
+	struct ads7846_packet	*packet;
 
 	struct spi_transfer	xfer[18];
 	struct spi_message	msg[5];
@@ -463,10 +472,11 @@
 				     const char *buf, size_t count)
 {
 	struct ads7846 *ts = dev_get_drvdata(dev);
-	char *endp;
-	int i;
+	long i;
 
-	i = simple_strtoul(buf, &endp, 10);
+	if (strict_strtoul(buf, 10, &i))
+		return -EINVAL;
+
 	spin_lock_irq(&ts->lock);
 
 	if (i)
@@ -512,16 +522,17 @@
 static void ads7846_rx(void *ads)
 {
 	struct ads7846		*ts = ads;
+	struct ads7846_packet	*packet = ts->packet;
 	unsigned		Rt;
 	u16			x, y, z1, z2;
 
 	/* ads7846_rx_val() did in-place conversion (including byteswap) from
 	 * on-the-wire format as part of debouncing to get stable readings.
 	 */
-	x = ts->tc.x;
-	y = ts->tc.y;
-	z1 = ts->tc.z1;
-	z2 = ts->tc.z2;
+	x = packet->tc.x;
+	y = packet->tc.y;
+	z1 = packet->tc.z1;
+	z2 = packet->tc.z2;
 
 	/* range filtering */
 	if (x == MAX_12BIT)
@@ -545,10 +556,10 @@
 	 * the maximum. Don't report it to user space, repeat at least
 	 * once more the measurement
 	 */
-	if (ts->tc.ignore || Rt > ts->pressure_max) {
+	if (packet->tc.ignore || Rt > ts->pressure_max) {
 #ifdef VERBOSE
 		pr_debug("%s: ignored %d pressure %d\n",
-			ts->spi->dev.bus_id, ts->tc.ignore, Rt);
+			ts->spi->dev.bus_id, packet->tc.ignore, Rt);
 #endif
 		hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
 			      HRTIMER_MODE_REL);
@@ -641,6 +652,7 @@
 static void ads7846_rx_val(void *ads)
 {
 	struct ads7846 *ts = ads;
+	struct ads7846_packet *packet = ts->packet;
 	struct spi_message *m;
 	struct spi_transfer *t;
 	int val;
@@ -660,7 +672,7 @@
 	case ADS7846_FILTER_REPEAT:
 		break;
 	case ADS7846_FILTER_IGNORE:
-		ts->tc.ignore = 1;
+		packet->tc.ignore = 1;
 		/* Last message will contain ads7846_rx() as the
 		 * completion function.
 		 */
@@ -668,7 +680,7 @@
 		break;
 	case ADS7846_FILTER_OK:
 		*(u16 *)t->rx_buf = val;
-		ts->tc.ignore = 0;
+		packet->tc.ignore = 0;
 		m = &ts->msg[++ts->msg_idx];
 		break;
 	default:
@@ -773,7 +785,6 @@
 	/* we know the chip's in lowpower mode since we always
 	 * leave it that way after every request
 	 */
-
 }
 
 /* Must be called with ts->lock held */
@@ -849,6 +860,7 @@
 static int __devinit ads7846_probe(struct spi_device *spi)
 {
 	struct ads7846			*ts;
+	struct ads7846_packet		*packet;
 	struct input_dev		*input_dev;
 	struct ads7846_platform_data	*pdata = spi->dev.platform_data;
 	struct spi_message		*m;
@@ -884,14 +896,16 @@
 		return err;
 
 	ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
+	packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
 	input_dev = input_allocate_device();
-	if (!ts || !input_dev) {
+	if (!ts || !packet || !input_dev) {
 		err = -ENOMEM;
 		goto err_free_mem;
 	}
 
 	dev_set_drvdata(&spi->dev, ts);
 
+	ts->packet = packet;
 	ts->spi = spi;
 	ts->input = input_dev;
 	ts->vref_mv = pdata->vref_mv;
@@ -963,13 +977,13 @@
 	spi_message_init(m);
 
 	/* y- still on; turn on only y+ (and ADC) */
-	ts->read_y = READ_Y(vref);
-	x->tx_buf = &ts->read_y;
+	packet->read_y = READ_Y(vref);
+	x->tx_buf = &packet->read_y;
 	x->len = 1;
 	spi_message_add_tail(x, m);
 
 	x++;
-	x->rx_buf = &ts->tc.y;
+	x->rx_buf = &packet->tc.y;
 	x->len = 2;
 	spi_message_add_tail(x, m);
 
@@ -981,12 +995,12 @@
 		x->delay_usecs = pdata->settle_delay_usecs;
 
 		x++;
-		x->tx_buf = &ts->read_y;
+		x->tx_buf = &packet->read_y;
 		x->len = 1;
 		spi_message_add_tail(x, m);
 
 		x++;
-		x->rx_buf = &ts->tc.y;
+		x->rx_buf = &packet->tc.y;
 		x->len = 2;
 		spi_message_add_tail(x, m);
 	}
@@ -999,13 +1013,13 @@
 
 	/* turn y- off, x+ on, then leave in lowpower */
 	x++;
-	ts->read_x = READ_X(vref);
-	x->tx_buf = &ts->read_x;
+	packet->read_x = READ_X(vref);
+	x->tx_buf = &packet->read_x;
 	x->len = 1;
 	spi_message_add_tail(x, m);
 
 	x++;
-	x->rx_buf = &ts->tc.x;
+	x->rx_buf = &packet->tc.x;
 	x->len = 2;
 	spi_message_add_tail(x, m);
 
@@ -1014,12 +1028,12 @@
 		x->delay_usecs = pdata->settle_delay_usecs;
 
 		x++;
-		x->tx_buf = &ts->read_x;
+		x->tx_buf = &packet->read_x;
 		x->len = 1;
 		spi_message_add_tail(x, m);
 
 		x++;
-		x->rx_buf = &ts->tc.x;
+		x->rx_buf = &packet->tc.x;
 		x->len = 2;
 		spi_message_add_tail(x, m);
 	}
@@ -1033,13 +1047,13 @@
 		spi_message_init(m);
 
 		x++;
-		ts->read_z1 = READ_Z1(vref);
-		x->tx_buf = &ts->read_z1;
+		packet->read_z1 = READ_Z1(vref);
+		x->tx_buf = &packet->read_z1;
 		x->len = 1;
 		spi_message_add_tail(x, m);
 
 		x++;
-		x->rx_buf = &ts->tc.z1;
+		x->rx_buf = &packet->tc.z1;
 		x->len = 2;
 		spi_message_add_tail(x, m);
 
@@ -1048,12 +1062,12 @@
 			x->delay_usecs = pdata->settle_delay_usecs;
 
 			x++;
-			x->tx_buf = &ts->read_z1;
+			x->tx_buf = &packet->read_z1;
 			x->len = 1;
 			spi_message_add_tail(x, m);
 
 			x++;
-			x->rx_buf = &ts->tc.z1;
+			x->rx_buf = &packet->tc.z1;
 			x->len = 2;
 			spi_message_add_tail(x, m);
 		}
@@ -1065,13 +1079,13 @@
 		spi_message_init(m);
 
 		x++;
-		ts->read_z2 = READ_Z2(vref);
-		x->tx_buf = &ts->read_z2;
+		packet->read_z2 = READ_Z2(vref);
+		x->tx_buf = &packet->read_z2;
 		x->len = 1;
 		spi_message_add_tail(x, m);
 
 		x++;
-		x->rx_buf = &ts->tc.z2;
+		x->rx_buf = &packet->tc.z2;
 		x->len = 2;
 		spi_message_add_tail(x, m);
 
@@ -1080,12 +1094,12 @@
 			x->delay_usecs = pdata->settle_delay_usecs;
 
 			x++;
-			x->tx_buf = &ts->read_z2;
+			x->tx_buf = &packet->read_z2;
 			x->len = 1;
 			spi_message_add_tail(x, m);
 
 			x++;
-			x->rx_buf = &ts->tc.z2;
+			x->rx_buf = &packet->tc.z2;
 			x->len = 2;
 			spi_message_add_tail(x, m);
 		}
@@ -1099,13 +1113,13 @@
 	spi_message_init(m);
 
 	x++;
-	ts->pwrdown = PWRDOWN;
-	x->tx_buf = &ts->pwrdown;
+	packet->pwrdown = PWRDOWN;
+	x->tx_buf = &packet->pwrdown;
 	x->len = 1;
 	spi_message_add_tail(x, m);
 
 	x++;
-	x->rx_buf = &ts->dummy;
+	x->rx_buf = &packet->dummy;
 	x->len = 2;
 	CS_CHANGE(*x);
 	spi_message_add_tail(x, m);
@@ -1158,6 +1172,7 @@
 		ts->filter_cleanup(ts->filter_data);
  err_free_mem:
 	input_free_device(input_dev);
+	kfree(packet);
 	kfree(ts);
 	return err;
 }
@@ -1183,6 +1198,7 @@
 	if (ts->filter_cleanup)
 		ts->filter_cleanup(ts->filter_data);
 
+	kfree(ts->packet);
 	kfree(ts);
 
 	dev_dbg(&spi->dev, "unregistered touchscreen\n");
diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
index eee126b..a89a6a8 100644
--- a/drivers/input/touchscreen/atmel_tsadcc.c
+++ b/drivers/input/touchscreen/atmel_tsadcc.c
@@ -91,6 +91,9 @@
 	char			phys[32];
 	struct clk		*clk;
 	int			irq;
+	unsigned int		prev_absx;
+	unsigned int		prev_absy;
+	unsigned char		bufferedmeasure;
 };
 
 static void __iomem		*tsc_base;
@@ -100,10 +103,9 @@
 
 static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
 {
-	struct input_dev *input_dev = ((struct atmel_tsadcc *)dev)->input;
+	struct atmel_tsadcc	*ts_dev = (struct atmel_tsadcc *)dev;
+	struct input_dev	*input_dev = ts_dev->input;
 
-	unsigned int absx;
-	unsigned int absy;
 	unsigned int status;
 	unsigned int reg;
 
@@ -121,6 +123,7 @@
 		atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
 
 		input_report_key(input_dev, BTN_TOUCH, 0);
+		ts_dev->bufferedmeasure = 0;
 		input_sync(input_dev);
 
 	} else if (status & ATMEL_TSADCC_PENCNT) {
@@ -138,16 +141,23 @@
 	} else if (status & ATMEL_TSADCC_EOC(3)) {
 		/* Conversion finished */
 
-		absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
-		absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
+		if (ts_dev->bufferedmeasure) {
+			/* Last measurement is always discarded, since it can
+			 * be erroneous.
+			 * Always report previous measurement */
+			input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
+			input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
+			input_report_key(input_dev, BTN_TOUCH, 1);
+			input_sync(input_dev);
+		} else
+			ts_dev->bufferedmeasure = 1;
 
-		absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
-		absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
+		/* Now make new measurement */
+		ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
+		ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
 
-		input_report_abs(input_dev, ABS_X, absx);
-		input_report_abs(input_dev, ABS_Y, absy);
-		input_report_key(input_dev, BTN_TOUCH, 1);
-		input_sync(input_dev);
+		ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
+		ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
 	}
 
 	return IRQ_HANDLED;
@@ -223,6 +233,7 @@
 	}
 
 	ts_dev->input = input_dev;
+	ts_dev->bufferedmeasure = 0;
 
 	snprintf(ts_dev->phys, sizeof(ts_dev->phys),
 		 "%s/input0", pdev->dev.bus_id);
diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c
index 37a555f..ba64875 100644
--- a/drivers/input/touchscreen/mainstone-wm97xx.c
+++ b/drivers/input/touchscreen/mainstone-wm97xx.c
@@ -3,8 +3,7 @@
  *                         Wolfson WM97xx AC97 Codecs.
  *
  * Copyright 2004, 2007 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  * Parts Copyright : Ian Molton <spyro@f2s.com>
  *                   Andrew Zabolotny <zap@homelink.ru>
  *
@@ -296,6 +295,6 @@
 module_exit(mainstone_wm97xx_exit);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
 MODULE_DESCRIPTION("wm97xx continuous touch driver for mainstone");
 MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c
index 372efbc..6b5be74 100644
--- a/drivers/input/touchscreen/wm9705.c
+++ b/drivers/input/touchscreen/wm9705.c
@@ -2,8 +2,7 @@
  * wm9705.c  --  Codec driver for Wolfson WM9705 AC97 Codec.
  *
  * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  * Parts Copyright : Ian Molton <spyro@f2s.com>
  *                   Andrew Zabolotny <zap@homelink.ru>
  *                   Russell King <rmk@arm.linux.org.uk>
@@ -347,6 +346,6 @@
 EXPORT_SYMBOL_GPL(wm9705_codec);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
 MODULE_DESCRIPTION("WM9705 Touch Screen Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c
index c8bb1e7..7490b05 100644
--- a/drivers/input/touchscreen/wm9712.c
+++ b/drivers/input/touchscreen/wm9712.c
@@ -2,8 +2,7 @@
  * wm9712.c  --  Codec driver for Wolfson WM9712 AC97 Codecs.
  *
  * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  * Parts Copyright : Ian Molton <spyro@f2s.com>
  *                   Andrew Zabolotny <zap@homelink.ru>
  *                   Russell King <rmk@arm.linux.org.uk>
@@ -462,6 +461,6 @@
 EXPORT_SYMBOL_GPL(wm9712_codec);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
 MODULE_DESCRIPTION("WM9712 Touch Screen Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c
index 781ee83..238b513 100644
--- a/drivers/input/touchscreen/wm9713.c
+++ b/drivers/input/touchscreen/wm9713.c
@@ -2,8 +2,7 @@
  * wm9713.c  --  Codec touch driver for Wolfson WM9713 AC97 Codec.
  *
  * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  * Parts Copyright : Ian Molton <spyro@f2s.com>
  *                   Andrew Zabolotny <zap@homelink.ru>
  *                   Russell King <rmk@arm.linux.org.uk>
@@ -476,6 +475,6 @@
 EXPORT_SYMBOL_GPL(wm9713_codec);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
 MODULE_DESCRIPTION("WM9713 Touch Screen Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index d589ab0..d15aa11 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -3,8 +3,7 @@
  *                    and WM9713 AC97 Codecs.
  *
  * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  * Parts Copyright : Ian Molton <spyro@f2s.com>
  *                   Andrew Zabolotny <zap@homelink.ru>
  *                   Russell King <rmk@arm.linux.org.uk>
@@ -824,6 +823,6 @@
 module_exit(wm97xx_exit);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
 MODULE_DESCRIPTION("WM97xx Core - Touch Screen / AUX ADC / GPIO Driver");
 MODULE_LICENSE("GPL");
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 282a504..bf9aca5 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -107,6 +107,7 @@
 header-y += limits.h
 header-y += magic.h
 header-y += major.h
+header-y += map_to_7segment.h
 header-y += matroxfb.h
 header-y += meye.h
 header-y += minix_fs.h
diff --git a/include/linux/gameport.h b/include/linux/gameport.h
index f64e29c..0cd825f 100644
--- a/include/linux/gameport.h
+++ b/include/linux/gameport.h
@@ -146,10 +146,11 @@
 	mutex_unlock(&gameport->drv_mutex);
 }
 
-void __gameport_register_driver(struct gameport_driver *drv, struct module *owner);
-static inline void gameport_register_driver(struct gameport_driver *drv)
+int __gameport_register_driver(struct gameport_driver *drv,
+				struct module *owner, const char *mod_name);
+static inline int __must_check gameport_register_driver(struct gameport_driver *drv)
 {
-	__gameport_register_driver(drv, THIS_MODULE);
+	return __gameport_register_driver(drv, THIS_MODULE, KBUILD_MODNAME);
 }
 
 void gameport_unregister_driver(struct gameport_driver *drv);
diff --git a/include/linux/input.h b/include/linux/input.h
index a5802c9..b86fb55 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -577,9 +577,22 @@
 #define KEY_BRL_DOT9		0x1f9
 #define KEY_BRL_DOT10		0x1fa
 
+#define KEY_NUMERIC_0		0x200	/* used by phones, remote controls, */
+#define KEY_NUMERIC_1		0x201	/* and other keypads */
+#define KEY_NUMERIC_2		0x202
+#define KEY_NUMERIC_3		0x203
+#define KEY_NUMERIC_4		0x204
+#define KEY_NUMERIC_5		0x205
+#define KEY_NUMERIC_6		0x206
+#define KEY_NUMERIC_7		0x207
+#define KEY_NUMERIC_8		0x208
+#define KEY_NUMERIC_9		0x209
+#define KEY_NUMERIC_STAR	0x20a
+#define KEY_NUMERIC_POUND	0x20b
+
 /* We avoid low common keys in module aliases so they don't get huge. */
 #define KEY_MIN_INTERESTING	KEY_MUTE
-#define KEY_MAX			0x1ff
+#define KEY_MAX			0x2ff
 #define KEY_CNT			(KEY_MAX+1)
 
 /*
diff --git a/drivers/input/misc/map_to_7segment.h b/include/linux/map_to_7segment.h
similarity index 98%
rename from drivers/input/misc/map_to_7segment.h
rename to include/linux/map_to_7segment.h
index a424094..7df8432 100644
--- a/drivers/input/misc/map_to_7segment.h
+++ b/include/linux/map_to_7segment.h
@@ -1,6 +1,4 @@
 /*
- * drivers/usb/input/map_to_7segment.h
- *
  * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
  *
  * This program is free software; you can redistribute it and/or
@@ -36,7 +34,7 @@
  * Usage:
  *
  *   Register a map variable, and fill it with a character set:
- * 	static SEG7_DEFAULT_MAP(map_seg7);
+ *	static SEG7_DEFAULT_MAP(map_seg7);
  *
  *
  *   Then use for conversion:
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index d6a3f47..eb71b45 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -284,7 +284,7 @@
 /* Input */
 #define INPUT_DEVICE_ID_EV_MAX		0x1f
 #define INPUT_DEVICE_ID_KEY_MIN_INTERESTING	0x71
-#define INPUT_DEVICE_ID_KEY_MAX		0x1ff
+#define INPUT_DEVICE_ID_KEY_MAX		0x2ff
 #define INPUT_DEVICE_ID_REL_MAX		0x0f
 #define INPUT_DEVICE_ID_ABS_MAX		0x3f
 #define INPUT_DEVICE_ID_MSC_MAX		0x07