[alsa-devel] [PATCH] hda: add SW_LINEOUT_INSERT support
Add support for detecting line out pin insertion and reporting back to userspace with the jack abstraction layer. Line outs are reported with the macro defined SW_LINEOUT_INSERT code.
Signed-off-by: Matthew Ranostay mranostay@embeddedalley.com ---
diff --git a/include/linux/input.h b/include/linux/input.h index a5802c9..7323d2f 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -644,6 +644,7 @@ struct input_absinfo { #define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_DOCK 0x05 /* set = plugged into dock */ +#define SW_LINEOUT_INSERT 0x06 /* set = inserted */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1)
diff --git a/include/sound/jack.h b/include/sound/jack.h index b1b2b8b..7cb25f4 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -35,6 +35,7 @@ enum snd_jack_types { SND_JACK_HEADPHONE = 0x0001, SND_JACK_MICROPHONE = 0x0002, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE, + SND_JACK_LINEOUT = 0x0004, };
struct snd_jack { diff --git a/sound/core/jack.c b/sound/core/jack.c index bd2d9e6..4978db1 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -102,6 +102,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (type & SND_JACK_HEADPHONE) input_set_capability(jack->input_dev, EV_SW, SW_HEADPHONE_INSERT); + if (type & SND_JACK_LINEOUT) + input_set_capability(jack->input_dev, EV_SW, + SW_LINEOUT_INSERT); if (type & SND_JACK_MICROPHONE) input_set_capability(jack->input_dev, EV_SW, SW_MICROPHONE_INSERT); @@ -153,6 +156,9 @@ void snd_jack_report(struct snd_jack *jack, int status) if (jack->type & SND_JACK_HEADPHONE) input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, status & SND_JACK_HEADPHONE); + if (jack->type & SND_JACK_LINEOUT) + input_report_switch(jack->input_dev, SW_LINEOUT_INSERT, + status & SND_JACK_LINEOUT); if (jack->type & SND_JACK_MICROPHONE) input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, status & SND_JACK_MICROPHONE); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d106ea5..1b3cba8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -36,6 +36,7 @@ #include "hda_patch.h" #include "hda_beep.h"
+#define STAC_LINEOUT_EVENT 0x10 #define STAC_PWR_EVENT 0x20 #define STAC_HP_EVENT 0x30 #define STAC_VREF_EVENT 0x40 @@ -217,7 +218,8 @@ struct sigmatel_spec { struct hda_pcm pcm_rec[2]; /* PCM information */
/* jack detection */ - struct snd_jack *jack; + struct snd_jack *hp_jack; + struct snd_jack *lineout_jack;
/* dynamic controls and input_mux */ struct auto_pin_cfg autocfg; @@ -3635,9 +3637,15 @@ static int stac92xx_init(struct hda_codec *codec) /* jack detection */ err = snd_jack_new(codec->bus->card, "Headphone Jack", - SND_JACK_HEADPHONE, &spec->jack); + SND_JACK_HEADPHONE, &spec->hp_jack); if (err < 0) return err; + err = snd_jack_new(codec->bus->card, + "Lineout Jack", + SND_JACK_LINEOUT, &spec->lineout_jack); + if (err < 0) + return err; + /* fake event to set up pins */ codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); } else { @@ -3661,6 +3669,16 @@ static int stac92xx_init(struct hda_codec *codec) for (i = 0; i < spec->num_dmics; i++) stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], AC_PINCTL_IN_EN); + for (i = 0; i < cfg->line_outs; i++) { + int def_conf = snd_hda_codec_read(codec, cfg->line_out_pins[i], + 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + def_conf = get_defcfg_connect(def_conf); + + if (def_conf && def_conf != AC_JACK_PORT_FIXED) + continue; + enable_pin_detect(codec, cfg->line_out_pins[i], + STAC_LINEOUT_EVENT); + } for (i = 0; i < spec->num_pwrs; i++) { int event = is_nid_hp_pin(cfg, spec->pwr_nids[i]) ? STAC_HP_EVENT : STAC_PWR_EVENT; @@ -3717,8 +3735,10 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return;
- if (spec->jack) - snd_device_free(codec->bus->card, spec->jack); + if (spec->hp_jack) + snd_device_free(codec->bus->card, spec->hp_jack); + if (spec->lineout_jack) + snd_device_free(codec->bus->card, spec->lineout_jack);
if (spec->bios_pin_configs) kfree(spec->bios_pin_configs); @@ -3804,7 +3824,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) break; presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); } - snd_jack_report(spec->jack, + snd_jack_report(spec->hp_jack, presence ? SND_JACK_HEADPHONE : 0);
if (presence) { @@ -3840,6 +3860,28 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); }
+static void stac92xx_lineout_detect(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int presence, i; + + for (i = 0; i < cfg->line_outs; i++) { + int def_conf = snd_hda_codec_read(codec, + cfg->line_out_pins[i], 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + def_conf = get_defcfg_connect(def_conf); + + if (def_conf && def_conf != AC_JACK_PORT_FIXED) + continue; + presence = get_hp_pin_presence(codec, + cfg->line_out_pins[i]); + if (presence) + break; + } + snd_jack_report(spec->lineout_jack, presence ? SND_JACK_LINEOUT : 0); +} + static void stac92xx_pin_sense(struct hda_codec *codec, int idx) { struct sigmatel_spec *spec = codec->spec; @@ -3868,15 +3910,20 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) { struct sigmatel_spec *spec = codec->spec; int idx = res >> 26 & 0x0f; + int event = (res >> 26) & 0x70;
- switch ((res >> 26) & 0x70) { + switch (event) { case STAC_HP_EVENT: stac92xx_hp_detect(codec, res); /* fallthru */ case STAC_PWR_EVENT: if (spec->num_pwrs > 0) stac92xx_pin_sense(codec, idx); - break; + /* fallthru */ + case STAC_LINEOUT_EVENT: + if (event == STAC_HP_EVENT) + break; + stac92xx_lineout_detect(codec); case STAC_VREF_EVENT: { int data = snd_hda_codec_read(codec, codec->afg, 0, AC_VERB_GET_GPIO_DATA, 0);
At Thu, 16 Oct 2008 22:18:40 -0400, Matthew Ranostay wrote:
Add support for detecting line out pin insertion and reporting back to userspace with the jack abstraction layer. Line outs are reported with the macro defined SW_LINEOUT_INSERT code.
Signed-off-by: Matthew Ranostay mranostay@embeddedalley.com
Thanks for the patch. Added Dmitry and Mark to Cc for review.
Adding one element should be fine, but I'm wondering whether more and more pin type would come up in future...
More comments below.
diff --git a/include/linux/input.h b/include/linux/input.h index a5802c9..7323d2f 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -644,6 +644,7 @@ struct input_absinfo { #define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_DOCK 0x05 /* set = plugged into dock */ +#define SW_LINEOUT_INSERT 0x06 /* set = inserted */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1)
diff --git a/include/sound/jack.h b/include/sound/jack.h index b1b2b8b..7cb25f4 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -35,6 +35,7 @@ enum snd_jack_types { SND_JACK_HEADPHONE = 0x0001, SND_JACK_MICROPHONE = 0x0002, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
- SND_JACK_LINEOUT = 0x0004,
};
So, you don't need to judge different line-outs, such as front and rear?
struct snd_jack { diff --git a/sound/core/jack.c b/sound/core/jack.c index bd2d9e6..4978db1 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -102,6 +102,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (type & SND_JACK_HEADPHONE) input_set_capability(jack->input_dev, EV_SW, SW_HEADPHONE_INSERT);
- if (type & SND_JACK_LINEOUT)
input_set_capability(jack->input_dev, EV_SW,
if (type & SND_JACK_MICROPHONE) input_set_capability(jack->input_dev, EV_SW, SW_MICROPHONE_INSERT);SW_LINEOUT_INSERT);
@@ -153,6 +156,9 @@ void snd_jack_report(struct snd_jack *jack, int status) if (jack->type & SND_JACK_HEADPHONE) input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, status & SND_JACK_HEADPHONE);
- if (jack->type & SND_JACK_LINEOUT)
input_report_switch(jack->input_dev, SW_LINEOUT_INSERT,
if (jack->type & SND_JACK_MICROPHONE) input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, status & SND_JACK_MICROPHONE);status & SND_JACK_LINEOUT);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d106ea5..1b3cba8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -36,6 +36,7 @@ #include "hda_patch.h" #include "hda_beep.h"
+#define STAC_LINEOUT_EVENT 0x10 #define STAC_PWR_EVENT 0x20 #define STAC_HP_EVENT 0x30 #define STAC_VREF_EVENT 0x40 @@ -217,7 +218,8 @@ struct sigmatel_spec { struct hda_pcm pcm_rec[2]; /* PCM information */
/* jack detection */
- struct snd_jack *jack;
struct snd_jack *hp_jack;
struct snd_jack *lineout_jack;
/* dynamic controls and input_mux */ struct auto_pin_cfg autocfg;
@@ -3635,9 +3637,15 @@ static int stac92xx_init(struct hda_codec *codec) /* jack detection */ err = snd_jack_new(codec->bus->card, "Headphone Jack",
SND_JACK_HEADPHONE, &spec->jack);
if (err < 0) return err;SND_JACK_HEADPHONE, &spec->hp_jack);
err = snd_jack_new(codec->bus->card,
"Lineout Jack",
SND_JACK_LINEOUT, &spec->lineout_jack);
if (err < 0)
return err;
- /* fake event to set up pins */ codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); } else {
@@ -3661,6 +3669,16 @@ static int stac92xx_init(struct hda_codec *codec) for (i = 0; i < spec->num_dmics; i++) stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], AC_PINCTL_IN_EN);
- for (i = 0; i < cfg->line_outs; i++) {
int def_conf = snd_hda_codec_read(codec, cfg->line_out_pins[i],
0, AC_VERB_GET_CONFIG_DEFAULT, 0);
def_conf = get_defcfg_connect(def_conf);
if (def_conf && def_conf != AC_JACK_PORT_FIXED)
continue;
enable_pin_detect(codec, cfg->line_out_pins[i],
STAC_LINEOUT_EVENT);
- } for (i = 0; i < spec->num_pwrs; i++) { int event = is_nid_hp_pin(cfg, spec->pwr_nids[i]) ? STAC_HP_EVENT : STAC_PWR_EVENT;
@@ -3717,8 +3735,10 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return;
- if (spec->jack)
snd_device_free(codec->bus->card, spec->jack);
- if (spec->hp_jack)
snd_device_free(codec->bus->card, spec->hp_jack);
- if (spec->lineout_jack)
snd_device_free(codec->bus->card, spec->lineout_jack);
Good that you already caught the recent change ;)
if (spec->bios_pin_configs) kfree(spec->bios_pin_configs); @@ -3804,7 +3824,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) break; presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); }
- snd_jack_report(spec->jack,
snd_jack_report(spec->hp_jack, presence ? SND_JACK_HEADPHONE : 0);
if (presence) {
@@ -3840,6 +3860,28 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); }
+static void stac92xx_lineout_detect(struct hda_codec *codec) +{
- struct sigmatel_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int presence, i;
- for (i = 0; i < cfg->line_outs; i++) {
int def_conf = snd_hda_codec_read(codec,
cfg->line_out_pins[i], 0,
AC_VERB_GET_CONFIG_DEFAULT, 0);
def_conf = get_defcfg_connect(def_conf);
if (def_conf && def_conf != AC_JACK_PORT_FIXED)
continue;
presence = get_hp_pin_presence(codec,
cfg->line_out_pins[i]);
if (presence)
break;
- }
- snd_jack_report(spec->lineout_jack, presence ? SND_JACK_LINEOUT : 0);
+}
static void stac92xx_pin_sense(struct hda_codec *codec, int idx) { struct sigmatel_spec *spec = codec->spec; @@ -3868,15 +3910,20 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) { struct sigmatel_spec *spec = codec->spec; int idx = res >> 26 & 0x0f;
- int event = (res >> 26) & 0x70;
- switch ((res >> 26) & 0x70) {
- switch (event) { case STAC_HP_EVENT: stac92xx_hp_detect(codec, res); /* fallthru */ case STAC_PWR_EVENT: if (spec->num_pwrs > 0) stac92xx_pin_sense(codec, idx);
break;
/* fallthru */
- case STAC_LINEOUT_EVENT:
if (event == STAC_HP_EVENT)
break;
stac92xx_lineout_detect(codec);
Is here also fallthru? Then I'd suggest you to rewrite with a simple if, or separate somehow better. Too many fallthru in a switch is difficult to follow the code flow.
thanks,
Takashi
On Fri, Oct 17, 2008 at 08:06:21AM +0200, Takashi Iwai wrote:
Matthew Ranostay wrote:
Add support for detecting line out pin insertion and reporting back to userspace with the jack abstraction layer. Line outs are reported with the macro defined SW_LINEOUT_INSERT code.
Signed-off-by: Matthew Ranostay mranostay@embeddedalley.com
Thanks for the patch. Added Dmitry and Mark to Cc for review.
Matthew, as a general comment it would be helpful if you would split your patches up to separate out changes more and post as a series rather than as a single patch. Doing that makes review easier. For example, this patch includes both an addition to the jack reporting API and support for using it in a particular device.
Adding one element should be fine, but I'm wondering whether more and more pin type would come up in future...
That was a fear here - the conclusion was that we deal with that when it gets to be a problem.
SND_JACK_HEADPHONE = 0x0001, SND_JACK_MICROPHONE = 0x0002, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
- SND_JACK_LINEOUT = 0x0004,
};
So, you don't need to judge different line-outs, such as front and rear?
For line outputs I think providing that information in the device name would be better - the reason for providing the distinction in the switch is to provide information when the function of the device attached to the jack changes at runtime. As far as the hardware is concerned one line output is much the same as another.
err = snd_jack_new(codec->bus->card,
"Lineout Jack",
SND_JACK_LINEOUT, &spec->lineout_jack);
"Line Out" with two words.
Mark Brown wrote:
On Fri, Oct 17, 2008 at 08:06:21AM +0200, Takashi Iwai wrote:
Matthew Ranostay wrote:
Add support for detecting line out pin insertion and reporting back to userspace with the jack abstraction layer. Line outs are reported with the macro defined SW_LINEOUT_INSERT code.
Signed-off-by: Matthew Ranostay mranostay@embeddedalley.com
Thanks for the patch. Added Dmitry and Mark to Cc for review.
Matthew, as a general comment it would be helpful if you would split your patches up to separate out changes more and post as a series rather than as a single patch. Doing that makes review easier. For example, this patch includes both an addition to the jack reporting API and support for using it in a particular device.
Duly noted.
Adding one element should be fine, but I'm wondering whether more and more pin type would come up in future...
That was a fear here - the conclusion was that we deal with that when it gets to be a problem.
SND_JACK_HEADPHONE = 0x0001, SND_JACK_MICROPHONE = 0x0002, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
- SND_JACK_LINEOUT = 0x0004,
};
So, you don't need to judge different line-outs, such as front and rear?
No, at least not at the moment.
For line outputs I think providing that information in the device name would be better - the reason for providing the distinction in the switch is to provide information when the function of the device attached to the jack changes at runtime. As far as the hardware is concerned one line output is much the same as another.
err = snd_jack_new(codec->bus->card, "Jack Detection", SND_JACK_HEADPHONE | SND_JACK_LINEOUT, &spec->jack);
Do you mean something like this? Of course this will require some changes in snd_jack_report.
err = snd_jack_new(codec->bus->card,
"Lineout Jack",
SND_JACK_LINEOUT, &spec->lineout_jack);
"Line Out" with two words.
On Fri, Oct 17, 2008 at 08:21:17AM -0400, Matthew Ranostay wrote:
Mark Brown wrote:
For line outputs I think providing that information in the device name would be better - the reason for providing the distinction in the switch is to provide information when the function of the device attached to the jack changes at runtime. As far as the hardware is concerned one line output is much the same as another.
err = snd_jack_new(codec->bus->card, "Jack Detection", SND_JACK_HEADPHONE | SND_JACK_LINEOUT, &spec->jack);
Do you mean something like this?
I'm not sure exactly what you mean by that change. What the code says is that you have a single jack and can detect at runtime if the device plugged into it is a line or headphone. If that is the case then yes, you should do something like that though that's not a very good name for the jack (ideally it should correspond to something like the label given to the jack on the machine case).
Of course this will require some changes
in snd_jack_report.
Could you explain what changes you think are required? The API already supports multi-function jacks.
Mark Brown wrote:
On Fri, Oct 17, 2008 at 08:21:17AM -0400, Matthew Ranostay wrote:
Mark Brown wrote:
For line outputs I think providing that information in the device name would be better - the reason for providing the distinction in the switch is to provide information when the function of the device attached to the jack changes at runtime. As far as the hardware is concerned one line output is much the same as another.
err = snd_jack_new(codec->bus->card, "Jack Detection", SND_JACK_HEADPHONE | SND_JACK_LINEOUT, &spec->jack);
Do you mean something like this?
I'm not sure exactly what you mean by that change. What the code says is that you have a single jack and can detect at runtime if the device plugged into it is a line or headphone. If that is the case then yes, you should do something like that though that's not a very good name for the jack (ideally it should correspond to something like the label given to the jack on the machine case).
Well is generally only one HP out jack, but there can be several line-out reported by the one instance(lineout_jack). I assume this isn't the correct usage.
Of course this will require some changes
in snd_jack_report.
Could you explain what changes you think are required? The API already supports multi-function jacks.
On Fri, Oct 17, 2008 at 08:53:17AM -0400, Matthew Ranostay wrote:
Well is generally only one HP out jack, but there can be several line-out reported by the one instance(lineout_jack). I assume this isn't the correct usage.
Could you provide a bit more detail here? Are you saying that the hardware has several line outputs and can report connection status but is unable to identify which of them is connected?
Mark Brown wrote:
On Fri, Oct 17, 2008 at 08:53:17AM -0400, Matthew Ranostay wrote:
Well is generally only one HP out jack, but there can be several line-out reported by the one instance(lineout_jack). I assume this isn't the correct usage.
Could you provide a bit more detail here? Are you saying that the hardware has several line outputs and can report connection status but is unable to identify which of them is connected?
Yep, just wondering if that is an incorrect way of using the jack abstraction layer. As of yet we are only using this to confirm if an HP and Line Out is connected for use in ALSA plugin, if there is the stream processing is turned off.
So basically if you plug into two or more line outs, each time you unplug a line out, it will still send a event as if a line out was connected until all line outs are removed.
-Matt
On Fri, Oct 17, 2008 at 09:15:48AM -0400, Matthew Ranostay wrote:
Mark Brown wrote:
[Please fix your MUA to wrap at something less than 80 columns, currently your lines are ~90 characters long which makes your mails harder to read.]
Could you provide a bit more detail here? Are you saying that the hardware has several line outputs and can report connection status but is unable to identify which of them is connected?
Yep, just wondering if that is an incorrect way of using the jack abstraction layer.
It'd be easier to comment if you could provide more detail here. What is the hardware actually capable of doing? Without knowing what you're trying to represent it's hard to say for sure if your code matches up with that.
As of yet we are only using this to confirm if an HP and Line Out is connected for use in ALSA plugin, if there is the stream processing is turned off.
Right, that's one of the things I'd expected user space to be able to do with this.
So basically if you plug into two or more line outs, each time you unplug a line out, it will still send a event as if a line out was connected until all line outs are removed.
I *think* from this that you have multiple line output jacks and the hardware is able to do detection on each individually? In that case then yes, you are using the API incorrectly - you should be registering one jack per physical jack.
participants (3)
-
Mark Brown
-
Matthew Ranostay
-
Takashi Iwai