linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Vicki Pfau <vi@endrift.com>
To: linux-input@vger.kernel.org
Cc: Roderick Colenbrander <roderick.colenbrander@sony.com>,
	Jiri Kosina <jikos@kernel.org>,
	Benjamin Tissoires <benjamin.tissoires@redhat.com>,
	Dmitry Torokhov <dmitry.torokhov@gmail.com>,
	Vicki Pfau <vi@endrift.com>
Subject: [PATCH 4/6] HID: hid-sony: Allow removal of touchpad
Date: Wed, 27 Apr 2022 15:45:24 -0700	[thread overview]
Message-ID: <20220427224526.35657-4-vi@endrift.com> (raw)
In-Reply-To: <20220427224526.35657-1-vi@endrift.com>

This allows the touchpad input_dev to be removed and have the driver remain
functional without its presence. This will be used to allow the touchpad to
be disabled, e.g. by a module parameter.

Signed-off-by: Vicki Pfau <vi@endrift.com>
---
 drivers/hid/hid-sony.c | 163 +++++++++++++++++++++++++++--------------
 1 file changed, 110 insertions(+), 53 deletions(-)

diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 8319b0ce385a..1c347b3ca992 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -39,6 +39,7 @@
 #include <linux/crc32.h>
 #include <linux/usb.h>
 #include <linux/timer.h>
+#include <linux/rcupdate.h>
 #include <asm/unaligned.h>
 
 #include "hid-ids.h"
@@ -556,7 +557,7 @@ struct sony_sc {
 	spinlock_t lock;
 	struct list_head list_node;
 	struct hid_device *hdev;
-	struct input_dev *touchpad;
+	struct input_dev __rcu *touchpad;
 	struct input_dev *sensor_dev;
 	struct led_classdev *leds[MAX_LEDS];
 	unsigned long quirks;
@@ -565,6 +566,7 @@ struct sony_sc {
 	void (*send_output_report)(struct sony_sc *);
 	struct power_supply *battery;
 	struct power_supply_desc battery_desc;
+	struct mutex mutex;
 	int device_id;
 	unsigned fw_version;
 	bool fw_version_created;
@@ -1041,6 +1043,7 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size)
 	struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
 						struct hid_input, list);
 	struct input_dev *input_dev = hidinput->input;
+	struct input_dev *touchpad = NULL;
 	unsigned long flags;
 	int n, m, offset, num_touch_data, max_touch_data;
 	u8 cable_state, battery_capacity;
@@ -1050,9 +1053,15 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size)
 	/* When using Bluetooth the header is 2 bytes longer, so skip these. */
 	int data_offset = (sc->quirks & DUALSHOCK4_CONTROLLER_BT) ? 2 : 0;
 
+	rcu_read_lock();
+	touchpad = rcu_dereference(sc->touchpad);
+	rcu_read_unlock();
+
 	/* Second bit of third button byte is for the touchpad button. */
-	offset = data_offset + DS4_INPUT_REPORT_BUTTON_OFFSET;
-	input_report_key(sc->touchpad, BTN_LEFT, rd[offset+2] & 0x2);
+	if (touchpad) {
+		offset = data_offset + DS4_INPUT_REPORT_BUTTON_OFFSET;
+		input_report_key(touchpad, BTN_LEFT, rd[offset+2] & 0x2);
+	}
 
 	/*
 	 * The default behavior of the Dualshock 4 is to send reports using
@@ -1197,6 +1206,9 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size)
 	sc->battery_status = battery_status;
 	spin_unlock_irqrestore(&sc->lock, flags);
 
+	if (!touchpad)
+		return;
+
 	/*
 	 * The Dualshock 4 multi-touch trackpad data starts at offset 33 on USB
 	 * and 35 on Bluetooth.
@@ -1231,24 +1243,25 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size)
 			y = ((rd[offset+2] & 0xF0) >> 4) | (rd[offset+3] << 4);
 
 			active = !(rd[offset] >> 7);
-			input_mt_slot(sc->touchpad, n);
-			input_mt_report_slot_state(sc->touchpad, MT_TOOL_FINGER, active);
+			input_mt_slot(touchpad, n);
+			input_mt_report_slot_state(touchpad, MT_TOOL_FINGER, active);
 
 			if (active) {
-				input_report_abs(sc->touchpad, ABS_MT_POSITION_X, x);
-				input_report_abs(sc->touchpad, ABS_MT_POSITION_Y, y);
+				input_report_abs(touchpad, ABS_MT_POSITION_X, x);
+				input_report_abs(touchpad, ABS_MT_POSITION_Y, y);
 			}
 
 			offset += 4;
 		}
-		input_mt_sync_frame(sc->touchpad);
-		input_sync(sc->touchpad);
+		input_mt_sync_frame(touchpad);
+		input_sync(touchpad);
 	}
 }
 
 static void nsg_mrxu_parse_report(struct sony_sc *sc, u8 *rd, int size)
 {
 	int n, offset, relx, rely;
+	struct input_dev *touchpad;
 	u8 active;
 
 	/*
@@ -1271,7 +1284,13 @@ static void nsg_mrxu_parse_report(struct sony_sc *sc, u8 *rd, int size)
 	 */
 	offset = 1;
 
-	input_report_key(sc->touchpad, BTN_LEFT, rd[offset] & 0x0F);
+	rcu_read_lock();
+	touchpad = rcu_dereference(sc->touchpad);
+	rcu_read_unlock();
+	if (!touchpad)
+		return;
+
+	input_report_key(touchpad, BTN_LEFT, rd[offset] & 0x0F);
 	active = (rd[offset] >> 4);
 	relx = (s8) rd[offset+5];
 	rely = ((s8) rd[offset+10]) * -1;
@@ -1285,20 +1304,20 @@ static void nsg_mrxu_parse_report(struct sony_sc *sc, u8 *rd, int size)
 		x = rd[offset] | ((rd[offset+1] & 0x0F) << 8);
 		y = ((rd[offset+1] & 0xF0) >> 4) | (rd[offset+2] << 4);
 
-		input_mt_slot(sc->touchpad, n);
-		input_mt_report_slot_state(sc->touchpad, MT_TOOL_FINGER, active & 0x03);
+		input_mt_slot(touchpad, n);
+		input_mt_report_slot_state(touchpad, MT_TOOL_FINGER, active & 0x03);
 
 		if (active & 0x03) {
 			contactx = rd[offset+3] & 0x0F;
 			contacty = rd[offset+3] >> 4;
-			input_report_abs(sc->touchpad, ABS_MT_TOUCH_MAJOR,
+			input_report_abs(touchpad, ABS_MT_TOUCH_MAJOR,
 				max(contactx, contacty));
-			input_report_abs(sc->touchpad, ABS_MT_TOUCH_MINOR,
+			input_report_abs(touchpad, ABS_MT_TOUCH_MINOR,
 				min(contactx, contacty));
-			input_report_abs(sc->touchpad, ABS_MT_ORIENTATION,
+			input_report_abs(touchpad, ABS_MT_ORIENTATION,
 				(bool) (contactx > contacty));
-			input_report_abs(sc->touchpad, ABS_MT_POSITION_X, x);
-			input_report_abs(sc->touchpad, ABS_MT_POSITION_Y,
+			input_report_abs(touchpad, ABS_MT_POSITION_X, x);
+			input_report_abs(touchpad, ABS_MT_POSITION_Y,
 				NSG_MRXU_MAX_Y - y);
 			/*
 			 * The relative coordinates belong to the first touch
@@ -1306,8 +1325,8 @@ static void nsg_mrxu_parse_report(struct sony_sc *sc, u8 *rd, int size)
 			 * when the first is not active.
 			 */
 			if ((n == 0) || ((n == 1) && (active & 0x01))) {
-				input_report_rel(sc->touchpad, REL_X, relx);
-				input_report_rel(sc->touchpad, REL_Y, rely);
+				input_report_rel(touchpad, REL_X, relx);
+				input_report_rel(touchpad, REL_Y, rely);
 			}
 		}
 
@@ -1315,9 +1334,9 @@ static void nsg_mrxu_parse_report(struct sony_sc *sc, u8 *rd, int size)
 		active >>= 2;
 	}
 
-	input_mt_sync_frame(sc->touchpad);
+	input_mt_sync_frame(touchpad);
 
-	input_sync(sc->touchpad);
+	input_sync(touchpad);
 }
 
 static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
@@ -1496,19 +1515,20 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
 	size_t name_sz;
 	char *name;
 	int ret;
+	struct input_dev *touchpad;
 
-	sc->touchpad = devm_input_allocate_device(&sc->hdev->dev);
-	if (!sc->touchpad)
+	touchpad = devm_input_allocate_device(&sc->hdev->dev);
+	if (!touchpad)
 		return -ENOMEM;
 
-	input_set_drvdata(sc->touchpad, sc);
-	sc->touchpad->dev.parent = &sc->hdev->dev;
-	sc->touchpad->phys = sc->hdev->phys;
-	sc->touchpad->uniq = sc->hdev->uniq;
-	sc->touchpad->id.bustype = sc->hdev->bus;
-	sc->touchpad->id.vendor = sc->hdev->vendor;
-	sc->touchpad->id.product = sc->hdev->product;
-	sc->touchpad->id.version = sc->hdev->version;
+	input_set_drvdata(touchpad, sc);
+	touchpad->dev.parent = &sc->hdev->dev;
+	touchpad->phys = sc->hdev->phys;
+	touchpad->uniq = sc->hdev->uniq;
+	touchpad->id.bustype = sc->hdev->bus;
+	touchpad->id.vendor = sc->hdev->vendor;
+	touchpad->id.product = sc->hdev->product;
+	touchpad->id.version = sc->hdev->version;
 
 	/* Append a suffix to the controller name as there are various
 	 * DS4 compatible non-Sony devices with different names.
@@ -1518,39 +1538,41 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
 	if (!name)
 		return -ENOMEM;
 	snprintf(name, name_sz, "%s" DS4_TOUCHPAD_SUFFIX, sc->hdev->name);
-	sc->touchpad->name = name;
+	touchpad->name = name;
 
 	/* We map the button underneath the touchpad to BTN_LEFT. */
-	__set_bit(EV_KEY, sc->touchpad->evbit);
-	__set_bit(BTN_LEFT, sc->touchpad->keybit);
-	__set_bit(INPUT_PROP_BUTTONPAD, sc->touchpad->propbit);
+	__set_bit(EV_KEY, touchpad->evbit);
+	__set_bit(BTN_LEFT, touchpad->keybit);
+	__set_bit(INPUT_PROP_BUTTONPAD, touchpad->propbit);
 
-	input_set_abs_params(sc->touchpad, ABS_MT_POSITION_X, 0, w, 0, 0);
-	input_set_abs_params(sc->touchpad, ABS_MT_POSITION_Y, 0, h, 0, 0);
+	input_set_abs_params(touchpad, ABS_MT_POSITION_X, 0, w, 0, 0);
+	input_set_abs_params(touchpad, ABS_MT_POSITION_Y, 0, h, 0, 0);
 
 	if (touch_major > 0) {
-		input_set_abs_params(sc->touchpad, ABS_MT_TOUCH_MAJOR, 
+		input_set_abs_params(touchpad, ABS_MT_TOUCH_MAJOR, 
 			0, touch_major, 0, 0);
 		if (touch_minor > 0)
-			input_set_abs_params(sc->touchpad, ABS_MT_TOUCH_MINOR, 
+			input_set_abs_params(touchpad, ABS_MT_TOUCH_MINOR, 
 				0, touch_minor, 0, 0);
 		if (orientation > 0)
-			input_set_abs_params(sc->touchpad, ABS_MT_ORIENTATION, 
+			input_set_abs_params(touchpad, ABS_MT_ORIENTATION, 
 				0, orientation, 0, 0);
 	}
 
 	if (sc->quirks & NSG_MRXU_REMOTE) {
-		__set_bit(EV_REL, sc->touchpad->evbit);
+		__set_bit(EV_REL, touchpad->evbit);
 	}
 
-	ret = input_mt_init_slots(sc->touchpad, touch_count, INPUT_MT_POINTER);
+	ret = input_mt_init_slots(touchpad, touch_count, INPUT_MT_POINTER);
 	if (ret < 0)
 		return ret;
 
-	ret = input_register_device(sc->touchpad);
+	ret = input_register_device(touchpad);
 	if (ret < 0)
 		return ret;
 
+	rcu_assign_pointer(sc->touchpad, touchpad);
+
 	return 0;
 }
 
@@ -1627,6 +1649,48 @@ static int sony_register_sensors(struct sony_sc *sc)
 	return 0;
 }
 
+static void sony_unregister_touchpad(struct sony_sc *sc)
+{
+	struct input_dev *touchpad;
+
+	rcu_read_lock();
+	touchpad = rcu_dereference(sc->touchpad);
+	rcu_read_unlock();
+
+	if (!touchpad)
+		return;
+
+	RCU_INIT_POINTER(sc->touchpad, NULL);
+	synchronize_rcu();
+	input_unregister_device(touchpad);
+}
+
+static int sony_register_ds4_touchpad(struct sony_sc *sc)
+{
+	struct input_dev *touchpad;
+	int ret;
+
+	rcu_read_lock();
+	touchpad = rcu_dereference(sc->touchpad);
+	rcu_read_unlock();
+
+	if (touchpad)
+		return 0;
+
+	/*
+	 * The Dualshock 4 touchpad supports 2 touches and has a
+	 * resolution of 1920x942 (44.86 dots/mm).
+	 */
+	ret = sony_register_touchpad(sc, 2, 1920, 942, 0, 0, 0);
+	if (ret) {
+		hid_err(sc->hdev,
+		"Unable to initialize multi-touch slots: %d\n",
+		ret);
+	}
+
+	return ret;
+}
+
 /*
  * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
  * to "operational".  Without this, the ps3 controller will not report any
@@ -2876,17 +2940,9 @@ static int sony_input_configured(struct hid_device *hdev,
 		}
 		sc->hw_version_created = true;
 
-		/*
-		 * The Dualshock 4 touchpad supports 2 touches and has a
-		 * resolution of 1920x942 (44.86 dots/mm).
-		 */
-		ret = sony_register_touchpad(sc, 2, 1920, 942, 0, 0, 0);
-		if (ret) {
-			hid_err(sc->hdev,
-			"Unable to initialize multi-touch slots: %d\n",
-			ret);
+		ret = sony_register_ds4_touchpad(sc);
+		if (ret)
 			goto err_stop;
-		}
 
 		ret = sony_register_sensors(sc);
 		if (ret) {
@@ -2996,6 +3052,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	}
 
 	spin_lock_init(&sc->lock);
+	mutex_init(&sc->mutex);
 
 	sc->quirks = quirks;
 	hid_set_drvdata(hdev, sc);
-- 
2.36.0


  parent reply	other threads:[~2022-04-27 22:46 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-27 22:45 [PATCH 1/6] HID: hid-playstation: Allow removal of touchpad Vicki Pfau
2022-04-27 22:45 ` [PATCH 2/6] HID: hid-playstation: Add touchpad_mouse param Vicki Pfau
2022-05-05  8:52   ` Benjamin Tissoires
2022-05-05 22:00     ` Vicki Pfau
2022-04-27 22:45 ` [PATCH 3/6] HID: hid-playstation: Disable touchpad reporting when hidraw open Vicki Pfau
2022-05-05  8:57   ` Benjamin Tissoires
2022-05-05 22:03     ` Vicki Pfau
2022-05-06  6:00       ` Roderick Colenbrander
2022-05-06  6:54         ` Benjamin Tissoires
2022-05-06  6:57       ` Benjamin Tissoires
2022-04-27 22:45 ` Vicki Pfau [this message]
2022-04-27 22:45 ` [PATCH 5/6] HID: hid-sony: Add touchpad_mouse param Vicki Pfau
2022-04-27 22:45 ` [PATCH 6/6] HID: hid-sony: Disable touchpad reporting when hidraw open Vicki Pfau
2022-05-05  8:50 ` [PATCH 1/6] HID: hid-playstation: Allow removal of touchpad Benjamin Tissoires
2022-05-05 16:55   ` Dmitry Torokhov
2022-05-06  5:21     ` Roderick Colenbrander
2022-05-06  6:46       ` Vicki Pfau
2022-05-06  6:59     ` Roderick Colenbrander
2022-05-06  8:23       ` Benjamin Tissoires
2022-05-05 21:57   ` Vicki Pfau

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220427224526.35657-4-vi@endrift.com \
    --to=vi@endrift.com \
    --cc=benjamin.tissoires@redhat.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=jikos@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=roderick.colenbrander@sony.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).