@@ -2363,6 +2363,105 @@ static int dell_dock_mixer_init(struct usb_mixer_interface *mixer)
23632363 return 0 ;
23642364}
23652365
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+
23662465/* RME Class Compliant device quirks */
23672466
23682467#define SND_RME_GET_STATUS1 23
@@ -4414,6 +4513,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
44144513 case USB_ID (0x2b73 , 0x0034 ): /* Pioneer DJ DJM-V10 */
44154514 err = snd_djm_controls_create (mixer , SND_DJM_V10_IDX );
44164515 break ;
4516+ case USB_ID (0x03f0 , 0x0269 ): /* HP TB Dock G2 */
4517+ err = hp_dock_mixer_create (mixer );
4518+ break ;
44174519 }
44184520
44194521 return err ;
0 commit comments