From patchwork Wed Apr 27 22:45:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vicki Pfau X-Patchwork-Id: 569155 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 50D91C433F5 for ; Wed, 27 Apr 2022 22:46:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233652AbiD0WtV (ORCPT ); Wed, 27 Apr 2022 18:49:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48178 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233828AbiD0WtT (ORCPT ); Wed, 27 Apr 2022 18:49:19 -0400 Received: from endrift.com (endrift.com [173.255.198.10]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7D65D2C13B for ; Wed, 27 Apr 2022 15:46:07 -0700 (PDT) Received: from localhost.localdomain (unknown [50.106.20.54]) by endrift.com (Postfix) with ESMTPSA id 3EBD2A1E6; Wed, 27 Apr 2022 15:46:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=endrift.com; s=2020; t=1651099566; bh=0eKaw8XAkNEXzVJE+7PSO5iBS8o1os/X4wo9arSo0Vk=; h=From:To:Cc:Subject:Date:From; b=EbfqHbB6j+vlD28Opw/jq8CaQfpvDhWtfC9GBXJa654BhE7VY77jTQuN2pjFjMrOC uJ+tYtGWxzbDhjwGf4AGrcyplCATINXrCKNu2loOty9V6WJVPfcj7ugUC6jfvst0LO eXuXcm0h2cBzitIuRBpxkFkV2pkkf/mgjTSEZ0vJp5AhL9+wAu/ms1TurjFQs4JnWt qAHqvBnxTVSkKrM//FXiJXH68VoazynLHBgOC6WQh8qu9fVDX9UcVASpVyZy7kS+xh IMd8TBZ/jd1zg8om4CxABXrieG3VzXpKvdoMLHX0omtm2XzgoqFV+PCJIkXDSmyNll EYss4bAzQn9qg== From: Vicki Pfau To: linux-input@vger.kernel.org Cc: Roderick Colenbrander , Jiri Kosina , Benjamin Tissoires , Dmitry Torokhov , Vicki Pfau Subject: [PATCH 1/6] HID: hid-playstation: Allow removal of touchpad Date: Wed, 27 Apr 2022 15:45:21 -0700 Message-Id: <20220427224526.35657-1-vi@endrift.com> X-Mailer: git-send-email 2.36.0 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org 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 --- drivers/hid/hid-playstation.c | 60 +++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index ab7c82c2e886..f859a8dd8a2e 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -29,6 +29,7 @@ static DEFINE_IDA(ps_player_id_allocator); struct ps_device { struct list_head list; struct hid_device *hdev; + struct mutex mutex; spinlock_t lock; uint32_t player_id; @@ -130,7 +131,7 @@ struct dualsense { struct ps_device base; struct input_dev *gamepad; struct input_dev *sensors; - struct input_dev *touchpad; + struct input_dev __rcu *touchpad; /* Calibration data for accelerometer and gyroscope. */ struct ps_calibration_data accel_calib_data[3]; @@ -590,6 +591,22 @@ static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width, return touchpad; } +static void dualsense_unregister_touchpad(struct dualsense *ds) +{ + struct input_dev *touchpad; + + rcu_read_lock(); + touchpad = rcu_dereference(ds->touchpad); + rcu_read_unlock(); + + if (!touchpad) + return; + + RCU_INIT_POINTER(ds->touchpad, NULL); + synchronize_rcu(); + input_unregister_device(touchpad); +} + static ssize_t firmware_version_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -888,6 +905,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r struct hid_device *hdev = ps_dev->hdev; struct dualsense *ds = container_of(ps_dev, struct dualsense, base); struct dualsense_input_report *ds_report; + struct input_dev *touchpad = NULL; uint8_t battery_data, battery_capacity, charging_status, value; int battery_status; uint32_t sensor_timestamp; @@ -1002,24 +1020,29 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r input_event(ds->sensors, EV_MSC, MSC_TIMESTAMP, ds->sensor_timestamp_us); input_sync(ds->sensors); - for (i = 0; i < ARRAY_SIZE(ds_report->points); i++) { - struct dualsense_touch_point *point = &ds_report->points[i]; - bool active = (point->contact & DS_TOUCH_POINT_INACTIVE) ? false : true; + rcu_read_lock(); + touchpad = rcu_dereference(ds->touchpad); + rcu_read_unlock(); + if (touchpad) { + for (i = 0; i < ARRAY_SIZE(ds_report->points); i++) { + struct dualsense_touch_point *point = &ds_report->points[i]; + bool active = (point->contact & DS_TOUCH_POINT_INACTIVE) ? false : true; - input_mt_slot(ds->touchpad, i); - input_mt_report_slot_state(ds->touchpad, MT_TOOL_FINGER, active); + input_mt_slot(ds->touchpad, i); + input_mt_report_slot_state(ds->touchpad, MT_TOOL_FINGER, active); - if (active) { - int x = (point->x_hi << 8) | point->x_lo; - int y = (point->y_hi << 4) | point->y_lo; + if (active) { + int x = (point->x_hi << 8) | point->x_lo; + int y = (point->y_hi << 4) | point->y_lo; - input_report_abs(ds->touchpad, ABS_MT_POSITION_X, x); - input_report_abs(ds->touchpad, ABS_MT_POSITION_Y, y); + input_report_abs(ds->touchpad, ABS_MT_POSITION_X, x); + input_report_abs(ds->touchpad, ABS_MT_POSITION_Y, y); + } } + input_mt_sync_frame(ds->touchpad); + input_report_key(ds->touchpad, BTN_LEFT, ds_report->buttons[2] & DS_BUTTONS2_TOUCHPAD); + input_sync(ds->touchpad); } - input_mt_sync_frame(ds->touchpad); - input_report_key(ds->touchpad, BTN_LEFT, ds_report->buttons[2] & DS_BUTTONS2_TOUCHPAD); - input_sync(ds->touchpad); battery_data = ds_report->status & DS_STATUS_BATTERY_CAPACITY; charging_status = (ds_report->status & DS_STATUS_CHARGING) >> DS_STATUS_CHARGING_SHIFT; @@ -1141,6 +1164,7 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) { struct dualsense *ds; struct ps_device *ps_dev; + struct input_dev *touchpad; uint8_t max_output_report_size; int ret; @@ -1157,6 +1181,7 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) ps_dev = &ds->base; ps_dev->hdev = hdev; spin_lock_init(&ps_dev->lock); + mutex_init(&ps_dev->mutex); ps_dev->battery_capacity = 100; /* initial value until parse_report. */ ps_dev->battery_status = POWER_SUPPLY_STATUS_UNKNOWN; ps_dev->parse_report = dualsense_parse_report; @@ -1204,11 +1229,12 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) goto err; } - ds->touchpad = ps_touchpad_create(hdev, DS_TOUCHPAD_WIDTH, DS_TOUCHPAD_HEIGHT, 2); - if (IS_ERR(ds->touchpad)) { - ret = PTR_ERR(ds->touchpad); + touchpad = ps_touchpad_create(hdev, DS_TOUCHPAD_WIDTH, DS_TOUCHPAD_HEIGHT, 2); + if (IS_ERR(touchpad)) { + ret = PTR_ERR(touchpad); goto err; } + rcu_assign_pointer(ds->touchpad, touchpad); ret = ps_device_register_battery(ps_dev); if (ret) From patchwork Wed Apr 27 22:45:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vicki Pfau X-Patchwork-Id: 566897 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4D740C433EF for ; Wed, 27 Apr 2022 22:46:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233828AbiD0WtV (ORCPT ); Wed, 27 Apr 2022 18:49:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47874 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235141AbiD0WtU (ORCPT ); Wed, 27 Apr 2022 18:49:20 -0400 Received: from endrift.com (endrift.com [173.255.198.10]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2088A2B269 for ; Wed, 27 Apr 2022 15:46:08 -0700 (PDT) Received: from localhost.localdomain (unknown [50.106.20.54]) by endrift.com (Postfix) with ESMTPSA id F0971A276; Wed, 27 Apr 2022 15:46:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=endrift.com; s=2020; t=1651099567; bh=Fhen1b3U4qY0y8pPJVLjOgAj2TmislX9tcDOzO998lo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=0YNXvqCduox3qiEMVfFSZ+vjv0J5vzLdbfMjjy0BXr7K0XS6VehH0xDL3q2sThOpK UwShgU0KvmSdp8mN60gXNlANxcGNlwB5pW78QbhJoVMa7+WWwbIpqUHszwJcdsCKyD KavGBXdBf/MSQF+Q43C5WnuYIgoHdZFUrUum/9awYS2xrP9UDuGADxFNrpOpRVNhZC NUaKnqch0Nv0J3313p1JLEudf0u022v0etFXg/UXTo94fuoXNerFXt0g6SWWeu5Xe1 jHWS83vVNlTu6cvHHHfcvZcJMA/0E2FjpDeyguYQUyJ8KOruDj5ltWVCfAFEmmoc2c alnIYoXI/2aMA== From: Vicki Pfau To: linux-input@vger.kernel.org Cc: Roderick Colenbrander , Jiri Kosina , Benjamin Tissoires , Dmitry Torokhov , Vicki Pfau Subject: [PATCH 2/6] HID: hid-playstation: Add touchpad_mouse param Date: Wed, 27 Apr 2022 15:45:22 -0700 Message-Id: <20220427224526.35657-2-vi@endrift.com> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20220427224526.35657-1-vi@endrift.com> References: <20220427224526.35657-1-vi@endrift.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Add parameter "touchpad_mouse" to enable disabling or re-enabling exposing the touchpad input_dev, which can be changed while the module is loaded. Signed-off-by: Vicki Pfau --- drivers/hid/hid-playstation.c | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index f859a8dd8a2e..ad0da4470615 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -23,6 +23,8 @@ static LIST_HEAD(ps_devices_list); static DEFINE_IDA(ps_player_id_allocator); +static bool touchpad_mouse = true; + #define HID_PLAYSTATION_VERSION_PATCH 0x8000 /* Base class for playstation devices. */ @@ -1343,6 +1345,45 @@ static void ps_remove(struct hid_device *hdev) hid_hw_stop(hdev); } +static int ps_param_set_touchpad_mouse(const char *val, + const struct kernel_param *kp) +{ + struct ps_device *dev; + struct dualsense *ds; + struct input_dev *touchpad; + int ret; + + ret = param_set_bool(val, kp); + if (ret) + return ret; + + mutex_lock(&ps_devices_lock); + list_for_each_entry(dev, &ps_devices_list, list) { + mutex_lock(&dev->mutex); + if (dev->hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER) { + ds = container_of(dev, struct dualsense, base); + if (touchpad_mouse) { + touchpad = ps_touchpad_create(dev->hdev, DS_TOUCHPAD_WIDTH, DS_TOUCHPAD_HEIGHT, 2); + if (IS_ERR(touchpad)) + continue; + rcu_assign_pointer(ds->touchpad, touchpad); + } else + dualsense_unregister_touchpad(ds); + } + mutex_unlock(&dev->mutex); + } + mutex_unlock(&ps_devices_lock); + return 0; +} + +static const struct kernel_param_ops ps_touchpad_mouse_ops = { + .set = ps_param_set_touchpad_mouse, + .get = param_get_bool, +}; + +module_param_cb(touchpad_mouse, &ps_touchpad_mouse_ops, &touchpad_mouse, 0644); +MODULE_PARM_DESC(touchpad_mouse, "Enable mouse emulation using the touchpad"); + static const struct hid_device_id ps_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) }, From patchwork Wed Apr 27 22:45:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vicki Pfau X-Patchwork-Id: 566896 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6F77DC433FE for ; Wed, 27 Apr 2022 22:46:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233569AbiD0WtW (ORCPT ); Wed, 27 Apr 2022 18:49:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48310 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233681AbiD0WtV (ORCPT ); Wed, 27 Apr 2022 18:49:21 -0400 Received: from endrift.com (endrift.com [173.255.198.10]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EAACA2E683 for ; Wed, 27 Apr 2022 15:46:08 -0700 (PDT) Received: from localhost.localdomain (unknown [50.106.20.54]) by endrift.com (Postfix) with ESMTPSA id A82F9A280; Wed, 27 Apr 2022 15:46:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=endrift.com; s=2020; t=1651099568; bh=p8+VYzUhmpUfHrNxOPRwhnvd7sDVJgUwT40132Cf/a0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RBSwmpHjyIJ84/qpetmzbaRxnOKFBeg3sm4pFaaZWlpCQCWzfBWXs5UEMYHCzZFRW 5Gtp4eivaBg0nnrojsBna/27By+R2TqgNtKGDHgpxWOh5/2gjlTQjXNKMYuxrwWO1T OGX6mAWMTbGRX18JJf6QxLVysDCnAehka9AOwcLNafFg/9sIjhzE3dxalyJeEQcVOo gWwM8QorMedP7nz1434Or35HXdak/Mtz5sQXw6gamNzx/ipcLquSJD7LDnXxYlzcU4 QoX32hQ9SKSOQN5uE5eBY/K4gGDdKISqQGbz9WNXVqE/wsbyhnfIQJLhwW+jpVAgWI W0CMib5xaR+Tg== From: Vicki Pfau To: linux-input@vger.kernel.org Cc: Roderick Colenbrander , Jiri Kosina , Benjamin Tissoires , Dmitry Torokhov , Vicki Pfau Subject: [PATCH 3/6] HID: hid-playstation: Disable touchpad reporting when hidraw open Date: Wed, 27 Apr 2022 15:45:23 -0700 Message-Id: <20220427224526.35657-3-vi@endrift.com> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20220427224526.35657-1-vi@endrift.com> References: <20220427224526.35657-1-vi@endrift.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org When using the hidraw node directly, disable the touchpad endpoint to prevent it from sending separate mouse-like reports. This is accomplished in the same way that the hid-steam driver does it, by creating and attaching an input_dev with a custom low-level transport driver, which monitors and reports when the hidraw node is opened or closed. Reports sent by the real device are reported to the "fake" device, and the real device is prevented from creating a hidraw node. This "fake" device is connected with only a hidraw node, and is exposed with identifying information that is identical to the original device, so the "fake" device's hidraw node appears as the node associated with the dev. Signed-off-by: Vicki Pfau --- drivers/hid/hid-playstation.c | 144 +++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index ad0da4470615..3746c9c550d6 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -30,9 +30,10 @@ static bool touchpad_mouse = true; /* Base class for playstation devices. */ struct ps_device { struct list_head list; - struct hid_device *hdev; + struct hid_device *hdev, *client_hdev; struct mutex mutex; spinlock_t lock; + bool client_opened; uint32_t player_id; @@ -643,6 +644,102 @@ static const struct attribute_group ps_device_attribute_group = { .attrs = ps_device_attributes, }; +static int ps_client_ll_parse(struct hid_device *hdev) +{ + struct ps_device *dev = hdev->driver_data; + + return hid_parse_report(hdev, dev->hdev->dev_rdesc, + dev->hdev->dev_rsize); +} + +static int ps_client_ll_start(struct hid_device *hdev) +{ + return 0; +} + +static void ps_client_ll_stop(struct hid_device *hdev) +{ +} + +static int ps_client_ll_open(struct hid_device *hdev) +{ + struct ps_device *dev = hdev->driver_data; + struct dualsense *ds; + + mutex_lock(&dev->mutex); + dev->client_opened = true; + mutex_unlock(&dev->mutex); + + if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER) { + ds = container_of(dev, struct dualsense, base); + dualsense_unregister_touchpad(ds); + } + + return 0; +} + +static void ps_client_ll_close(struct hid_device *hdev) +{ + struct ps_device *dev = hdev->driver_data; + struct dualsense *ds; + struct input_dev *touchpad; + + mutex_lock(&dev->mutex); + dev->client_opened = false; + mutex_unlock(&dev->mutex); + + if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER) { + ds = container_of(dev, struct dualsense, base); + touchpad = ps_touchpad_create(hdev, DS_TOUCHPAD_WIDTH, DS_TOUCHPAD_HEIGHT, 2); + if (IS_ERR(touchpad)) + return; + rcu_assign_pointer(ds->touchpad, touchpad); + } +} + +static int ps_client_ll_raw_request(struct hid_device *hdev, + unsigned char reportnum, u8 *buf, + size_t count, unsigned char report_type, + int reqtype) +{ + struct ps_device *dev = hdev->driver_data; + + return hid_hw_raw_request(dev->hdev, reportnum, buf, count, + report_type, reqtype); +} + +static struct hid_ll_driver ps_client_ll_driver = { + .parse = ps_client_ll_parse, + .start = ps_client_ll_start, + .stop = ps_client_ll_stop, + .open = ps_client_ll_open, + .close = ps_client_ll_close, + .raw_request = ps_client_ll_raw_request, +}; + +static struct hid_device *ps_create_client_hid(struct hid_device *hdev) +{ + struct hid_device *client_hdev; + + client_hdev = hid_allocate_device(); + if (IS_ERR(client_hdev)) + return client_hdev; + + client_hdev->ll_driver = &ps_client_ll_driver; + client_hdev->dev.parent = hdev->dev.parent; + client_hdev->bus = hdev->bus; + client_hdev->vendor = hdev->vendor; + client_hdev->product = hdev->product; + client_hdev->version = hdev->version; + client_hdev->type = hdev->type; + client_hdev->country = hdev->country; + strlcpy(client_hdev->name, hdev->name, + sizeof(client_hdev->name)); + strlcpy(client_hdev->phys, hdev->phys, + sizeof(client_hdev->phys)); + return client_hdev; +} + static int dualsense_get_calibration_data(struct dualsense *ds) { short gyro_pitch_bias, gyro_pitch_plus, gyro_pitch_minus; @@ -1190,6 +1287,11 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) INIT_WORK(&ds->output_worker, dualsense_output_worker); hid_set_drvdata(hdev, ds); + ps_dev->client_hdev = ps_create_client_hid(hdev); + if (IS_ERR(ps_dev->client_hdev)) + return ERR_CAST(ps_dev->client_hdev); + ps_dev->client_hdev->driver_data = ps_dev; + max_output_report_size = sizeof(struct dualsense_output_report_bt); ds->output_report_dmabuf = devm_kzalloc(&hdev->dev, max_output_report_size, GFP_KERNEL); if (!ds->output_report_dmabuf) @@ -1280,8 +1382,20 @@ static int ps_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { struct ps_device *dev = hid_get_drvdata(hdev); + int ret = 0; + + if (!dev) + return 0; - if (dev && dev->parse_report) + if (dev->client_opened) { + ret = hid_input_report(dev->client_hdev, HID_INPUT_REPORT, data, size, 0); + if (ret) { + hid_err(hdev, "can't send input report to client hdev: %d\n", ret); + return ret; + } + } + + if (dev->parse_report) return dev->parse_report(dev, report, data, size); return 0; @@ -1291,6 +1405,7 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct ps_device *dev; int ret; + unsigned int connect_mask = 0; ret = hid_parse(hdev); if (ret) { @@ -1298,12 +1413,22 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } - ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (hdev->ll_driver == &ps_client_ll_driver) + connect_mask = HID_CONNECT_HIDRAW; + + ret = hid_hw_start(hdev, connect_mask); if (ret) { hid_err(hdev, "Failed to start HID device\n"); return ret; } + /* + * The virtual client_dev is only used for hidraw. Since we've already + * started the hw, return early to avoid the recursive probe. + */ + if (hdev->ll_driver == &ps_client_ll_driver) + return ret; + ret = hid_hw_open(hdev); if (ret) { hid_err(hdev, "Failed to open HID device\n"); @@ -1325,9 +1450,19 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_close; } + if (dev->client_hdev) + ret = hid_add_device(dev->client_hdev); + if (ret) { + hid_err(hdev, "Failed to start client device failed\n"); + goto err_close; + } + return ret; err_close: + if (dev->client_hdev) + hid_destroy_device(dev->client_hdev); + hid_hw_close(hdev); err_stop: hid_hw_stop(hdev); @@ -1341,6 +1476,9 @@ static void ps_remove(struct hid_device *hdev) ps_devices_list_remove(dev); ps_device_release_player_id(dev); + if (dev->client_hdev) + hid_destroy_device(dev->client_hdev); + hid_hw_close(hdev); hid_hw_stop(hdev); } From patchwork Wed Apr 27 22:45:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vicki Pfau X-Patchwork-Id: 569153 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A2463C433EF for ; Wed, 27 Apr 2022 22:46:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234412AbiD0WtY (ORCPT ); Wed, 27 Apr 2022 18:49:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48370 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235178AbiD0WtW (ORCPT ); Wed, 27 Apr 2022 18:49:22 -0400 Received: from endrift.com (endrift.com [173.255.198.10]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 920562AE05 for ; Wed, 27 Apr 2022 15:46:09 -0700 (PDT) Received: from localhost.localdomain (unknown [50.106.20.54]) by endrift.com (Postfix) with ESMTPSA id 5DAA7A289; Wed, 27 Apr 2022 15:46:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=endrift.com; s=2020; t=1651099568; bh=8PTQ970/Utp5Hq6RweQvDROvSdomgPPb3BgBQZ09gYI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vCLt3hv3ZIUk/8gssrPnS0VPtJG+xKxpQKV5Kz/pTcA3lXjOHO5qlLUn2dFXGuCue ebnIRFIAzRahDxiZS2kXoqld/7jgiAA2+VA0FpaE75luauOdYBcjuLjpYNk3jis9Fy b/Ow8oZ7w+1LY70IaG3Vk+dvEFZzNqXqs7pGsfTwKx2xDxZOHhWHTwRGpiTdkcEUdN tLCyvDnP6YK+JoAm+dh1giRZTt2lByCDYYaFqm3+wHhj4MZAkGRkOP4SPJTkF5VKnf cjo4IVL2iI7A3SWma3WOfqfL881h7QAqd9Wkc87Z7WDLI3sjQFyKUa8Zy+osUo99/B orbKrzXqkpjow== From: Vicki Pfau To: linux-input@vger.kernel.org Cc: Roderick Colenbrander , Jiri Kosina , Benjamin Tissoires , Dmitry Torokhov , Vicki Pfau Subject: [PATCH 4/6] HID: hid-sony: Allow removal of touchpad Date: Wed, 27 Apr 2022 15:45:24 -0700 Message-Id: <20220427224526.35657-4-vi@endrift.com> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20220427224526.35657-1-vi@endrift.com> References: <20220427224526.35657-1-vi@endrift.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org 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 --- 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 #include #include +#include #include #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); From patchwork Wed Apr 27 22:45:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vicki Pfau X-Patchwork-Id: 569154 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0B7FDC4332F for ; Wed, 27 Apr 2022 22:46:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233681AbiD0WtX (ORCPT ); Wed, 27 Apr 2022 18:49:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48372 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235141AbiD0WtW (ORCPT ); Wed, 27 Apr 2022 18:49:22 -0400 Received: from endrift.com (endrift.com [173.255.198.10]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 485F72DA97 for ; Wed, 27 Apr 2022 15:46:10 -0700 (PDT) Received: from localhost.localdomain (unknown [50.106.20.54]) by endrift.com (Postfix) with ESMTPSA id 138E8A2F1; Wed, 27 Apr 2022 15:46:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=endrift.com; s=2020; t=1651099569; bh=3gQAL/xpHu6O84vTuq3cvacPA1PAzFm+VRTfvF7e68g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=D0+wNSYbFUhgeiK1jBxclK47ZQvYaiiCB2prhaDm/Fhz09nvX9WNp7a9xkAE3bM5p HKd2Ss+WNzR8FgnX1TfMDmI3OwyhXH0dKeqoqzV+a3ohaZJGNZsAeDIUmC0aASdhT4 O6cfk9kSKJN7MbDr/4ZsGmWiRRDIZiW1Sksbc3C5clAexzBIw5hTwWhijja/z3r9WQ EvI3RpVjNWVqgqx44pokm5Y4QrmWSrE/CzFrFGr+RGRL7TQlGyUx9SkIEVJV+df4dR G6w1x0k2eU7oCuSXKdcTVNmphNc3W950nJlVMbfP1zFy5gWV/KQc/FXhER8yMMjvBO 72umJzGExtujQ== From: Vicki Pfau To: linux-input@vger.kernel.org Cc: Roderick Colenbrander , Jiri Kosina , Benjamin Tissoires , Dmitry Torokhov , Vicki Pfau Subject: [PATCH 5/6] HID: hid-sony: Add touchpad_mouse param Date: Wed, 27 Apr 2022 15:45:25 -0700 Message-Id: <20220427224526.35657-5-vi@endrift.com> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20220427224526.35657-1-vi@endrift.com> References: <20220427224526.35657-1-vi@endrift.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Add parameter "touchpad_mouse" to enable disabling or re-enabling exposing the touchpad input_dev, which can be changed while the module is loaded. Signed-off-by: Vicki Pfau --- drivers/hid/hid-sony.c | 49 +++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 1c347b3ca992..c4ccad95ee9a 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -98,6 +98,8 @@ static const char ghl_ps3wiiu_magic_data[] = { 0x02, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static bool touchpad_mouse = true; + /* PS/3 Motion controller */ static u8 motion_rdesc[] = { 0x05, 0x01, /* Usage Page (Desktop), */ @@ -525,7 +527,7 @@ struct motion_output_report_02 { #define SIXAXIS_INPUT_REPORT_ACC_X_OFFSET 41 #define SIXAXIS_ACC_RES_PER_G 113 -static DEFINE_SPINLOCK(sony_dev_list_lock); +static DEFINE_MUTEX(sony_dev_list_lock); static LIST_HEAD(sony_device_list); static DEFINE_IDA(sony_device_id_allocator); @@ -1670,6 +1672,9 @@ static int sony_register_ds4_touchpad(struct sony_sc *sc) struct input_dev *touchpad; int ret; + if (!touchpad_mouse) + return 0; + rcu_read_lock(); touchpad = rcu_dereference(sc->touchpad); rcu_read_unlock(); @@ -2599,10 +2604,9 @@ static inline int sony_compare_connection_type(struct sony_sc *sc0, static int sony_check_add_dev_list(struct sony_sc *sc) { struct sony_sc *entry; - unsigned long flags; int ret; - spin_lock_irqsave(&sony_dev_list_lock, flags); + mutex_lock(&sony_dev_list_lock); list_for_each_entry(entry, &sony_device_list, list_node) { ret = memcmp(sc->mac_address, entry->mac_address, @@ -2624,18 +2628,16 @@ static int sony_check_add_dev_list(struct sony_sc *sc) list_add(&(sc->list_node), &sony_device_list); unlock: - spin_unlock_irqrestore(&sony_dev_list_lock, flags); + mutex_unlock(&sony_dev_list_lock); return ret; } static void sony_remove_dev_list(struct sony_sc *sc) { - unsigned long flags; - if (sc->list_node.next) { - spin_lock_irqsave(&sony_dev_list_lock, flags); + mutex_lock(&sony_dev_list_lock); list_del(&(sc->list_node)); - spin_unlock_irqrestore(&sony_dev_list_lock, flags); + mutex_unlock(&sony_dev_list_lock); } } @@ -3171,6 +3173,37 @@ static int sony_resume(struct hid_device *hdev) #endif +static int sony_param_set_touchpad_mouse(const char *val, + const struct kernel_param *kp) +{ + struct sony_sc *sc; + int ret; + + ret = param_set_bool(val, kp); + if (ret) + return ret; + + mutex_lock(&sony_dev_list_lock); + list_for_each_entry(sc, &sony_device_list, list_node) { + mutex_lock(&sc->mutex); + if (touchpad_mouse) + sony_register_ds4_touchpad(sc); + else + sony_unregister_touchpad(sc); + mutex_unlock(&sc->mutex); + } + mutex_unlock(&sony_dev_list_lock); + return 0; +} + +static const struct kernel_param_ops sony_touchpad_mouse_ops = { + .set = sony_param_set_touchpad_mouse, + .get = param_get_bool, +}; + +module_param_cb(touchpad_mouse, &sony_touchpad_mouse_ops, &touchpad_mouse, 0644); +MODULE_PARM_DESC(touchpad_mouse, "Enable mouse emulation using the touchpad"); + static const struct hid_device_id sony_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB }, From patchwork Wed Apr 27 22:45:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vicki Pfau X-Patchwork-Id: 566895 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69C56C433F5 for ; Wed, 27 Apr 2022 22:46:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234902AbiD0WtY (ORCPT ); Wed, 27 Apr 2022 18:49:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48428 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236689AbiD0WtX (ORCPT ); Wed, 27 Apr 2022 18:49:23 -0400 Received: from endrift.com (endrift.com [173.255.198.10]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EF18A3135A for ; Wed, 27 Apr 2022 15:46:10 -0700 (PDT) Received: from localhost.localdomain (unknown [50.106.20.54]) by endrift.com (Postfix) with ESMTPSA id BF4C6A302; Wed, 27 Apr 2022 15:46:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=endrift.com; s=2020; t=1651099570; bh=ImZAmCXXztV7HcGmpYwrljAL1R5jTQeW8QMrlzqz3x0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bFr+6Toe2ioXRT4Yy6HHQwf+UeLy0SrMZjCG7A4W+NYeXt1wc8YDn0WeHJI2P6AM3 O/CnGN2L9czJ4iw7JGAKi5ulMyrsUvg1IAA7qAsWmYuf4wjMcO3PFjxueWWyMbhp/G SjEX4+UjERfZhv7P+XATQ5FGUrend7drl3URLVlvjCZP7N8lN0s4J6GyJS8MnctPnM J0/F55LWOZcbauY9RS2p+l7WlNsxkb4r4fl2uwRFJV9Ymx8GZyDiIdmOPqNneJIlsY bnfP0yu3ICeO7oe8gNHATSbt69wjt8GGHluzaVsoLlWtNOoZoHaS2y79Ch5c1hnuzz 1Bk5yMAAfVFYQ== From: Vicki Pfau To: linux-input@vger.kernel.org Cc: Roderick Colenbrander , Jiri Kosina , Benjamin Tissoires , Dmitry Torokhov , Vicki Pfau Subject: [PATCH 6/6] HID: hid-sony: Disable touchpad reporting when hidraw open Date: Wed, 27 Apr 2022 15:45:26 -0700 Message-Id: <20220427224526.35657-6-vi@endrift.com> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20220427224526.35657-1-vi@endrift.com> References: <20220427224526.35657-1-vi@endrift.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org When using the hidraw node directly, disable the touchpad endpoint to prevent it from sending separate mouse-like reports. This is accomplished in the same way that the hid-steam driver does it, by creating and attaching an input_dev with a custom low-level transport driver, which monitors and reports when the hidraw node is opened or closed. Reports sent by the real device are reported to the "fake" device, and the real device is prevented from creating a hidraw node. This "fake" device is connected with only a hidraw node, and is exposed with identifying information that is identical to the original device, so the "fake" device's hidraw node appears as the node associated with the dev. Signed-off-by: Vicki Pfau --- drivers/hid/hid-sony.c | 167 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 155 insertions(+), 12 deletions(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index c4ccad95ee9a..5b6f1e5ae8db 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -457,6 +457,8 @@ static enum power_supply_property sony_battery_props[] = { POWER_SUPPLY_PROP_STATUS, }; +static struct hid_ll_driver sony_client_ll_driver; + struct sixaxis_led { u8 time_enabled; /* the total time the led is active (0xff means forever) */ u8 duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */ @@ -558,7 +560,7 @@ enum sony_worker { struct sony_sc { spinlock_t lock; struct list_head list_node; - struct hid_device *hdev; + struct hid_device *hdev, *client_hdev; struct input_dev __rcu *touchpad; struct input_dev *sensor_dev; struct led_classdev *leds[MAX_LEDS]; @@ -569,6 +571,7 @@ struct sony_sc { struct power_supply *battery; struct power_supply_desc battery_desc; struct mutex mutex; + bool client_opened; int device_id; unsigned fw_version; bool fw_version_created; @@ -947,7 +950,7 @@ static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc, { struct sony_sc *sc = hid_get_drvdata(hdev); - if (sc->quirks & (SINO_LITE_CONTROLLER | FUTUREMAX_DANCE_MAT)) + if (!sc || (sc->quirks & (SINO_LITE_CONTROLLER | FUTUREMAX_DANCE_MAT))) return rdesc; /* @@ -1345,6 +1348,22 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *rd, int size) { struct sony_sc *sc = hid_get_drvdata(hdev); + int ret; + + /* + * Check if we're the client hdev, which is only used for a separate + * hidraw device. If so, there's nothing to be done here. + */ + if (hdev->ll_driver == &sony_client_ll_driver) + return 0; + + if (sc->client_opened) { + ret = hid_input_report(sc->client_hdev, HID_INPUT_REPORT, rd, size, 0); + if (ret) { + hid_err(hdev, "can't send input report to client hdev: %d\n", ret); + return ret; + } + } /* * Sixaxis HID report has acclerometers/gyro with MSByte first, this @@ -3034,6 +3053,92 @@ static int sony_input_configured(struct hid_device *hdev, return ret; } +static int sony_client_ll_parse(struct hid_device *hdev) +{ + struct sony_sc *sc = hdev->driver_data; + + return hid_parse_report(hdev, sc->hdev->dev_rdesc, + sc->hdev->dev_rsize); +} + +static int sony_client_ll_start(struct hid_device *hdev) +{ + return 0; +} + +static void sony_client_ll_stop(struct hid_device *hdev) +{ +} + +static int sony_client_ll_open(struct hid_device *hdev) +{ + struct sony_sc *sc = hdev->driver_data; + + mutex_lock(&sc->mutex); + sc->client_opened = true; + mutex_unlock(&sc->mutex); + + if (sc->quirks & DUALSHOCK4_CONTROLLER) + sony_unregister_touchpad(sc); + + return 0; +} + +static void sony_client_ll_close(struct hid_device *hdev) +{ + struct sony_sc *sc = hdev->driver_data; + + mutex_lock(&sc->mutex); + sc->client_opened = false; + mutex_unlock(&sc->mutex); + + if (sc->quirks & DUALSHOCK4_CONTROLLER) + sony_register_ds4_touchpad(sc); +} + +static int sony_client_ll_raw_request(struct hid_device *hdev, + unsigned char reportnum, u8 *buf, + size_t count, unsigned char report_type, + int reqtype) +{ + struct sony_sc *sc = hdev->driver_data; + + return hid_hw_raw_request(sc->hdev, reportnum, buf, count, + report_type, reqtype); +} + +static struct hid_ll_driver sony_client_ll_driver = { + .parse = sony_client_ll_parse, + .start = sony_client_ll_start, + .stop = sony_client_ll_stop, + .open = sony_client_ll_open, + .close = sony_client_ll_close, + .raw_request = sony_client_ll_raw_request, +}; + +static struct hid_device *sony_create_client_hid(struct hid_device *hdev) +{ + struct hid_device *client_hdev; + + client_hdev = hid_allocate_device(); + if (IS_ERR(client_hdev)) + return client_hdev; + + client_hdev->ll_driver = &sony_client_ll_driver; + client_hdev->dev.parent = hdev->dev.parent; + client_hdev->bus = hdev->bus; + client_hdev->vendor = hdev->vendor; + client_hdev->product = hdev->product; + client_hdev->version = hdev->version; + client_hdev->type = hdev->type; + client_hdev->country = hdev->country; + strlcpy(client_hdev->name, hdev->name, + sizeof(client_hdev->name)); + strlcpy(client_hdev->phys, hdev->phys, + sizeof(client_hdev->phys)); + return client_hdev; +} + static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; @@ -3041,6 +3146,19 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) struct sony_sc *sc; unsigned int connect_mask = HID_CONNECT_DEFAULT; + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + return ret; + } + + /* + * The virtual client_dev is only used for hidraw. + * Also avoid the recursive probe. + */ + if (hdev->ll_driver == &sony_client_ll_driver) + return hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (!strcmp(hdev->name, "FutureMax Dance Mat")) quirks |= FUTUREMAX_DANCE_MAT; @@ -3060,12 +3178,6 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) hid_set_drvdata(hdev, sc); sc->hdev = hdev; - ret = hid_parse(hdev); - if (ret) { - hid_err(hdev, "parse failed\n"); - return ret; - } - if (sc->quirks & VAIO_RDESC_CONSTANT) connect_mask |= HID_CONNECT_HIDDEV_FORCE; else if (sc->quirks & SIXAXIS_CONTROLLER) @@ -3080,12 +3192,32 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) if (sc->quirks & (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)) hdev->version |= 0x8000; + /* For DualShock 4 controllers, we create a client_hid device so that + * we can tell when it's been opened directly and disable the touchpad + * from being used as a mouse at the same time. + */ + if (sc->quirks & DUALSHOCK4_CONTROLLER) { + connect_mask &= ~HID_CONNECT_HIDRAW; + sc->client_hdev = sony_create_client_hid(hdev); + if (IS_ERR(sc->client_hdev)) + return PTR_ERR(sc->client_hdev); + sc->client_hdev->driver_data = sc; + } + ret = hid_hw_start(hdev, connect_mask); if (ret) { hid_err(hdev, "hw start failed\n"); return ret; } + if (sc->client_hdev) + ret = hid_add_device(sc->client_hdev); + if (ret) { + hid_err(hdev, "client hw start failed\n"); + hid_hw_stop(hdev); + return ret; + } + /* sony_input_configured can fail, but this doesn't result * in hid_hw_start failures (intended). Check whether * the HID layer claimed the device else fail. @@ -3096,6 +3228,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) */ if (!(hdev->claimed & HID_CLAIMED_INPUT)) { hid_err(hdev, "failed to claim input\n"); + if (sc->client_hdev) + hid_destroy_device(sc->client_hdev); hid_hw_stop(hdev); return -ENODEV; } @@ -3113,6 +3247,13 @@ static void sony_remove(struct hid_device *hdev) { struct sony_sc *sc = hid_get_drvdata(hdev); + if (!sc || hdev->ll_driver == &sony_client_ll_driver) { + hid_hw_stop(hdev); + return; + } + if (sc->client_hdev) + hid_destroy_device(sc->client_hdev); + if (sc->quirks & GHL_GUITAR_PS3WIIU) del_timer_sync(&sc->ghl_poke_timer); @@ -3186,10 +3327,12 @@ static int sony_param_set_touchpad_mouse(const char *val, mutex_lock(&sony_dev_list_lock); list_for_each_entry(sc, &sony_device_list, list_node) { mutex_lock(&sc->mutex); - if (touchpad_mouse) - sony_register_ds4_touchpad(sc); - else - sony_unregister_touchpad(sc); + if (!sc->client_opened) { + if (touchpad_mouse) + sony_register_ds4_touchpad(sc); + else + sony_unregister_touchpad(sc); + } mutex_unlock(&sc->mutex); } mutex_unlock(&sony_dev_list_lock);