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
next prev 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).