[alsa-devel] [PATCH] hda: add support for jack detection on IDT/Sigmatel
Added support for jack detection reporting to userspace for IDT/Sigmatel codecs.
Signed-off-by: Matthew Ranostay mranostay@embeddedalley.com ---
diff --git a/core/jack.c b/core/jack.c index 8133a2b..7a5b07b 100644 --- a/core/jack.c +++ b/core/jack.c @@ -95,7 +95,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, goto fail_input; }
- jack->input_dev->phys = "ALSA"; + jack->input_dev->phys = "ALSA Jack Detection";
jack->type = type;
diff --git a/pci/Kconfig b/pci/Kconfig index 7003711..7e40890 100644 --- a/pci/Kconfig +++ b/pci/Kconfig @@ -501,6 +501,7 @@ config SND_HDA_INTEL tristate "Intel HD Audio" select SND_PCM select SND_VMASTER + select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for Intel "High Definition Audio" (Azalia) motherboard devices. diff --git a/pci/hda/hda_codec.h b/pci/hda/hda_codec.h index 60468f5..93dc961 100644 --- a/pci/hda/hda_codec.h +++ b/pci/hda/hda_codec.h @@ -729,6 +729,9 @@ struct hda_codec {
struct snd_hwdep *hwdep; /* assigned hwdep device */
+ /* jack detection */ + struct snd_jack *jack; + /* misc flags */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each * status change diff --git a/pci/hda/hda_proc.c b/pci/hda/hda_proc.c index 743d779..e07652a 100644 --- a/pci/hda/hda_proc.c +++ b/pci/hda/hda_proc.c @@ -425,6 +425,22 @@ static void print_unsol_cap(struct snd_info_buffer *buffer, (unsol & AC_UNSOL_ENABLED) ? 1 : 0); }
+static void print_presence_cap(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + int presence = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_SENSE, 0); + int def_conf = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0x00); + def_conf = get_defcfg_connect(def_conf); + if (def_conf && def_conf != AC_JACK_PORT_FIXED) + return; + snd_iprintf(buffer, + " Jack Presence: %s\n", + (presence & AC_PINSENSE_PRESENCE) + ? "Plugged in" : "Unplugged"); +} + static void print_proc_caps(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { @@ -552,6 +568,9 @@ static void print_codec_info(struct snd_info_entry *entry, AC_PAR_AUDIO_WIDGET_CAP); unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + unsigned int pincap = snd_hda_param_read(codec, nid, + AC_PAR_PIN_CAP); + hda_nid_t conn[HDA_MAX_CONNECTIONS]; int conn_len = 0;
@@ -632,6 +651,9 @@ static void print_codec_info(struct snd_info_entry *entry, if (wid_caps & AC_WCAP_UNSOL_CAP) print_unsol_cap(buffer, codec, nid);
+ if (pincap & AC_PINCAP_PRES_DETECT) + print_presence_cap(buffer, codec, nid); + if (wid_caps & AC_WCAP_POWER) print_power_state(buffer, codec, nid);
diff --git a/pci/hda/patch_sigmatel.c b/pci/hda/patch_sigmatel.c index a2ac720..a406fa7 100644 --- a/pci/hda/patch_sigmatel.c +++ b/pci/hda/patch_sigmatel.c @@ -30,6 +30,7 @@ #include <linux/pci.h> #include <sound/core.h> #include <sound/asoundef.h> +#include <sound/jack.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_patch.h" @@ -3617,7 +3618,7 @@ static int stac92xx_init(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i; + int i, err;
snd_hda_sequence_write(codec, spec->init);
@@ -3639,6 +3640,12 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], AC_PINCTL_OUT_EN); stac92xx_auto_init_hp_out(codec); + /* jack detection */ + err = snd_jack_new(codec->bus->card, + "Headphone Jack Detection", + SND_JACK_HEADPHONE, &codec->jack); + if (err < 0) + return err; /* fake event to set up pins */ codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); } else { @@ -3797,6 +3804,10 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); }
+ if (codec->jack) + snd_jack_report(codec->jack, + presence ? SND_JACK_HEADPHONE : 0); + if (presence) { /* disable lineouts, enable hp */ if (spec->hp_switch)
At Wed, 15 Oct 2008 10:43:28 -0400, Matthew Ranostay wrote:
diff --git a/core/jack.c b/core/jack.c index 8133a2b..7a5b07b 100644 --- a/core/jack.c +++ b/core/jack.c @@ -95,7 +95,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, goto fail_input; }
- jack->input_dev->phys = "ALSA";
- jack->input_dev->phys = "ALSA Jack Detection";
Any reason to change?
Well, I think even the original phys value "ALSA" is a bit strange in comparison with values of other input drivers, such as "isa0060/serio0/input0", "PNP0C0C/button/input0", too... Mark, what do you think?
jack->type = type;
diff --git a/pci/Kconfig b/pci/Kconfig index 7003711..7e40890 100644 --- a/pci/Kconfig +++ b/pci/Kconfig @@ -501,6 +501,7 @@ config SND_HDA_INTEL tristate "Intel HD Audio" select SND_PCM select SND_VMASTER
- select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for Intel "High Definition Audio" (Azalia) motherboard devices.
diff --git a/pci/hda/hda_codec.h b/pci/hda/hda_codec.h index 60468f5..93dc961 100644 --- a/pci/hda/hda_codec.h +++ b/pci/hda/hda_codec.h @@ -729,6 +729,9 @@ struct hda_codec {
struct snd_hwdep *hwdep; /* assigned hwdep device */
- /* jack detection */
- struct snd_jack *jack;
- /* misc flags */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each * status change
Does this have to be in hda_codec core now? Maybe later, but I feel it's too early to change the core side unless you really need it. Note that you may have multiple headphone, mic, line-in and whatever jacks. So, if any, it should be either an array or a list as a more generic representation.
And, if you add struct snd_jack there, include <sound/jack.h> in that header, or add a forward declaration of the struct.
diff --git a/pci/hda/hda_proc.c b/pci/hda/hda_proc.c index 743d779..e07652a 100644 --- a/pci/hda/hda_proc.c +++ b/pci/hda/hda_proc.c @@ -425,6 +425,22 @@ static void print_unsol_cap(struct snd_info_buffer *buffer, (unsol & AC_UNSOL_ENABLED) ? 1 : 0); }
+static void print_presence_cap(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid)
+{
- int presence = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_SENSE, 0);
- int def_conf = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONFIG_DEFAULT, 0x00);
- def_conf = get_defcfg_connect(def_conf);
- if (def_conf && def_conf != AC_JACK_PORT_FIXED)
return;
- snd_iprintf(buffer,
" Jack Presence: %s\n",
(presence & AC_PINSENSE_PRESENCE)
? "Plugged in" : "Unplugged");
+}
static void print_proc_caps(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { @@ -552,6 +568,9 @@ static void print_codec_info(struct snd_info_entry *entry, AC_PAR_AUDIO_WIDGET_CAP); unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
unsigned int pincap = snd_hda_param_read(codec, nid,
AC_PAR_PIN_CAP);
- hda_nid_t conn[HDA_MAX_CONNECTIONS]; int conn_len = 0;
@@ -632,6 +651,9 @@ static void print_codec_info(struct snd_info_entry *entry, if (wid_caps & AC_WCAP_UNSOL_CAP) print_unsol_cap(buffer, codec, nid);
if (pincap & AC_PINCAP_PRES_DETECT)
print_presence_cap(buffer, codec, nid);
- if (wid_caps & AC_WCAP_POWER) print_power_state(buffer, codec, nid);
Sorry, I don't want to put this into proc file. In some obscure hardwares, you can't call jack-detect verb always even if the pin shows it's possible, and it breaks the later jack-sense reading (believe nor not :) In some cases, it needs triggering. So, "just read" is dangerous.
BTW, this change has nothing to do with the addition of jack layer support. If this addition is inevitably necessary, please split to an individual patch.
Thanks,
Takashi
Takashi Iwai wrote:
At Wed, 15 Oct 2008 10:43:28 -0400, Matthew Ranostay wrote:
diff --git a/core/jack.c b/core/jack.c index 8133a2b..7a5b07b 100644 --- a/core/jack.c +++ b/core/jack.c @@ -95,7 +95,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, goto fail_input; }
- jack->input_dev->phys = "ALSA";
- jack->input_dev->phys = "ALSA Jack Detection";
Any reason to change?
Well, I think even the original phys value "ALSA" is a bit strange in comparison with values of other input drivers, such as "isa0060/serio0/input0", "PNP0C0C/button/input0", too... Mark, what do you think?
jack->type = type;
diff --git a/pci/Kconfig b/pci/Kconfig index 7003711..7e40890 100644 --- a/pci/Kconfig +++ b/pci/Kconfig @@ -501,6 +501,7 @@ config SND_HDA_INTEL tristate "Intel HD Audio" select SND_PCM select SND_VMASTER
- select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for Intel "High Definition Audio" (Azalia) motherboard devices.
diff --git a/pci/hda/hda_codec.h b/pci/hda/hda_codec.h index 60468f5..93dc961 100644 --- a/pci/hda/hda_codec.h +++ b/pci/hda/hda_codec.h @@ -729,6 +729,9 @@ struct hda_codec {
struct snd_hwdep *hwdep; /* assigned hwdep device */
- /* jack detection */
- struct snd_jack *jack;
- /* misc flags */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each * status change
Does this have to be in hda_codec core now? Maybe later, but I feel it's too early to change the core side unless you really need it. Note that you may have multiple headphone, mic, line-in and whatever jacks. So, if any, it should be either an array or a list as a more generic representation.
And, if you add struct snd_jack there, include <sound/jack.h> in that header, or add a forward declaration of the struct.
diff --git a/pci/hda/hda_proc.c b/pci/hda/hda_proc.c index 743d779..e07652a 100644 --- a/pci/hda/hda_proc.c +++ b/pci/hda/hda_proc.c @@ -425,6 +425,22 @@ static void print_unsol_cap(struct snd_info_buffer *buffer, (unsol & AC_UNSOL_ENABLED) ? 1 : 0); }
+static void print_presence_cap(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid)
+{
- int presence = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_SENSE, 0);
- int def_conf = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONFIG_DEFAULT, 0x00);
- def_conf = get_defcfg_connect(def_conf);
- if (def_conf && def_conf != AC_JACK_PORT_FIXED)
return;
- snd_iprintf(buffer,
" Jack Presence: %s\n",
(presence & AC_PINSENSE_PRESENCE)
? "Plugged in" : "Unplugged");
+}
static void print_proc_caps(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { @@ -552,6 +568,9 @@ static void print_codec_info(struct snd_info_entry *entry, AC_PAR_AUDIO_WIDGET_CAP); unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
unsigned int pincap = snd_hda_param_read(codec, nid,
AC_PAR_PIN_CAP);
- hda_nid_t conn[HDA_MAX_CONNECTIONS]; int conn_len = 0;
@@ -632,6 +651,9 @@ static void print_codec_info(struct snd_info_entry *entry, if (wid_caps & AC_WCAP_UNSOL_CAP) print_unsol_cap(buffer, codec, nid);
if (pincap & AC_PINCAP_PRES_DETECT)
print_presence_cap(buffer, codec, nid);
- if (wid_caps & AC_WCAP_POWER) print_power_state(buffer, codec, nid);
Sorry, I don't want to put this into proc file. In some obscure hardwares, you can't call jack-detect verb always even if the pin shows it's possible, and it breaks the later jack-sense reading (believe nor not :) In some cases, it needs triggering. So, "just read" is dangerous.
So what is the safest way to report the initial state of the jacks then?
BTW, this change has nothing to do with the addition of jack layer support. If this addition is inevitably necessary, please split to an individual patch.
Thanks,
Takashi
At Wed, 15 Oct 2008 11:19:10 -0400, Matthew Ranostay wrote:
Takashi Iwai wrote:
At Wed, 15 Oct 2008 10:43:28 -0400, Matthew Ranostay wrote:
diff --git a/core/jack.c b/core/jack.c index 8133a2b..7a5b07b 100644 --- a/core/jack.c +++ b/core/jack.c @@ -95,7 +95,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, goto fail_input; }
- jack->input_dev->phys = "ALSA";
- jack->input_dev->phys = "ALSA Jack Detection";
Any reason to change?
Well, I think even the original phys value "ALSA" is a bit strange in comparison with values of other input drivers, such as "isa0060/serio0/input0", "PNP0C0C/button/input0", too... Mark, what do you think?
jack->type = type;
diff --git a/pci/Kconfig b/pci/Kconfig index 7003711..7e40890 100644 --- a/pci/Kconfig +++ b/pci/Kconfig @@ -501,6 +501,7 @@ config SND_HDA_INTEL tristate "Intel HD Audio" select SND_PCM select SND_VMASTER
- select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for Intel "High Definition Audio" (Azalia) motherboard devices.
diff --git a/pci/hda/hda_codec.h b/pci/hda/hda_codec.h index 60468f5..93dc961 100644 --- a/pci/hda/hda_codec.h +++ b/pci/hda/hda_codec.h @@ -729,6 +729,9 @@ struct hda_codec {
struct snd_hwdep *hwdep; /* assigned hwdep device */
- /* jack detection */
- struct snd_jack *jack;
- /* misc flags */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each * status change
Does this have to be in hda_codec core now? Maybe later, but I feel it's too early to change the core side unless you really need it. Note that you may have multiple headphone, mic, line-in and whatever jacks. So, if any, it should be either an array or a list as a more generic representation.
And, if you add struct snd_jack there, include <sound/jack.h> in that header, or add a forward declaration of the struct.
diff --git a/pci/hda/hda_proc.c b/pci/hda/hda_proc.c index 743d779..e07652a 100644 --- a/pci/hda/hda_proc.c +++ b/pci/hda/hda_proc.c @@ -425,6 +425,22 @@ static void print_unsol_cap(struct snd_info_buffer *buffer, (unsol & AC_UNSOL_ENABLED) ? 1 : 0); }
+static void print_presence_cap(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid)
+{
- int presence = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_SENSE, 0);
- int def_conf = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONFIG_DEFAULT, 0x00);
- def_conf = get_defcfg_connect(def_conf);
- if (def_conf && def_conf != AC_JACK_PORT_FIXED)
return;
- snd_iprintf(buffer,
" Jack Presence: %s\n",
(presence & AC_PINSENSE_PRESENCE)
? "Plugged in" : "Unplugged");
+}
static void print_proc_caps(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { @@ -552,6 +568,9 @@ static void print_codec_info(struct snd_info_entry *entry, AC_PAR_AUDIO_WIDGET_CAP); unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
unsigned int pincap = snd_hda_param_read(codec, nid,
AC_PAR_PIN_CAP);
- hda_nid_t conn[HDA_MAX_CONNECTIONS]; int conn_len = 0;
@@ -632,6 +651,9 @@ static void print_codec_info(struct snd_info_entry *entry, if (wid_caps & AC_WCAP_UNSOL_CAP) print_unsol_cap(buffer, codec, nid);
if (pincap & AC_PINCAP_PRES_DETECT)
print_presence_cap(buffer, codec, nid);
- if (wid_caps & AC_WCAP_POWER) print_power_state(buffer, codec, nid);
Sorry, I don't want to put this into proc file. In some obscure hardwares, you can't call jack-detect verb always even if the pin shows it's possible, and it breaks the later jack-sense reading (believe nor not :) In some cases, it needs triggering. So, "just read" is dangerous.
So what is the safest way to report the initial state of the jacks then?
Purely depends on the hardware. Really. In most hardwares, just reading jack-sense verb would be fine, though.
Takashi
On Wed, Oct 15, 2008 at 05:02:14PM +0200, Takashi Iwai wrote:
Matthew Ranostay wrote:
- jack->input_dev->phys = "ALSA Jack Detection";
Any reason to change?
Not like that. The only reason it's set at all at the minute is because evdev prints it out for diagnostic purposes and it'd show up as "(NULL)" which sets off alarm bells for people. The particular string isn't really important and the terseness varies between drivers that use fixed strings.
Note that this isn't the device name - that should generally be verbose (and is currently the card longname plus jack name which is idiomatic for this).
Well, I think even the original phys value "ALSA" is a bit strange in comparison with values of other input drivers, such as "isa0060/serio0/input0", "PNP0C0C/button/input0", too... Mark, what do you think?
It should ideally be something based off the location of the card in the system (like those you quote above) - the idea is that it's something that doesn't change between reboots and identifies the device. Not all input devices put something meaningful there. If we change it to anything it should probably be to something based off the bus_id of the input device.
It mostly only comes into play if you've got more than one of a device in the system and even then AIUI user space just uses sysfs these days, which is why I didn't bother originally.
On Wed, Oct 15, 2008 at 10:43:28AM -0400, Matthew Ranostay wrote:
@@ -3639,6 +3640,12 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], AC_PINCTL_OUT_EN); stac92xx_auto_init_hp_out(codec);
/* jack detection */
err = snd_jack_new(codec->bus->card,
"Headphone Jack Detection",
SND_JACK_HEADPHONE, &codec->jack);
if (err < 0)
That should probably just be "Headphone Jack".
return err;
...
- if (codec->jack)
snd_jack_report(codec->jack,
presence ? SND_JACK_HEADPHONE : 0);
Since you appear to fail init if you can't create the jack there should be no need to check for the jack being initialised here. For ease of use I'll just submit a patch folding that check into snd_jack_report(), though.
Mark Brown wrote:
On Wed, Oct 15, 2008 at 10:43:28AM -0400, Matthew Ranostay wrote:
@@ -3639,6 +3640,12 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], AC_PINCTL_OUT_EN); stac92xx_auto_init_hp_out(codec);
/* jack detection */
err = snd_jack_new(codec->bus->card,
"Headphone Jack Detection",
SND_JACK_HEADPHONE, &codec->jack);
if (err < 0)
That should probably just be "Headphone Jack".
return err;
...
- if (codec->jack)
snd_jack_report(codec->jack,
presence ? SND_JACK_HEADPHONE : 0);
Since you appear to fail init if you can't create the jack there should be no need to check for the jack being initialised here. For ease of use I'll just submit a patch folding that check into snd_jack_report(), though.
Good catch.
Thanks,
Matt Ranostay
At Wed, 15 Oct 2008 16:44:02 +0100, Mark Brown wrote:
- if (codec->jack)
snd_jack_report(codec->jack,
presence ? SND_JACK_HEADPHONE : 0);
Since you appear to fail init if you can't create the jack there should be no need to check for the jack being initialised here. For ease of use I'll just submit a patch folding that check into snd_jack_report(), though.
Such a change can go to 2.6.28, too, if received timely :)
Takashi
participants (3)
-
Mark Brown
-
Matthew Ranostay
-
Takashi Iwai