Skip to content

Commit c26e48b

Browse files
Roderick Colenbranderbentiss
authored andcommitted
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. Signed-off-by: Roderick Colenbrander <roderick.colenbrander@sony.com> Reviewed-by: Barnabás Pőcze <pobrn@protonmail.com> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
1 parent 8e5198a commit c26e48b

1 file changed

Lines changed: 44 additions & 0 deletions

File tree

drivers/hid/hid-playstation.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ struct ps_calibration_data {
8585
#define DS_BUTTONS1_R3 BIT(7)
8686
#define DS_BUTTONS2_PS_HOME BIT(0)
8787
#define DS_BUTTONS2_TOUCHPAD BIT(1)
88+
#define DS_BUTTONS2_MIC_MUTE BIT(2)
8889

8990
/* Status field of DualSense input report. */
9091
#define DS_STATUS_BATTERY_CAPACITY GENMASK(3, 0)
@@ -103,9 +104,12 @@ struct ps_calibration_data {
103104
/* Flags for DualSense output report. */
104105
#define DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION BIT(0)
105106
#define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT BIT(1)
107+
#define DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE BIT(0)
108+
#define DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE BIT(1)
106109
#define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2)
107110
#define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3)
108111
#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1)
112+
#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4)
109113
#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1)
110114

111115
/* DualSense hardware limits */
@@ -142,6 +146,11 @@ struct dualsense {
142146
uint8_t lightbar_green;
143147
uint8_t lightbar_blue;
144148

149+
/* Microphone */
150+
bool update_mic_mute;
151+
bool mic_muted;
152+
bool last_btn_mic_state;
153+
145154
struct work_struct output_worker;
146155
void *output_report_dmabuf;
147156
uint8_t output_seq; /* Sequence number for output report. */
@@ -815,6 +824,23 @@ static void dualsense_output_worker(struct work_struct *work)
815824
ds->update_lightbar = false;
816825
}
817826

827+
if (ds->update_mic_mute) {
828+
common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE;
829+
common->mute_button_led = ds->mic_muted;
830+
831+
if (ds->mic_muted) {
832+
/* Disable microphone */
833+
common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE;
834+
common->power_save_control |= DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE;
835+
} else {
836+
/* Enable microphone */
837+
common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE;
838+
common->power_save_control &= ~DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE;
839+
}
840+
841+
ds->update_mic_mute = false;
842+
}
843+
818844
spin_unlock_irqrestore(&ds->base.lock, flags);
819845

820846
dualsense_send_output_report(ds, &report);
@@ -829,6 +855,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r
829855
uint8_t battery_data, battery_capacity, charging_status, value;
830856
int battery_status;
831857
uint32_t sensor_timestamp;
858+
bool btn_mic_state;
832859
unsigned long flags;
833860
int i;
834861

@@ -884,6 +911,23 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r
884911
input_report_key(ds->gamepad, BTN_MODE, ds_report->buttons[2] & DS_BUTTONS2_PS_HOME);
885912
input_sync(ds->gamepad);
886913

914+
/*
915+
* The DualSense has an internal microphone, which can be muted through a mute button
916+
* on the device. The driver is expected to read the button state and program the device
917+
* to mute/unmute audio at the hardware level.
918+
*/
919+
btn_mic_state = !!(ds_report->buttons[2] & DS_BUTTONS2_MIC_MUTE);
920+
if (btn_mic_state && !ds->last_btn_mic_state) {
921+
spin_lock_irqsave(&ps_dev->lock, flags);
922+
ds->update_mic_mute = true;
923+
ds->mic_muted = !ds->mic_muted; /* toggle */
924+
spin_unlock_irqrestore(&ps_dev->lock, flags);
925+
926+
/* Schedule updating of microphone state at hardware level. */
927+
schedule_work(&ds->output_worker);
928+
}
929+
ds->last_btn_mic_state = btn_mic_state;
930+
887931
/* Parse and calibrate gyroscope data. */
888932
for (i = 0; i < ARRAY_SIZE(ds_report->gyro); i++) {
889933
int raw_data = (short)le16_to_cpu(ds_report->gyro[i]);

0 commit comments

Comments
 (0)