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

Commit 70935050 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge remote branch 'alsa/devel' into topic/hda

parents a9e06057 5e26dfd0
Loading
Loading
Loading
Loading
+73 −6
Original line number Original line Diff line number Diff line
@@ -931,6 +931,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
#endif
#endif
	list_del(&codec->list);
	list_del(&codec->list);
	snd_array_free(&codec->mixers);
	snd_array_free(&codec->mixers);
	snd_array_free(&codec->nids);
	codec->bus->caddr_tbl[codec->addr] = NULL;
	codec->bus->caddr_tbl[codec->addr] = NULL;
	if (codec->patch_ops.free)
	if (codec->patch_ops.free)
		codec->patch_ops.free(codec);
		codec->patch_ops.free(codec);
@@ -985,7 +986,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
	mutex_init(&codec->control_mutex);
	mutex_init(&codec->control_mutex);
	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
	snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60);
	snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
	snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);
	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
	snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
	snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
	if (codec->bus->modelname) {
	if (codec->bus->modelname) {
@@ -1706,7 +1708,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);


/**
/**
 * snd_hda_ctl-add - Add a control element and assign to the codec
 * snd_hda_ctl_add - Add a control element and assign to the codec
 * @codec: HD-audio codec
 * @codec: HD-audio codec
 * @nid: corresponding NID (optional)
 * @nid: corresponding NID (optional)
 * @kctl: the control element to assign
 * @kctl: the control element to assign
@@ -1721,19 +1723,25 @@ EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
 *
 *
 * snd_hda_ctl_add() checks the control subdev id field whether
 * snd_hda_ctl_add() checks the control subdev id field whether
 * #HDA_SUBDEV_NID_FLAG bit is set.  If set (and @nid is zero), the lower
 * #HDA_SUBDEV_NID_FLAG bit is set.  If set (and @nid is zero), the lower
 * bits value is taken as the NID to assign.
 * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit
 * specifies if kctl->private_value is a HDA amplifier value.
 */
 */
int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
		    struct snd_kcontrol *kctl)
		    struct snd_kcontrol *kctl)
{
{
	int err;
	int err;
	unsigned short flags = 0;
	struct hda_nid_item *item;
	struct hda_nid_item *item;


	if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) {
	if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) {
		flags |= HDA_NID_ITEM_AMP;
		if (nid == 0)
		if (nid == 0)
			nid = get_amp_nid_(kctl->private_value);
	}
	if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0)
		nid = kctl->id.subdevice & 0xffff;
		nid = kctl->id.subdevice & 0xffff;
	if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG))
		kctl->id.subdevice = 0;
		kctl->id.subdevice = 0;
	}
	err = snd_ctl_add(codec->bus->card, kctl);
	err = snd_ctl_add(codec->bus->card, kctl);
	if (err < 0)
	if (err < 0)
		return err;
		return err;
@@ -1742,10 +1750,40 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
		return -ENOMEM;
		return -ENOMEM;
	item->kctl = kctl;
	item->kctl = kctl;
	item->nid = nid;
	item->nid = nid;
	item->flags = flags;
	return 0;
	return 0;
}
}
EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
EXPORT_SYMBOL_HDA(snd_hda_ctl_add);


/**
 * snd_hda_add_nid - Assign a NID to a control element
 * @codec: HD-audio codec
 * @nid: corresponding NID (optional)
 * @kctl: the control element to assign
 * @index: index to kctl
 *
 * Add the given control element to an array inside the codec instance.
 * This function is used when #snd_hda_ctl_add cannot be used for 1:1
 * NID:KCTL mapping - for example "Capture Source" selector.
 */
int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
		    unsigned int index, hda_nid_t nid)
{
	struct hda_nid_item *item;

	if (nid > 0) {
		item = snd_array_new(&codec->nids);
		if (!item)
			return -ENOMEM;
		item->kctl = kctl;
		item->index = index;
		item->nid = nid;
		return 0;
	}
	return -EINVAL;
}
EXPORT_SYMBOL_HDA(snd_hda_add_nid);

/**
/**
 * snd_hda_ctls_clear - Clear all controls assigned to the given codec
 * snd_hda_ctls_clear - Clear all controls assigned to the given codec
 * @codec: HD-audio codec
 * @codec: HD-audio codec
@@ -1757,6 +1795,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
	for (i = 0; i < codec->mixers.used; i++)
	for (i = 0; i < codec->mixers.used; i++)
		snd_ctl_remove(codec->bus->card, items[i].kctl);
		snd_ctl_remove(codec->bus->card, items[i].kctl);
	snd_array_free(&codec->mixers);
	snd_array_free(&codec->mixers);
	snd_array_free(&codec->nids);
}
}


/* pseudo device locking
/* pseudo device locking
@@ -3476,6 +3515,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)


	for (; knew->name; knew++) {
	for (; knew->name; knew++) {
		struct snd_kcontrol *kctl;
		struct snd_kcontrol *kctl;
		if (knew->iface == -1)	/* skip this codec private value */
			continue;
		kctl = snd_ctl_new1(knew, codec);
		kctl = snd_ctl_new1(knew, codec);
		if (!kctl)
		if (!kctl)
			return -ENOMEM;
			return -ENOMEM;
@@ -3496,6 +3537,32 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
}
}
EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);


/**
 * snd_hda_add_nids - assign nids to controls from the array
 * @codec: the HDA codec
 * @kctl: struct snd_kcontrol
 * @index: index to kctl
 * @nids: the array of hda_nid_t
 * @size: count of hda_nid_t items
 *
 * This helper function assigns NIDs in the given array to a control element.
 *
 * Returns 0 if successful, or a negative error code.
 */
int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl,
		     unsigned int index, hda_nid_t *nids, unsigned int size)
{
	int err;

	for ( ; size > 0; size--, nids++) {
		err = snd_hda_add_nid(codec, kctl, index, *nids);
		if (err < 0)
			return err;
	}
	return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_add_nids);

#ifdef CONFIG_SND_HDA_POWER_SAVE
#ifdef CONFIG_SND_HDA_POWER_SAVE
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
				unsigned int power_state);
				unsigned int power_state);
+1 −0
Original line number Original line Diff line number Diff line
@@ -789,6 +789,7 @@ struct hda_codec {
	u32 *wcaps;
	u32 *wcaps;


	struct snd_array mixers;	/* list of assigned mixer elements */
	struct snd_array mixers;	/* list of assigned mixer elements */
	struct snd_array nids;		/* list of mapped mixer elements */


	struct hda_cache_rec amp_cache;	/* cache for amp access */
	struct hda_cache_rec amp_cache;	/* cache for amp access */
	struct hda_cache_rec cmd_cache;	/* cache for other commands */
	struct hda_cache_rec cmd_cache;	/* cache for other commands */
+2 −1
Original line number Original line Diff line number Diff line
@@ -861,7 +861,8 @@ static int build_input_controls(struct hda_codec *codec)
	}
	}


	/* create input MUX if multiple sources are available */
	/* create input MUX if multiple sources are available */
	err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec));
	err = snd_hda_ctl_add(codec, spec->adc_node->nid,
			      snd_ctl_new1(&cap_sel, codec));
	if (err < 0)
	if (err < 0)
		return err;
		return err;


+13 −3
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@
 * in snd_hda_ctl_add(), so that this value won't appear in the outside.
 * in snd_hda_ctl_add(), so that this value won't appear in the outside.
 */
 */
#define HDA_SUBDEV_NID_FLAG	(1U << 31)
#define HDA_SUBDEV_NID_FLAG	(1U << 31)
#define HDA_SUBDEV_AMP_FLAG	(1U << 30)


/*
/*
 * for mixer controls
 * for mixer controls
@@ -42,7 +43,7 @@
/* mono volume with index (index=0,1,...) (channel=1,2) */
/* mono volume with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
	  .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
	  .subdevice = HDA_SUBDEV_AMP_FLAG, \
	  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
	  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
	  	    SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
	  	    SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
	  	    SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
	  	    SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
@@ -63,7 +64,7 @@
/* mono mute switch with index (index=0,1,...) (channel=1,2) */
/* mono mute switch with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
	  .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
	  .subdevice = HDA_SUBDEV_AMP_FLAG, \
	  .info = snd_hda_mixer_amp_switch_info, \
	  .info = snd_hda_mixer_amp_switch_info, \
	  .get = snd_hda_mixer_amp_switch_get, \
	  .get = snd_hda_mixer_amp_switch_get, \
	  .put = snd_hda_mixer_amp_switch_put, \
	  .put = snd_hda_mixer_amp_switch_put, \
@@ -81,7 +82,7 @@
/* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */
/* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
#define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
	  .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \
	  .subdevice = HDA_SUBDEV_AMP_FLAG, \
	  .info = snd_hda_mixer_amp_switch_info, \
	  .info = snd_hda_mixer_amp_switch_info, \
	  .get = snd_hda_mixer_amp_switch_get, \
	  .get = snd_hda_mixer_amp_switch_get, \
	  .put = snd_hda_mixer_amp_switch_put_beep, \
	  .put = snd_hda_mixer_amp_switch_put_beep, \
@@ -342,6 +343,8 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
                               const struct snd_pci_quirk *tbl);
                               const struct snd_pci_quirk *tbl);
int snd_hda_add_new_ctls(struct hda_codec *codec,
int snd_hda_add_new_ctls(struct hda_codec *codec,
			 struct snd_kcontrol_new *knew);
			 struct snd_kcontrol_new *knew);
int snd_hda_add_nids(struct hda_codec *codec, struct snd_kcontrol *kctl,
		     unsigned int index, hda_nid_t *nids, unsigned int size);


/*
/*
 * unsolicited event handler
 * unsolicited event handler
@@ -464,13 +467,20 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);


/* flags for hda_nid_item */
#define HDA_NID_ITEM_AMP	(1<<0)

struct hda_nid_item {
struct hda_nid_item {
	struct snd_kcontrol *kctl;
	struct snd_kcontrol *kctl;
	unsigned int index;
	hda_nid_t nid;
	hda_nid_t nid;
	unsigned short flags;
};
};


int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
		    struct snd_kcontrol *kctl);
		    struct snd_kcontrol *kctl);
int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
		    unsigned int index, hda_nid_t nid);
void snd_hda_ctls_clear(struct hda_codec *codec);
void snd_hda_ctls_clear(struct hda_codec *codec);


/*
/*
+22 −9
Original line number Original line Diff line number Diff line
@@ -61,18 +61,29 @@ static const char *get_wid_type_name(unsigned int wid_value)
		return "UNKNOWN Widget";
		return "UNKNOWN Widget";
}
}


static void print_nid_mixers(struct snd_info_buffer *buffer,
static void print_nid_array(struct snd_info_buffer *buffer,
			     struct hda_codec *codec, hda_nid_t nid)
			    struct hda_codec *codec, hda_nid_t nid,
			    struct snd_array *array)
{
{
	int i;
	int i;
	struct hda_nid_item *items = codec->mixers.list;
	struct hda_nid_item *items = array->list, *item;
	struct snd_kcontrol *kctl;
	struct snd_kcontrol *kctl;
	for (i = 0; i < codec->mixers.used; i++) {
	for (i = 0; i < array->used; i++) {
		if (items[i].nid == nid) {
		item = &items[i];
			kctl = items[i].kctl;
		if (item->nid == nid) {
			kctl = item->kctl;
			snd_iprintf(buffer,
			snd_iprintf(buffer,
			  "  Control: name=\"%s\", index=%i, device=%i\n",
			  "  Control: name=\"%s\", index=%i, device=%i\n",
			  kctl->id.name, kctl->id.index, kctl->id.device);
			  kctl->id.name, kctl->id.index + item->index,
			  kctl->id.device);
			if (item->flags & HDA_NID_ITEM_AMP)
				snd_iprintf(buffer,
				  "    ControlAmp: chs=%lu, dir=%s, "
				  "idx=%lu, ofs=%lu\n",
				  get_amp_channels(kctl),
				  get_amp_direction(kctl) ? "Out" : "In",
				  get_amp_index(kctl),
				  get_amp_offset(kctl));
		}
		}
	}
	}
}
}
@@ -528,7 +539,8 @@ static void print_gpio(struct snd_info_buffer *buffer,
			    (data & (1<<i)) ? 1 : 0,
			    (data & (1<<i)) ? 1 : 0,
			    (unsol & (1<<i)) ? 1 : 0);
			    (unsol & (1<<i)) ? 1 : 0);
	/* FIXME: add GPO and GPI pin information */
	/* FIXME: add GPO and GPI pin information */
	print_nid_mixers(buffer, codec, nid);
	print_nid_array(buffer, codec, nid, &codec->mixers);
	print_nid_array(buffer, codec, nid, &codec->nids);
}
}


static void print_codec_info(struct snd_info_entry *entry,
static void print_codec_info(struct snd_info_entry *entry,
@@ -608,7 +620,8 @@ static void print_codec_info(struct snd_info_entry *entry,
			snd_iprintf(buffer, " CP");
			snd_iprintf(buffer, " CP");
		snd_iprintf(buffer, "\n");
		snd_iprintf(buffer, "\n");


		print_nid_mixers(buffer, codec, nid);
		print_nid_array(buffer, codec, nid, &codec->mixers);
		print_nid_array(buffer, codec, nid, &codec->nids);
		print_nid_pcms(buffer, codec, nid);
		print_nid_pcms(buffer, codec, nid);


		/* volume knob is a special widget that always have connection
		/* volume knob is a special widget that always have connection
Loading