summary refs log tree commit diff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-19 13:31:34 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-19 13:31:34 -0800
commitd43a338e395371733a80ec473b40baac5f74d768 (patch)
treed4c01b62865bed1af2463d7a4eb4cb25ca46c66e /drivers
parentcb4aaf46c0283dd79ab2e8b8b165c0bf13ab6194 (diff)
parent62b529a7b9c11880a8820494a25db0e2ecdf3bed (diff)
downloadlinux-d43a338e395371733a80ec473b40baac5f74d768.tar.gz
Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/dtor/input:
  Input: remove obsolete setup parameters from input drivers
  Input: HIL - fix improper call to release_region()
  Input: hid-lgff - treat devices as joysticks unless told otherwise
  Input: HID - add support for Logitech Formula Force EX
  Input: gpio-keys - switch to common GPIO API
  Input: do not lock device when showing name, phys and uniq
  Input: i8042 - let serio bus suspend ports
  Input: psmouse - properly reset mouse on shutdown/suspend
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/input.c17
-rw-r--r--drivers/input/joystick/amijoy.c2
-rw-r--r--drivers/input/joystick/analog.c2
-rw-r--r--drivers/input/joystick/db9.c4
-rw-r--r--drivers/input/joystick/gamecon.c6
-rw-r--r--drivers/input/joystick/turbografx.c4
-rw-r--r--drivers/input/keyboard/Kconfig6
-rw-r--r--drivers/input/keyboard/atkbd.c4
-rw-r--r--drivers/input/keyboard/gpio_keys.c15
-rw-r--r--drivers/input/keyboard/hilkbd.c2
-rw-r--r--drivers/input/mouse/inport.c2
-rw-r--r--drivers/input/mouse/logibm.c2
-rw-r--r--drivers/input/mouse/psmouse-base.c34
-rw-r--r--drivers/input/mouse/psmouse.h1
-rw-r--r--drivers/input/mouse/synaptics.c1
-rw-r--r--drivers/input/serio/i8042.c63
-rw-r--r--drivers/input/serio/serio.c36
-rw-r--r--drivers/usb/input/Kconfig6
-rw-r--r--drivers/usb/input/hid-ff.c3
-rw-r--r--drivers/usb/input/hid-lgff.c12
20 files changed, 124 insertions, 98 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c
index efa1b1f75393..a9a706f8fff9 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -588,18 +588,9 @@ static inline void input_proc_exit(void) { }
 static ssize_t input_dev_show_##name(struct class_device *dev, char *buf)	\
 {										\
 	struct input_dev *input_dev = to_input_dev(dev);			\
-	int retval;								\
 										\
-	retval = mutex_lock_interruptible(&input_dev->mutex);			\
-	if (retval)								\
-		return retval;							\
-										\
-	retval = scnprintf(buf, PAGE_SIZE,					\
-			   "%s\n", input_dev->name ? input_dev->name : "");	\
-										\
-	mutex_unlock(&input_dev->mutex);					\
-										\
-	return retval;								\
+	return scnprintf(buf, PAGE_SIZE, "%s\n",				\
+			 input_dev->name ? input_dev->name : "");		\
 }										\
 static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL);
 
@@ -1049,10 +1040,6 @@ void input_unregister_device(struct input_dev *dev)
 	sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
 	sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
 
-	mutex_lock(&dev->mutex);
-	dev->name = dev->phys = dev->uniq = NULL;
-	mutex_unlock(&dev->mutex);
-
 	class_device_unregister(&dev->cdev);
 
 	input_wakeup_procfs_readers();
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index e608691b5a61..b0f5541ec3e6 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -50,8 +50,6 @@ static int amijoy[2] = { 0, 1 };
 module_param_array_named(map, amijoy, uint, NULL, 0);
 MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is 0,1)");
 
-__obsolete_setup("amijoy=");
-
 static int amijoy_used;
 static DEFINE_MUTEX(amijoy_mutex);
 static struct input_dev *amijoy_dev[2];
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 7ef68456d7d6..51f1e4bfff3e 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -58,8 +58,6 @@ static int analog_options[ANALOG_PORTS];
 module_param_array_named(map, js, charp, &js_nargs, 0);
 MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities");
 
-__obsolete_setup("js=");
-
 /*
  * Times, feature definitions.
  */
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index 5080e15c6d30..b41bd2eb37dd 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -59,10 +59,6 @@ MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)");
 module_param_array_named(dev3, db9[2].args, int, &db9[2].nargs, 0);
 MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)");
 
-__obsolete_setup("db9=");
-__obsolete_setup("db9_2=");
-__obsolete_setup("db9_3=");
-
 #define DB9_ARG_PARPORT		0
 #define DB9_ARG_MODE		1
 
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index fe12aa37393d..711e4b3e9e61 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -60,10 +60,6 @@ MODULE_PARM_DESC(map2, "Describes second set of devices");
 module_param_array_named(map3, gc[2].args, int, &gc[2].nargs, 0);
 MODULE_PARM_DESC(map3, "Describes third set of devices");
 
-__obsolete_setup("gc=");
-__obsolete_setup("gc_2=");
-__obsolete_setup("gc_3=");
-
 /* see also gs_psx_delay parameter in PSX support section */
 
 #define GC_SNES		1
@@ -403,8 +399,6 @@ static int gc_psx_delay = GC_PSX_DELAY;
 module_param_named(psx_delay, gc_psx_delay, uint, 0);
 MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)");
 
-__obsolete_setup("gc_psx_delay=");
-
 static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
 static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
 				BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 5570fd5487c7..037d3487fcc7 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -60,10 +60,6 @@ MODULE_PARM_DESC(map2, "Describes second set of devices");
 module_param_array_named(map3, tgfx[2].args, int, &tgfx[2].nargs, 0);
 MODULE_PARM_DESC(map3, "Describes third set of devices");
 
-__obsolete_setup("tgfx=");
-__obsolete_setup("tgfx_2=");
-__obsolete_setup("tgfx_3=");
-
 #define TGFX_REFRESH_TIME	HZ/100	/* 10 ms */
 
 #define TGFX_TRIGGER		0x08
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 1b81a72e19d9..64509689fa65 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -215,11 +215,11 @@ config KEYBOARD_AAED2000
 	  module will be called aaed2000_kbd.
 
 config KEYBOARD_GPIO
-        tristate "Buttons on CPU GPIOs (PXA)"
-        depends on ARCH_PXA
+	tristate "Buttons on CPU GPIOs (PXA)"
+	depends on (ARCH_SA1100 || ARCH_PXA || ARCH_S3C2410)
 	help
 	  This driver implements support for buttons connected
-	  directly to GPIO pins of PXA CPUs.
+	  directly to GPIO pins of SA1100, PXA or S3C24xx CPUs.
 
 	  Say Y here if your device has buttons connected
 	  directly to GPIO pins of the CPU.
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index c621a9177a56..663877076bc7 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -63,10 +63,6 @@ static int atkbd_extra;
 module_param_named(extra, atkbd_extra, bool, 0);
 MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
 
-__obsolete_setup("atkbd_set=");
-__obsolete_setup("atkbd_reset");
-__obsolete_setup("atkbd_softrepeat=");
-
 /*
  * Scancode to keycode tables. These are just the default setting, and
  * are loadable via an userland utility.
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 7ad479e4e3b3..fa03a00b4c6d 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -24,7 +24,7 @@
 #include <linux/input.h>
 #include <linux/irq.h>
 
-#include <asm/arch/pxa-regs.h>
+#include <asm/gpio.h>
 #include <asm/arch/hardware.h>
 
 #include <asm/hardware/gpio_keys.h>
@@ -38,8 +38,8 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
 
 	for (i = 0; i < pdata->nbuttons; i++) {
 		int gpio = pdata->buttons[i].gpio;
-		if (irq == IRQ_GPIO(gpio)) {
-			int state = ((GPLR(gpio) & GPIO_bit(gpio)) ? 1 : 0) ^ (pdata->buttons[i].active_low);
+		if (irq == gpio_to_irq(gpio)) {
+			int state = (gpio_get_value(gpio) ? 1 : 0) ^ (pdata->buttons[i].active_low);
 
 			input_report_key(input, pdata->buttons[i].keycode, state);
 			input_sync(input);
@@ -75,14 +75,15 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 
 	for (i = 0; i < pdata->nbuttons; i++) {
 		int code = pdata->buttons[i].keycode;
-		int irq = IRQ_GPIO(pdata->buttons[i].gpio);
+		int irq = gpio_to_irq(pdata->buttons[i].gpio);
 
 		set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
 		error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM,
 				     pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys",
 				     pdev);
 		if (error) {
-			printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n", irq, ret);
+			printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
+				irq, error);
 			goto fail;
 		}
 		set_bit(code, input->keybit);
@@ -98,7 +99,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 
  fail:
 	for (i = i - 1; i >= 0; i--)
-		free_irq(IRQ_GPIO(pdata->buttons[i].gpio), pdev);
+		free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
 
 	input_free_device(input);
 
@@ -112,7 +113,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 	int i;
 
 	for (i = 0; i < pdata->nbuttons; i++) {
-		int irq = IRQ_GPIO(pdata->buttons[i].gpio);
+		int irq = gpio_to_irq(pdata->buttons[i].gpio);
 		free_irq(irq, pdev);
 	}
 
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index 255a6ec75a48..4de4dc297d50 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -294,8 +294,10 @@ err3:
 	disable_irq(HIL_IRQ);
 	free_irq(HIL_IRQ, hil_dev.dev_id);
 err2:
+#if defined(CONFIG_HP300)
 	release_region(HILBASE + HIL_DATA, 2);
 err1:
+#endif
 	input_free_device(hil_dev.dev);
 	hil_dev.dev = NULL;
 	return err;
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
index 701ebd5473cf..79b624fe8994 100644
--- a/drivers/input/mouse/inport.c
+++ b/drivers/input/mouse/inport.c
@@ -84,8 +84,6 @@ static int inport_irq = INPORT_IRQ;
 module_param_named(irq, inport_irq, uint, 0);
 MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 
-__obsolete_setup("inport_irq=");
-
 static struct input_dev *inport_dev;
 
 static irqreturn_t inport_interrupt(int irq, void *dev_id)
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
index db205995bffd..26c3b2e2ca94 100644
--- a/drivers/input/mouse/logibm.c
+++ b/drivers/input/mouse/logibm.c
@@ -75,8 +75,6 @@ static int logibm_irq = LOGIBM_IRQ;
 module_param_named(irq, logibm_irq, uint, 0);
 MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 
-__obsolete_setup("logibm_irq=");
-
 static struct input_dev *logibm_dev;
 
 static irqreturn_t logibm_interrupt(int irq, void *dev_id)
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index a0e4a033e2db..0fe5869d7d4c 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -93,12 +93,6 @@ static struct attribute_group psmouse_attribute_group = {
 	.attrs	= psmouse_attributes,
 };
 
-__obsolete_setup("psmouse_noext");
-__obsolete_setup("psmouse_resolution=");
-__obsolete_setup("psmouse_smartscroll=");
-__obsolete_setup("psmouse_resetafter=");
-__obsolete_setup("psmouse_rate=");
-
 /*
  * psmouse_mutex protects all operations changing state of mouse
  * (connecting, disconnecting, changing rate or resolution via
@@ -987,8 +981,36 @@ static void psmouse_resync(struct work_struct *work)
 static void psmouse_cleanup(struct serio *serio)
 {
 	struct psmouse *psmouse = serio_get_drvdata(serio);
+	struct psmouse *parent = NULL;
+
+	mutex_lock(&psmouse_mutex);
+
+	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+		parent = serio_get_drvdata(serio->parent);
+		psmouse_deactivate(parent);
+	}
+
+	psmouse_deactivate(psmouse);
+
+	if (psmouse->cleanup)
+		psmouse->cleanup(psmouse);
 
 	psmouse_reset(psmouse);
+
+/*
+ * Some boxes, such as HP nx7400, get terribly confused if mouse
+ * is not fully enabled before suspending/shutting down.
+ */
+	ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+	if (parent) {
+		if (parent->pt_deactivate)
+			parent->pt_deactivate(parent);
+
+		psmouse_activate(parent);
+	}
+
+	mutex_unlock(&psmouse_mutex);
 }
 
 /*
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 1b74cae8a556..cf1de95b6f27 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -68,6 +68,7 @@ struct psmouse {
 
 	int (*reconnect)(struct psmouse *psmouse);
 	void (*disconnect)(struct psmouse *psmouse);
+	void (*cleanup)(struct psmouse *psmouse);
 	int (*poll)(struct psmouse *psmouse);
 
 	void (*pt_activate)(struct psmouse *psmouse);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 49ac696d6cff..f0f9413d762c 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -652,6 +652,7 @@ int synaptics_init(struct psmouse *psmouse)
 	psmouse->set_rate = synaptics_set_rate;
 	psmouse->disconnect = synaptics_disconnect;
 	psmouse->reconnect = synaptics_reconnect;
+	psmouse->cleanup = synaptics_reset;
 	psmouse->pktsize = 6;
 	/* Synaptics can usually stay in sync without extra help */
 	psmouse->resync_time = 0;
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index c3fdfc1f342a..ec195a36e8f6 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -76,13 +76,6 @@ module_param_named(debug, i8042_debug, bool, 0600);
 MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
 #endif
 
-__obsolete_setup("i8042_noaux");
-__obsolete_setup("i8042_nomux");
-__obsolete_setup("i8042_unlock");
-__obsolete_setup("i8042_reset");
-__obsolete_setup("i8042_direct");
-__obsolete_setup("i8042_dumbkbd");
-
 #include "i8042.h"
 
 static DEFINE_SPINLOCK(i8042_lock);
@@ -724,7 +717,7 @@ static int i8042_controller_init(void)
 	if (~i8042_read_status() & I8042_STR_KEYLOCK) {
 		if (i8042_unlock)
 			i8042_ctr |= I8042_CTR_IGNKEYLOCK;
-		 else
+		else
 			printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
 	}
 	spin_unlock_irqrestore(&i8042_lock, flags);
@@ -791,27 +784,6 @@ static void i8042_controller_reset(void)
 
 
 /*
- * Here we try to reset everything back to a state in which the BIOS will be
- * able to talk to the hardware when rebooting.
- */
-
-static void i8042_controller_cleanup(void)
-{
-	int i;
-
-/*
- * Reset anything that is connected to the ports.
- */
-
-	for (i = 0; i < I8042_NUM_PORTS; i++)
-		if (i8042_ports[i].serio)
-			serio_cleanup(i8042_ports[i].serio);
-
-	i8042_controller_reset();
-}
-
-
-/*
  * i8042_panic_blink() will flash the keyboard LEDs and is called when
  * kernel panics. Flashing LEDs is useful for users running X who may
  * not see the console and will help distingushing panics from "real"
@@ -857,13 +829,22 @@ static long i8042_panic_blink(long count)
 
 #undef DELAY
 
+#ifdef CONFIG_PM
 /*
- * Here we try to restore the original BIOS settings
+ * Here we try to restore the original BIOS settings. We only want to
+ * do that once, when we really suspend, not when we taking memory
+ * snapshot for swsusp (in this case we'll perform required cleanup
+ * as part of shutdown process).
  */
 
 static int i8042_suspend(struct platform_device *dev, pm_message_t state)
 {
-	i8042_controller_cleanup();
+	if (dev->dev.power.power_state.event != state.event) {
+		if (state.event == PM_EVENT_SUSPEND)
+			i8042_controller_reset();
+
+		dev->dev.power.power_state = state;
+	}
 
 	return 0;
 }
@@ -877,6 +858,12 @@ static int i8042_resume(struct platform_device *dev)
 {
 	int error;
 
+/*
+ * Do not bother with restoring state if we haven't suspened yet
+ */
+	if (dev->dev.power.power_state.event == PM_EVENT_ON)
+		return 0;
+
 	error = i8042_controller_check();
 	if (error)
 		return error;
@@ -886,9 +873,12 @@ static int i8042_resume(struct platform_device *dev)
 		return error;
 
 /*
- * Restore pre-resume CTR value and disable all ports
+ * Restore original CTR value and disable all ports
  */
 
+	i8042_ctr = i8042_initial_ctr;
+	if (i8042_direct)
+		i8042_ctr &= ~I8042_CTR_XLATE;
 	i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
 	i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
@@ -909,8 +899,11 @@ static int i8042_resume(struct platform_device *dev)
 
 	i8042_interrupt(0, NULL);
 
+	dev->dev.power.power_state = PMSG_ON;
+
 	return 0;
 }
+#endif /* CONFIG_PM */
 
 /*
  * We need to reset the 8042 back to original mode on system shutdown,
@@ -919,7 +912,7 @@ static int i8042_resume(struct platform_device *dev)
 
 static void i8042_shutdown(struct platform_device *dev)
 {
-	i8042_controller_cleanup();
+	i8042_controller_reset();
 }
 
 static int __devinit i8042_create_kbd_port(void)
@@ -1154,9 +1147,11 @@ static struct platform_driver i8042_driver = {
 	},
 	.probe		= i8042_probe,
 	.remove		= __devexit_p(i8042_remove),
+	.shutdown	= i8042_shutdown,
+#ifdef CONFIG_PM
 	.suspend	= i8042_suspend,
 	.resume		= i8042_resume,
-	.shutdown	= i8042_shutdown,
+#endif
 };
 
 static int __init i8042_init(void)
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 17c8c63cbe1a..a15e531ec755 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -778,6 +778,19 @@ static int serio_driver_remove(struct device *dev)
 	return 0;
 }
 
+static void serio_cleanup(struct serio *serio)
+{
+	if (serio->drv && serio->drv->cleanup)
+		serio->drv->cleanup(serio);
+}
+
+static void serio_shutdown(struct device *dev)
+{
+	struct serio *serio = to_serio_port(dev);
+
+	serio_cleanup(serio);
+}
+
 static void serio_attach_driver(struct serio_driver *drv)
 {
 	int error;
@@ -910,11 +923,25 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf
 
 #endif /* CONFIG_HOTPLUG */
 
+#ifdef CONFIG_PM
+static int serio_suspend(struct device *dev, pm_message_t state)
+{
+	if (dev->power.power_state.event != state.event) {
+		if (state.event == PM_EVENT_SUSPEND)
+			serio_cleanup(to_serio_port(dev));
+
+		dev->power.power_state = state;
+	}
+
+	return 0;
+}
+
 static int serio_resume(struct device *dev)
 {
 	struct serio *serio = to_serio_port(dev);
 
-	if (serio_reconnect_driver(serio)) {
+	if (dev->power.power_state.event != PM_EVENT_ON &&
+	    serio_reconnect_driver(serio)) {
 		/*
 		 * Driver re-probing can take a while, so better let kseriod
 		 * deal with it.
@@ -922,8 +949,11 @@ static int serio_resume(struct device *dev)
 		serio_rescan(serio);
 	}
 
+	dev->power.power_state = PMSG_ON;
+
 	return 0;
 }
+#endif /* CONFIG_PM */
 
 /* called from serio_driver->connect/disconnect methods under serio_mutex */
 int serio_open(struct serio *serio, struct serio_driver *drv)
@@ -974,7 +1004,11 @@ static struct bus_type serio_bus = {
 	.uevent		= serio_uevent,
 	.probe		= serio_driver_probe,
 	.remove		= serio_driver_remove,
+	.shutdown	= serio_shutdown,
+#ifdef CONFIG_PM
+	.suspend	= serio_suspend,
 	.resume		= serio_resume,
+#endif
 };
 
 static int __init serio_init(void)
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index 2e71d3cca198..69a9f3b6d0a9 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -58,13 +58,17 @@ config HID_PID
 	  devices.
 
 config LOGITECH_FF
-	bool "Logitech WingMan *3D support"
+	bool "Logitech devices support"
 	depends on HID_FF
 	select INPUT_FF_MEMLESS if USB_HID
 	help
 	  Say Y here if you have one of these devices:
 	  - Logitech WingMan Cordless RumblePad
+	  - Logitech WingMan Cordless RumblePad 2
 	  - Logitech WingMan Force 3D
+	  - Logitech Formula Force EX
+	  - Logitech MOMO Force wheel
+
 	  and if you want to enable force feedback for them.
 	  Note: if you say N here, this device will still be supported, but without
 	  force feedback.
diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
index bc7f8e6f8c97..e431faaa6abc 100644
--- a/drivers/usb/input/hid-ff.c
+++ b/drivers/usb/input/hid-ff.c
@@ -54,9 +54,10 @@ struct hid_ff_initializer {
 static struct hid_ff_initializer inits[] = {
 #ifdef CONFIG_LOGITECH_FF
 	{ 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */
+	{ 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
 	{ 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
+	{ 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */
 	{ 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
-	{ 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
 	{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
 #endif
 #ifdef CONFIG_PANTHERLORD_FF
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
index 4df0968f852e..e6f3af3e66d1 100644
--- a/drivers/usb/input/hid-lgff.c
+++ b/drivers/usb/input/hid-lgff.c
@@ -52,8 +52,9 @@ static const struct dev_type devices[] = {
 	{ 0x046d, 0xc211, ff_rumble },
 	{ 0x046d, 0xc219, ff_rumble },
 	{ 0x046d, 0xc283, ff_joystick },
+	{ 0x046d, 0xc294, ff_joystick },
+	{ 0x046d, 0xc295, ff_joystick },
 	{ 0x046d, 0xca03, ff_joystick },
-	{ 0x0000, 0x0000, ff_joystick }
 };
 
 static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
@@ -105,8 +106,9 @@ int hid_lgff_init(struct hid_device* hid)
 	struct input_dev *dev = hidinput->input;
 	struct hid_report *report;
 	struct hid_field *field;
+	const signed short *ff_bits = ff_joystick;
 	int error;
-	int i, j;
+	int i;
 
 	/* Find the report to use */
 	if (list_empty(report_list)) {
@@ -130,12 +132,14 @@ int hid_lgff_init(struct hid_device* hid)
 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
 		if (dev->id.vendor == devices[i].idVendor &&
 		    dev->id.product == devices[i].idProduct) {
-			for (j = 0; devices[i].ff[j] >= 0; j++)
-				set_bit(devices[i].ff[j], dev->ffbit);
+			ff_bits = devices[i].ff;
 			break;
 		}
 	}
 
+	for (i = 0; ff_bits[i] >= 0; i++)
+		set_bit(ff_bits[i], dev->ffbit);
+
 	error = input_ff_create_memless(dev, NULL, hid_lgff_play);
 	if (error)
 		return error;