diff options
Diffstat (limited to '')
-rw-r--r-- | sound/pci/hda/hda_jack.c | 112 |
1 files changed, 107 insertions, 5 deletions
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 02cc682caa55..7d7786df60ea 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -158,6 +158,17 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid, int dev_id) return jack; } +void snd_hda_jack_tbl_disconnect(struct hda_codec *codec) +{ + struct hda_jack_tbl *jack = codec->jacktbl.list; + int i; + + for (i = 0; i < codec->jacktbl.used; i++, jack++) { + if (!codec->bus->shutdown && jack->jack) + snd_device_disconnect(codec->card, jack->jack); + } +} + void snd_hda_jack_tbl_clear(struct hda_codec *codec) { struct hda_jack_tbl *jack = codec->jacktbl.list; @@ -213,7 +224,7 @@ static void jack_detect_update(struct hda_codec *codec, } /** - * snd_hda_set_dirty_all - Mark all the cached as dirty + * snd_hda_jack_set_dirty_all - Mark all the cached as dirty * @codec: the HDA codec * * This function sets the dirty flag to all entries of jack table. @@ -275,8 +286,25 @@ int snd_hda_jack_detect_state_mst(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state_mst); +static struct hda_jack_callback * +find_callback_from_list(struct hda_jack_tbl *jack, + hda_jack_callback_fn func) +{ + struct hda_jack_callback *cb; + + if (!func) + return NULL; + + for (cb = jack->callback; cb; cb = cb->next) { + if (cb->func == func) + return cb; + } + + return NULL; +} + /** - * snd_hda_jack_detect_enable_mst - enable the jack-detection + * snd_hda_jack_detect_enable_callback_mst - enable the jack-detection * @codec: the HDA codec * @nid: pin NID to enable * @func: callback function to register @@ -297,7 +325,10 @@ snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, jack = snd_hda_jack_tbl_new(codec, nid, dev_id); if (!jack) return ERR_PTR(-ENOMEM); - if (func) { + + callback = find_callback_from_list(jack, func); + + if (func && !callback) { callback = kzalloc(sizeof(*callback), GFP_KERNEL); if (!callback) return ERR_PTR(-ENOMEM); @@ -369,6 +400,69 @@ int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); /** + * snd_hda_jack_bind_keymap - bind keys generated from one NID to another jack. + * @codec: the HDA codec + * @key_nid: key event is generated by this pin NID + * @keymap: map of key type and key code + * @jack_nid: key reports to the jack of this pin NID + * + * This function is used in the case of key is generated from one NID while is + * reported to the jack of another NID. + */ +int snd_hda_jack_bind_keymap(struct hda_codec *codec, hda_nid_t key_nid, + const struct hda_jack_keymap *keymap, + hda_nid_t jack_nid) +{ + const struct hda_jack_keymap *map; + struct hda_jack_tbl *key_gen = snd_hda_jack_tbl_get(codec, key_nid); + struct hda_jack_tbl *report_to = snd_hda_jack_tbl_get(codec, jack_nid); + + WARN_ON(codec->dp_mst); + + if (!key_gen || !report_to || !report_to->jack) + return -EINVAL; + + key_gen->key_report_jack = jack_nid; + + if (keymap) + for (map = keymap; map->type; map++) + snd_jack_set_key(report_to->jack, map->type, map->key); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_jack_bind_keymap); + +/** + * snd_hda_jack_set_button_state - report button event to the hda_jack_tbl button_state. + * @codec: the HDA codec + * @jack_nid: the button event reports to the jack_tbl of this NID + * @button_state: the button event captured by codec + * + * Codec driver calls this function to report the button event. + */ +void snd_hda_jack_set_button_state(struct hda_codec *codec, hda_nid_t jack_nid, + int button_state) +{ + struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, jack_nid); + + if (!jack) + return; + + if (jack->key_report_jack) { + struct hda_jack_tbl *report_to = + snd_hda_jack_tbl_get(codec, jack->key_report_jack); + + if (report_to) { + report_to->button_state = button_state; + return; + } + } + + jack->button_state = button_state; +} +EXPORT_SYMBOL_GPL(snd_hda_jack_set_button_state); + +/** * snd_hda_jack_report_sync - sync the states of all jacks and report if changed * @codec: the HDA codec */ @@ -510,7 +604,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, !is_jack_detectable(codec, nid); if (base_name) - strlcpy(name, base_name, sizeof(name)); + strscpy(name, base_name, sizeof(name)); else snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL); if (phantom_jack) @@ -631,7 +725,15 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) } if (!event) return; - event->jack_dirty = 1; + + if (event->key_report_jack) { + struct hda_jack_tbl *report_to = + snd_hda_jack_tbl_get_mst(codec, event->key_report_jack, + event->dev_id); + if (report_to) + report_to->jack_dirty = 1; + } else + event->jack_dirty = 1; call_jack_callback(codec, res, event); snd_hda_jack_report_sync(codec); |