Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98827691 authored by Roderick Colenbrander's avatar Roderick Colenbrander Committed by Kishor Krishna Bhat
Browse files

UPSTREAM: HID: playstation: Add microphone mute support for DualSense



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.

Bug: 167947264
CRs-fixed: 2971837
Change-Id: I6fce08b0b28c1cf41c682a2ff5655f00d7a52843
Signed-off-by: default avatarRoderick Colenbrander <roderick.colenbrander@sony.com>
Reviewed-by: default avatarBarnabás Pőcze <pobrn@protonmail.com>
Signed-off-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarFarid Chahla <farid.chahla@sony.com>
Signed-off-by: default avatarSiarhei Vishniakou <svv@google.com>
Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git


Git-commit: c26e48b150fccb07c4b7f0f419f2b0a2c42e57d2
Signed-off-by: default avatarKishor Krishna Bhat <kishkris@codeaurora.org>
parent 85f00312
Loading
Loading
Loading
Loading
+50 −0
Original line number Diff line number Diff line
@@ -84,6 +84,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)
@@ -102,9 +103,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)

#define DS_ACC_RES_PER_G       8192
@@ -141,6 +145,11 @@ struct dualsense {
	uint8_t lightbar_green;
	uint8_t lightbar_blue;

	/* Microphone */
	bool update_mic_mute;
	bool mic_muted;
	bool last_btn_mic_state;

	struct work_struct output_worker;
	void *output_report_dmabuf;
	uint8_t output_seq; /* Sequence number for output report. */
@@ -817,6 +826,28 @@ 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);
@@ -831,6 +862,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev,
	uint8_t battery_data, battery_capacity, charging_status, value;
	int battery_status;
	unsigned long flags;
	bool btn_mic_state;
	uint32_t sensor_timestamp;
	int i;

@@ -888,6 +920,24 @@ static int dualsense_parse_report(struct ps_device *ps_dev,
	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 bemuted
	 * 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]);