Re: [alsa-devel] [RFC] hda - is_jack_detectable()
2011/11/14 Takashi Iwai tiwai@suse.de:
At Sat, 12 Nov 2011 19:31:20 +0800, Raymond Yau wrote:
2011/11/9 Takashi Iwai tiwai@suse.de:
At Wed, 09 Nov 2011 08:08:17 +0100, Takashi Iwai wrote:
At Wed, 9 Nov 2011 12:06:04 +0800, Raymond Yau wrote:
2011/11/6 Takashi Iwai tiwai@suse.de:
At Sat, 5 Nov 2011 13:30:21 +0800, Raymond Yau wrote: > > 2011/11/2 Takashi Iwai tiwai@suse.de: > > At Tue, 01 Nov 2011 17:03:29 -0400, > > David Henningsson wrote: > >> > >> 2011-10-24 23:31, Raymond Yau skrev: > >> > sorry, it should be > >> > > >> > static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) > >> > { > >> > return (snd_hda_query_pin_caps(codec, nid)& AC_PINCAP_PRES_DETECT)&& > >> > + !(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid) > >> > & AC_DEFCFG_MISC_NO_PRESENCE))&& > >> > (get_wcaps(codec, nid)& AC_WCAP_UNSOL_CAP); > >> > } > >> > > >> I also think it is a good idea, in fact I thought it was this way > >> already. Can we merge this patch? > > > > OK, I checked through alsa-info series and confirmed that this causes > > no harm, so I merged it now. > > > > > > thanks, > > > > Takashi > > > > > > Sorry the previous patch is wrong
Ugh, so actually changing it would may bring too many changes, and most likely regressions, too. I disabled the code for now for 3.2-rc1. Once when we cover all test cases and fix broken BIOS devices enough, we can re-enable it in near future.
> attach the patch and test cases (pins 0x11 and 0x14) front panel > green and pink jacks when set Front Audio Panel to AC97 or HD in BIOS > setup
OK, thanks, we can refer to this for more tests.
Takashi
If bit 0 is set, it indicates that the jack has no presence detect capability
The Configuration Default register is defined as shown in Figure 66. 31:30 29:24 23:20 19:16 15:12 11:8 7:4 3:0 Port Location Default Connection Color Misc Default Sequence Connectivity Device Type Association Figure 66. Configuration Data Structure
This mean that bit 0 of Misc is bit 8 of the Configuration Default register
!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & AC_DEFCFG_MISC_NO_PRESENCE)&&
Yeah, I already tried it and it still gives too many false-positives. Many ASUS laptops (also mobo) set this bit to all pins no matter whether it's an obviously detectable jack or not. Some Toshiba laptops do so, too.
That being said, checking this bit alone isn't reliable because of too many BIOS bugs. A bit more clever test is necessary.
It seems that a broken BIOS sets this bit on all pins in general. So, the patch below (against the latest sound git tree or 3.2-rc1 kernel) seems working well by filtering out such a brokenness.
Let me know if this works. If it's OK, I'll try to merge it for 3.2-rc2.
The patch seem ok
Need a hack to build the hda-jack branch
It is quite simple to enable unsolicited event for all proper jacks by
snd_hda_jack_add_kctrls(codec,(codec->spec->autocfg));
and
static void ad1988_unsol_event(struct hda_codec *codec, unsigned int res) { struct ad198x_spec *spec = codec->spec; struct hda_jack_tbl *jack; u32 sense, caps; int pin; jack = snd_hda_jack_tbl_get_from_tag(codec, res >> 26); pin = jack->nid; caps = snd_hda_codec_get_pincfg(codec, pin); sense = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_PIN_SENSE, 0); if (sense & AC_PINSENSE_PRESENCE) snd_printdd("Pin 0x%x pd=1 imp=%d %s at %s %s %s\n", pin, sense & AC_PINSENSE_IMPEDANCE_MASK, snd_hda_get_jack_type(caps), snd_hda_get_jack_connectivity(caps), snd_hda_get_jack_location(caps), get_jack_color(caps)); else snd_printdd("Pin 0x%x pd=0 %s at %s %s %s\n", pin, snd_hda_get_jack_type(caps), snd_hda_get_jack_connectivity(caps), snd_hda_get_jack_location(caps), get_jack_color(caps));
if (pin == spec->autocfg.hp_pins[0] && !spec->independent_hp) ad198x_hp_automute(codec); if (pin == spec->ext_mic_pin) ad198x_mic_automute(codec); }
However it seem that result is different in kctl
amixer -c1 contents numid=5,iface=CARD,name='Front Headphone Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off numid=6,iface=CARD,name='Front Mic Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off numid=8,iface=CARD,name='Line Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off numid=1,iface=CARD,name='Line-Out Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off numid=2,iface=CARD,name='Line-Out Jack',index=1 ; type=BOOLEAN,access=r-------,values=1 : values=off numid=3,iface=CARD,name='Line-Out Jack',index=2 ; type=BOOLEAN,access=r-------,values=1 : values=off numid=4,iface=CARD,name='Line-Out Jack',index=3 ; type=BOOLEAN,access=r-------,values=1 : values=off numid=7,iface=CARD,name='Rear Mic Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off
./hda-jack-sense-test.py -c1 Pin 0x11 Green HP Out (Ext Front): Present = NO Pin 0x12 Green Line Out (Ext Rear): Present = YES Impedance = 19 Pin 0x14 Pink Mic (Ext Front): Present = NO Pin 0x15 Blue Line In (Ext Rear): Present = NO Pin 0x16 Black Line Out (Ext Rear): Present = YES Impedance = 3200 Pin 0x17 Pink Mic (Ext Rear): Present = YES Impedance = 896 Pin 0x18 Black CD (Int ATAPI): No jack detect capability Pin 0x1a Other (Int ATAPI): No jack detect capability Pin 0x1b Other SPDIF Out (Ext Rear): No jack detect capability Pin 0x24 Orange Line Out (Ext Rear): Present = NO Pin 0x25 Grey Line Out (Ext Rear): Present = YES Impedance = 3200
It need "SET_PIN_SENSE" and some delay to get the correct impedance of the jacks during driver load
int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, unsigned char action) {
- int ret;
struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid); if (!jack) return -ENOMEM; if (jack->jack_detect) return 0; /* already registered */ jack->jack_detect = 1; if (action) jack->action = action;
- ret = snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | jack->tag);
- if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IMP_SENSE) {
snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
- msleep(200);
- }
- return ret;
The lack of the initial pin-state of kclts was fixed in a different patch now. But, the need of 200ms delay worries me whether it's needed generically at each pin-sense reading or it's just only for the initial reading.
Does the pin-sense reading work in general after loading the driver stably?
Presence detect bit is alway correct, without the delay.
the only issue is the impedance measurement of the plugged jacks at computer boot need a delay 200ms
For the user application to know the impedance , it seem the client application have to issue 1) set_pin_sense 2) delay 3) get_pin_sense to get the correct impedance of the attached device
just like my modified hda-jack-sense-test in previous email
Can it measure the impedance of the jacks of your computer ?
At Wed, 16 Nov 2011 15:14:17 +0800, Raymond Yau wrote:
2011/11/14 Takashi Iwai tiwai@suse.de:
At Sat, 12 Nov 2011 19:31:20 +0800, Raymond Yau wrote:
2011/11/9 Takashi Iwai tiwai@suse.de:
At Wed, 09 Nov 2011 08:08:17 +0100, Takashi Iwai wrote:
At Wed, 9 Nov 2011 12:06:04 +0800, Raymond Yau wrote:
2011/11/6 Takashi Iwai tiwai@suse.de: > At Sat, 5 Nov 2011 13:30:21 +0800, > Raymond Yau wrote: >> >> 2011/11/2 Takashi Iwai tiwai@suse.de: >> > At Tue, 01 Nov 2011 17:03:29 -0400, >> > David Henningsson wrote: >> >> >> >> 2011-10-24 23:31, Raymond Yau skrev: >> >> > sorry, it should be >> >> > >> >> > static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) >> >> > { >> >> > return (snd_hda_query_pin_caps(codec, nid)& AC_PINCAP_PRES_DETECT)&& >> >> > + !(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid) >> >> > & AC_DEFCFG_MISC_NO_PRESENCE))&& >> >> > (get_wcaps(codec, nid)& AC_WCAP_UNSOL_CAP); >> >> > } >> >> > >> >> I also think it is a good idea, in fact I thought it was this way >> >> already. Can we merge this patch? >> > >> > OK, I checked through alsa-info series and confirmed that this causes >> > no harm, so I merged it now. >> > >> > >> > thanks, >> > >> > Takashi >> > >> > >> >> Sorry the previous patch is wrong > > Ugh, so actually changing it would may bring too many changes, and > most likely regressions, too. I disabled the code for now for 3.2-rc1. > Once when we cover all test cases and fix broken BIOS devices enough, > we can re-enable it in near future. > >> attach the patch and test cases (pins 0x11 and 0x14) front panel >> green and pink jacks when set Front Audio Panel to AC97 or HD in BIOS >> setup > > OK, thanks, we can refer to this for more tests. > > > Takashi >
If bit 0 is set, it indicates that the jack has no presence detect capability
The Configuration Default register is defined as shown in Figure 66. 31:30 29:24 23:20 19:16 15:12 11:8 7:4 3:0 Port Location Default Connection Color Misc Default Sequence Connectivity Device Type Association Figure 66. Configuration Data Structure
This mean that bit 0 of Misc is bit 8 of the Configuration Default register
!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & AC_DEFCFG_MISC_NO_PRESENCE)&&
Yeah, I already tried it and it still gives too many false-positives. Many ASUS laptops (also mobo) set this bit to all pins no matter whether it's an obviously detectable jack or not. Some Toshiba laptops do so, too.
That being said, checking this bit alone isn't reliable because of too many BIOS bugs. A bit more clever test is necessary.
It seems that a broken BIOS sets this bit on all pins in general. So, the patch below (against the latest sound git tree or 3.2-rc1 kernel) seems working well by filtering out such a brokenness.
Let me know if this works. If it's OK, I'll try to merge it for 3.2-rc2.
The patch seem ok
Need a hack to build the hda-jack branch
It is quite simple to enable unsolicited event for all proper jacks by
snd_hda_jack_add_kctrls(codec,(codec->spec->autocfg));
and
static void ad1988_unsol_event(struct hda_codec *codec, unsigned int res) { struct ad198x_spec *spec = codec->spec; struct hda_jack_tbl *jack; u32 sense, caps; int pin; jack = snd_hda_jack_tbl_get_from_tag(codec, res >> 26); pin = jack->nid; caps = snd_hda_codec_get_pincfg(codec, pin); sense = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_PIN_SENSE, 0); if (sense & AC_PINSENSE_PRESENCE) snd_printdd("Pin 0x%x pd=1 imp=%d %s at %s %s %s\n", pin, sense & AC_PINSENSE_IMPEDANCE_MASK, snd_hda_get_jack_type(caps), snd_hda_get_jack_connectivity(caps), snd_hda_get_jack_location(caps), get_jack_color(caps)); else snd_printdd("Pin 0x%x pd=0 %s at %s %s %s\n", pin, snd_hda_get_jack_type(caps), snd_hda_get_jack_connectivity(caps), snd_hda_get_jack_location(caps), get_jack_color(caps));
if (pin == spec->autocfg.hp_pins[0] && !spec->independent_hp) ad198x_hp_automute(codec); if (pin == spec->ext_mic_pin) ad198x_mic_automute(codec); }
However it seem that result is different in kctl
amixer -c1 contents numid=5,iface=CARD,name='Front Headphone Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off numid=6,iface=CARD,name='Front Mic Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off numid=8,iface=CARD,name='Line Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off numid=1,iface=CARD,name='Line-Out Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off numid=2,iface=CARD,name='Line-Out Jack',index=1 ; type=BOOLEAN,access=r-------,values=1 : values=off numid=3,iface=CARD,name='Line-Out Jack',index=2 ; type=BOOLEAN,access=r-------,values=1 : values=off numid=4,iface=CARD,name='Line-Out Jack',index=3 ; type=BOOLEAN,access=r-------,values=1 : values=off numid=7,iface=CARD,name='Rear Mic Jack' ; type=BOOLEAN,access=r-------,values=1 : values=off
./hda-jack-sense-test.py -c1 Pin 0x11 Green HP Out (Ext Front): Present = NO Pin 0x12 Green Line Out (Ext Rear): Present = YES Impedance = 19 Pin 0x14 Pink Mic (Ext Front): Present = NO Pin 0x15 Blue Line In (Ext Rear): Present = NO Pin 0x16 Black Line Out (Ext Rear): Present = YES Impedance = 3200 Pin 0x17 Pink Mic (Ext Rear): Present = YES Impedance = 896 Pin 0x18 Black CD (Int ATAPI): No jack detect capability Pin 0x1a Other (Int ATAPI): No jack detect capability Pin 0x1b Other SPDIF Out (Ext Rear): No jack detect capability Pin 0x24 Orange Line Out (Ext Rear): Present = NO Pin 0x25 Grey Line Out (Ext Rear): Present = YES Impedance = 3200
It need "SET_PIN_SENSE" and some delay to get the correct impedance of the jacks during driver load
int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, unsigned char action) {
- int ret;
struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid); if (!jack) return -ENOMEM; if (jack->jack_detect) return 0; /* already registered */ jack->jack_detect = 1; if (action) jack->action = action;
- ret = snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | jack->tag);
- if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IMP_SENSE) {
snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
- msleep(200);
- }
- return ret;
The lack of the initial pin-state of kclts was fixed in a different patch now. But, the need of 200ms delay worries me whether it's needed generically at each pin-sense reading or it's just only for the initial reading.
Does the pin-sense reading work in general after loading the driver stably?
Presence detect bit is alway correct, without the delay.
the only issue is the impedance measurement of the plugged jacks at computer boot need a delay 200ms
For the user application to know the impedance , it seem the client application have to issue
- set_pin_sense
- delay
- get_pin_sense to get the correct impedance of the attached device
just like my modified hda-jack-sense-test in previous email
Can it measure the impedance of the jacks of your computer ?
It seems that this doesn't work machines here with Realtek codecs. So, this must be pretty depending on the codec chip.
Anyway, currently there is no use of impedance, and the jack presence can be detected immediately without delay, we can keep the code as is now.
thanks,
Takashi
2011/11/17, Takashi Iwai tiwai@suse.de:
At Wed, 16 Nov 2011 15:14:17 +0800, Raymond Yau wrote:
2011/11/14 Takashi Iwai tiwai@suse.de:
The lack of the initial pin-state of kclts was fixed in a different patch now. But, the need of 200ms delay worries me whether it's needed generically at each pin-sense reading or it's just only for the initial reading.
Does the pin-sense reading work in general after loading the driver stably?
Presence detect bit is alway correct, without the delay.
the only issue is the impedance measurement of the plugged jacks at computer boot need a delay 200ms
For the user application to know the impedance , it seem the client application have to issue
- set_pin_sense
- delay
- get_pin_sense to get the correct impedance of the attached device
just like my modified hda-jack-sense-test in previous email
Can it measure the impedance of the jacks of your computer ?
It seems that this doesn't work machines here with Realtek codecs. So, this must be pretty depending on the codec chip.
Anyway, currently there is no use of impedance, and the jack presence can be detected immediately without delay, we can keep the code as is now.
How can I add the new hda-jack detect to patch_analog.c ?
Only ad1988 use snd_hda_parse_pin_def_config() to parse the pin, other ad198x codecs are used model since snd_hda_jack_add_ctls() require those pin info from autocfg
The auto model of ad1988 use init_verbs ad1988_6stack_init which cannot handle those 3 stack motherboard asus m2n
What is the reason to call snd_hda_jack_report_sync() at the end of unsol event handler ?
At Fri, 23 Dec 2011 10:37:15 +0800, Raymond Yau wrote:
2011/11/17, Takashi Iwai tiwai@suse.de:
At Wed, 16 Nov 2011 15:14:17 +0800, Raymond Yau wrote:
2011/11/14 Takashi Iwai tiwai@suse.de:
The lack of the initial pin-state of kclts was fixed in a different patch now. But, the need of 200ms delay worries me whether it's needed generically at each pin-sense reading or it's just only for the initial reading.
Does the pin-sense reading work in general after loading the driver stably?
Presence detect bit is alway correct, without the delay.
the only issue is the impedance measurement of the plugged jacks at computer boot need a delay 200ms
For the user application to know the impedance , it seem the client application have to issue
- set_pin_sense
- delay
- get_pin_sense to get the correct impedance of the attached device
just like my modified hda-jack-sense-test in previous email
Can it measure the impedance of the jacks of your computer ?
It seems that this doesn't work machines here with Realtek codecs. So, this must be pretty depending on the codec chip.
Anyway, currently there is no use of impedance, and the jack presence can be detected immediately without delay, we can keep the code as is now.
How can I add the new hda-jack detect to patch_analog.c ?
Only ad1988 use snd_hda_parse_pin_def_config() to parse the pin, other ad198x codecs are used model since snd_hda_jack_add_ctls() require those pin info from autocfg
Not necessarily. You can call snd_hda_jack_add_kctl() and enable the pin-detection via snd_hda_jack_detect_enable() directly.
The auto model of ad1988 use init_verbs ad1988_6stack_init which cannot handle those 3 stack motherboard asus m2n
What is the reason to call snd_hda_jack_report_sync() at the end of unsol event handler ?
To notify the jack-detection.
Takashi
2011/12/23, Takashi Iwai tiwai@suse.de:
At Fri, 23 Dec 2011 10:37:15 +0800, Raymond Yau wrote:
How can I add the new hda-jack detect to patch_analog.c ?
Only ad1988 use snd_hda_parse_pin_def_config() to parse the pin, other ad198x codecs are used model since snd_hda_jack_add_ctls() require those pin info from autocfg
Not necessarily. You can call snd_hda_jack_add_kctl() and enable the pin-detection via snd_hda_jack_detect_enable() directly.
The auto model of ad1988 use init_verbs ad1988_6stack_init which cannot handle those 3 stack motherboard asus m2n
What is the reason to call snd_hda_jack_report_sync() at the end of unsol event handler ?
To notify the jack-detection.
It seem that I need to add jack->dirty = 1 in ad1988_unsol_event to force snd_hda_jack_detect() to call read_pin_sense() since jack->jack_detect is set when calling snd_hda_jack_detect_enable()
Using snd_hda_jack_detect_enable(codec, pin, pin) instead of snd_hda_jack_detect_enable(codec, pin, HP_EVENT) simiar to hdmi so that all the detectable pins are assigned different tag
+static void ad1988_hp_automute(struct hda_codec *codec) +{ + int i, present; + struct ad198x_spec *spec = codec->spec; + + present = snd_hda_jack_detect(codec, 0x11); + if (spec->independent_hp) + return; + for (i=0; i < spec->multiout.num_dacs; i++) + snd_hda_codec_write(codec, spec->autocfg.line_out_pins[i], + 0, AC_VERB_SET_AMP_GAIN_MUTE, + present ? AMP_OUT_MUTE : AMP_OUT_UNMUTE); + + if (spec->autocfg.mono_out_pin) + snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, + 0, AC_VERB_SET_AMP_GAIN_MUTE, + present ? AMP_OUT_MUTE : AMP_OUT_UNMUTE); + + for (i=0; i < spec->autocfg.speaker_outs; i++) { + snd_hda_codec_write(codec, spec->autocfg.speaker_pins[i], + 0, AC_VERB_SET_AMP_GAIN_MUTE, + present ? AMP_OUT_MUTE : AMP_OUT_UNMUTE); + } +} + +static void ad1988_unsol_event(struct hda_codec *codec, unsigned int res) +{ + struct hda_jack_tbl *jack = snd_hda_jack_tbl_get_from_tag(codec, res >> 26); + struct ad198x_spec *spec = codec->spec; + jack->jack_dirty = 1; + if (jack->nid == spec->autocfg.hp_pins[0]) + ad1988_hp_automute(codec); + snd_hda_jack_report_sync(codec); +} + +#define check_jack_detect(c, p) if (is_jack_detectable(c, p)) snd_hda_jack_detect_enable(c, p, p) + +void ad1988_auto_init_unsol_event(struct hda_codec *codec) +{ + int i; + struct ad198x_spec *spec = codec->spec; + check_jack_detect(codec, spec->autocfg.hp_pins[0]); + for (i=0; i<spec->autocfg.line_outs; i++) + check_jack_detect(codec, spec->autocfg.line_out_pins[0]); + for (i=0; i<spec->autocfg.num_inputs; i++) + check_jack_detect(codec, spec->autocfg.inputs[i].pin); + snd_hda_jack_add_kctls(codec, &spec->autocfg); + snd_hda_jack_report_sync(codec); +}
static int ad1988_auto_init(struct hda_codec *codec) { ad198x_init(codec); ad1988_auto_init_multi_out(codec); ad1988_auto_init_extra_out(codec); ad1988_auto_init_analog_input(codec); + ad1988_auto_init_unsol_event(codec); return 0; }
codec->patch_ops = ad198x_patch_ops; switch (board_config) { case AD1988_AUTO: codec->patch_ops.init = ad1988_auto_init; + codec->patch_ops.unsol_event = ad1988_unsol_event; break;
participants (2)
-
Raymond Yau
-
Takashi Iwai