diff mbox series

[11/11] HID: playstation: Support DualSense audio jack event reporting

Message ID 20250526-dualsense-hid-jack-v1-11-a65fee4a60cc@collabora.com
State New
Headers show
Series HID: playstation: Add support for audio jack handling on DualSense | expand

Commit Message

Cristian Ciocaltea May 26, 2025, 12:51 p.m. UTC
The DualSense controller complies with v1.0 of the USB Audio Class spec
(UAC1), hence it cannot advertise any jack detection capability.

However, this feature can be implemented in the generic USB audio driver
via quirks, i.e. by configuring an input handler to receive hotplug
events from the HID driver.

Register a dedicated input device for the audio jack and use it to
report all headphone and headset mic insert events.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
 drivers/hid/hid-playstation.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
diff mbox series

Patch

diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c
index ed8e67c5bf5d3a9e9721da31a6bd84f0b6802b14..1231165098691398cd471e71cb9787651f753023 100644
--- a/drivers/hid/hid-playstation.c
+++ b/drivers/hid/hid-playstation.c
@@ -178,6 +178,7 @@  struct dualsense {
 	struct input_dev *gamepad;
 	struct input_dev *sensors;
 	struct input_dev *touchpad;
+	struct input_dev *jack;
 
 	/* Update version is used as a feature/capability version. */
 	u16 update_version;
@@ -958,6 +959,25 @@  static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width,
 	return touchpad;
 }
 
+static struct input_dev *ps_headset_jack_create(struct hid_device *hdev)
+{
+	struct input_dev *jack;
+	int ret;
+
+	jack = ps_allocate_input_dev(hdev, "Headset Jack");
+	if (IS_ERR(jack))
+		return ERR_CAST(jack);
+
+	input_set_capability(jack, EV_SW, SW_HEADPHONE_INSERT);
+	input_set_capability(jack, EV_SW, SW_MICROPHONE_INSERT);
+
+	ret = input_register_device(jack);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return jack;
+}
+
 static ssize_t firmware_version_show(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
@@ -1360,8 +1380,15 @@  static void dualsense_output_worker(struct work_struct *work)
 				common->audio_flags2 =
 					FIELD_PREP(DS_OUTPUT_AUDIO_FLAGS2_SP_PREAMP_GAIN, 0x2);
 			}
+
+			input_report_switch(ds->jack, SW_HEADPHONE_INSERT, val);
 		}
 
+		val = ds->plugged_state & DS_STATUS_PLUGGED_MIC;
+		if (val != (ds->prev_plugged_state & DS_STATUS_PLUGGED_MIC))
+			input_report_switch(ds->jack, SW_MICROPHONE_INSERT, val);
+
+		input_sync(ds->jack);
 		ds->prev_plugged_state = ds->plugged_state;
 	}
 
@@ -1775,6 +1802,12 @@  static struct ps_device *dualsense_create(struct hid_device *hdev)
 		goto err;
 	}
 
+	ds->jack = ps_headset_jack_create(hdev);
+	if (IS_ERR(ds->jack)) {
+		ret = PTR_ERR(ds->jack);
+		goto err;
+	}
+
 	ret = ps_device_register_battery(ps_dev);
 	if (ret)
 		goto err;