From patchwork Mon Feb 15 00:45:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roderick Colenbrander X-Patchwork-Id: 383087 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 764D8C433E9 for ; Mon, 15 Feb 2021 00:46:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3EAE364E52 for ; Mon, 15 Feb 2021 00:46:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229948AbhBOAqo (ORCPT ); Sun, 14 Feb 2021 19:46:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47620 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229875AbhBOAqm (ORCPT ); Sun, 14 Feb 2021 19:46:42 -0500 Received: from mail-pl1-x635.google.com (mail-pl1-x635.google.com [IPv6:2607:f8b0:4864:20::635]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2856FC061786 for ; Sun, 14 Feb 2021 16:46:02 -0800 (PST) Received: by mail-pl1-x635.google.com with SMTP id b8so2777251plh.12 for ; Sun, 14 Feb 2021 16:46:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gaikai-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=uzBte6r7kxC0wtPH+qtBYHjK6eZ3c0NP6i9Dj0b96+Q=; b=lF5c4f2pMgf1p6UtuUxjSHLpmt4qHykUTcaRn6LkiWznxiykIzCKjfJ1plM0elUwKW oW3TDj3Z9Pv6Ut4tJI7gyfOoRLItYGEgr4+6zWGwmmFCJd1sbAsvCpMZ6XrWeYR4geqe Bax4U4i6Vr5qlXVBb3mFgA9KwHxvtpVdrMNgUUx0TR8mJF+jSYmqwlKDtbiDQrqtC55O dWdtd8n9Kvv3Q2njCFxUiApipJ1grVBfAYt8tYRI9L6npE1OnLlyaZcIQtGRrBsYrlpZ LdOwumGdTTxWxU6aN4m4uIvwADf7vOPmWBy4gFbnUPbQg6WORkTib/KRDl10pqBolbzV W4JA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=uzBte6r7kxC0wtPH+qtBYHjK6eZ3c0NP6i9Dj0b96+Q=; b=jkbeqwVUgYS7+gb5ix390H2a1iWMnZ0mt9JKg0TiloLGEQFROkLk+Z4919EglLxkJr 95VV5wzIvOd3Lm7djUqp2yc/AnU4QAxO/JCs0QFoJ34mPhhQSka/+D7RzHciNDvuhW40 LD8Vu5BAXb/m9bVot2+y68qjBys/sqkMWQ/pcNM8p2+1tGopNiDzNqDWzB+io5TTQaG2 vKubC3mugIhIErCbC/ZxmGhA1SFO6QEOJlVNwukdUdXir6+zQz5ysBVqwsZTTIGYmB8u dOSwCZ/tbusGBUhn6kFJ1ThmmEcvuWPxyt6H1uUfYFCZQ3G9RL1LCDiqWEBRS/4jC3MX cNbw== X-Gm-Message-State: AOAM531ta5fgiZrV1hq/+KaomQnhbDLqMn4ShDJkbk94qTgbYlUgUMhZ eX39ZWeNa92Mq6fU7cIvcRqEOg== X-Google-Smtp-Source: ABdhPJzlNLG3TxLVXVEZ4XE1YJyZrjM65lM8qi46hGsb0wfqRyDClS+b7hBapO2vkr8t2qVxu/tDvQ== X-Received: by 2002:a17:902:cf88:b029:e3:5daa:3239 with SMTP id l8-20020a170902cf88b02900e35daa3239mr926751ply.35.1613349961658; Sun, 14 Feb 2021 16:46:01 -0800 (PST) Received: from us8c16456344dc.lan (cpe-76-87-77-78.socal.res.rr.com. [76.87.77.78]) by smtp.gmail.com with ESMTPSA id q188sm16127746pfb.8.2021.02.14.16.46.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 14 Feb 2021 16:46:01 -0800 (PST) From: Roderick Colenbrander To: Jiri Kosina , Benjamin Tissoires , Pavel Machek , Marek Behun , dmitry.torokhov@gmail.com, pobm@protonmail.com Cc: linux-input@vger.kernel.org, linux-leds@vger.kernel.org, Roderick Colenbrander Subject: [PATCH v6 1/4] HID: playstation: add DualSense lightbar support Date: Sun, 14 Feb 2021 16:45:46 -0800 Message-Id: <20210215004549.135251-2-roderick@gaikai.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210215004549.135251-1-roderick@gaikai.com> References: <20210215004549.135251-1-roderick@gaikai.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: Roderick Colenbrander Expose the DualSense its RGB lightbar using the new multicolor LED framework. Signed-off-by: Roderick Colenbrander --- drivers/hid/Kconfig | 1 + drivers/hid/hid-playstation.c | 118 ++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 54b4eee222f9..cfa29dc17064 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -857,6 +857,7 @@ config HID_PLAYSTATION tristate "PlayStation HID Driver" depends on HID select CRC32 + select LEDS_CLASS_MULTICOLOR select POWER_SUPPLY help Provides support for Sony PS5 controllers including support for diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 64193fdeaa0d..97c1118ba78f 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -99,6 +100,10 @@ struct ps_calibration_data { /* Flags for DualSense output report. */ #define DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION BIT(0) #define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT BIT(1) +#define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2) +#define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3) +#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1) +#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1) /* DualSense hardware limits */ #define DS_ACC_RES_PER_G 8192 @@ -128,6 +133,13 @@ struct dualsense { uint8_t motor_left; uint8_t motor_right; + /* RGB lightbar */ + struct led_classdev_mc lightbar; + bool update_lightbar; + uint8_t lightbar_red; + uint8_t lightbar_green; + uint8_t lightbar_blue; + struct work_struct output_worker; void *output_report_dmabuf; uint8_t output_seq; /* Sequence number for output report. */ @@ -473,6 +485,45 @@ static int ps_get_report(struct hid_device *hdev, uint8_t report_id, uint8_t *bu return 0; } +/* Register a DualSense/DualShock4 RGB lightbar represented by a multicolor LED. */ +static int ps_lightbar_register(struct ps_device *ps_dev, struct led_classdev_mc *lightbar_mc_dev, + int (*brightness_set)(struct led_classdev *, enum led_brightness)) +{ + struct hid_device *hdev = ps_dev->hdev; + struct mc_subled *mc_led_info; + struct led_classdev *led_cdev; + int ret; + + mc_led_info = devm_kmalloc_array(&hdev->dev, 3, sizeof(*mc_led_info), + GFP_KERNEL | __GFP_ZERO); + if (!mc_led_info) + return -ENOMEM; + + mc_led_info[0].color_index = LED_COLOR_ID_RED; + mc_led_info[1].color_index = LED_COLOR_ID_GREEN; + mc_led_info[2].color_index = LED_COLOR_ID_BLUE; + + lightbar_mc_dev->subled_info = mc_led_info; + lightbar_mc_dev->num_colors = 3; + + led_cdev = &lightbar_mc_dev->led_cdev; + led_cdev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "playstation::%pMR::rgb", + ps_dev->mac_address); + if (!led_cdev->name) + return -ENOMEM; + led_cdev->brightness = 255; + led_cdev->max_brightness = 255; + led_cdev->brightness_set_blocking = brightness_set; + + ret = devm_led_classdev_multicolor_register(&hdev->dev, lightbar_mc_dev); + if (ret < 0) { + hid_err(hdev, "Cannot register multicolor LED device\n"); + return ret; + } + + return 0; +} + static struct input_dev *ps_sensors_create(struct hid_device *hdev, int accel_range, int accel_res, int gyro_range, int gyro_res) { @@ -651,6 +702,26 @@ static int dualsense_get_mac_address(struct dualsense *ds) return ret; } +static int dualsense_lightbar_set_brightness(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); + struct dualsense *ds = container_of(mc_cdev, struct dualsense, lightbar); + unsigned long flags; + + led_mc_calc_color_components(mc_cdev, brightness); + + spin_lock_irqsave(&ds->base.lock, flags); + ds->update_lightbar = true; + ds->lightbar_red = mc_cdev->subled_info[0].brightness; + ds->lightbar_green = mc_cdev->subled_info[1].brightness; + ds->lightbar_blue = mc_cdev->subled_info[2].brightness; + spin_unlock_irqrestore(&ds->base.lock, flags); + + schedule_work(&ds->output_worker); + return 0; +} + static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_output_report *rp, void *buf) { @@ -734,6 +805,15 @@ static void dualsense_output_worker(struct work_struct *work) ds->update_rumble = false; } + if (ds->update_lightbar) { + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE; + common->lightbar_red = ds->lightbar_red; + common->lightbar_green = ds->lightbar_green; + common->lightbar_blue = ds->lightbar_blue; + + ds->update_lightbar = false; + } + spin_unlock_irqrestore(&ds->base.lock, flags); dualsense_send_output_report(ds, &report); @@ -918,6 +998,31 @@ static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_ef return 0; } +static int dualsense_reset_leds(struct dualsense *ds) +{ + struct dualsense_output_report report; + uint8_t *buf; + + buf = kzalloc(sizeof(struct dualsense_output_report_bt), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + dualsense_init_output_report(ds, &report, buf); + /* + * On Bluetooth the DualSense outputs an animation on the lightbar + * during startup and maintains a color afterwards. We need to explicitly + * reconfigure the lightbar before we can do any programming later on. + * In USB the lightbar is not on by default, but redoing the setup there + * doesn't hurt. + */ + report.common->valid_flag2 = DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE; + report.common->lightbar_setup = DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT; /* Fade light out. */ + dualsense_send_output_report(ds, &report); + + kfree(buf); + return 0; +} + static struct ps_device *dualsense_create(struct hid_device *hdev) { struct dualsense *ds; @@ -989,6 +1094,19 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) if (ret) goto err; + /* + * The hardware may have control over the LEDs (e.g. in Bluetooth on startup). + * Reset the LEDs (lightbar, mute, player leds), so we can control them + * from software. + */ + ret = dualsense_reset_leds(ds); + if (ret) + goto err; + + ret = ps_lightbar_register(ps_dev, &ds->lightbar, dualsense_lightbar_set_brightness); + if (ret) + goto err; + return &ds->base; err: From patchwork Mon Feb 15 00:45:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roderick Colenbrander X-Patchwork-Id: 383520 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7BAFAC43381 for ; Mon, 15 Feb 2021 00:46:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5329964DBA for ; Mon, 15 Feb 2021 00:46:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229829AbhBOAqq (ORCPT ); Sun, 14 Feb 2021 19:46:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47624 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229837AbhBOAqn (ORCPT ); Sun, 14 Feb 2021 19:46:43 -0500 Received: from mail-pl1-x62e.google.com (mail-pl1-x62e.google.com [IPv6:2607:f8b0:4864:20::62e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 269F9C061788 for ; Sun, 14 Feb 2021 16:46:03 -0800 (PST) Received: by mail-pl1-x62e.google.com with SMTP id u11so2771893plg.13 for ; Sun, 14 Feb 2021 16:46:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gaikai-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Etz2J9pmlf+SykinxfpX+1GU6HYDag0pYFAujUJqgBs=; b=jrH2pdx5iyCgnxZE83jrb3MCfraOtI7qW/kMtnJB3h65fXmmfheUGyxk4gg2Q5W/9e 2LWq3nxcT6P2TKuj1C1MS/cqBsXoj7qeiZex9OUN1RZ0f49Ev8c5WLdGElPM1Jet45sj NuN2eyGF6FZF8D3ht+qBsHYW/+e5EfdnO6Z0Tm6g1JSUA2j32lPMIQH7bul1gQCRPEsn F490jWLCaydKNWw6pLzxmmoCtwLQVPHugC1ZxoirDPF5KXMiqUbuUMqRJ08QGAC1LViI CPCgKARtqRxb+mMhDHBAEBTPq+VIi0v5zfqrhC8DZjIv3QgmO5Yzeq2M1oje91MVuJBf r96A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Etz2J9pmlf+SykinxfpX+1GU6HYDag0pYFAujUJqgBs=; b=OD+7JLPHGO4HA57Qyb/+0Jrfik/b8LfjK+9JkeOY8L8FI+kS/zHF4e0uJwMcqAEum6 LEF3dPFZB80FmVoU6A9EwgNGUD5GxIk4HrmyCLBFCZBeZJ9fv79CdhTRfecJ/H/2RKLr 1uGB7dAG7T/bPVdljKUjnjFzFI/wpl0nfeBqLdbOPH6yulnZnnnZRjyuSL+70I61zpi9 ycPuFspcePifx1AxTaha3cKiGFiejjldlJOUESnX+yCqfKLC+sLqE6X2nEzmFYhbgvUS idrsUYP/VMaWlfVoFCV71FRrOmVf9p/jgoIqv6MawvCZXNtp6ujBnFQHoZuSi0L/i7Es Jc5w== X-Gm-Message-State: AOAM531gnaPORKgOjQvk2l0gkBZFMH/m8comESEomP6LFHQYSzca+n6O iYa8vEwGaT5pYU6g62tn+xgQyw== X-Google-Smtp-Source: ABdhPJwmSIGc/SjYilCiIDdO8rKue74S6WoVt8zJEP7a/Y5PL71PwZj/FsJltTdRd0oH0AtCA6c+1w== X-Received: by 2002:a17:90a:cb13:: with SMTP id z19mr7849648pjt.52.1613349962746; Sun, 14 Feb 2021 16:46:02 -0800 (PST) Received: from us8c16456344dc.lan (cpe-76-87-77-78.socal.res.rr.com. [76.87.77.78]) by smtp.gmail.com with ESMTPSA id q188sm16127746pfb.8.2021.02.14.16.46.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 14 Feb 2021 16:46:02 -0800 (PST) From: Roderick Colenbrander To: Jiri Kosina , Benjamin Tissoires , Pavel Machek , Marek Behun , dmitry.torokhov@gmail.com, pobm@protonmail.com Cc: linux-input@vger.kernel.org, linux-leds@vger.kernel.org, Roderick Colenbrander Subject: [PATCH v6 2/4] HID: playstation: add microphone mute support for DualSense. Date: Sun, 14 Feb 2021 16:45:47 -0800 Message-Id: <20210215004549.135251-3-roderick@gaikai.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210215004549.135251-1-roderick@gaikai.com> References: <20210215004549.135251-1-roderick@gaikai.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: Roderick Colenbrander The DualSense controller has a built-in microphone exposed as an audio device over USB (or HID using Bluetooth). A dedicated button on the controller handles mute, but software has to configure the device to mute the audio stream. This patch captures the mute button and schedules an output report to mute/unmute the audio stream as well as toggle the mute LED. Signed-off-by: Roderick Colenbrander --- drivers/hid/Kconfig | 2 + drivers/hid/hid-playstation.c | 99 +++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index cfa29dc17064..446a4d579908 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -857,6 +857,8 @@ config HID_PLAYSTATION tristate "PlayStation HID Driver" depends on HID select CRC32 + select NEW_LEDS + select LEDS_CLASS select LEDS_CLASS_MULTICOLOR select POWER_SUPPLY help diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 97c1118ba78f..c436ac8f7a6f 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,12 @@ struct ps_calibration_data { int sens_denom; }; +struct ps_led_info { + const char *name; + enum led_brightness (*brightness_get)(struct led_classdev *cdev); + void (*brightness_set)(struct led_classdev *cdev, enum led_brightness); +}; + /* Seed values for DualShock4 / DualSense CRC32 for different report types. */ #define PS_INPUT_CRC32_SEED 0xA1 #define PS_OUTPUT_CRC32_SEED 0xA2 @@ -82,6 +89,7 @@ struct ps_calibration_data { #define DS_BUTTONS1_R3 BIT(7) #define DS_BUTTONS2_PS_HOME BIT(0) #define DS_BUTTONS2_TOUCHPAD BIT(1) +#define DS_BUTTONS2_MIC_MUTE BIT(2) /* Status field of DualSense input report. */ #define DS_STATUS_BATTERY_CAPACITY GENMASK(3, 0) @@ -100,9 +108,12 @@ struct ps_calibration_data { /* Flags for DualSense output report. */ #define DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION BIT(0) #define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT BIT(1) +#define DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE BIT(0) +#define DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE BIT(1) #define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2) #define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3) #define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1) +#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4) #define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1) /* DualSense hardware limits */ @@ -140,6 +151,12 @@ struct dualsense { uint8_t lightbar_green; uint8_t lightbar_blue; + /* Microphone */ + bool update_mic_mute; + bool mic_muted; + bool last_btn_mic_state; + struct led_classdev mute_led; + struct work_struct output_worker; void *output_report_dmabuf; uint8_t output_seq; /* Sequence number for output report. */ @@ -485,6 +502,32 @@ static int ps_get_report(struct hid_device *hdev, uint8_t report_id, uint8_t *bu return 0; } +static int ps_led_register(struct ps_device *ps_dev, struct led_classdev *led, + const struct ps_led_info *led_info) +{ + int ret; + + led->name = devm_kasprintf(&ps_dev->hdev->dev, GFP_KERNEL, + "playstation::%pMR::%s", ps_dev->mac_address, led_info->name); + + if (!led->name) + return -ENOMEM; + + led->brightness = 0; + led->max_brightness = 1; + led->flags = LED_CORE_SUSPENDRESUME; + led->brightness_get = led_info->brightness_get; + led->brightness_set = led_info->brightness_set; + + ret = devm_led_classdev_register(&ps_dev->hdev->dev, led); + if (ret) { + hid_err(ps_dev->hdev, "Failed to register LED %s: %d\n", led_info->name, ret); + return ret; + } + + return 0; +} + /* Register a DualSense/DualShock4 RGB lightbar represented by a multicolor LED. */ static int ps_lightbar_register(struct ps_device *ps_dev, struct led_classdev_mc *lightbar_mc_dev, int (*brightness_set)(struct led_classdev *, enum led_brightness)) @@ -722,6 +765,19 @@ static int dualsense_lightbar_set_brightness(struct led_classdev *cdev, return 0; } +static enum led_brightness dualsense_mute_led_get_brightness(struct led_classdev *led) +{ + struct dualsense *ds = container_of(led, struct dualsense, mute_led); + + return ds->mic_muted; +} + +/* The mute LED is treated as read-only. This set call prevents ENOTSUP errors e.g. on unload. */ +static void dualsense_mute_led_set_brightness(struct led_classdev *led, enum led_brightness value) +{ + +} + static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_output_report *rp, void *buf) { @@ -814,6 +870,23 @@ static void dualsense_output_worker(struct work_struct *work) ds->update_lightbar = false; } + if (ds->update_mic_mute) { + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE; + common->mute_button_led = ds->mic_muted; + + if (ds->mic_muted) { + /* Disable microphone */ + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE; + common->power_save_control |= DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE; + } else { + /* Enable microphone */ + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE; + common->power_save_control &= ~DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE; + } + + ds->update_mic_mute = false; + } + spin_unlock_irqrestore(&ds->base.lock, flags); dualsense_send_output_report(ds, &report); @@ -828,6 +901,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r uint8_t battery_data, battery_capacity, charging_status, value; int battery_status; uint32_t sensor_timestamp; + bool btn_mic_state; unsigned long flags; int i; @@ -883,6 +957,23 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r input_report_key(ds->gamepad, BTN_MODE, ds_report->buttons[2] & DS_BUTTONS2_PS_HOME); input_sync(ds->gamepad); + /* + * The DualSense has an internal microphone, which can be muted through a mute button + * on the device. The driver is expected to read the button state and program the device + * to mute/unmute audio at the hardware level. + */ + btn_mic_state = !!(ds_report->buttons[2] & DS_BUTTONS2_MIC_MUTE); + if (btn_mic_state && !ds->last_btn_mic_state) { + spin_lock_irqsave(&ps_dev->lock, flags); + ds->update_mic_mute = true; + ds->mic_muted = !ds->mic_muted; /* toggle */ + spin_unlock_irqrestore(&ps_dev->lock, flags); + + /* Schedule updating of microphone state at hardware level. */ + schedule_work(&ds->output_worker); + } + ds->last_btn_mic_state = btn_mic_state; + /* Parse and calibrate gyroscope data. */ for (i = 0; i < ARRAY_SIZE(ds_report->gyro); i++) { int raw_data = (short)le16_to_cpu(ds_report->gyro[i]); @@ -1030,6 +1121,10 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) uint8_t max_output_report_size; int ret; + static const struct ps_led_info mute_led_info = { + "micmute", dualsense_mute_led_get_brightness, dualsense_mute_led_set_brightness + }; + ds = devm_kzalloc(&hdev->dev, sizeof(*ds), GFP_KERNEL); if (!ds) return ERR_PTR(-ENOMEM); @@ -1107,6 +1202,10 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) if (ret) goto err; + ret = ps_led_register(ps_dev, &ds->mute_led, &mute_led_info); + if (ret) + goto err; + return &ds->base; err: From patchwork Mon Feb 15 00:45:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roderick Colenbrander X-Patchwork-Id: 383086 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6BC15C433DB for ; Mon, 15 Feb 2021 00:47:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3ED6664DBA for ; Mon, 15 Feb 2021 00:47:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230006AbhBOArW (ORCPT ); Sun, 14 Feb 2021 19:47:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47772 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229958AbhBOArV (ORCPT ); Sun, 14 Feb 2021 19:47:21 -0500 Received: from mail-pj1-x1034.google.com (mail-pj1-x1034.google.com [IPv6:2607:f8b0:4864:20::1034]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8268AC06178C for ; Sun, 14 Feb 2021 16:46:04 -0800 (PST) Received: by mail-pj1-x1034.google.com with SMTP id t2so2903559pjq.2 for ; Sun, 14 Feb 2021 16:46:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gaikai-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=BS7DivJFl5AT7V+WqM5Kz27qKRGDnECZ9lanj9m1Rjc=; b=J7I2+hAmZyI2mTzpmyULZ5YsGUxeG1OKnMwGuoVR6PGbWgx4ti200A83q9m7ShHRvF t2UeqeCEzZ9XzHsxk2Ju426GTdqsn+jJEqbqipImqvWM8/CYc4NINaXvdtQ2x/aIoWf/ q98ZxskWK44Ij2JNs0OgcPcmmSJbDfJCmxycarbNU15uXUzsmYuCzXRbPf/28o61qQ8F 9FPrIJ2D0P2ngKKNR1oG7vnB6BwiSsz71Uzr5oB5hZqMd4cTxFpX+pvw37NWEV8vqX67 IL34Ut5aVSY63S6w77v0k4Fop1xN0Bge9L5A0zslVdCjpQ6dl800qt/nYj7FujKF2CDV b5GQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=BS7DivJFl5AT7V+WqM5Kz27qKRGDnECZ9lanj9m1Rjc=; b=IAcd/ClacQEblFIaopPOBDXQY0l2XcYDlatrM/UEh2VI4BltUwOeYzXjzztgCq7gTo Pcr4aG8jBsmv9HfK5CHgYeHGmN1wCG4gy+rFunrFmJKPkmENSFStkZD4E9ccMiS18xTk phCUqTILIupMb4N0U6VypJntjAR1nMkI4l8xckzOy/i8nt4Z6LsYzjvzZQshzF16kgrz Z0aAA4RakFAifUnF7nxZ4lHkFVOdWWWBXHxcOpKdENu7OlK0eqaIH9iJvr3yd4Ow+ZrG B/QfM9J0BUamORyhVZP5qHXDlplq3GnYwmaj0pDyuwI+qKAyMnfyDpurhUKQe2Y5YGpI xicw== X-Gm-Message-State: AOAM530fABy/3Sr3aVBm7fShbmVzCin7s+CV9EPBYRPhYRwUQGPJHvoL lU8R8osPkp3pCkY5WSom/ybDuw== X-Google-Smtp-Source: ABdhPJyYywoyi/Q7cnk+ojLDE3GHMvQf9JyUc249OoQZGhHs9fjSRSIBE9anElkmklW9BdBmvn/ASg== X-Received: by 2002:a17:90a:6385:: with SMTP id f5mr13583174pjj.91.1613349964069; Sun, 14 Feb 2021 16:46:04 -0800 (PST) Received: from us8c16456344dc.lan (cpe-76-87-77-78.socal.res.rr.com. [76.87.77.78]) by smtp.gmail.com with ESMTPSA id q188sm16127746pfb.8.2021.02.14.16.46.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 14 Feb 2021 16:46:03 -0800 (PST) From: Roderick Colenbrander To: Jiri Kosina , Benjamin Tissoires , Pavel Machek , Marek Behun , dmitry.torokhov@gmail.com, pobm@protonmail.com Cc: linux-input@vger.kernel.org, linux-leds@vger.kernel.org, Roderick Colenbrander Subject: [PATCH v6 3/4] HID: playstation: add DualSense player LEDs support. Date: Sun, 14 Feb 2021 16:45:48 -0800 Message-Id: <20210215004549.135251-4-roderick@gaikai.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210215004549.135251-1-roderick@gaikai.com> References: <20210215004549.135251-1-roderick@gaikai.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: Roderick Colenbrander The DualSense features 5 player LEDs below its touchpad, which are meant as player id indications. This patch exposes the player LEDs as individual LEDs. Signed-off-by: Roderick Colenbrander --- drivers/hid/hid-playstation.c | 60 ++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index c436ac8f7a6f..2d96785c397d 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -112,6 +112,7 @@ struct ps_led_info { #define DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE BIT(1) #define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2) #define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3) +#define DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE BIT(4) #define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1) #define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4) #define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1) @@ -157,6 +158,11 @@ struct dualsense { bool last_btn_mic_state; struct led_classdev mute_led; + /* Player leds */ + bool update_player_leds; + uint8_t player_leds_state; + struct led_classdev player_leds[5]; + struct work_struct output_worker; void *output_report_dmabuf; uint8_t output_seq; /* Sequence number for output report. */ @@ -778,6 +784,35 @@ static void dualsense_mute_led_set_brightness(struct led_classdev *led, enum led } +static enum led_brightness dualsense_player_led_get_brightness(struct led_classdev *led) +{ + struct hid_device *hdev = to_hid_device(led->dev->parent); + struct dualsense *ds = hid_get_drvdata(hdev); + + return !!(ds->player_leds_state & BIT(led - ds->player_leds)); +} + +static void dualsense_player_led_set_brightness(struct led_classdev *led, enum led_brightness value) +{ + struct hid_device *hdev = to_hid_device(led->dev->parent); + struct dualsense *ds = hid_get_drvdata(hdev); + unsigned long flags; + unsigned int led_index; + + spin_lock_irqsave(&ds->base.lock, flags); + + led_index = led - ds->player_leds; + if (value == LED_OFF) + ds->player_leds_state &= ~BIT(led_index); + else + ds->player_leds_state |= BIT(led_index); + + ds->update_player_leds = true; + spin_unlock_irqrestore(&ds->base.lock, flags); + + schedule_work(&ds->output_worker); +} + static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_output_report *rp, void *buf) { @@ -870,6 +905,13 @@ static void dualsense_output_worker(struct work_struct *work) ds->update_lightbar = false; } + if (ds->update_player_leds) { + common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE; + common->player_leds = ds->player_leds_state; + + ds->update_player_leds = false; + } + if (ds->update_mic_mute) { common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE; common->mute_button_led = ds->mic_muted; @@ -1119,12 +1161,20 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) struct dualsense *ds; struct ps_device *ps_dev; uint8_t max_output_report_size; - int ret; + int i, ret; static const struct ps_led_info mute_led_info = { "micmute", dualsense_mute_led_get_brightness, dualsense_mute_led_set_brightness }; + static const struct ps_led_info player_leds_info[] = { + { "led1", dualsense_player_led_get_brightness, dualsense_player_led_set_brightness }, + { "led2", dualsense_player_led_get_brightness, dualsense_player_led_set_brightness }, + { "led3", dualsense_player_led_get_brightness, dualsense_player_led_set_brightness }, + { "led4", dualsense_player_led_get_brightness, dualsense_player_led_set_brightness }, + { "led5", dualsense_player_led_get_brightness, dualsense_player_led_set_brightness } + }; + ds = devm_kzalloc(&hdev->dev, sizeof(*ds), GFP_KERNEL); if (!ds) return ERR_PTR(-ENOMEM); @@ -1206,6 +1256,14 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) if (ret) goto err; + for (i = 0; i < ARRAY_SIZE(player_leds_info); i++) { + const struct ps_led_info *led_info = &player_leds_info[i]; + + ret = ps_led_register(ps_dev, &ds->player_leds[i], led_info); + if (ret < 0) + goto err; + } + return &ds->base; err: From patchwork Mon Feb 15 00:45:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roderick Colenbrander X-Patchwork-Id: 383519 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 26303C433E9 for ; Mon, 15 Feb 2021 00:47:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F16ED64DDA for ; Mon, 15 Feb 2021 00:47:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229956AbhBOArX (ORCPT ); Sun, 14 Feb 2021 19:47:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47774 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229961AbhBOArW (ORCPT ); Sun, 14 Feb 2021 19:47:22 -0500 Received: from mail-pf1-x42c.google.com (mail-pf1-x42c.google.com [IPv6:2607:f8b0:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BB8B3C061793 for ; Sun, 14 Feb 2021 16:46:05 -0800 (PST) Received: by mail-pf1-x42c.google.com with SMTP id w18so3189513pfu.9 for ; Sun, 14 Feb 2021 16:46:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gaikai-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=MmcKsFVK0P14KymYonH17v2gPDioHATwv8SN0tz8rmc=; b=cVcbqVVvD4DqfnA59AUDkEhTIKLYdXgiIdzbhceBJvPndK2kamGJx+lA13eT8f1CSs EpWQ//I6r0ksHlX+vdfPM73Xp0L4p9ANI6UaygqTbArVEB+EUokzUC91SwxC8Drsipj6 v9UEAW04tTOiEAP1TtJayq9CfXB7uwXmuxMWRjiK06pZe1mbkigboAOOdyEgkNh8uJlC Y3TGzSDryAtxm5Po29T8Eu+qYtuIpSHzZVy9Txsv4lkiE1v8CVJ/pyD2oNivTYiN6LJg Dv+k8OlDMh8cLXSBY82JUInq7S4+dlFnErBzfXFc4OnQ6YAYABMlBzcDuByZepJGCJ5o pFmg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=MmcKsFVK0P14KymYonH17v2gPDioHATwv8SN0tz8rmc=; b=i8j3AjHvdyMgKGrJEsbZHTHpRs+fYsi3UKXVX1t3MwBCgHlkMkJnMipIm/ztJx9DIX tiNgA8+YwA0GaGY/zs4JZNKdN0vWGher7C/E+GBbdarXCRxI+jMjYbMYEEUc7WkZKidD avaQCTOl+TwDLR3tKKdbQTraucH0y5QbRxowIpGCTsoxl87K7GVzUT9HVAnWBrPAOW09 BLnyRdod5bN3pqbJAibHWQvNll8n6sO7+sQIloY6WmeMN1Jx0umYKfvKiCGA9r4Tqi9f 0lri65pHnP3lyd0KHLfSHuhzBTpdJvCzXyfeS+J08SBRVjInSic9hMTZZfd0tp0GNddo Dvhw== X-Gm-Message-State: AOAM532KA4q60377ehOXHlYMY1t+MdpkYDMBThtX7TzajILZyfxfy0US wU/VJTPvJ2Vwh2TdnJejLtzHYg== X-Google-Smtp-Source: ABdhPJyIjYxN1CDJvwX5KSp1VQ+ENKtJmzlhRCQJjlhuuvtw2QnWcQWbetk7hWemw5l4IOQHe61sjw== X-Received: by 2002:a63:ac19:: with SMTP id v25mr12942086pge.258.1613349965171; Sun, 14 Feb 2021 16:46:05 -0800 (PST) Received: from us8c16456344dc.lan (cpe-76-87-77-78.socal.res.rr.com. [76.87.77.78]) by smtp.gmail.com with ESMTPSA id q188sm16127746pfb.8.2021.02.14.16.46.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 14 Feb 2021 16:46:04 -0800 (PST) From: Roderick Colenbrander To: Jiri Kosina , Benjamin Tissoires , Pavel Machek , Marek Behun , dmitry.torokhov@gmail.com, pobm@protonmail.com Cc: linux-input@vger.kernel.org, linux-leds@vger.kernel.org, Roderick Colenbrander Subject: [PATCH v6 4/4] HID: playstation: DualSense set LEDs to default player id. Date: Sun, 14 Feb 2021 16:45:49 -0800 Message-Id: <20210215004549.135251-5-roderick@gaikai.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210215004549.135251-1-roderick@gaikai.com> References: <20210215004549.135251-1-roderick@gaikai.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org From: Roderick Colenbrander Add a ID allocator to assign player ids to ps_device instances. Utilize the player id to set a default color on the DualSense its player LED strip. Signed-off-by: Roderick Colenbrander --- drivers/hid/hid-playstation.c | 70 ++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 2d96785c397d..973c1fe61e8a 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,8 @@ static DEFINE_MUTEX(ps_devices_lock); static LIST_HEAD(ps_devices_list); +static DEFINE_IDA(ps_player_id_allocator); + #define HID_PLAYSTATION_VERSION_PATCH 0x8000 /* Base class for playstation devices. */ @@ -30,6 +33,8 @@ struct ps_device { struct hid_device *hdev; spinlock_t lock; + uint32_t player_id; + struct power_supply_desc battery_desc; struct power_supply *battery; uint8_t battery_capacity; @@ -321,6 +326,24 @@ static int ps_devices_list_remove(struct ps_device *dev) return 0; } +static int ps_device_set_player_id(struct ps_device *dev) +{ + int ret = ida_alloc(&ps_player_id_allocator, GFP_KERNEL); + + if (ret < 0) + return ret; + + dev->player_id = ret; + return 0; +} + +static void ps_device_release_player_id(struct ps_device *dev) +{ + ida_free(&ps_player_id_allocator, dev->player_id); + + dev->player_id = U32_MAX; +} + static struct input_dev *ps_allocate_input_dev(struct hid_device *hdev, const char *name_suffix) { struct input_dev *input_dev; @@ -1156,6 +1179,29 @@ static int dualsense_reset_leds(struct dualsense *ds) return 0; } +static void dualsense_set_player_leds(struct dualsense *ds) +{ + /* + * The DualSense controller has a row of 5 LEDs used for player ids. + * Behavior on the PlayStation 5 console is to center the player id + * across the LEDs, so e.g. player 1 would be "--x--" with x being 'on'. + * Follow a similar mapping here. + */ + static const int player_ids[5] = { + BIT(2), + BIT(3) | BIT(1), + BIT(4) | BIT(2) | BIT(0), + BIT(4) | BIT(3) | BIT(1) | BIT(0), + BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0) + }; + + uint8_t player_id = ds->base.player_id % ARRAY_SIZE(player_ids); + + ds->update_player_leds = true; + ds->player_leds_state = player_ids[player_id]; + schedule_work(&ds->output_worker); +} + static struct ps_device *dualsense_create(struct hid_device *hdev) { struct dualsense *ds; @@ -1264,6 +1310,15 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) goto err; } + ret = ps_device_set_player_id(ps_dev); + if (ret) { + hid_err(hdev, "Failed to assign player id for DualSense: %d\n", ret); + goto err; + } + + /* Set player LEDs to our player id. */ + dualsense_set_player_leds(ds); + return &ds->base; err: @@ -1328,6 +1383,7 @@ static void ps_remove(struct hid_device *hdev) struct ps_device *dev = hid_get_drvdata(hdev); ps_devices_list_remove(dev); + ps_device_release_player_id(dev); hid_hw_close(hdev); hid_hw_stop(hdev); @@ -1348,7 +1404,19 @@ static struct hid_driver ps_driver = { .raw_event = ps_raw_event, }; -module_hid_driver(ps_driver); +static int __init ps_init(void) +{ + return hid_register_driver(&ps_driver); +} + +static void __exit ps_exit(void) +{ + hid_unregister_driver(&ps_driver); + ida_destroy(&ps_player_id_allocator); +} + +module_init(ps_init); +module_exit(ps_exit); MODULE_AUTHOR("Sony Interactive Entertainment"); MODULE_DESCRIPTION("HID Driver for PlayStation peripherals.");