aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_jack.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sound/pci/hda/hda_jack.c112
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);