Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fec6489f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: hda - Fix the connection selection of ADCs on Cirrus codecs
  ALSA: hda - Update URLs in document
  ALSA: hda - move eld->spk_alloc fixup to hdmi_update_eld()
  ALSA: hda - delayed ELD repoll
  ALSA: hda - fix ELD memory leak
  ALSA: hda/realtek: remove redundant semicolon
  ALSA: hda - pwr_nids cleanup for IDT codecs
parents aa1b052a 05ee7964
Loading
Loading
Loading
Loading
+4 −4
Original line number Original line Diff line number Diff line
@@ -579,7 +579,7 @@ Development Tree
~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~
The latest development codes for HD-audio are found on sound git tree:
The latest development codes for HD-audio are found on sound git tree:


- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git


The master branch or for-next branches can be used as the main
The master branch or for-next branches can be used as the main
development branches in general while the HD-audio specific patches
development branches in general while the HD-audio specific patches
@@ -594,7 +594,7 @@ is, installed via the usual spells: configure, make and make
install(-modules).  See INSTALL in the package.  The snapshot tarballs
install(-modules).  See INSTALL in the package.  The snapshot tarballs
are found at:
are found at:


- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/
- ftp://ftp.suse.com/pub/people/tiwai/snapshot/




Sending a Bug Report
Sending a Bug Report
@@ -696,7 +696,7 @@ via hda-verb won't change the mixer value.


The hda-verb program is found in the ftp directory:
The hda-verb program is found in the ftp directory:


- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/
- ftp://ftp.suse.com/pub/people/tiwai/misc/


Also a git repository is available:
Also a git repository is available:


@@ -764,7 +764,7 @@ operation, the jack plugging simulation, etc.


The package is found in:
The package is found in:


- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/
- ftp://ftp.suse.com/pub/people/tiwai/misc/


A git repository is available:
A git repository is available:


+9 −4
Original line number Original line Diff line number Diff line
@@ -297,10 +297,18 @@ static int hdmi_update_eld(struct hdmi_eld *e,
					buf + ELD_FIXED_BYTES + mnl + 3 * i);
					buf + ELD_FIXED_BYTES + mnl + 3 * i);
	}
	}


	/*
	 * HDMI sink's ELD info cannot always be retrieved for now, e.g.
	 * in console or for audio devices. Assume the highest speakers
	 * configuration, to _not_ prohibit multi-channel audio playback.
	 */
	if (!e->spk_alloc)
		e->spk_alloc = 0xffff;

	e->eld_valid = true;
	return 0;
	return 0;


out_fail:
out_fail:
	e->eld_ver = 0;
	return -EINVAL;
	return -EINVAL;
}
}


@@ -323,9 +331,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
	 * ELD is valid, actual eld_size is assigned in hdmi_update_eld()
	 * ELD is valid, actual eld_size is assigned in hdmi_update_eld()
	 */
	 */


	if (!eld->eld_valid)
		return -ENOENT;

	size = snd_hdmi_get_eld_size(codec, nid);
	size = snd_hdmi_get_eld_size(codec, nid);
	if (size == 0) {
	if (size == 0) {
		/* wfg: workaround for ASUS P5E-VM HDMI board */
		/* wfg: workaround for ASUS P5E-VM HDMI board */
+3 −0
Original line number Original line Diff line number Diff line
@@ -653,6 +653,9 @@ struct hdmi_eld {
	int	spk_alloc;
	int	spk_alloc;
	int	sad_count;
	int	sad_count;
	struct cea_sad sad[ELD_MAX_SAD];
	struct cea_sad sad[ELD_MAX_SAD];
	/*
	 * all fields above eld_buffer will be cleared before updating ELD
	 */
	char    eld_buffer[ELD_MAX_SIZE];
	char    eld_buffer[ELD_MAX_SIZE];
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_PROC_FS
	struct snd_info_entry *proc_entry;
	struct snd_info_entry *proc_entry;
+13 −10
Original line number Original line Diff line number Diff line
@@ -237,6 +237,15 @@ static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
	return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
	return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
}
}


static void cs_update_input_select(struct hda_codec *codec)
{
	struct cs_spec *spec = codec->spec;
	if (spec->cur_adc)
		snd_hda_codec_write(codec, spec->cur_adc, 0,
				    AC_VERB_SET_CONNECT_SEL,
				    spec->adc_idx[spec->cur_input]);
}

/*
/*
 * Analog capture
 * Analog capture
 */
 */
@@ -250,6 +259,7 @@ static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
	spec->cur_adc = spec->adc_nid[spec->cur_input];
	spec->cur_adc = spec->adc_nid[spec->cur_input];
	spec->cur_adc_stream_tag = stream_tag;
	spec->cur_adc_stream_tag = stream_tag;
	spec->cur_adc_format = format;
	spec->cur_adc_format = format;
	cs_update_input_select(codec);
	snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
	snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
	return 0;
	return 0;
}
}
@@ -689,10 +699,8 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx,
					   spec->cur_adc_stream_tag, 0,
					   spec->cur_adc_stream_tag, 0,
					   spec->cur_adc_format);
					   spec->cur_adc_format);
	}
	}
	snd_hda_codec_write(codec, spec->cur_adc, 0,
			    AC_VERB_SET_CONNECT_SEL,
			    spec->adc_idx[idx]);
	spec->cur_input = idx;
	spec->cur_input = idx;
	cs_update_input_select(codec);
	return 1;
	return 1;
}
}


@@ -973,10 +981,7 @@ static void cs_automic(struct hda_codec *codec)
		} else  {
		} else  {
			spec->cur_input = spec->last_input;
			spec->cur_input = spec->last_input;
		}
		}

		cs_update_input_select(codec);
		snd_hda_codec_write_cache(codec, spec->cur_adc, 0,
					AC_VERB_SET_CONNECT_SEL,
					spec->adc_idx[spec->cur_input]);
	} else {
	} else {
		if (present)
		if (present)
			change_cur_input(codec, spec->automic_idx, 0);
			change_cur_input(codec, spec->automic_idx, 0);
@@ -1073,9 +1078,7 @@ static void init_input(struct hda_codec *codec)
			cs_automic(codec);
			cs_automic(codec);
		else  {
		else  {
			spec->cur_adc = spec->adc_nid[spec->cur_input];
			spec->cur_adc = spec->adc_nid[spec->cur_input];
			snd_hda_codec_write(codec, spec->cur_adc, 0,
			cs_update_input_select(codec);
					AC_VERB_SET_CONNECT_SEL,
					spec->adc_idx[spec->cur_input]);
		}
		}
	} else {
	} else {
		change_cur_input(codec, spec->cur_input, 1);
		change_cur_input(codec, spec->cur_input, 1);
+33 −22
Original line number Original line Diff line number Diff line
@@ -65,7 +65,10 @@ struct hdmi_spec_per_pin {
	hda_nid_t pin_nid;
	hda_nid_t pin_nid;
	int num_mux_nids;
	int num_mux_nids;
	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];

	struct hda_codec *codec;
	struct hdmi_eld sink_eld;
	struct hdmi_eld sink_eld;
	struct delayed_work work;
};
};


struct hdmi_spec {
struct hdmi_spec {
@@ -745,8 +748,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
 * Unsolicited events
 * Unsolicited events
 */
 */


static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry);
			       struct hdmi_eld *eld);


static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
{
{
@@ -755,7 +757,6 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
	int pd = !!(res & AC_UNSOL_RES_PD);
	int pd = !!(res & AC_UNSOL_RES_PD);
	int eldv = !!(res & AC_UNSOL_RES_ELDV);
	int eldv = !!(res & AC_UNSOL_RES_ELDV);
	int pin_idx;
	int pin_idx;
	struct hdmi_eld *eld;


	printk(KERN_INFO
	printk(KERN_INFO
		"HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
		"HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
@@ -764,17 +765,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
	pin_idx = pin_nid_to_pin_index(spec, pin_nid);
	pin_idx = pin_nid_to_pin_index(spec, pin_nid);
	if (pin_idx < 0)
	if (pin_idx < 0)
		return;
		return;
	eld = &spec->pins[pin_idx].sink_eld;

	hdmi_present_sense(codec, pin_nid, eld);


	/*
	hdmi_present_sense(&spec->pins[pin_idx], true);
	 * HDMI sink's ELD info cannot always be retrieved for now, e.g.
	 * in console or for audio devices. Assume the highest speakers
	 * configuration, to _not_ prohibit multi-channel audio playback.
	 */
	if (!eld->spk_alloc)
		eld->spk_alloc = 0xffff;
}
}


static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -968,9 +960,11 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
	return 0;
	return 0;
}
}


static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, bool retry)
			       struct hdmi_eld *eld)
{
{
	struct hda_codec *codec = per_pin->codec;
	struct hdmi_eld *eld = &per_pin->sink_eld;
	hda_nid_t pin_nid = per_pin->pin_nid;
	/*
	/*
	 * Always execute a GetPinSense verb here, even when called from
	 * Always execute a GetPinSense verb here, even when called from
	 * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
	 * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
@@ -980,26 +974,39 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
	 * the unsolicited response to avoid custom WARs.
	 * the unsolicited response to avoid custom WARs.
	 */
	 */
	int present = snd_hda_pin_sense(codec, pin_nid);
	int present = snd_hda_pin_sense(codec, pin_nid);
	bool eld_valid = false;


	memset(eld, 0, sizeof(*eld));
	memset(eld, 0, offsetof(struct hdmi_eld, eld_buffer));


	eld->monitor_present	= !!(present & AC_PINSENSE_PRESENCE);
	eld->monitor_present	= !!(present & AC_PINSENSE_PRESENCE);
	if (eld->monitor_present)
	if (eld->monitor_present)
		eld->eld_valid	= !!(present & AC_PINSENSE_ELDV);
		eld_valid	= !!(present & AC_PINSENSE_ELDV);
	else
		eld->eld_valid	= 0;


	printk(KERN_INFO
	printk(KERN_INFO
		"HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
		"HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
		codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
		codec->addr, pin_nid, eld->monitor_present, eld_valid);


	if (eld->eld_valid)
	if (eld_valid) {
		if (!snd_hdmi_get_eld(eld, codec, pin_nid))
		if (!snd_hdmi_get_eld(eld, codec, pin_nid))
			snd_hdmi_show_eld(eld);
			snd_hdmi_show_eld(eld);
		else if (retry) {
			queue_delayed_work(codec->bus->workq,
					   &per_pin->work,
					   msecs_to_jiffies(300));
		}
	}


	snd_hda_input_jack_report(codec, pin_nid);
	snd_hda_input_jack_report(codec, pin_nid);
}
}


static void hdmi_repoll_eld(struct work_struct *work)
{
	struct hdmi_spec_per_pin *per_pin =
	container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);

	hdmi_present_sense(per_pin, false);
}

static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
{
{
	struct hdmi_spec *spec = codec->spec;
	struct hdmi_spec *spec = codec->spec;
@@ -1228,7 +1235,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
	if (err < 0)
	if (err < 0)
		return err;
		return err;


	hdmi_present_sense(codec, per_pin->pin_nid, &per_pin->sink_eld);
	hdmi_present_sense(per_pin, false);
	return 0;
	return 0;
}
}


@@ -1279,6 +1286,8 @@ static int generic_hdmi_init(struct hda_codec *codec)
				    AC_VERB_SET_UNSOLICITED_ENABLE,
				    AC_VERB_SET_UNSOLICITED_ENABLE,
				    AC_USRSP_EN | pin_nid);
				    AC_USRSP_EN | pin_nid);


		per_pin->codec = codec;
		INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
		snd_hda_eld_proc_new(codec, eld, pin_idx);
		snd_hda_eld_proc_new(codec, eld, pin_idx);
	}
	}
	return 0;
	return 0;
@@ -1293,10 +1302,12 @@ static void generic_hdmi_free(struct hda_codec *codec)
		struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
		struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
		struct hdmi_eld *eld = &per_pin->sink_eld;
		struct hdmi_eld *eld = &per_pin->sink_eld;


		cancel_delayed_work(&per_pin->work);
		snd_hda_eld_proc_free(codec, eld);
		snd_hda_eld_proc_free(codec, eld);
	}
	}
	snd_hda_input_jack_free(codec);
	snd_hda_input_jack_free(codec);


	flush_workqueue(codec->bus->workq);
	kfree(spec);
	kfree(spec);
}
}


Loading