diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index ffad14280..41da4f33b 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -506,6 +506,12 @@ static const struct min_max_quirk min_max_pnpid_table[] = {
 	{ }
 };
 
+
+static bool synaptics_ps2_transparent_mode = false;
+module_param_named(synaptics_ps2_transparent_mode, synaptics_ps2_transparent_mode, bool, 0644);
+MODULE_PARM_DESC(synaptics_ps2_transparent_mode, "Enable transparent pass-through mode from PS2 guest to host.");
+
+
 /*****************************************************************************
  *	Synaptics communications functions
  ****************************************************************************/
@@ -625,12 +631,44 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
 /*****************************************************************************
  *	Synaptics pass-through PS/2 port support
  ****************************************************************************/
+static int synaptics_enter_transparent_mode(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+
+	priv->mode |= SYN_BIT_TRANSPARENT_MODE;
+
+	if (synaptics_mode_cmd(psmouse, priv->mode))
+		return -EIO;
+
+	return 0;
+}
+
+static int synaptics_exit_transparent_mode(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+
+	if (ps2_command(&psmouse->ps2dev, NULL, 0x00e7))
+		return -EIO;
+	if (ps2_command(&psmouse->ps2dev, NULL, 0x00e6))
+		return -EIO;
+
+	priv->mode &= ~SYN_BIT_TRANSPARENT_MODE;
+
+	return 0;
+}
+
 static int synaptics_pt_write(struct serio *serio, u8 c)
 {
 	struct psmouse *parent = serio_get_drvdata(serio->parent);
+	struct synaptics_data *priv = parent->private;
+
 	u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
 	int error;
 
+	if (priv->transparent_mode) {
+		return parent->ps2dev.serio->write(parent->ps2dev.serio, c);
+	}
+
 	error = ps2_sliced_command(&parent->ps2dev, c);
 	if (error)
 		return error;
@@ -642,6 +680,8 @@ static int synaptics_pt_write(struct serio *serio, u8 c)
 	return 0;
 }
 
+static void synaptics_update_protocol_handler(struct psmouse *psmouse);
+
 static int synaptics_pt_start(struct serio *serio)
 {
 	struct psmouse *parent = serio_get_drvdata(serio->parent);
@@ -651,6 +691,8 @@ static int synaptics_pt_start(struct serio *serio)
 	priv->pt_port = serio;
 	serio_continue_rx(parent->ps2dev.serio);
 
+	synaptics_update_protocol_handler(parent);
+
 	return 0;
 }
 
@@ -662,6 +704,8 @@ static void synaptics_pt_stop(struct serio *serio)
 	serio_pause_rx(parent->ps2dev.serio);
 	priv->pt_port = NULL;
 	serio_continue_rx(parent->ps2dev.serio);
+
+	synaptics_update_protocol_handler(parent);
 }
 
 static int synaptics_is_pt_packet(u8 *buf)
@@ -689,6 +733,10 @@ static void synaptics_pt_activate(struct psmouse *psmouse)
 	struct synaptics_data *priv = psmouse->private;
 	struct psmouse *child = serio_get_drvdata(priv->pt_port);
 
+	/* don't need change mode if transparent mode is active */
+	if (priv->transparent_mode)
+		return;
+
 	/* adjust the touchpad to child's choice of protocol */
 	if (child) {
 		if (child->pktsize == 4)
@@ -1228,6 +1276,31 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
 		PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
 }
 
+static psmouse_ret_t transparent_process_byte(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	struct psmouse *child;
+
+	if (!priv->pt_port) {
+		return PSMOUSE_BAD_DATA;
+	}
+
+	serio_interrupt(priv->pt_port, psmouse->packet[psmouse->pktcnt - 1], 0);
+
+	// spontaneous reset
+	if (unlikely(
+	    psmouse->packet[0] == PSMOUSE_RET_BAT &&
+	    psmouse->packet[1] == PSMOUSE_RET_BAT &&
+	    psmouse->pktcnt <= 2)) {
+		psmouse_queue_work(psmouse, &priv->reset_work, 0);
+	}
+
+	child = serio_get_drvdata(priv->pt_port);
+	if (child && psmouse->pktcnt >= child->pktsize)
+		return PSMOUSE_FULL_PACKET;
+	return PSMOUSE_GOOD_DATA;
+}
+
 /*****************************************************************************
  *	Driver initialization/cleanup functions
  ****************************************************************************/
@@ -1400,6 +1473,52 @@ PSMOUSE_DEFINE_ATTR(disable_gesture, S_IWUSR | S_IRUGO, NULL,
 		    synaptics_show_disable_gesture,
 		    synaptics_set_disable_gesture);
 
+static ssize_t synaptics_show_transparent_mode(struct psmouse *psmouse,
+					      void *data, char *buf)
+{
+	struct synaptics_data *priv = psmouse->private;
+
+	return sprintf(buf, "%c\n", priv->transparent_mode ? '1' : '0');
+}
+
+static ssize_t synaptics_set_transparent_mode(struct psmouse *psmouse,
+					     void *data, const char *buf,
+					     size_t len)
+{
+	struct synaptics_data *priv = psmouse->private;
+	unsigned int value;
+	int err;
+
+	err = kstrtouint(buf, 10, &value);
+	if (err)
+		return err;
+
+	if (value > 1)
+		return -EINVAL;
+
+	if (value == priv->transparent_mode)
+		return len;
+
+	priv->transparent_mode = value;
+
+	synaptics_update_protocol_handler(psmouse);
+
+	if (value) {
+		if (synaptics_enter_transparent_mode(psmouse))
+			return -EIO;
+	}
+	else {
+		if (synaptics_exit_transparent_mode(psmouse))
+			return -EIO;
+	}
+
+	return len;
+}
+
+PSMOUSE_DEFINE_ATTR(transparent_mode, S_IWUSR | S_IRUGO, NULL,
+		    synaptics_show_transparent_mode,
+		    synaptics_set_transparent_mode);
+
 static void synaptics_disconnect(struct psmouse *psmouse)
 {
 	struct synaptics_data *priv = psmouse->private;
@@ -1410,10 +1529,16 @@ static void synaptics_disconnect(struct psmouse *psmouse)
 	 */
 	psmouse_smbus_cleanup(psmouse);
 
+	if (priv->transparent_mode)
+		synaptics_exit_transparent_mode(psmouse);
+
 	if (!priv->absolute_mode &&
 			SYN_ID_DISGEST_SUPPORTED(priv->info.identity))
 		device_remove_file(&psmouse->ps2dev.serio->dev,
 				   &psmouse_attr_disable_gesture.dattr);
+	if (SYN_CAP_PASS_THROUGH(priv->info.capabilities))
+		device_remove_file(&psmouse->ps2dev.serio->dev,
+				   &psmouse_attr_transparent_mode.dattr);
 
 	synaptics_reset(psmouse);
 	kfree(priv);
@@ -1440,8 +1565,15 @@ static int synaptics_reconnect(struct psmouse *psmouse)
 			 */
 			ssleep(1);
 		}
-		ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETID);
-		error = synaptics_detect(psmouse, 0);
+		if (priv->transparent_mode) {
+			error = synaptics_enter_transparent_mode(psmouse);
+			if (!error)
+				return 0;
+		}
+		else {
+			ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETID);
+			error = synaptics_detect(psmouse, 0);
+		}
 	} while (error && ++retry < 3);
 
 	if (error)
@@ -1552,6 +1684,45 @@ void __init synaptics_module_init(void)
 	cr48_profile_sensor = dmi_check_system(cr48_dmi_table);
 }
 
+static void synaptics_update_protocol_handler(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	struct serio *pt_port = priv->pt_port;
+
+	bool absolute_mode = priv->absolute_mode;
+	bool transparent_mode = priv->transparent_mode;
+
+	if (transparent_mode && pt_port) {
+		psmouse->protocol_handler = transparent_process_byte;
+	}
+	else {
+		if (absolute_mode) {
+			psmouse->protocol_handler = synaptics_process_byte;
+			psmouse->pktsize = 6;
+		} else {
+			/* Relative mode follows standard PS/2 mouse protocol */
+			psmouse->protocol_handler = psmouse_process_byte;
+			psmouse->pktsize = 3;
+		}
+	}
+}
+
+static void pamouse_handle_spontaneous_reset(struct work_struct *work)
+{
+	struct synaptics_data *priv = container_of(work, struct synaptics_data, reset_work.work);
+	struct psmouse *child = serio_get_drvdata(priv->pt_port);
+	struct psmouse *psmouse;
+
+	if (!child || !child->ps2dev.serio->parent)
+		return;
+
+	psmouse = serio_get_drvdata(child->ps2dev.serio->parent);
+	if (psmouse) {
+		psmouse_err(psmouse, "spontaneous reset detected, reconnecting\n");
+		serio_reconnect(psmouse->ps2dev.serio);
+	}
+}
+
 static int synaptics_init_ps2(struct psmouse *psmouse,
 			      struct synaptics_device_info *info,
 			      bool absolute_mode)
@@ -1570,6 +1741,8 @@ static int synaptics_init_ps2(struct psmouse *psmouse,
 	if (SYN_ID_DISGEST_SUPPORTED(info->identity))
 		priv->disable_gesture = true;
 
+	INIT_DELAYED_WORK(&priv->reset_work, pamouse_handle_spontaneous_reset);
+
 	/*
 	 * Unfortunately ForcePad capability is not exported over PS/2,
 	 * so we have to resort to checking PNP IDs.
@@ -1610,14 +1783,7 @@ static int synaptics_init_ps2(struct psmouse *psmouse,
 	psmouse->model = ((info->model_id & 0x00ff0000) >> 8) |
 			  (info->model_id & 0x000000ff);
 
-	if (absolute_mode) {
-		psmouse->protocol_handler = synaptics_process_byte;
-		psmouse->pktsize = 6;
-	} else {
-		/* Relative mode follows standard PS/2 mouse protocol */
-		psmouse->protocol_handler = psmouse_process_byte;
-		psmouse->pktsize = 3;
-	}
+	synaptics_update_protocol_handler(psmouse);
 
 	psmouse->set_rate = synaptics_set_rate;
 	psmouse->disconnect = synaptics_disconnect;
@@ -1652,6 +1818,24 @@ static int synaptics_init_ps2(struct psmouse *psmouse,
 		}
 	}
 
+	if (SYN_CAP_PASS_THROUGH(info->capabilities)) {
+		err = device_create_file(&psmouse->ps2dev.serio->dev,
+					 &psmouse_attr_transparent_mode.dattr);
+		if (err) {
+			psmouse_err(psmouse,
+				    "Failed to create transparent_mode attribute (%d)",
+				    err);
+			goto init_fail;
+		}
+
+		if (synaptics_ps2_transparent_mode) {
+			priv->transparent_mode = true;
+			synaptics_update_protocol_handler(psmouse);
+			synaptics_enter_transparent_mode(psmouse);
+		}
+	}
+
+
 	return 0;
 
  init_fail:
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 08533d1b1..1a33d65fa 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -24,6 +24,7 @@
 /* synatics modes */
 #define SYN_BIT_ABSOLUTE_MODE		BIT(7)
 #define SYN_BIT_HIGH_RATE		BIT(6)
+#define SYN_BIT_TRANSPARENT_MODE	BIT(5)
 #define SYN_BIT_SLEEP_MODE		BIT(3)
 #define SYN_BIT_DISABLE_GESTURE		BIT(2)
 #define SYN_BIT_FOUR_BYTE_CLIENT	BIT(1)
@@ -186,8 +187,10 @@ struct synaptics_data {
 
 	bool absolute_mode;			/* run in Absolute mode */
 	bool disable_gesture;			/* disable gestures */
+	bool transparent_mode;			/* pass packets directly from guest */
 
 	struct serio *pt_port;			/* Pass-through serio port */
+	struct delayed_work reset_work;		/* Initiate device reset */
 
 	/*
 	 * Last received Advanced Gesture Mode (AGM) packet. An AGM packet
