Loading sound/core/seq/seq_ump_convert.c +23 −14 Original line number Diff line number Diff line Loading @@ -1192,44 +1192,53 @@ static int cvt_sysex_to_ump(struct snd_seq_client *dest, { struct snd_seq_ump_event ev_cvt; unsigned char status; u8 buf[6], *xbuf; u8 buf[8], *xbuf; int offset = 0; int len, err; bool finished = false; if (!snd_seq_ev_is_variable(event)) return 0; setup_ump_event(&ev_cvt, event); for (;;) { while (!finished) { len = snd_seq_expand_var_event_at(event, sizeof(buf), buf, offset); if (len <= 0) break; if (WARN_ON(len > 6)) if (WARN_ON(len > sizeof(buf))) break; offset += len; xbuf = buf; status = UMP_SYSEX_STATUS_CONTINUE; /* truncate the sysex start-marker */ if (*xbuf == UMP_MIDI1_MSG_SYSEX_START) { status = UMP_SYSEX_STATUS_START; xbuf++; len--; if (len > 0 && xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { status = UMP_SYSEX_STATUS_SINGLE; len--; offset++; xbuf++; } } else { if (xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { /* if the last of this packet or the 1st byte of the next packet * is the end-marker, finish the transfer with this packet */ if (len > 0 && len < 8 && xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { if (status == UMP_SYSEX_STATUS_START) status = UMP_SYSEX_STATUS_SINGLE; else status = UMP_SYSEX_STATUS_END; len--; } else { status = UMP_SYSEX_STATUS_CONTINUE; } finished = true; } len = min(len, 6); fill_sysex7_ump(dest_port, ev_cvt.ump, status, xbuf, len); err = __snd_seq_deliver_single_event(dest, dest_port, (struct snd_seq_event *)&ev_cvt, atomic, hop); if (err < 0) return err; offset += len; } return 0; } Loading sound/pci/hda/hda_generic.c +63 −0 Original line number Diff line number Diff line Loading @@ -4955,6 +4955,69 @@ void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on) } EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm); /* forcibly mute the speaker output without caching; return true if updated */ static bool force_mute_output_path(struct hda_codec *codec, hda_nid_t nid) { if (!nid) return false; if (!nid_has_mute(codec, nid, HDA_OUTPUT)) return false; /* no mute, skip */ if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & snd_hda_codec_amp_read(codec, nid, 1, HDA_OUTPUT, 0) & HDA_AMP_MUTE) return false; /* both channels already muted, skip */ /* direct amp update without caching */ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT | HDA_AMP_MUTE); return true; } /** * snd_hda_gen_shutup_speakers - Forcibly mute the speaker outputs * @codec: the HDA codec * * Forcibly mute the speaker outputs, to be called at suspend or shutdown. * * The mute state done by this function isn't cached, hence the original state * will be restored at resume. * * Return true if the mute state has been changed. */ bool snd_hda_gen_shutup_speakers(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; const int *paths; const struct nid_path *path; int i, p, num_paths; bool updated = false; /* if already powered off, do nothing */ if (!snd_hdac_is_power_on(&codec->core)) return false; if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) { paths = spec->out_paths; num_paths = spec->autocfg.line_outs; } else { paths = spec->speaker_paths; num_paths = spec->autocfg.speaker_outs; } for (i = 0; i < num_paths; i++) { path = snd_hda_get_path_from_idx(codec, paths[i]); if (!path) continue; for (p = 0; p < path->depth; p++) if (force_mute_output_path(codec, path->path[p])) updated = true; } return updated; } EXPORT_SYMBOL_GPL(snd_hda_gen_shutup_speakers); /** * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and * set up the hda_gen_spec Loading sound/pci/hda/hda_generic.h +1 −0 Original line number Diff line number Diff line Loading @@ -353,5 +353,6 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec, int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec, int (*callback)(struct led_classdev *, enum led_brightness)); bool snd_hda_gen_shutup_speakers(struct hda_codec *codec); #endif /* __SOUND_HDA_GENERIC_H */ sound/pci/hda/patch_conexant.c +11 −45 Original line number Diff line number Diff line Loading @@ -21,12 +21,6 @@ #include "hda_jack.h" #include "hda_generic.h" enum { CX_HEADSET_NOPRESENT = 0, CX_HEADSET_PARTPRESENT, CX_HEADSET_ALLPRESENT, }; struct conexant_spec { struct hda_gen_spec gen; Loading @@ -48,7 +42,6 @@ struct conexant_spec { unsigned int gpio_led; unsigned int gpio_mute_led_mask; unsigned int gpio_mic_led_mask; unsigned int headset_present_flag; bool is_cx8070_sn6140; }; Loading Loading @@ -212,6 +205,8 @@ static void cx_auto_shutdown(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; snd_hda_gen_shutup_speakers(codec); /* Turn the problematic codec into D3 to avoid spurious noises from the internal speaker during (and after) reboot */ cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false); Loading Loading @@ -250,48 +245,19 @@ static void cx_process_headset_plugin(struct hda_codec *codec) } } static void cx_update_headset_mic_vref(struct hda_codec *codec, unsigned int res) static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_callback *event) { unsigned int phone_present, mic_persent, phone_tag, mic_tag; struct conexant_spec *spec = codec->spec; unsigned int mic_present; /* In cx8070 and sn6140, the node 16 can only be config to headphone or disabled, * the node 19 can only be config to microphone or disabled. * Check hp&mic tag to process headset pulgin&plugout. */ phone_tag = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0); mic_tag = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0); if ((phone_tag & (res >> AC_UNSOL_RES_TAG_SHIFT)) || (mic_tag & (res >> AC_UNSOL_RES_TAG_SHIFT))) { phone_present = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_PIN_SENSE, 0x0); if (!(phone_present & AC_PINSENSE_PRESENCE)) {/* headphone plugout */ spec->headset_present_flag = CX_HEADSET_NOPRESENT; mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20); return; } if (spec->headset_present_flag == CX_HEADSET_NOPRESENT) { spec->headset_present_flag = CX_HEADSET_PARTPRESENT; } else if (spec->headset_present_flag == CX_HEADSET_PARTPRESENT) { mic_persent = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); /* headset is present */ if ((phone_present & AC_PINSENSE_PRESENCE) && (mic_persent & AC_PINSENSE_PRESENCE)) { else cx_process_headset_plugin(codec); spec->headset_present_flag = CX_HEADSET_ALLPRESENT; } } } } static void cx_jack_unsol_event(struct hda_codec *codec, unsigned int res) { struct conexant_spec *spec = codec->spec; if (spec->is_cx8070_sn6140) cx_update_headset_mic_vref(codec, res); snd_hda_jack_unsol_event(codec, res); } static int cx_auto_suspend(struct hda_codec *codec) Loading @@ -305,7 +271,7 @@ static const struct hda_codec_ops cx_auto_patch_ops = { .build_pcms = snd_hda_gen_build_pcms, .init = cx_auto_init, .free = cx_auto_free, .unsol_event = cx_jack_unsol_event, .unsol_event = snd_hda_jack_unsol_event, .suspend = cx_auto_suspend, .check_power_status = snd_hda_gen_check_power_status, }; Loading Loading @@ -1163,7 +1129,7 @@ static int patch_conexant_auto(struct hda_codec *codec) case 0x14f11f86: case 0x14f11f87: spec->is_cx8070_sn6140 = true; spec->headset_present_flag = CX_HEADSET_NOPRESENT; snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); break; } Loading sound/pci/hda/patch_realtek.c +1 −0 Original line number Diff line number Diff line Loading @@ -9872,6 +9872,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x0840, "Acer Aspire E1", ALC269VB_FIXUP_ASPIRE_E1_COEF), SND_PCI_QUIRK(0x1025, 0x100c, "Acer Aspire E5-574G", ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1025, 0x101c, "Acer Veriton N2510G", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1065, "Acer Aspire C20-820", ALC269VC_FIXUP_ACER_HEADSET_MIC), Loading Loading
sound/core/seq/seq_ump_convert.c +23 −14 Original line number Diff line number Diff line Loading @@ -1192,44 +1192,53 @@ static int cvt_sysex_to_ump(struct snd_seq_client *dest, { struct snd_seq_ump_event ev_cvt; unsigned char status; u8 buf[6], *xbuf; u8 buf[8], *xbuf; int offset = 0; int len, err; bool finished = false; if (!snd_seq_ev_is_variable(event)) return 0; setup_ump_event(&ev_cvt, event); for (;;) { while (!finished) { len = snd_seq_expand_var_event_at(event, sizeof(buf), buf, offset); if (len <= 0) break; if (WARN_ON(len > 6)) if (WARN_ON(len > sizeof(buf))) break; offset += len; xbuf = buf; status = UMP_SYSEX_STATUS_CONTINUE; /* truncate the sysex start-marker */ if (*xbuf == UMP_MIDI1_MSG_SYSEX_START) { status = UMP_SYSEX_STATUS_START; xbuf++; len--; if (len > 0 && xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { status = UMP_SYSEX_STATUS_SINGLE; len--; offset++; xbuf++; } } else { if (xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { /* if the last of this packet or the 1st byte of the next packet * is the end-marker, finish the transfer with this packet */ if (len > 0 && len < 8 && xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { if (status == UMP_SYSEX_STATUS_START) status = UMP_SYSEX_STATUS_SINGLE; else status = UMP_SYSEX_STATUS_END; len--; } else { status = UMP_SYSEX_STATUS_CONTINUE; } finished = true; } len = min(len, 6); fill_sysex7_ump(dest_port, ev_cvt.ump, status, xbuf, len); err = __snd_seq_deliver_single_event(dest, dest_port, (struct snd_seq_event *)&ev_cvt, atomic, hop); if (err < 0) return err; offset += len; } return 0; } Loading
sound/pci/hda/hda_generic.c +63 −0 Original line number Diff line number Diff line Loading @@ -4955,6 +4955,69 @@ void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on) } EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm); /* forcibly mute the speaker output without caching; return true if updated */ static bool force_mute_output_path(struct hda_codec *codec, hda_nid_t nid) { if (!nid) return false; if (!nid_has_mute(codec, nid, HDA_OUTPUT)) return false; /* no mute, skip */ if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & snd_hda_codec_amp_read(codec, nid, 1, HDA_OUTPUT, 0) & HDA_AMP_MUTE) return false; /* both channels already muted, skip */ /* direct amp update without caching */ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT | HDA_AMP_MUTE); return true; } /** * snd_hda_gen_shutup_speakers - Forcibly mute the speaker outputs * @codec: the HDA codec * * Forcibly mute the speaker outputs, to be called at suspend or shutdown. * * The mute state done by this function isn't cached, hence the original state * will be restored at resume. * * Return true if the mute state has been changed. */ bool snd_hda_gen_shutup_speakers(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; const int *paths; const struct nid_path *path; int i, p, num_paths; bool updated = false; /* if already powered off, do nothing */ if (!snd_hdac_is_power_on(&codec->core)) return false; if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) { paths = spec->out_paths; num_paths = spec->autocfg.line_outs; } else { paths = spec->speaker_paths; num_paths = spec->autocfg.speaker_outs; } for (i = 0; i < num_paths; i++) { path = snd_hda_get_path_from_idx(codec, paths[i]); if (!path) continue; for (p = 0; p < path->depth; p++) if (force_mute_output_path(codec, path->path[p])) updated = true; } return updated; } EXPORT_SYMBOL_GPL(snd_hda_gen_shutup_speakers); /** * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and * set up the hda_gen_spec Loading
sound/pci/hda/hda_generic.h +1 −0 Original line number Diff line number Diff line Loading @@ -353,5 +353,6 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec, int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec, int (*callback)(struct led_classdev *, enum led_brightness)); bool snd_hda_gen_shutup_speakers(struct hda_codec *codec); #endif /* __SOUND_HDA_GENERIC_H */
sound/pci/hda/patch_conexant.c +11 −45 Original line number Diff line number Diff line Loading @@ -21,12 +21,6 @@ #include "hda_jack.h" #include "hda_generic.h" enum { CX_HEADSET_NOPRESENT = 0, CX_HEADSET_PARTPRESENT, CX_HEADSET_ALLPRESENT, }; struct conexant_spec { struct hda_gen_spec gen; Loading @@ -48,7 +42,6 @@ struct conexant_spec { unsigned int gpio_led; unsigned int gpio_mute_led_mask; unsigned int gpio_mic_led_mask; unsigned int headset_present_flag; bool is_cx8070_sn6140; }; Loading Loading @@ -212,6 +205,8 @@ static void cx_auto_shutdown(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; snd_hda_gen_shutup_speakers(codec); /* Turn the problematic codec into D3 to avoid spurious noises from the internal speaker during (and after) reboot */ cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false); Loading Loading @@ -250,48 +245,19 @@ static void cx_process_headset_plugin(struct hda_codec *codec) } } static void cx_update_headset_mic_vref(struct hda_codec *codec, unsigned int res) static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_callback *event) { unsigned int phone_present, mic_persent, phone_tag, mic_tag; struct conexant_spec *spec = codec->spec; unsigned int mic_present; /* In cx8070 and sn6140, the node 16 can only be config to headphone or disabled, * the node 19 can only be config to microphone or disabled. * Check hp&mic tag to process headset pulgin&plugout. */ phone_tag = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0); mic_tag = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0); if ((phone_tag & (res >> AC_UNSOL_RES_TAG_SHIFT)) || (mic_tag & (res >> AC_UNSOL_RES_TAG_SHIFT))) { phone_present = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_PIN_SENSE, 0x0); if (!(phone_present & AC_PINSENSE_PRESENCE)) {/* headphone plugout */ spec->headset_present_flag = CX_HEADSET_NOPRESENT; mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20); return; } if (spec->headset_present_flag == CX_HEADSET_NOPRESENT) { spec->headset_present_flag = CX_HEADSET_PARTPRESENT; } else if (spec->headset_present_flag == CX_HEADSET_PARTPRESENT) { mic_persent = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); /* headset is present */ if ((phone_present & AC_PINSENSE_PRESENCE) && (mic_persent & AC_PINSENSE_PRESENCE)) { else cx_process_headset_plugin(codec); spec->headset_present_flag = CX_HEADSET_ALLPRESENT; } } } } static void cx_jack_unsol_event(struct hda_codec *codec, unsigned int res) { struct conexant_spec *spec = codec->spec; if (spec->is_cx8070_sn6140) cx_update_headset_mic_vref(codec, res); snd_hda_jack_unsol_event(codec, res); } static int cx_auto_suspend(struct hda_codec *codec) Loading @@ -305,7 +271,7 @@ static const struct hda_codec_ops cx_auto_patch_ops = { .build_pcms = snd_hda_gen_build_pcms, .init = cx_auto_init, .free = cx_auto_free, .unsol_event = cx_jack_unsol_event, .unsol_event = snd_hda_jack_unsol_event, .suspend = cx_auto_suspend, .check_power_status = snd_hda_gen_check_power_status, }; Loading Loading @@ -1163,7 +1129,7 @@ static int patch_conexant_auto(struct hda_codec *codec) case 0x14f11f86: case 0x14f11f87: spec->is_cx8070_sn6140 = true; spec->headset_present_flag = CX_HEADSET_NOPRESENT; snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); break; } Loading
sound/pci/hda/patch_realtek.c +1 −0 Original line number Diff line number Diff line Loading @@ -9872,6 +9872,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x0840, "Acer Aspire E1", ALC269VB_FIXUP_ASPIRE_E1_COEF), SND_PCI_QUIRK(0x1025, 0x100c, "Acer Aspire E5-574G", ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1025, 0x101c, "Acer Veriton N2510G", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1065, "Acer Aspire C20-820", ALC269VC_FIXUP_ACER_HEADSET_MIC), Loading