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

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

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

parents 45a6ac16 1e1be432
Loading
Loading
Loading
Loading
+287 −95
Original line number Diff line number Diff line
@@ -344,7 +344,7 @@ static void process_unsol_events(struct work_struct *work)
/*
 * initialize unsolicited queue
 */
static int __devinit init_unsol_queue(struct hda_bus *bus)
static int init_unsol_queue(struct hda_bus *bus)
{
	struct hda_bus_unsolicited *unsol;

@@ -393,6 +393,20 @@ static int snd_hda_bus_dev_free(struct snd_device *device)
	return snd_hda_bus_free(bus);
}

#ifdef CONFIG_SND_HDA_HWDEP
static int snd_hda_bus_dev_register(struct snd_device *device)
{
	struct hda_bus *bus = device->device_data;
	struct hda_codec *codec;
	list_for_each_entry(codec, &bus->codec_list, list) {
		snd_hda_hwdep_add_sysfs(codec);
	}
	return 0;
}
#else
#define snd_hda_bus_dev_register	NULL
#endif

/**
 * snd_hda_bus_new - create a HDA bus
 * @card: the card entry
@@ -408,6 +422,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
	struct hda_bus *bus;
	int err;
	static struct snd_device_ops dev_ops = {
		.dev_register = snd_hda_bus_dev_register,
		.dev_free = snd_hda_bus_dev_free,
	};

@@ -446,7 +461,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,

#ifdef CONFIG_SND_HDA_GENERIC
#define is_generic_config(codec) \
	(codec->bus->modelname && !strcmp(codec->bus->modelname, "generic"))
	(codec->modelname && !strcmp(codec->modelname, "generic"))
#else
#define is_generic_config(codec)	0
#endif
@@ -454,7 +469,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
/*
 * find a matching codec preset
 */
static const struct hda_codec_preset __devinit *
static const struct hda_codec_preset *
find_codec_preset(struct hda_codec *codec)
{
	const struct hda_codec_preset **tbl, *preset;
@@ -481,15 +496,14 @@ find_codec_preset(struct hda_codec *codec)
}

/*
 * snd_hda_get_codec_name - store the codec name
 * get_codec_name - store the codec name
 */
void snd_hda_get_codec_name(struct hda_codec *codec,
			    char *name, int namelen)
static int get_codec_name(struct hda_codec *codec)
{
	const struct hda_vendor_id *c;
	const char *vendor = NULL;
	u16 vendor_id = codec->vendor_id >> 16;
	char tmp[16];
	char tmp[16], name[32];

	for (c = hda_vendor_ids; c->id; c++) {
		if (c->id == vendor_id) {
@@ -502,10 +516,15 @@ void snd_hda_get_codec_name(struct hda_codec *codec,
		vendor = tmp;
	}
	if (codec->preset && codec->preset->name)
		snprintf(name, namelen, "%s %s", vendor, codec->preset->name);
		snprintf(name, sizeof(name), "%s %s", vendor,
			 codec->preset->name);
	else
		snprintf(name, namelen, "%s ID %x", vendor,
		snprintf(name, sizeof(name), "%s ID %x", vendor,
			 codec->vendor_id & 0xffff);
	codec->name = kstrdup(name, GFP_KERNEL);
	if (!codec->name)
		return -ENOMEM;
	return 0;
}

/*
@@ -570,11 +589,14 @@ static void snd_hda_codec_free(struct hda_codec *codec)
	flush_scheduled_work();
#endif
	list_del(&codec->list);
	snd_array_free(&codec->mixers);
	codec->bus->caddr_tbl[codec->addr] = NULL;
	if (codec->patch_ops.free)
		codec->patch_ops.free(codec);
	free_hda_cache(&codec->amp_cache);
	free_hda_cache(&codec->cmd_cache);
	kfree(codec->name);
	kfree(codec->modelname);
	kfree(codec->wcaps);
	kfree(codec);
}
@@ -616,6 +638,14 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
	mutex_init(&codec->spdif_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 snd_kcontrol *), 32);
	if (codec->bus->modelname) {
		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
		if (!codec->modelname) {
			snd_hda_codec_free(codec);
			return -ENODEV;
		}
	}

#ifdef CONFIG_SND_HDA_POWER_SAVE
	INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
@@ -661,12 +691,41 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
			snd_hda_codec_read(codec, nid, 0,
					   AC_VERB_GET_SUBSYSTEM_ID, 0);
	}
	if (bus->modelname)
		codec->modelname = kstrdup(bus->modelname, GFP_KERNEL);

	err = snd_hda_codec_configure(codec);
	if (err < 0) {
		snd_hda_codec_free(codec);
		return err;
	}
	snd_hda_codec_proc_new(codec);

	snd_hda_create_hwdep(codec);

	sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id,
		codec->subsystem_id, codec->revision_id);
	snd_component_add(codec->bus->card, component);

	if (codecp)
		*codecp = codec;
	return 0;
}

int snd_hda_codec_configure(struct hda_codec *codec)
{
	int err;

	codec->preset = find_codec_preset(codec);
	if (!codec->name) {
		err = get_codec_name(codec);
		if (err < 0)
			return err;
	}
	/* audio codec should override the mixer name */
	if (codec->afg || !*bus->card->mixername)
		snd_hda_get_codec_name(codec, bus->card->mixername,
				       sizeof(bus->card->mixername));
	if (codec->afg || !*codec->bus->card->mixername)
		strlcpy(codec->bus->card->mixername, codec->name,
			sizeof(codec->bus->card->mixername));

	if (is_generic_config(codec)) {
		err = snd_hda_parse_generic_codec(codec);
@@ -683,27 +742,11 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
		printk(KERN_ERR "hda-codec: No codec parser is available\n");

 patched:
	if (err < 0) {
		snd_hda_codec_free(codec);
	if (!err && codec->patch_ops.unsol_event)
		err = init_unsol_queue(codec->bus);
	return err;
}

	if (codec->patch_ops.unsol_event)
		init_unsol_queue(bus);

	snd_hda_codec_proc_new(codec);
#ifdef CONFIG_SND_HDA_HWDEP
	snd_hda_create_hwdep(codec);
#endif

	sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id);
	snd_component_add(codec->bus->card, component);

	if (codecp)
		*codecp = codec;
	return 0;
}

/**
 * snd_hda_codec_setup_stream - set up the codec for streaming
 * @codec: the CODEC to set up
@@ -756,12 +799,12 @@ static void __devinit init_hda_cache(struct hda_cache_rec *cache,
{
	memset(cache, 0, sizeof(*cache));
	memset(cache->hash, 0xff, sizeof(cache->hash));
	cache->record_size = record_size;
	snd_array_init(&cache->buf, record_size, 64);
}

static void free_hda_cache(struct hda_cache_rec *cache)
{
	kfree(cache->buffer);
	snd_array_free(&cache->buf);
}

/* query the hash.  allocate an entry if not found. */
@@ -770,38 +813,18 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache,
{
	u16 idx = key % (u16)ARRAY_SIZE(cache->hash);
	u16 cur = cache->hash[idx];
	struct hda_cache_head *info_head = cache->buf.list;
	struct hda_cache_head *info;

	while (cur != 0xffff) {
		info = (struct hda_cache_head *)(cache->buffer +
						 cur * cache->record_size);
		info = &info_head[cur];
		if (info->key == key)
			return info;
		cur = info->next;
	}

	/* add a new hash entry */
	if (cache->num_entries >= cache->size) {
		/* reallocate the array */
		unsigned int new_size = cache->size + 64;
		void *new_buffer;
		new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL);
		if (!new_buffer) {
			snd_printk(KERN_ERR "hda_codec: "
				   "can't malloc amp_info\n");
			return NULL;
		}
		if (cache->buffer) {
			memcpy(new_buffer, cache->buffer,
			       cache->size * cache->record_size);
			kfree(cache->buffer);
		}
		cache->size = new_size;
		cache->buffer = new_buffer;
	}
	cur = cache->num_entries++;
	info = (struct hda_cache_head *)(cache->buffer +
					 cur * cache->record_size);
	info = snd_array_new(&cache->buf);
	info->key = key;
	info->val = 0;
	info->next = cache->hash[idx];
@@ -942,10 +965,10 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
/* resume the all amp commands from the cache */
void snd_hda_codec_resume_amp(struct hda_codec *codec)
{
	struct hda_amp_info *buffer = codec->amp_cache.buffer;
	struct hda_amp_info *buffer = codec->amp_cache.buf.list;
	int i;

	for (i = 0; i < codec->amp_cache.size; i++, buffer++) {
	for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) {
		u32 key = buffer->head.key;
		hda_nid_t nid;
		unsigned int idx, dir, ch;
@@ -1097,6 +1120,57 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
	return _snd_hda_find_mixer_ctl(codec, name, 0);
}

/* Add a control element and assign to the codec */
int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
{
	int err;
	struct snd_kcontrol **knewp;

	err = snd_ctl_add(codec->bus->card, kctl);
	if (err < 0)
		return err;
	knewp = snd_array_new(&codec->mixers);
	if (!knewp)
		return -ENOMEM;
	*knewp = kctl;
	return 0;
}

/* Clear all controls assigned to the given codec */
void snd_hda_ctls_clear(struct hda_codec *codec)
{
	int i;
	struct snd_kcontrol **kctls = codec->mixers.list;
	for (i = 0; i < codec->mixers.used; i++)
		snd_ctl_remove(codec->bus->card, kctls[i]);
	snd_array_free(&codec->mixers);
}

void snd_hda_codec_reset(struct hda_codec *codec)
{
	int i;

#ifdef CONFIG_SND_HDA_POWER_SAVE
	cancel_delayed_work(&codec->power_work);
	flush_scheduled_work();
#endif
	snd_hda_ctls_clear(codec);
	/* relase PCMs */
	for (i = 0; i < codec->num_pcms; i++) {
		if (codec->pcm_info[i].pcm)
			snd_device_free(codec->bus->card,
					codec->pcm_info[i].pcm);
	}
	if (codec->patch_ops.free)
		codec->patch_ops.free(codec);
	codec->spec = NULL;
	free_hda_cache(&codec->amp_cache);
	free_hda_cache(&codec->cmd_cache);
	codec->num_pcms = 0;
	codec->pcm_info = NULL;
	codec->preset = NULL;
}

/* create a virtual master control and add slaves */
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
			unsigned int *tlv, const char **slaves)
@@ -1114,7 +1188,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
	kctl = snd_ctl_make_virtual_master(name, tlv);
	if (!kctl)
		return -ENOMEM;
	err = snd_ctl_add(codec->bus->card, kctl);
	err = snd_hda_ctl_add(codec, kctl);
	if (err < 0)
		return err;
	
@@ -1578,7 +1652,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
		kctl = snd_ctl_new1(dig_mix, codec);
		kctl->id.index = idx;
		kctl->private_value = nid;
		err = snd_ctl_add(codec->bus->card, kctl);
		err = snd_hda_ctl_add(codec, kctl);
		if (err < 0)
			return err;
	}
@@ -1622,7 +1696,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
	if (!mout->dig_out_nid)
		return 0;
	/* ATTENTION: here mout is passed as private_data, instead of codec */
	return snd_ctl_add(codec->bus->card,
	return snd_hda_ctl_add(codec,
			   snd_ctl_new1(&spdif_share_sw, mout));
}

@@ -1724,7 +1798,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
	for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
		kctl = snd_ctl_new1(dig_mix, codec);
		kctl->private_value = nid;
		err = snd_ctl_add(codec->bus->card, kctl);
		err = snd_hda_ctl_add(codec, kctl);
		if (err < 0)
			return err;
	}
@@ -1779,10 +1853,10 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
/* resume the all commands from the cache */
void snd_hda_codec_resume_cache(struct hda_codec *codec)
{
	struct hda_cache_head *buffer = codec->cmd_cache.buffer;
	struct hda_cache_head *buffer = codec->cmd_cache.buf.list;
	int i;

	for (i = 0; i < codec->cmd_cache.size; i++, buffer++) {
	for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) {
		u32 key = buffer->key;
		if (!key)
			continue;
@@ -1867,6 +1941,17 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
	}
}

#ifdef CONFIG_SND_HDA_HWDEP
/* execute additional init verbs */
static void hda_exec_init_verbs(struct hda_codec *codec)
{
	if (codec->init_verbs.list)
		snd_hda_sequence_write(codec, codec->init_verbs.list);
}
#else
static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
#endif

#ifdef SND_HDA_NEEDS_RESUME
/*
 * call suspend and power-down; used both from PM and power-save
@@ -1893,6 +1978,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
	hda_set_power_state(codec,
			    codec->afg ? codec->afg : codec->mfg,
			    AC_PWRST_D0);
	hda_exec_init_verbs(codec);
	if (codec->patch_ops.resume)
		codec->patch_ops.resume(codec);
	else {
@@ -1918,6 +2004,15 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus)
	struct hda_codec *codec;

	list_for_each_entry(codec, &bus->codec_list, list) {
		int err = snd_hda_codec_build_controls(codec);
		if (err < 0)
			return err;
	}
	return 0;
}

int snd_hda_codec_build_controls(struct hda_codec *codec)
{
	int err = 0;
	/* fake as if already powered-on */
	hda_keep_power_on(codec);
@@ -1925,6 +2020,7 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus)
	hda_set_power_state(codec,
			    codec->afg ? codec->afg : codec->mfg,
			    AC_PWRST_D0);
	hda_exec_init_verbs(codec);
	/* continue to initialize... */
	if (codec->patch_ops.init)
		err = codec->patch_ops.init(codec);
@@ -1933,8 +2029,6 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus)
	snd_hda_power_down(codec);
	if (err < 0)
		return err;
	}

	return 0;
}

@@ -2235,7 +2329,7 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo,
	return 0;
}

static int __devinit set_pcm_default_values(struct hda_codec *codec,
static int set_pcm_default_values(struct hda_codec *codec,
				  struct hda_pcm_stream *info)
{
	/* query support PCM information from the given NID */
@@ -2262,6 +2356,28 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec,
	return 0;
}

/*
 * attach a new PCM stream
 */
static int __devinit
snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
{
	struct hda_pcm_stream *info;
	int stream, err;

	if (!pcm->name)
		return -EINVAL;
	for (stream = 0; stream < 2; stream++) {
		info = &pcm->stream[stream];
		if (info->substreams) {
			err = set_pcm_default_values(codec, info);
			if (err < 0)
				return err;
		}
	}
	return codec->bus->ops.attach_pcm(codec, pcm);
}

/**
 * snd_hda_build_pcms - build PCM information
 * @bus: the BUS
@@ -2288,25 +2404,67 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec,
 *
 * This function returns 0 if successfull, or a negative error code.
 */
int __devinit snd_hda_build_pcms(struct hda_bus *bus)
int snd_hda_build_pcms(struct hda_bus *bus)
{
	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 num_devs[HDA_PCM_NTYPES];

	memset(num_devs, 0, sizeof(num_devs));
	list_for_each_entry(codec, &bus->codec_list, list) {
		unsigned int pcm, s;
		unsigned int pcm;
		int err;
		if (!codec->num_pcms) {
			if (!codec->patch_ops.build_pcms)
				continue;
			err = codec->patch_ops.build_pcms(codec);
			if (err < 0)
				return err;
		}
		for (pcm = 0; pcm < codec->num_pcms; pcm++) {
			for (s = 0; s < 2; s++) {
				struct hda_pcm_stream *info;
				info = &codec->pcm_info[pcm].stream[s];
				if (!info->substreams)
			struct hda_pcm *cpcm = &codec->pcm_info[pcm];
			int type = cpcm->pcm_type;
			int dev;
			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;
				err = set_pcm_default_values(codec, info);
				}
				dev = 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;
				}
				dev = dev_idx[type];
				break;
			default:
				snd_printk(KERN_WARNING
					   "Invalid PCM type %d\n", type);
				continue;
			}
			num_devs[type]++;
			if (!cpcm->pcm) {
				cpcm->device = dev;
				err = snd_hda_attach_pcm(codec, cpcm);
				if (err < 0)
					return err;
			}
@@ -2332,11 +2490,11 @@ int snd_hda_check_board_config(struct hda_codec *codec,
			       int num_configs, const char **models,
			       const struct snd_pci_quirk *tbl)
{
	if (codec->bus->modelname && models) {
	if (codec->modelname && models) {
		int i;
		for (i = 0; i < num_configs; i++) {
			if (models[i] &&
			    !strcmp(codec->bus->modelname, models[i])) {
			    !strcmp(codec->modelname, models[i])) {
				snd_printd(KERN_INFO "hda_codec: model '%s' is "
					   "selected\n", models[i]);
				return i;
@@ -2389,7 +2547,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
		kctl = snd_ctl_new1(knew, codec);
		if (!kctl)
			return -ENOMEM;
		err = snd_ctl_add(codec->bus->card, kctl);
		err = snd_hda_ctl_add(codec, kctl);
		if (err < 0) {
			if (!codec->addr)
				return err;
@@ -2397,7 +2555,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
			if (!kctl)
				return -ENOMEM;
			kctl->id.device = codec->addr;
			err = snd_ctl_add(codec->bus->card, kctl);
			err = snd_hda_ctl_add(codec, kctl);
			if (err < 0)
				return err;
		}
@@ -3138,3 +3296,37 @@ int snd_hda_codecs_inuse(struct hda_bus *bus)
}
#endif
#endif

/*
 * generic arrays
 */

/* get a new element from the given array
 * if it exceeds the pre-allocated array size, re-allocate the array
 */
void *snd_array_new(struct snd_array *array)
{
	if (array->used >= array->alloced) {
		int num = array->alloced + array->alloc_align;
		void *nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL);
		if (!nlist)
			return NULL;
		if (array->list) {
			memcpy(nlist, array->list,
			       array->elem_size * array->alloced);
			kfree(array->list);
		}
		array->list = nlist;
		array->alloced = num;
	}
	return array->list + (array->used++ * array->elem_size);
}

/* free the given array elements */
void snd_array_free(struct snd_array *array)
{
	kfree(array->list);
	array->used = 0;
	array->alloced = 0;
	array->list = NULL;
}
+34 −5
Original line number Diff line number Diff line
@@ -519,6 +519,26 @@ enum {
/* max. codec address */
#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
 */
@@ -542,6 +562,8 @@ struct hda_bus_ops {
	unsigned int (*get_response)(struct hda_codec *codec);
	/* free the private data */
	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
	/* notify power-up/down from codec to controller */
	void (*pm_notify)(struct hda_codec *codec);
@@ -635,10 +657,7 @@ struct hda_amp_info {

struct hda_cache_rec {
	u16 hash[64];			/* hash table for index */
	unsigned int num_entries;	/* number of assigned entries */
	unsigned int size;		/* allocated size */
	unsigned int record_size;	/* record size (including header) */
	void *buffer;			/* hash table entries */
	struct snd_array buf;		/* record entries */
};

/* PCM callbacks */
@@ -680,7 +699,8 @@ struct hda_pcm {
	char *name;
	struct hda_pcm_stream stream[2];
	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 */
@@ -699,6 +719,8 @@ struct hda_codec {

	/* detected preset */
	const struct hda_codec_preset *preset;
	const char *name;	/* codec name */
	const char *modelname;	/* model name for preset */

	/* set by patch */
	struct hda_codec_ops patch_ops;
@@ -718,6 +740,8 @@ struct hda_codec {
	hda_nid_t start_nid;
	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 cmd_cache;	/* cache for other commands */

@@ -727,7 +751,11 @@ struct hda_codec {
	unsigned int spdif_in_enable;	/* SPDIF input enable? */
	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_array init_verbs;	/* additional init verbs */
	struct snd_array hints;		/* additional hints */
#endif

	/* misc flags */
	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);
 * Mixer
 */
int snd_hda_build_controls(struct hda_bus *bus);
int snd_hda_codec_build_controls(struct hda_codec *codec);

/*
 * PCM
+12 −8
Original line number Diff line number Diff line
@@ -723,7 +723,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
		if (is_loopback)
			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);
		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;
		created = 1;
	} 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,
		if (is_loopback)
			add_input_loopback(codec, node->nid, HDA_OUTPUT, 0);
		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;
		created = 1;
	}
@@ -745,14 +747,16 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node,
	    (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) {
		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);
		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;
		created = 1;
	} else if ((node->wid_caps & AC_WCAP_OUT_AMP) &&
		   (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) {
		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);
		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;
		created = 1;
	}
@@ -849,8 +853,8 @@ static int build_input_controls(struct hda_codec *codec)
	}

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

	/* no volume control? */
@@ -867,8 +871,8 @@ static int build_input_controls(struct hda_codec *codec)
			HDA_CODEC_VOLUME(name, adc_node->nid,
					 spec->input_mux.items[i].index,
					 HDA_INPUT);
		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;
	}

+228 −0

File changed.

Preview size limit exceeded, changes collapsed.

+35 −86
Original line number Diff line number Diff line
@@ -1180,6 +1180,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
	return 0;
}

static int azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm);

/*
 * Codec initialization
@@ -1212,6 +1213,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
	bus_temp.pci = chip->pci;
	bus_temp.ops.command = azx_send_cmd;
	bus_temp.ops.get_response = azx_get_response;
	bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
#ifdef CONFIG_SND_HDA_POWER_SAVE
	bus_temp.ops.pm_notify = azx_power_notify;
#endif
@@ -1718,111 +1720,58 @@ static struct snd_pcm_ops azx_pcm_ops = {

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,
				      struct hda_pcm *cpcm)
static int
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 azx_pcm *apcm;
	int pcm_dev = cpcm->device;
	int s, err;

	/* if no substreams are defined for both playback and capture,
	 * it's just a placeholder.  ignore it.
	 */
	if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
		return 0;

	if (snd_BUG_ON(!cpcm->name))
	if (pcm_dev >= AZX_MAX_PCMS) {
		snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
			   pcm_dev);
		return -EINVAL;

	err = snd_pcm_new(chip->card, cpcm->name, cpcm->device,
			  cpcm->stream[0].substreams,
			  cpcm->stream[1].substreams,
	}
	if (chip->pcm[pcm_dev]) {
		snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
		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);
	if (err < 0)
		return err;
	strcpy(pcm->name, cpcm->name);
	apcm = kmalloc(sizeof(*apcm), GFP_KERNEL);
	apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
	if (apcm == NULL)
		return -ENOMEM;
	apcm->chip = chip;
	apcm->codec = codec;
	apcm->hinfo[0] = &cpcm->stream[0];
	apcm->hinfo[1] = &cpcm->stream[1];
	pcm->private_data = apcm;
	pcm->private_free = azx_pcm_free;
	if (cpcm->stream[0].substreams)
		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
	if (cpcm->stream[1].substreams)
		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
	if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
		pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
	chip->pcm[pcm_dev] = pcm;
	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_dma_pci_data(chip->pci),
					      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;
}

@@ -2324,7 +2273,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
	}

	/* create PCM streams */
	err = azx_pcm_create(chip);
	err = snd_hda_build_pcms(chip->bus);
	if (err < 0) {
		snd_card_free(card);
		return err;
Loading