Input: appletouch - implement reset-resume logic

On some boxes the touchpad needs to be reinitialized after resume to make
it function again. This fixes bugzilla #10825.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 8dd3942..ce6fdec 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -589,6 +589,21 @@
 	dev->open = 0;
 }
 
+static int atp_handle_geyser(struct atp *dev)
+{
+	struct usb_device *udev = dev->udev;
+
+	if (!atp_is_fountain(dev)) {
+		/* switch to raw sensor mode */
+		if (atp_geyser_init(udev))
+			return -EIO;
+
+		printk(KERN_INFO "appletouch: Geyser mode initialized.\n");
+	}
+
+	return 0;
+}
+
 static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id)
 {
 	struct atp *dev;
@@ -633,14 +648,6 @@
 	else
 		dev->datalen = 81;
 
-	if (!atp_is_fountain(dev)) {
-		/* switch to raw sensor mode */
-		if (atp_geyser_init(udev))
-			goto err_free_devs;
-
-		printk(KERN_INFO "appletouch: Geyser mode initialized.\n");
-	}
-
 	dev->urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!dev->urb)
 		goto err_free_devs;
@@ -654,6 +661,10 @@
 			 usb_rcvintpipe(udev, int_in_endpointAddr),
 			 dev->data, dev->datalen, atp_complete, dev, 1);
 
+	error = atp_handle_geyser(dev);
+	if (error)
+		goto err_free_buffer;
+
 	usb_make_path(udev, dev->phys, sizeof(dev->phys));
 	strlcat(dev->phys, "/input0", sizeof(dev->phys));
 
@@ -744,6 +755,20 @@
 	printk(KERN_INFO "input: appletouch disconnected\n");
 }
 
+static int atp_recover(struct atp *dev)
+{
+	int error;
+
+	error = atp_handle_geyser(dev);
+	if (error)
+		return error;
+
+	if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
+		return -EIO;
+
+	return 0;
+}
+
 static int atp_suspend(struct usb_interface *iface, pm_message_t message)
 {
 	struct atp *dev = usb_get_intfdata(iface);
@@ -764,12 +789,20 @@
 	return 0;
 }
 
+static int atp_reset_resume(struct usb_interface *iface)
+{
+	struct atp *dev = usb_get_intfdata(iface);
+
+	return atp_recover(dev);
+}
+
 static struct usb_driver atp_driver = {
 	.name		= "appletouch",
 	.probe		= atp_probe,
 	.disconnect	= atp_disconnect,
 	.suspend	= atp_suspend,
 	.resume		= atp_resume,
+	.reset_resume	= atp_reset_resume,
 	.id_table	= atp_table,
 };