Commit 42dc2378 authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/hda-next' into topic/hda

parents da74ae3e 74aeaabc
...@@ -644,6 +644,7 @@ struct input_absinfo { ...@@ -644,6 +644,7 @@ struct input_absinfo {
#define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_RADIO SW_RFKILL_ALL /* deprecated */
#define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */
#define SW_DOCK 0x05 /* set = plugged into dock */ #define SW_DOCK 0x05 /* set = plugged into dock */
#define SW_LINEOUT_INSERT 0x06 /* set = inserted */
#define SW_MAX 0x0f #define SW_MAX 0x0f
#define SW_CNT (SW_MAX+1) #define SW_CNT (SW_MAX+1)
......
...@@ -35,6 +35,7 @@ enum snd_jack_types { ...@@ -35,6 +35,7 @@ enum snd_jack_types {
SND_JACK_HEADPHONE = 0x0001, SND_JACK_HEADPHONE = 0x0001,
SND_JACK_MICROPHONE = 0x0002, SND_JACK_MICROPHONE = 0x0002,
SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE,
SND_JACK_LINEOUT = 0x0004,
}; };
struct snd_jack { struct snd_jack {
......
...@@ -34,6 +34,7 @@ static int snd_jack_dev_free(struct snd_device *device) ...@@ -34,6 +34,7 @@ static int snd_jack_dev_free(struct snd_device *device)
else else
input_free_device(jack->input_dev); input_free_device(jack->input_dev);
kfree(jack->id);
kfree(jack); kfree(jack);
return 0; return 0;
...@@ -87,7 +88,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, ...@@ -87,7 +88,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
if (jack == NULL) if (jack == NULL)
return -ENOMEM; return -ENOMEM;
jack->id = id; jack->id = kstrdup(id, GFP_KERNEL);
jack->input_dev = input_allocate_device(); jack->input_dev = input_allocate_device();
if (jack->input_dev == NULL) { if (jack->input_dev == NULL) {
...@@ -102,6 +103,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, ...@@ -102,6 +103,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
if (type & SND_JACK_HEADPHONE) if (type & SND_JACK_HEADPHONE)
input_set_capability(jack->input_dev, EV_SW, input_set_capability(jack->input_dev, EV_SW,
SW_HEADPHONE_INSERT); SW_HEADPHONE_INSERT);
if (type & SND_JACK_LINEOUT)
input_set_capability(jack->input_dev, EV_SW,
SW_LINEOUT_INSERT);
if (type & SND_JACK_MICROPHONE) if (type & SND_JACK_MICROPHONE)
input_set_capability(jack->input_dev, EV_SW, input_set_capability(jack->input_dev, EV_SW,
SW_MICROPHONE_INSERT); SW_MICROPHONE_INSERT);
...@@ -150,6 +154,9 @@ void snd_jack_report(struct snd_jack *jack, int status) ...@@ -150,6 +154,9 @@ void snd_jack_report(struct snd_jack *jack, int status)
if (jack->type & SND_JACK_HEADPHONE) if (jack->type & SND_JACK_HEADPHONE)
input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT,
status & SND_JACK_HEADPHONE); status & SND_JACK_HEADPHONE);
if (jack->type & SND_JACK_LINEOUT)
input_report_switch(jack->input_dev, SW_LINEOUT_INSERT,
status & SND_JACK_LINEOUT);
if (jack->type & SND_JACK_MICROPHONE) if (jack->type & SND_JACK_MICROPHONE)
input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT,
status & SND_JACK_MICROPHONE); status & SND_JACK_MICROPHONE);
......
...@@ -501,6 +501,7 @@ config SND_HDA_INTEL ...@@ -501,6 +501,7 @@ config SND_HDA_INTEL
tristate "Intel HD Audio" tristate "Intel HD Audio"
select SND_PCM select SND_PCM
select SND_VMASTER select SND_VMASTER
select SND_JACK if INPUT=y || INPUT=SND
help help
Say Y here to include support for Intel "High Definition Say Y here to include support for Intel "High Definition
Audio" (Azalia) motherboard devices. Audio" (Azalia) motherboard devices.
......
This diff is collapsed.
...@@ -519,6 +519,26 @@ enum { ...@@ -519,6 +519,26 @@ enum {
/* max. codec address */ /* max. codec address */
#define HDA_MAX_CODEC_ADDRESS 0x0f #define HDA_MAX_CODEC_ADDRESS 0x0f
/*
* generic arrays
*/
struct snd_array {
unsigned int used;
unsigned int alloced;
unsigned int elem_size;
unsigned int alloc_align;
void *list;
};
void *snd_array_new(struct snd_array *array);
void snd_array_free(struct snd_array *array);
static inline void snd_array_init(struct snd_array *array, unsigned int size,
unsigned int align)
{
array->elem_size = size;
array->alloc_align = align;
}
/* /*
* Structures * Structures
*/ */
...@@ -542,6 +562,8 @@ struct hda_bus_ops { ...@@ -542,6 +562,8 @@ struct hda_bus_ops {
unsigned int (*get_response)(struct hda_codec *codec); unsigned int (*get_response)(struct hda_codec *codec);
/* free the private data */ /* free the private data */
void (*private_free)(struct hda_bus *); void (*private_free)(struct hda_bus *);
/* attach a PCM stream */
int (*attach_pcm)(struct hda_codec *codec, struct hda_pcm *pcm);
#ifdef CONFIG_SND_HDA_POWER_SAVE #ifdef CONFIG_SND_HDA_POWER_SAVE
/* notify power-up/down from codec to controller */ /* notify power-up/down from codec to controller */
void (*pm_notify)(struct hda_codec *codec); void (*pm_notify)(struct hda_codec *codec);
...@@ -635,10 +657,7 @@ struct hda_amp_info { ...@@ -635,10 +657,7 @@ struct hda_amp_info {
struct hda_cache_rec { struct hda_cache_rec {
u16 hash[64]; /* hash table for index */ u16 hash[64]; /* hash table for index */
unsigned int num_entries; /* number of assigned entries */ struct snd_array buf; /* record entries */
unsigned int size; /* allocated size */
unsigned int record_size; /* record size (including header) */
void *buffer; /* hash table entries */
}; };
/* PCM callbacks */ /* PCM callbacks */
...@@ -680,7 +699,8 @@ struct hda_pcm { ...@@ -680,7 +699,8 @@ struct hda_pcm {
char *name; char *name;
struct hda_pcm_stream stream[2]; struct hda_pcm_stream stream[2];
unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */ unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */
int device; /* assigned device number */ int device; /* device number to assign */
struct snd_pcm *pcm; /* assigned PCM instance */
}; };
/* codec information */ /* codec information */
...@@ -699,6 +719,8 @@ struct hda_codec { ...@@ -699,6 +719,8 @@ struct hda_codec {
/* detected preset */ /* detected preset */
const struct hda_codec_preset *preset; const struct hda_codec_preset *preset;
const char *name; /* codec name */
const char *modelname; /* model name for preset */
/* set by patch */ /* set by patch */
struct hda_codec_ops patch_ops; struct hda_codec_ops patch_ops;
...@@ -718,6 +740,8 @@ struct hda_codec { ...@@ -718,6 +740,8 @@ struct hda_codec {
hda_nid_t start_nid; hda_nid_t start_nid;
u32 *wcaps; u32 *wcaps;
struct snd_array mixers; /* list of assigned 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 */
...@@ -727,7 +751,11 @@ struct hda_codec { ...@@ -727,7 +751,11 @@ struct hda_codec {
unsigned int spdif_in_enable; /* SPDIF input enable? */ unsigned int spdif_in_enable; /* SPDIF input enable? */
hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
#ifdef CONFIG_SND_HDA_HWDEP
struct snd_hwdep *hwdep; /* assigned hwdep device */ struct snd_hwdep *hwdep; /* assigned hwdep device */
struct snd_array init_verbs; /* additional init verbs */
struct snd_array hints; /* additional hints */
#endif
/* misc flags */ /* misc flags */
unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
...@@ -799,6 +827,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec); ...@@ -799,6 +827,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec);
* Mixer * Mixer
*/ */
int snd_hda_build_controls(struct hda_bus *bus); int snd_hda_build_controls(struct hda_bus *bus);
int snd_hda_codec_build_controls(struct hda_codec *codec);
/* /*
* PCM * PCM
...@@ -830,6 +859,13 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); ...@@ -830,6 +859,13 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state);
int snd_hda_resume(struct hda_bus *bus); int snd_hda_resume(struct hda_bus *bus);
#endif #endif
/*
* get widget information
*/
const char *snd_hda_get_jack_connectivity(u32 cfg);
const char *snd_hda_get_jack_type(u32 cfg);
const char *snd_hda_get_jack_location(u32 cfg);
/* /*
* power saving * power saving
*/ */
......
...@@ -723,7 +723,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, ...@@ -723,7 +723,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
if (is_loopback) if (is_loopback)
add_input_loopback(codec, node->nid, HDA_INPUT, index); add_input_loopback(codec, node->nid, HDA_INPUT, index);
snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
if (err < 0)
return err; return err;
created = 1; created = 1;
} else if ((node->wid_caps & AC_WCAP_OUT_AMP) && } else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
...@@ -732,7 +733,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, ...@@ -732,7 +733,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
if (is_loopback) if (is_loopback)
add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
if (err < 0)
return err; return err;
created = 1; created = 1;
} }
...@@ -745,14 +747,16 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, ...@@ -745,14 +747,16 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
(node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) { (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT); knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT);
snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index);
if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
if (err < 0)
return err; return err;
created = 1; created = 1;
} else if ((node->wid_caps & AC_WCAP_OUT_AMP) && } else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
(node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) { (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT); knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT);
snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid);
if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
if (err < 0)
return err; return err;
created = 1; created = 1;
} }
...@@ -849,8 +853,8 @@ static int build_input_controls(struct hda_codec *codec) ...@@ -849,8 +853,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 */
if ((err = snd_ctl_add(codec->bus->card, err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec));
snd_ctl_new1(&cap_sel, codec))) < 0) if (err < 0)
return err; return err;
/* no volume control? */ /* no volume control? */
...@@ -867,8 +871,8 @@ static int build_input_controls(struct hda_codec *codec) ...@@ -867,8 +871,8 @@ static int build_input_controls(struct hda_codec *codec)
HDA_CODEC_VOLUME(name, adc_node->nid, HDA_CODEC_VOLUME(name, adc_node->nid,
spec->input_mux.items[i].index, spec->input_mux.items[i].index,
HDA_INPUT); HDA_INPUT);
if ((err = snd_ctl_add(codec->bus->card, err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec));
snd_ctl_new1(&knew, codec))) < 0) if (err < 0)
return err; return err;
} }
......
...@@ -23,10 +23,12 @@ ...@@ -23,10 +23,12 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/ctype.h>
#include <sound/core.h> #include <sound/core.h>
#include "hda_codec.h" #include "hda_codec.h"
#include "hda_local.h" #include "hda_local.h"
#include <sound/hda_hwdep.h> #include <sound/hda_hwdep.h>
#include <sound/minors.h>
/* /*
* write/read an out-of-bound verb * write/read an out-of-bound verb
...@@ -95,6 +97,25 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) ...@@ -95,6 +97,25 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
return 0; return 0;
} }
static void clear_hwdep_elements(struct hda_codec *codec)
{
char **head;
int i;
/* clear init verbs */
snd_array_free(&codec->init_verbs);
/* clear hints */
head = codec->hints.list;
for (i = 0; i < codec->hints.used; i++, head++)
kfree(*head);
snd_array_free(&codec->hints);
}
static void hwdep_free(struct snd_hwdep *hwdep)
{
clear_hwdep_elements(hwdep->private_data);
}
int __devinit snd_hda_create_hwdep(struct hda_codec *codec) int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
{ {
char hwname[16]; char hwname[16];
...@@ -109,6 +130,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) ...@@ -109,6 +130,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
sprintf(hwdep->name, "HDA Codec %d", codec->addr); sprintf(hwdep->name, "HDA Codec %d", codec->addr);
hwdep->iface = SNDRV_HWDEP_IFACE_HDA; hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
hwdep->private_data = codec; hwdep->private_data = codec;
hwdep->private_free = hwdep_free;
hwdep->exclusive = 1; hwdep->exclusive = 1;
hwdep->ops.open = hda_hwdep_open; hwdep->ops.open = hda_hwdep_open;
...@@ -117,5 +139,211 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) ...@@ -117,5 +139,211 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec)
hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
#endif #endif
snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
snd_array_init(&codec->hints, sizeof(char *), 32);
return 0;
}
/*
* sysfs interface
*/
static int clear_codec(struct hda_codec *codec)
{
snd_hda_codec_reset(codec);
clear_hwdep_elements(codec);
return 0;
}
static int reconfig_codec(struct hda_codec *codec)
{
int err;
snd_printk(KERN_INFO "hda-codec: reconfiguring\n");
snd_hda_codec_reset(codec);
err = snd_hda_codec_configure(codec);
if (err < 0)
return err;
/* rebuild PCMs */
err = snd_hda_build_pcms(codec->bus);
if (err < 0)
return err;
/* rebuild mixers */
err = snd_hda_codec_build_controls(codec);
if (err < 0)
return err;
return 0;
}
/*
* allocate a string at most len chars, and remove the trailing EOL
*/
static char *kstrndup_noeol(const char *src, size_t len)
{
char *s = kstrndup(src, len, GFP_KERNEL);
char *p;
if (!s)
return NULL;
p = strchr(s, '\n');
if (p)
*p = 0;
return s;
}
#define CODEC_INFO_SHOW(type) \
static ssize_t type##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
return sprintf(buf, "0x%x\n", codec->type); \
}
#define CODEC_INFO_STR_SHOW(type) \
static ssize_t type##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
return sprintf(buf, "%s\n", \
codec->type ? codec->type : ""); \
}
CODEC_INFO_SHOW(vendor_id);
CODEC_INFO_SHOW(subsystem_id);
CODEC_INFO_SHOW(revision_id);
CODEC_INFO_SHOW(afg);
CODEC_INFO_SHOW(mfg);
CODEC_INFO_STR_SHOW(name);
CODEC_INFO_STR_SHOW(modelname);
#define CODEC_INFO_STORE(type) \
static ssize_t type##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
char *after; \
codec->type = simple_strtoul(buf, &after, 0); \
return count; \
}
#define CODEC_INFO_STR_STORE(type) \
static ssize_t type##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
char *s = kstrndup_noeol(buf, 64); \
if (!s) \
return -ENOMEM; \
kfree(codec->type); \
codec->type = s; \
return count; \
}
CODEC_INFO_STORE(vendor_id);
CODEC_INFO_STORE(subsystem_id);
CODEC_INFO_STORE(revision_id);
CODEC_INFO_STR_STORE(name);
CODEC_INFO_STR_STORE(modelname);
#define CODEC_ACTION_STORE(type) \
static ssize_t type##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
struct hda_codec *codec = hwdep->private_data; \
int err = 0; \
if (*buf) \
err = type##_codec(codec); \
return err < 0 ? err : count; \
}
CODEC_ACTION_STORE(reconfig);
CODEC_ACTION_STORE(clear);
static ssize_t init_verbs_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
struct hda_codec *codec = hwdep->private_data;
char *p;
struct hda_verb verb, *v;
verb.nid = simple_strtoul(buf, &p, 0);
verb.verb = simple_strtoul(p, &p, 0);
verb.param = simple_strtoul(p, &p, 0);
if (!verb.nid || !verb.verb || !verb.param)
return -EINVAL;
v = snd_array_new(&codec->init_verbs);
if (!v)
return -ENOMEM;
*v = verb;
return count;
}
static ssize_t hints_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
struct hda_codec *codec = hwdep->private_data;
char *p;
char **hint;
if (!*buf || isspace(*buf) || *buf == '#' || *buf == '\n')
return count;
p = kstrndup_noeol(buf, 1024);
if (!p)
return -ENOMEM;
hint = snd_array_new(&codec->hints);
if (!hint) {
kfree(p);
return -ENOMEM;
}
*hint = p;
return count;
}
#define CODEC_ATTR_RW(type) \
__ATTR(type, 0644, type##_show, type##_store)
#define CODEC_ATTR_RO(type) \
__ATTR_RO(type)
#define CODEC_ATTR_WO(type) \
__ATTR(type, 0200, NULL, type##_store)
static struct device_attribute codec_attrs[] = {
CODEC_ATTR_RW(vendor_id),
CODEC_ATTR_RW(subsystem_id),
CODEC_ATTR_RW(revision_id),
CODEC_ATTR_RO(afg),
CODEC_ATTR_RO(mfg),
CODEC_ATTR_RW(name),
CODEC_ATTR_RW(modelname),
CODEC_ATTR_WO(init_verbs),
CODEC_ATTR_WO(hints),
CODEC_ATTR_WO(reconfig),
CODEC_ATTR_WO(clear),
};
/*
* create sysfs files on hwdep directory
*/
int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
{
struct snd_hwdep *hwdep = codec->hwdep;
int i;
for (i = 0; i < ARRAY_SIZE(codec_attrs); i++)
snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
hwdep->device, &codec_attrs[i]);
return 0; return 0;
} }
...@@ -1180,6 +1180,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) ...@@ -1180,6 +1180,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
return 0; return 0;
} }
static int azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm);
/* /*
* Codec initialization * Codec initialization
...@@ -1212,6 +1213,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, ...@@ -1212,6 +1213,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
bus_temp.pci = chip->pci; bus_temp.pci = chip->pci;
bus_temp.ops.command = azx_send_cmd; bus_temp.ops.command = azx_send_cmd;
bus_temp.ops.get_response = azx_get_response; bus_temp.ops.get_response = azx_get_response;
bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
#ifdef CONFIG_SND_HDA_POWER_SAVE #ifdef CONFIG_SND_HDA_POWER_SAVE
bus_temp.ops.pm_notify = azx_power_notify; bus_temp.ops.pm_notify = azx_power_notify;
#endif #endif
...@@ -1718,111 +1720,58 @@ static struct snd_pcm_ops azx_pcm_ops = { ...@@ -1718,111 +1720,58 @@ static struct snd_pcm_ops azx_pcm_ops = {
static void azx_pcm_free(struct snd_pcm *pcm) static void azx_pcm_free(struct snd_pcm *pcm)
{ {
kfree(pcm->private_data); struct azx_pcm *apcm = pcm->private_data;
if (apcm) {
apcm->chip->pcm[pcm->device] = NULL;
kfree(apcm);
}
} }
static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, static int
struct hda_pcm *cpcm) azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm)
{ {
int err; struct azx *chip = codec->bus->private_data;
struct snd_pcm *pcm; struct snd_pcm *pcm;
struct azx_pcm *apcm; struct azx_pcm *apcm;
int pcm_dev = cpcm->device;
int s, err;
/* if no substreams are defined for both playback and capture, if (pcm_dev >= AZX_MAX_PCMS) {
* it's just a placeholder. ignore it. snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
*/ pcm_dev);
if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
return 0;
if (snd_BUG_ON(!cpcm->name))
return -EINVAL; return -EINVAL;
}
err = snd_pcm_new(chip->card, cpcm->name, cpcm->device, if (chip->pcm[pcm_dev]) {
cpcm->stream[0].substreams, snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
cpcm->stream[1].substreams, return -EBUSY;
}
err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
&pcm); &pcm);
if (err < 0) if (err < 0)
return err; return err;
strcpy(pcm->name, cpcm->name); strcpy(pcm->name, cpcm->name);
apcm = kmalloc(sizeof(*apcm), GFP_KERNEL); apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
if (apcm == NULL) if (apcm == NULL)
return -ENOMEM; return -ENOMEM;
apcm->chip = chip; apcm->chip = chip;
apcm->codec = codec; apcm->codec = codec;
apcm->hinfo[0] = &cpcm->stream[0];
apcm->hinfo[1] = &cpcm->stream[1];
pcm->private_data = apcm; pcm->private_data = apcm;
pcm->private_free = azx_pcm_free; pcm->private_free = azx_pcm_free;
if (cpcm->stream[0].substreams) if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops); pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
if (cpcm->stream[1].substreams) chip->pcm[pcm_dev] = pcm;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); cpcm->pcm = pcm;
for (s = 0; s < 2; s++) {
apcm->hinfo[s] = &cpcm->stream[s];
if (cpcm->stream[s].substreams)
snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
}
/* buffer pre-allocation */
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci), snd_dma_pci_data(chip->pci),
1024 * 64, 32 * 1024 * 1024); 1024 * 64, 32 * 1024 * 1024);
chip->pcm[cpcm->device] = pcm;
return 0;
}
static int __devinit azx_pcm_create(struct azx *chip)
{
static const char *dev_name[HDA_PCM_NTYPES] = {
"Audio", "SPDIF", "HDMI", "Modem"
};
/* starting device index for each PCM type */
static int dev_idx[HDA_PCM_NTYPES] = {
[HDA_PCM_TYPE_AUDIO] = 0,
[HDA_PCM_TYPE_SPDIF] = 1,
[HDA_PCM_TYPE_HDMI] = 3,
[HDA_PCM_TYPE_MODEM] = 6
};
/* normal audio device indices; not linear to keep compatibility */
static int audio_idx[4] = { 0, 2, 4, 5 };
struct hda_codec *codec;
int c, err;
int num_devs[HDA_PCM_NTYPES];
err = snd_hda_build_pcms(chip->bus);
if (err < 0)
return err;
/* create audio PCMs */
memset(num_devs, 0, sizeof(num_devs));
list_for_each_entry(codec, &chip->bus->codec_list, list) {
for (c = 0; c < codec->num_pcms; c++) {
struct hda_pcm *cpcm = &codec->pcm_info[c];
int type = cpcm->pcm_type;
switch (type) {
case HDA_PCM_TYPE_AUDIO:
if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
snd_printk(KERN_WARNING
"Too many audio devices\n");
continue;
}
cpcm->device = audio_idx[num_devs[type]];
break;
case HDA_PCM_TYPE_SPDIF:
case HDA_PCM_TYPE_HDMI:
case HDA_PCM_TYPE_MODEM:
if (num_devs[type]) {
snd_printk(KERN_WARNING
"%s already defined\n",
dev_name[type]);
continue;
}
cpcm->device = dev_idx[type];
break;
default:
snd_printk(KERN_WARNING
"Invalid PCM type %d\n", type);
continue;
}
num_devs[type]++;
err = create_codec_pcm(chip, codec, cpcm);
if (err < 0)
return err;
}
}
return 0; return 0;
} }
...@@ -2324,7 +2273,7 @@ static int __devinit azx_probe(struct pci_dev *pci, ...@@ -2324,7 +2273,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
} }
/* create PCM streams */ /* create PCM streams */
err = azx_pcm_create(chip); err = snd_hda_build_pcms(chip->bus);
if (err < 0) { if (err < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
......
...@@ -96,6 +96,8 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, ...@@ -96,6 +96,8 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
const char *name); const char *name);
int snd_hda_add_vmaster(struct hda_codec *codec, char *name, int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
unsigned int *tlv, const char **slaves); unsigned int *tlv, const char **slaves);
void snd_hda_codec_reset(struct hda_codec *codec);
int snd_hda_codec_configure(struct hda_codec *codec);
/* amp value bits */ /* amp value bits */
#define HDA_AMP_MUTE 0x80 #define HDA_AMP_MUTE 0x80
...@@ -393,10 +395,18 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); ...@@ -393,10 +395,18 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int caps); unsigned int caps);
int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl);
void snd_hda_ctls_clear(struct hda_codec *codec);
/* /*
* hwdep interface * hwdep interface
*/ */
#ifdef CONFIG_SND_HDA_HWDEP
int snd_hda_create_hwdep(struct hda_codec *codec); int snd_hda_create_hwdep(struct hda_codec *codec);
int snd_hda_hwdep_add_sysfs(struct hda_codec *codec);
#else
static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
#endif
/* /*
* power-management * power-management
......
...@@ -145,32 +145,6 @@ static void print_pcm_caps(struct snd_info_buffer *buffer, ...@@ -145,32 +145,6 @@ static void print_pcm_caps(struct snd_info_buffer *buffer,
print_pcm_formats(buffer, stream); print_pcm_formats(buffer, stream);
} }
static const char *get_jack_location(u32 cfg)
{
static char *bases[7] = {
"N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom",
};
static unsigned char specials_idx[] = {
0x07, 0x08,
0x17, 0x18, 0x19,
0x37, 0x38
};
static char *specials[] = {
"Rear Panel", "Drive Bar",
"Riser", "HDMI", "ATAPI",
"Mobile-In", "Mobile-Out"
};
int i;
cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
if ((cfg & 0x0f) < 7)
return bases[cfg & 0x0f];
for (i = 0; i < ARRAY_SIZE(specials_idx); i++) {
if (cfg == specials_idx[i])
return specials[i];
}
return "UNKNOWN";
}
static const char *get_jack_connection(u32 cfg) static const char *get_jack_connection(u32 cfg)
{ {
static char *names[16] = { static char *names[16] = {
...@@ -206,13 +180,6 @@ static void print_pin_caps(struct snd_info_buffer *buffer, ...@@ -206,13 +180,6 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
int *supports_vref) int *supports_vref)
{ {
static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
static char *jack_types[16] = {
"Line Out", "Speaker", "HP Out", "CD",
"SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
"Line In", "Aux", "Mic", "Telephony",
"SPDIF In", "Digitial In", "Reserved", "Other"
};
static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
unsigned int caps, val; unsigned int caps, val;
caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
...@@ -274,9 +241,9 @@ static void print_pin_caps(struct snd_info_buffer *buffer, ...@@ -274,9 +241,9 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], snd_hda_get_jack_type(caps),
jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], snd_hda_get_jack_connectivity(caps),
get_jack_location(caps)); snd_hda_get_jack_location(caps));
snd_iprintf(buffer, " Conn = %s, Color = %s\n", snd_iprintf(buffer, " Conn = %s, Color = %s\n",
get_jack_connection(caps), get_jack_connection(caps),
get_jack_color(caps)); get_jack_color(caps));
...@@ -511,12 +478,11 @@ static void print_codec_info(struct snd_info_entry *entry, ...@@ -511,12 +478,11 @@ static void print_codec_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer) struct snd_info_buffer *buffer)
{ {
struct hda_codec *codec = entry->private_data; struct hda_codec *codec = entry->private_data;
char buf[32];
hda_nid_t nid; hda_nid_t nid;
int i, nodes; int i, nodes;
snd_hda_get_codec_name(codec, buf, sizeof(buf)); snd_iprintf(buffer, "Codec: %s\n",
snd_iprintf(buffer, "Codec: %s\n", buf); codec->name ? codec->name : "Not Set");
snd_iprintf(buffer, "Address: %d\n", codec->addr); snd_iprintf(buffer, "Address: %d\n", codec->addr);
snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id); snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id); snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
......
...@@ -67,8 +67,7 @@ struct ad198x_spec { ...@@ -67,8 +67,7 @@ struct ad198x_spec {
/* dynamic controls, init_verbs and input_mux */ /* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg; struct auto_pin_cfg autocfg;
unsigned int num_kctl_alloc, num_kctl_used; struct snd_array kctls;
struct snd_kcontrol_new *kctl_alloc;
struct hda_input_mux private_imux; struct hda_input_mux private_imux;
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
...@@ -154,6 +153,8 @@ static const char *ad_slave_sws[] = { ...@@ -154,6 +153,8 @@ static const char *ad_slave_sws[] = {
NULL NULL
}; };
static void ad198x_free_kctls(struct hda_codec *codec);
static int ad198x_build_controls(struct hda_codec *codec) static int ad198x_build_controls(struct hda_codec *codec)
{ {
struct ad198x_spec *spec = codec->spec; struct ad198x_spec *spec = codec->spec;
...@@ -202,6 +203,7 @@ static int ad198x_build_controls(struct hda_codec *codec) ...@@ -202,6 +203,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
return err; return err;
} }
ad198x_free_kctls(codec); /* no longer needed */
return 0; return 0;
} }
...@@ -375,16 +377,27 @@ static int ad198x_build_pcms(struct hda_codec *codec) ...@@ -375,16 +377,27 @@ static int ad198x_build_pcms(struct hda_codec *codec)
return 0; return 0;
} }
static void ad198x_free(struct hda_codec *codec) static void ad198x_free_kctls(struct hda_codec *codec)
{ {
struct ad198x_spec *spec = codec->spec; struct ad198x_spec *spec = codec->spec;
unsigned int i;
if (spec->kctl_alloc) { if (spec->kctls.list) {
for (i = 0; i < spec->num_kctl_used; i++) struct snd_kcontrol_new *kctl = spec->kctls.list;
kfree(spec->kctl_alloc[i].name); int i;
kfree(spec->kctl_alloc); for (i = 0; i < spec->kctls.used; i++)
kfree(kctl[i].name);
} }
snd_array_free(&spec->kctls);
}
static void ad198x_free(struct hda_codec *codec)
{
struct ad198x_spec *spec = codec->spec;
if (!spec)
return;
ad198x_free_kctls(codec);
kfree(codec->spec); kfree(codec->spec);
} }
...@@ -2452,9 +2465,6 @@ static struct hda_amp_list ad1988_loopbacks[] = { ...@@ -2452,9 +2465,6 @@ static struct hda_amp_list ad1988_loopbacks[] = {
* Automatic parse of I/O pins from the BIOS configuration * Automatic parse of I/O pins from the BIOS configuration
*/ */
#define NUM_CONTROL_ALLOC 32
#define NUM_VERB_ALLOC 32
enum { enum {
AD_CTL_WIDGET_VOL, AD_CTL_WIDGET_VOL,
AD_CTL_WIDGET_MUTE, AD_CTL_WIDGET_MUTE,
...@@ -2472,27 +2482,15 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, ...@@ -2472,27 +2482,15 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
{ {
struct snd_kcontrol_new *knew; struct snd_kcontrol_new *knew;
if (spec->num_kctl_used >= spec->num_kctl_alloc) { snd_array_init(&spec->kctls, sizeof(*knew), 32);
int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; knew = snd_array_new(&spec->kctls);
if (!knew)
knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ return -ENOMEM;
if (! knew)
return -ENOMEM;
if (spec->kctl_alloc) {
memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
kfree(spec->kctl_alloc);
}
spec->kctl_alloc = knew;
spec->num_kctl_alloc = num;
}
knew = &spec->kctl_alloc[spec->num_kctl_used];
*knew = ad1988_control_templates[type]; *knew = ad1988_control_templates[type];
knew->name = kstrdup(name, GFP_KERNEL); knew->name = kstrdup(name, GFP_KERNEL);
if (! knew->name) if (! knew->name)
return -ENOMEM; return -ENOMEM;
knew->private_value = val; knew->private_value = val;
spec->num_kctl_used++;
return 0; return 0;
} }
...@@ -2846,8 +2844,8 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) ...@@ -2846,8 +2844,8 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin) if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = AD1988_SPDIF_IN; spec->dig_in_nid = AD1988_SPDIF_IN;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs; spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
......
...@@ -86,8 +86,6 @@ struct conexant_spec { ...@@ -86,8 +86,6 @@ struct conexant_spec {
/* dynamic controls, init_verbs and input_mux */ /* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg; struct auto_pin_cfg autocfg;
unsigned int num_kctl_alloc, num_kctl_used;
struct snd_kcontrol_new *kctl_alloc;
struct hda_input_mux private_imux; struct hda_input_mux private_imux;
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
...@@ -344,15 +342,6 @@ static int conexant_init(struct hda_codec *codec) ...@@ -344,15 +342,6 @@ static int conexant_init(struct hda_codec *codec)
static void conexant_free(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec)
{ {
struct conexant_spec *spec = codec->spec;
unsigned int i;
if (spec->kctl_alloc) {
for (i = 0; i < spec->num_kctl_used; i++)
kfree(spec->kctl_alloc[i].name);
kfree(spec->kctl_alloc);
}
kfree(codec->spec); kfree(codec->spec);
} }
......
...@@ -284,8 +284,7 @@ struct alc_spec { ...@@ -284,8 +284,7 @@ struct alc_spec {
/* dynamic controls, init_verbs and input_mux */ /* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg; struct auto_pin_cfg autocfg;
unsigned int num_kctl_alloc, num_kctl_used; struct snd_array kctls;
struct snd_kcontrol_new *kctl_alloc;
struct hda_input_mux private_imux; struct hda_input_mux private_imux;
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
...@@ -1625,6 +1624,9 @@ static const char *alc_slave_sws[] = { ...@@ -1625,6 +1624,9 @@ static const char *alc_slave_sws[] = {
/* /*
* build control elements * build control elements
*/ */
static void alc_free_kctls(struct hda_codec *codec);
static int alc_build_controls(struct hda_codec *codec) static int alc_build_controls(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
...@@ -1671,6 +1673,7 @@ static int alc_build_controls(struct hda_codec *codec) ...@@ -1671,6 +1673,7 @@ static int alc_build_controls(struct hda_codec *codec)
return err; return err;
} }
alc_free_kctls(codec); /* no longer needed */
return 0; return 0;
} }
...@@ -2761,19 +2764,27 @@ static int alc_build_pcms(struct hda_codec *codec) ...@@ -2761,19 +2764,27 @@ static int alc_build_pcms(struct hda_codec *codec)
return 0; return 0;
} }
static void alc_free_kctls(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
if (spec->kctls.list) {
struct snd_kcontrol_new *kctl = spec->kctls.list;
int i;
for (i = 0; i < spec->kctls.used; i++)
kfree(kctl[i].name);
}
snd_array_free(&spec->kctls);
}
static void alc_free(struct hda_codec *codec) static void alc_free(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
unsigned int i;
if (!spec) if (!spec)
return; return;
if (spec->kctl_alloc) { alc_free_kctls(codec);
for (i = 0; i < spec->num_kctl_used; i++)
kfree(spec->kctl_alloc[i].name);
kfree(spec->kctl_alloc);
}
kfree(spec); kfree(spec);
codec->spec = NULL; /* to be sure */ codec->spec = NULL; /* to be sure */
} }
...@@ -3458,9 +3469,6 @@ static struct alc_config_preset alc880_presets[] = { ...@@ -3458,9 +3469,6 @@ static struct alc_config_preset alc880_presets[] = {
* Automatic parse of I/O pins from the BIOS configuration * Automatic parse of I/O pins from the BIOS configuration
*/ */
#define NUM_CONTROL_ALLOC 32
#define NUM_VERB_ALLOC 32
enum { enum {
ALC_CTL_WIDGET_VOL, ALC_CTL_WIDGET_VOL,
ALC_CTL_WIDGET_MUTE, ALC_CTL_WIDGET_MUTE,
...@@ -3478,29 +3486,15 @@ static int add_control(struct alc_spec *spec, int type, const char *name, ...@@ -3478,29 +3486,15 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
{ {
struct snd_kcontrol_new *knew; struct snd_kcontrol_new *knew;
if (spec->num_kctl_used >= spec->num_kctl_alloc) { snd_array_init(&spec->kctls, sizeof(*knew), 32);
int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; knew = snd_array_new(&spec->kctls);
if (!knew)
/* array + terminator */ return -ENOMEM;
knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
if (!knew)
return -ENOMEM;
if (spec->kctl_alloc) {
memcpy(knew, spec->kctl_alloc,
sizeof(*knew) * spec->num_kctl_alloc);
kfree(spec->kctl_alloc);
}
spec->kctl_alloc = knew;
spec->num_kctl_alloc = num;
}
knew = &spec->kctl_alloc[spec->num_kctl_used];
*knew = alc880_control_templates[type]; *knew = alc880_control_templates[type];
knew->name = kstrdup(name, GFP_KERNEL); knew->name = kstrdup(name, GFP_KERNEL);
if (!knew->name) if (!knew->name)
return -ENOMEM; return -ENOMEM;
knew->private_value = val; knew->private_value = val;
spec->num_kctl_used++;
return 0; return 0;
} }
...@@ -3824,8 +3818,8 @@ static int alc880_parse_auto_config(struct hda_codec *codec) ...@@ -3824,8 +3818,8 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin) if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = ALC880_DIGIN_NID; spec->dig_in_nid = ALC880_DIGIN_NID;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
...@@ -5218,7 +5212,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec) ...@@ -5218,7 +5212,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg); err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
if (err < 0) if (err < 0)
return err; return err;
if (!spec->kctl_alloc) if (!spec->kctls.list)
return 0; /* can't find valid BIOS pin config */ return 0; /* can't find valid BIOS pin config */
err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg); err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
if (err < 0) if (err < 0)
...@@ -5228,8 +5222,8 @@ static int alc260_parse_auto_config(struct hda_codec *codec) ...@@ -5228,8 +5222,8 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin) if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs; spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
...@@ -10302,8 +10296,8 @@ static int alc262_parse_auto_config(struct hda_codec *codec) ...@@ -10302,8 +10296,8 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin) if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = ALC262_DIGIN_NID; spec->dig_in_nid = ALC262_DIGIN_NID;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs; spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
spec->num_mux_defs = 1; spec->num_mux_defs = 1;
...@@ -11433,8 +11427,8 @@ static int alc268_parse_auto_config(struct hda_codec *codec) ...@@ -11433,8 +11427,8 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin) if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC268_DIGOUT_NID; spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
if (spec->autocfg.speaker_pins[0] != 0x1d) if (spec->autocfg.speaker_pins[0] != 0x1d)
spec->mixers[spec->num_mixers++] = alc268_beep_mixer; spec->mixers[spec->num_mixers++] = alc268_beep_mixer;
...@@ -12205,8 +12199,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec) ...@@ -12205,8 +12199,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin) if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC269_DIGOUT_NID; spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
/* create a beep mixer control if the pin 0x1d isn't assigned */ /* create a beep mixer control if the pin 0x1d isn't assigned */
for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++) for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
...@@ -13303,8 +13297,8 @@ static int alc861_parse_auto_config(struct hda_codec *codec) ...@@ -13303,8 +13297,8 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin) if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs; spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
...@@ -14414,8 +14408,8 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) ...@@ -14414,8 +14408,8 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin) if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->init_verbs[spec->num_init_verbs++] spec->init_verbs[spec->num_init_verbs++]
= alc861vd_volume_init_verbs; = alc861vd_volume_init_verbs;
...@@ -16241,8 +16235,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec) ...@@ -16241,8 +16235,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_out_pin) if (spec->autocfg.dig_out_pin)
spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->num_mux_defs = 1; spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux; spec->input_mux = &spec->private_imux;
......
This diff is collapsed.
...@@ -53,9 +53,6 @@ ...@@ -53,9 +53,6 @@
#define AMP_VAL_IDX_SHIFT 19 #define AMP_VAL_IDX_SHIFT 19
#define AMP_VAL_IDX_MASK (0x0f<<19) #define AMP_VAL_IDX_MASK (0x0f<<19)
#define NUM_CONTROL_ALLOC 32
#define NUM_VERB_ALLOC 32
/* Pin Widget NID */ /* Pin Widget NID */
#define VT1708_HP_NID 0x13 #define VT1708_HP_NID 0x13
#define VT1708_DIGOUT_NID 0x14 #define VT1708_DIGOUT_NID 0x14
...@@ -227,8 +224,7 @@ struct via_spec { ...@@ -227,8 +224,7 @@ struct via_spec {
/* dynamic controls, init_verbs and input_mux */ /* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg; struct auto_pin_cfg autocfg;
unsigned int num_kctl_alloc, num_kctl_used; struct snd_array kctls;
struct snd_kcontrol_new *kctl_alloc;
struct hda_input_mux private_imux[2]; struct hda_input_mux private_imux[2];
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
...@@ -272,33 +268,31 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, ...@@ -272,33 +268,31 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
{ {
struct snd_kcontrol_new *knew; struct snd_kcontrol_new *knew;
if (spec->num_kctl_used >= spec->num_kctl_alloc) { snd_array_init(&spec->kctls, sizeof(*knew), 32);
int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; knew = snd_array_new(&spec->kctls);
if (!knew)
/* array + terminator */ return -ENOMEM;
knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
if (!knew)
return -ENOMEM;
if (spec->kctl_alloc) {
memcpy(knew, spec->kctl_alloc,
sizeof(*knew) * spec->num_kctl_alloc);
kfree(spec->kctl_alloc);
}
spec->kctl_alloc = knew;
spec->num_kctl_alloc = num;
}
knew = &spec->kctl_alloc[spec->num_kctl_used];
*knew = vt1708_control_templates[type]; *knew = vt1708_control_templates[type];
knew->name = kstrdup(name, GFP_KERNEL); knew->name = kstrdup(name, GFP_KERNEL);
if (!knew->name) if (!knew->name)
return -ENOMEM; return -ENOMEM;
knew->private_value = val; knew->private_value = val;
spec->num_kctl_used++;
return 0; return 0;
} }
static void via_free_kctls(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
if (spec->kctls.list) {
struct snd_kcontrol_new *kctl = spec->kctls.list;
int i;
for (i = 0; i < spec->kctls.used; i++)
kfree(kctl[i].name);
}
snd_array_free(&spec->kctls);
}
/* create input playback/capture controls for the given pin */ /* create input playback/capture controls for the given pin */
static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin, static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
const char *ctlname, int idx, int mix_nid) const char *ctlname, int idx, int mix_nid)
...@@ -896,6 +890,7 @@ static int via_build_controls(struct hda_codec *codec) ...@@ -896,6 +890,7 @@ static int via_build_controls(struct hda_codec *codec)
if (err < 0) if (err < 0)
return err; return err;
} }
via_free_kctls(codec); /* no longer needed */
return 0; return 0;
} }
...@@ -941,17 +936,11 @@ static int via_build_pcms(struct hda_codec *codec) ...@@ -941,17 +936,11 @@ static int via_build_pcms(struct hda_codec *codec)
static void via_free(struct hda_codec *codec) static void via_free(struct hda_codec *codec)
{ {
struct via_spec *spec = codec->spec; struct via_spec *spec = codec->spec;
unsigned int i;
if (!spec) if (!spec)
return; return;
if (spec->kctl_alloc) { via_free_kctls(codec);
for (i = 0; i < spec->num_kctl_used; i++)
kfree(spec->kctl_alloc[i].name);
kfree(spec->kctl_alloc);
}
kfree(codec->spec); kfree(codec->spec);
} }
...@@ -1373,8 +1362,8 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) ...@@ -1373,8 +1362,8 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin) if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = VT1708_DIGIN_NID; spec->dig_in_nid = VT1708_DIGIN_NID;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs; spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
...@@ -1846,8 +1835,8 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) ...@@ -1846,8 +1835,8 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin) if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = VT1709_DIGIN_NID; spec->dig_in_nid = VT1709_DIGIN_NID;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->input_mux = &spec->private_imux[0]; spec->input_mux = &spec->private_imux[0];
...@@ -2390,8 +2379,8 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) ...@@ -2390,8 +2379,8 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
if (spec->autocfg.dig_in_pin) if (spec->autocfg.dig_in_pin)
spec->dig_in_nid = VT1708B_DIGIN_NID; spec->dig_in_nid = VT1708B_DIGIN_NID;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->input_mux = &spec->private_imux[0]; spec->input_mux = &spec->private_imux[0];
...@@ -2855,8 +2844,8 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) ...@@ -2855,8 +2844,8 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
spec->extra_dig_out_nid = 0x15; spec->extra_dig_out_nid = 0x15;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->input_mux = &spec->private_imux[0]; spec->input_mux = &spec->private_imux[0];
...@@ -3174,8 +3163,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) ...@@ -3174,8 +3163,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
spec->extra_dig_out_nid = 0x1B; spec->extra_dig_out_nid = 0x1B;
if (spec->kctl_alloc) if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->mixers[spec->num_mixers++] = spec->kctls.list;
spec->input_mux = &spec->private_imux[0]; spec->input_mux = &spec->private_imux[0];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment