Skip to content

Commit

Permalink
Merge remote branch 'alsa/devel' into topic/hda
Browse files Browse the repository at this point in the history
  • Loading branch information
Takashi Iwai committed Dec 15, 2009
2 parents a9e0605 + 5e26dfd commit 7093505
Show file tree
Hide file tree
Showing 13 changed files with 455 additions and 143 deletions.
79 changes: 73 additions & 6 deletions sound/pci/hda/hda_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
#endif
list_del(&codec->list);
snd_array_free(&codec->mixers);
snd_array_free(&codec->nids);
codec->bus->caddr_tbl[codec->addr] = NULL;
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
Expand Down Expand Up @@ -985,7 +986,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr
mutex_init(&codec->control_mutex);
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
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->driver_pins, sizeof(struct hda_pincfg), 16);
if (codec->bus->modelname) {
Expand Down Expand Up @@ -1706,7 +1708,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
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
* @nid: corresponding NID (optional)
* @kctl: the control element to assign
Expand All @@ -1721,19 +1723,25 @@ EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
*
* 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
* 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,
struct snd_kcontrol *kctl)
{
int err;
unsigned short flags = 0;
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)
nid = kctl->id.subdevice & 0xffff;
kctl->id.subdevice = 0;
nid = get_amp_nid_(kctl->private_value);
}
if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0)
nid = kctl->id.subdevice & 0xffff;
if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG))
kctl->id.subdevice = 0;
err = snd_ctl_add(codec->bus->card, kctl);
if (err < 0)
return err;
Expand All @@ -1742,10 +1750,40 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
return -ENOMEM;
item->kctl = kctl;
item->nid = nid;
item->flags = flags;
return 0;
}
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
* @codec: HD-audio codec
Expand All @@ -1757,6 +1795,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
for (i = 0; i < codec->mixers.used; i++)
snd_ctl_remove(codec->bus->card, items[i].kctl);
snd_array_free(&codec->mixers);
snd_array_free(&codec->nids);
}

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

for (; knew->name; knew++) {
struct snd_kcontrol *kctl;
if (knew->iface == -1) /* skip this codec private value */
continue;
kctl = snd_ctl_new1(knew, codec);
if (!kctl)
return -ENOMEM;
Expand All @@ -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);

/**
* 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
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state);
Expand Down
1 change: 1 addition & 0 deletions sound/pci/hda/hda_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,7 @@ struct hda_codec {
u32 *wcaps;

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 cmd_cache; /* cache for other commands */
Expand Down
3 changes: 2 additions & 1 deletion sound/pci/hda/hda_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,8 @@ static int build_input_controls(struct hda_codec *codec)
}

/* 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)
return err;

Expand Down
16 changes: 13 additions & 3 deletions sound/pci/hda/hda_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* 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_AMP_FLAG (1U << 30)

/*
* for mixer controls
Expand All @@ -42,7 +43,7 @@
/* mono volume with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .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 | \
SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
Expand All @@ -63,7 +64,7 @@
/* mono mute switch with index (index=0,1,...) (channel=1,2) */
#define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
{ .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, \
.get = snd_hda_mixer_amp_switch_get, \
.put = snd_hda_mixer_amp_switch_put, \
Expand All @@ -81,7 +82,7 @@
/* 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) \
{ .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, \
.get = snd_hda_mixer_amp_switch_get, \
.put = snd_hda_mixer_amp_switch_put_beep, \
Expand Down Expand Up @@ -342,6 +343,8 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
const struct snd_pci_quirk *tbl);
int snd_hda_add_new_ctls(struct hda_codec *codec,
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
Expand Down Expand Up @@ -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);
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 snd_kcontrol *kctl;
unsigned int index;
hda_nid_t nid;
unsigned short flags;
};

int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
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);

/*
Expand Down
31 changes: 22 additions & 9 deletions sound/pci/hda/hda_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,29 @@ static const char *get_wid_type_name(unsigned int wid_value)
return "UNKNOWN Widget";
}

static void print_nid_mixers(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid)
static void print_nid_array(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid,
struct snd_array *array)
{
int i;
struct hda_nid_item *items = codec->mixers.list;
struct hda_nid_item *items = array->list, *item;
struct snd_kcontrol *kctl;
for (i = 0; i < codec->mixers.used; i++) {
if (items[i].nid == nid) {
kctl = items[i].kctl;
for (i = 0; i < array->used; i++) {
item = &items[i];
if (item->nid == nid) {
kctl = item->kctl;
snd_iprintf(buffer,
" 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));
}
}
}
Expand Down Expand Up @@ -528,7 +539,8 @@ static void print_gpio(struct snd_info_buffer *buffer,
(data & (1<<i)) ? 1 : 0,
(unsol & (1<<i)) ? 1 : 0);
/* 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,
Expand Down Expand Up @@ -608,7 +620,8 @@ static void print_codec_info(struct snd_info_entry *entry,
snd_iprintf(buffer, " CP");
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);

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

0 comments on commit 7093505

Please sign in to comment.