Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Tasos Sahanidis and committed by
Takashi Iwai
92099de8 fba27476

+102
+102
sound/usb/mixer_quirks.c
··· 2363 2363 return 0; 2364 2364 } 2365 2365 2366 + /* 2367 + * HP Thunderbolt Dock G2 jack detection 2368 + * 2369 + * Similar to the Dell WD15/WD19, but with different commands. 2370 + */ 2371 + 2372 + #define HP_DOCK_JACK_INTERRUPT_NODE 7 2373 + 2374 + #define HP_DOCK_GET 37 2375 + 2376 + #define HP_DOCK_JACK_PRESENCE 0xffb8 2377 + #define HP_DOCK_JACK_PRESENCE_BIT BIT(2) 2378 + 2379 + #define HP_DOCK_MIC_SENSE 0xf753 2380 + #define HP_DOCK_MIC_SENSE_COMPLETE_BIT BIT(4) 2381 + 2382 + #define HP_DOCK_MIC_SENSE_MASK (BIT(2) | BIT(1) | BIT(0)) 2383 + /* #define HP_DOCK_MIC_SENSE_PRESENT 0x2 */ 2384 + #define HP_DOCK_MIC_SENSE_NOT_PRESENT 0x4 2385 + 2386 + static int hp_dock_ctl_connector_get(struct snd_kcontrol *kcontrol, 2387 + struct snd_ctl_elem_value *ucontrol) 2388 + { 2389 + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); 2390 + struct snd_usb_audio *chip = cval->head.mixer->chip; 2391 + u32 pv = kcontrol->private_value; 2392 + bool presence; 2393 + int err; 2394 + u8 buf; 2395 + 2396 + CLASS(snd_usb_lock, pm)(chip); 2397 + if (pm.err < 0) 2398 + return pm.err; 2399 + 2400 + err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), 2401 + HP_DOCK_GET, 2402 + USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_IN, 2403 + 0, HP_DOCK_JACK_PRESENCE, &buf, sizeof(buf)); 2404 + if (err < 0) 2405 + return err; 2406 + 2407 + presence = !(buf & HP_DOCK_JACK_PRESENCE_BIT); 2408 + 2409 + if (pv && presence) { 2410 + for (int i = 0; i < 20; i++) { 2411 + err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), 2412 + HP_DOCK_GET, 2413 + USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_IN, 2414 + 0, HP_DOCK_MIC_SENSE, &buf, sizeof(buf)); 2415 + if (err < 0) 2416 + return err; 2417 + 2418 + /* Mic sense is complete, we have a result. */ 2419 + if (buf & HP_DOCK_MIC_SENSE_COMPLETE_BIT) 2420 + break; 2421 + 2422 + msleep(100); 2423 + } 2424 + 2425 + /* 2426 + * If we reach the retry limit without mic sense having 2427 + * completed, buf will contain HP_DOCK_MIC_SENSE_PRESENT, 2428 + * thus presence remains true even when detection fails. 2429 + */ 2430 + if ((buf & HP_DOCK_MIC_SENSE_MASK) == HP_DOCK_MIC_SENSE_NOT_PRESENT) 2431 + presence = false; 2432 + } 2433 + ucontrol->value.integer.value[0] = presence; 2434 + return 0; 2435 + } 2436 + 2437 + static const struct snd_kcontrol_new hp_dock_connector_ctl_ro = { 2438 + .iface = SNDRV_CTL_ELEM_IFACE_CARD, 2439 + .name = "", /* will be filled later manually */ 2440 + .access = SNDRV_CTL_ELEM_ACCESS_READ, 2441 + .info = snd_ctl_boolean_mono_info, 2442 + .get = hp_dock_ctl_connector_get, 2443 + }; 2444 + 2445 + static int hp_dock_mixer_create(struct usb_mixer_interface *mixer) 2446 + { 2447 + int err; 2448 + 2449 + err = realtek_add_jack(mixer, "Headsets Playback Jack", 0, 2450 + HP_DOCK_JACK_INTERRUPT_NODE, 2451 + &hp_dock_connector_ctl_ro); 2452 + if (err < 0) 2453 + return err; 2454 + 2455 + err = realtek_add_jack(mixer, "Headset Capture Jack", 1, 2456 + HP_DOCK_JACK_INTERRUPT_NODE, 2457 + &hp_dock_connector_ctl_ro); 2458 + if (err < 0) 2459 + return err; 2460 + 2461 + return 0; 2462 + } 2463 + 2464 + 2366 2465 /* RME Class Compliant device quirks */ 2367 2466 2368 2467 #define SND_RME_GET_STATUS1 23 ··· 4512 4413 break; 4513 4414 case USB_ID(0x2b73, 0x0034): /* Pioneer DJ DJM-V10 */ 4514 4415 err = snd_djm_controls_create(mixer, SND_DJM_V10_IDX); 4416 + break; 4417 + case USB_ID(0x03f0, 0x0269): /* HP TB Dock G2 */ 4418 + err = hp_dock_mixer_create(mixer); 4515 4419 break; 4516 4420 } 4517 4421