mirror of https://github.com/torvalds/linux.git
ALSA: usb-audio: Implement jack detection for HP Thunderbolt Dock G2
The HP Thunderbolt Dock G2 includes a headset jack with support for jack detection. However, this being a UAC1 device, detection is implemented via vendor-defined URB Controls. Implement it in a similar way to the Dell WD15/19 docks, but with different commands. Signed-off-by: Tasos Sahanidis <tasos@tasossah.com> Link: https://patch.msgid.link/20251126003805.2705503-3-tasos@tasossah.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
fba274760d
commit
92099de846
|
|
@ -2363,6 +2363,105 @@ static int dell_dock_mixer_init(struct usb_mixer_interface *mixer)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HP Thunderbolt Dock G2 jack detection
|
||||||
|
*
|
||||||
|
* Similar to the Dell WD15/WD19, but with different commands.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define HP_DOCK_JACK_INTERRUPT_NODE 7
|
||||||
|
|
||||||
|
#define HP_DOCK_GET 37
|
||||||
|
|
||||||
|
#define HP_DOCK_JACK_PRESENCE 0xffb8
|
||||||
|
#define HP_DOCK_JACK_PRESENCE_BIT BIT(2)
|
||||||
|
|
||||||
|
#define HP_DOCK_MIC_SENSE 0xf753
|
||||||
|
#define HP_DOCK_MIC_SENSE_COMPLETE_BIT BIT(4)
|
||||||
|
|
||||||
|
#define HP_DOCK_MIC_SENSE_MASK (BIT(2) | BIT(1) | BIT(0))
|
||||||
|
/* #define HP_DOCK_MIC_SENSE_PRESENT 0x2 */
|
||||||
|
#define HP_DOCK_MIC_SENSE_NOT_PRESENT 0x4
|
||||||
|
|
||||||
|
static int hp_dock_ctl_connector_get(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct snd_usb_audio *chip = cval->head.mixer->chip;
|
||||||
|
u32 pv = kcontrol->private_value;
|
||||||
|
bool presence;
|
||||||
|
int err;
|
||||||
|
u8 buf;
|
||||||
|
|
||||||
|
CLASS(snd_usb_lock, pm)(chip);
|
||||||
|
if (pm.err < 0)
|
||||||
|
return pm.err;
|
||||||
|
|
||||||
|
err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
|
||||||
|
HP_DOCK_GET,
|
||||||
|
USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_IN,
|
||||||
|
0, HP_DOCK_JACK_PRESENCE, &buf, sizeof(buf));
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
presence = !(buf & HP_DOCK_JACK_PRESENCE_BIT);
|
||||||
|
|
||||||
|
if (pv && presence) {
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
|
||||||
|
HP_DOCK_GET,
|
||||||
|
USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_IN,
|
||||||
|
0, HP_DOCK_MIC_SENSE, &buf, sizeof(buf));
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Mic sense is complete, we have a result. */
|
||||||
|
if (buf & HP_DOCK_MIC_SENSE_COMPLETE_BIT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
msleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we reach the retry limit without mic sense having
|
||||||
|
* completed, buf will contain HP_DOCK_MIC_SENSE_PRESENT,
|
||||||
|
* thus presence remains true even when detection fails.
|
||||||
|
*/
|
||||||
|
if ((buf & HP_DOCK_MIC_SENSE_MASK) == HP_DOCK_MIC_SENSE_NOT_PRESENT)
|
||||||
|
presence = false;
|
||||||
|
}
|
||||||
|
ucontrol->value.integer.value[0] = presence;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct snd_kcontrol_new hp_dock_connector_ctl_ro = {
|
||||||
|
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
|
||||||
|
.name = "", /* will be filled later manually */
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_READ,
|
||||||
|
.info = snd_ctl_boolean_mono_info,
|
||||||
|
.get = hp_dock_ctl_connector_get,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int hp_dock_mixer_create(struct usb_mixer_interface *mixer)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = realtek_add_jack(mixer, "Headsets Playback Jack", 0,
|
||||||
|
HP_DOCK_JACK_INTERRUPT_NODE,
|
||||||
|
&hp_dock_connector_ctl_ro);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = realtek_add_jack(mixer, "Headset Capture Jack", 1,
|
||||||
|
HP_DOCK_JACK_INTERRUPT_NODE,
|
||||||
|
&hp_dock_connector_ctl_ro);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* RME Class Compliant device quirks */
|
/* RME Class Compliant device quirks */
|
||||||
|
|
||||||
#define SND_RME_GET_STATUS1 23
|
#define SND_RME_GET_STATUS1 23
|
||||||
|
|
@ -4414,6 +4513,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
|
||||||
case USB_ID(0x2b73, 0x0034): /* Pioneer DJ DJM-V10 */
|
case USB_ID(0x2b73, 0x0034): /* Pioneer DJ DJM-V10 */
|
||||||
err = snd_djm_controls_create(mixer, SND_DJM_V10_IDX);
|
err = snd_djm_controls_create(mixer, SND_DJM_V10_IDX);
|
||||||
break;
|
break;
|
||||||
|
case USB_ID(0x03f0, 0x0269): /* HP TB Dock G2 */
|
||||||
|
err = hp_dock_mixer_create(mixer);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue