diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 87498235787a..74b46952fc98 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -339,9 +339,15 @@ void snd_hda_jack_report_sync(struct hda_codec *codec) if (jack->nid) { if (!jack->jack || jack->block_report) continue; - state = get_jack_plug_state(jack->pin_sense); - snd_jack_report(jack->jack, - state ? jack->type : 0); + state = jack->button_state; + if (get_jack_plug_state(jack->pin_sense)) + state |= jack->type; + snd_jack_report(jack->jack, state); + if (jack->button_state) { + snd_jack_report(jack->jack, + state & ~jack->button_state); + jack->button_state = 0; /* button released */ + } } } EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync); @@ -379,15 +385,19 @@ static void hda_free_jack_priv(struct snd_jack *jack) * @nid: pin NID to assign * @name: string name for the jack * @phantom_jack: flag to deal as a phantom jack + * @type: jack type bits to be reported, 0 for guessing from pincfg + * @keymap: optional jack / key mapping * * This assigns a jack-detection kctl to the given pin. The kcontrol * will have the given name and index. */ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, - const char *name, bool phantom_jack) + const char *name, bool phantom_jack, + int type, const struct hda_jack_keymap *keymap) { struct hda_jack_tbl *jack; - int err, state, type; + const struct hda_jack_keymap *map; + int err, state, buttons; jack = snd_hda_jack_tbl_new(codec, nid); if (!jack) @@ -395,16 +405,30 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, if (jack->jack) return 0; /* already created */ - type = get_input_jack_type(codec, nid); - err = snd_jack_new(codec->card, name, type, + if (!type) + type = get_input_jack_type(codec, nid); + + buttons = 0; + if (keymap) { + for (map = keymap; map->type; map++) + buttons |= map->type; + } + + err = snd_jack_new(codec->card, name, type | buttons, &jack->jack, true, phantom_jack); if (err < 0) return err; jack->phantom_jack = !!phantom_jack; jack->type = type; + jack->button_state = 0; jack->jack->private_data = jack; jack->jack->private_free = hda_free_jack_priv; + if (keymap) { + for (map = keymap; map->type; map++) + snd_jack_set_key(jack->jack, map->type, map->key); + } + state = snd_hda_jack_detect(codec, nid); snd_jack_report(jack->jack, state ? jack->type : 0); @@ -437,7 +461,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, if (phantom_jack) /* Example final name: "Internal Mic Phantom Jack" */ strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); - err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack); + err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL); if (err < 0) return err; diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 695a652cc6b3..1d713201c160 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -13,6 +13,7 @@ #define __SOUND_HDA_JACK_H #include +#include struct auto_pin_cfg; struct hda_jack_tbl; @@ -42,9 +43,15 @@ struct hda_jack_tbl { hda_nid_t gating_jack; /* valid when gating jack plugged */ hda_nid_t gated_jack; /* gated is dependent on this jack */ int type; + int button_state; struct snd_jack *jack; }; +struct hda_jack_keymap { + enum snd_jack_types type; + int key; +}; + struct hda_jack_tbl * snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid); struct hda_jack_tbl * @@ -84,7 +91,8 @@ static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid); int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, - const char *name, bool phantom_jack); + const char *name, bool phantom_jack, + int type, const struct hda_jack_keymap *keymap); int snd_hda_jack_add_kctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 5fb3fa660b89..1e5412800d24 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2142,7 +2142,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx) strncat(hdmi_str, " Phantom", sizeof(hdmi_str) - strlen(hdmi_str) - 1); ret = snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str, - phantom_jack); + phantom_jack, 0, NULL); if (ret < 0) return ret; jack = snd_hda_jack_tbl_get(codec, per_pin->pin_nid);