brintos

brintos / linux-shallow public Read only

0
0
Text · 31.4 KiB · 8f5df9b Raw
1185 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Dummy soundcard4 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>5 */6 7#include <linux/init.h>8#include <linux/err.h>9#include <linux/platform_device.h>10#include <linux/jiffies.h>11#include <linux/slab.h>12#include <linux/time.h>13#include <linux/wait.h>14#include <linux/hrtimer.h>15#include <linux/math64.h>16#include <linux/module.h>17#include <sound/core.h>18#include <sound/control.h>19#include <sound/tlv.h>20#include <sound/pcm.h>21#include <sound/rawmidi.h>22#include <sound/info.h>23#include <sound/initval.h>24 25MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");26MODULE_DESCRIPTION("Dummy soundcard (/dev/null)");27MODULE_LICENSE("GPL");28 29#define MAX_PCM_DEVICES		430#define MAX_PCM_SUBSTREAMS	12831#define MAX_MIDI_DEVICES	232 33/* defaults */34#define MAX_BUFFER_SIZE		(64*1024)35#define MIN_PERIOD_SIZE		6436#define MAX_PERIOD_SIZE		MAX_BUFFER_SIZE37#define USE_FORMATS 		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)38#define USE_RATE		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_4800039#define USE_RATE_MIN		550040#define USE_RATE_MAX		4800041#define USE_CHANNELS_MIN 	142#define USE_CHANNELS_MAX 	243#define USE_PERIODS_MIN 	144#define USE_PERIODS_MAX 	102445#define USE_MIXER_VOLUME_LEVEL_MIN	-5046#define USE_MIXER_VOLUME_LEVEL_MAX	10047 48static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */49static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */50static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};51static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL};52static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};53static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};54//static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};55static int mixer_volume_level_min = USE_MIXER_VOLUME_LEVEL_MIN;56static int mixer_volume_level_max = USE_MIXER_VOLUME_LEVEL_MAX;57#ifdef CONFIG_HIGH_RES_TIMERS58static bool hrtimer = 1;59#endif60static bool fake_buffer = 1;61 62module_param_array(index, int, NULL, 0444);63MODULE_PARM_DESC(index, "Index value for dummy soundcard.");64module_param_array(id, charp, NULL, 0444);65MODULE_PARM_DESC(id, "ID string for dummy soundcard.");66module_param_array(enable, bool, NULL, 0444);67MODULE_PARM_DESC(enable, "Enable this dummy soundcard.");68module_param_array(model, charp, NULL, 0444);69MODULE_PARM_DESC(model, "Soundcard model.");70module_param_array(pcm_devs, int, NULL, 0444);71MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver.");72module_param_array(pcm_substreams, int, NULL, 0444);73MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-128) for dummy driver.");74//module_param_array(midi_devs, int, NULL, 0444);75//MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver.");76module_param(mixer_volume_level_min, int, 0444);77MODULE_PARM_DESC(mixer_volume_level_min, "Minimum mixer volume level for dummy driver. Default: -50");78module_param(mixer_volume_level_max, int, 0444);79MODULE_PARM_DESC(mixer_volume_level_max, "Maximum mixer volume level for dummy driver. Default: 100");80module_param(fake_buffer, bool, 0444);81MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations.");82#ifdef CONFIG_HIGH_RES_TIMERS83module_param(hrtimer, bool, 0644);84MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source.");85#endif86 87static struct platform_device *devices[SNDRV_CARDS];88 89#define MIXER_ADDR_MASTER	090#define MIXER_ADDR_LINE		191#define MIXER_ADDR_MIC		292#define MIXER_ADDR_SYNTH	393#define MIXER_ADDR_CD		494#define MIXER_ADDR_LAST		495 96struct dummy_timer_ops {97	int (*create)(struct snd_pcm_substream *);98	void (*free)(struct snd_pcm_substream *);99	int (*prepare)(struct snd_pcm_substream *);100	int (*start)(struct snd_pcm_substream *);101	int (*stop)(struct snd_pcm_substream *);102	snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);103};104 105#define get_dummy_ops(substream) \106	(*(const struct dummy_timer_ops **)(substream)->runtime->private_data)107 108struct dummy_model {109	const char *name;110	int (*playback_constraints)(struct snd_pcm_runtime *runtime);111	int (*capture_constraints)(struct snd_pcm_runtime *runtime);112	u64 formats;113	size_t buffer_bytes_max;114	size_t period_bytes_min;115	size_t period_bytes_max;116	unsigned int periods_min;117	unsigned int periods_max;118	unsigned int rates;119	unsigned int rate_min;120	unsigned int rate_max;121	unsigned int channels_min;122	unsigned int channels_max;123};124 125struct snd_dummy {126	struct snd_card *card;127	const struct dummy_model *model;128	struct snd_pcm *pcm;129	struct snd_pcm_hardware pcm_hw;130	spinlock_t mixer_lock;131	int mixer_volume[MIXER_ADDR_LAST+1][2];132	int capture_source[MIXER_ADDR_LAST+1][2];133	int iobox;134	struct snd_kcontrol *cd_volume_ctl;135	struct snd_kcontrol *cd_switch_ctl;136};137 138/*139 * card models140 */141 142static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)143{144	int err;145	err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);146	if (err < 0)147		return err;148	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);149	if (err < 0)150		return err;151	return 0;152}153 154static const struct dummy_model model_emu10k1 = {155	.name = "emu10k1",156	.playback_constraints = emu10k1_playback_constraints,157	.buffer_bytes_max = 128 * 1024,158};159 160static const struct dummy_model model_rme9652 = {161	.name = "rme9652",162	.buffer_bytes_max = 26 * 64 * 1024,163	.formats = SNDRV_PCM_FMTBIT_S32_LE,164	.channels_min = 26,165	.channels_max = 26,166	.periods_min = 2,167	.periods_max = 2,168};169 170static const struct dummy_model model_ice1712 = {171	.name = "ice1712",172	.buffer_bytes_max = 256 * 1024,173	.formats = SNDRV_PCM_FMTBIT_S32_LE,174	.channels_min = 10,175	.channels_max = 10,176	.periods_min = 1,177	.periods_max = 1024,178};179 180static const struct dummy_model model_uda1341 = {181	.name = "uda1341",182	.buffer_bytes_max = 16380,183	.formats = SNDRV_PCM_FMTBIT_S16_LE,184	.channels_min = 2,185	.channels_max = 2,186	.periods_min = 2,187	.periods_max = 255,188};189 190static const struct dummy_model model_ac97 = {191	.name = "ac97",192	.formats = SNDRV_PCM_FMTBIT_S16_LE,193	.channels_min = 2,194	.channels_max = 2,195	.rates = SNDRV_PCM_RATE_48000,196	.rate_min = 48000,197	.rate_max = 48000,198};199 200static const struct dummy_model model_ca0106 = {201	.name = "ca0106",202	.formats = SNDRV_PCM_FMTBIT_S16_LE,203	.buffer_bytes_max = ((65536-64)*8),204	.period_bytes_max = (65536-64),205	.periods_min = 2,206	.periods_max = 8,207	.channels_min = 2,208	.channels_max = 2,209	.rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000,210	.rate_min = 48000,211	.rate_max = 192000,212};213 214static const struct dummy_model *dummy_models[] = {215	&model_emu10k1,216	&model_rme9652,217	&model_ice1712,218	&model_uda1341,219	&model_ac97,220	&model_ca0106,221	NULL222};223 224/*225 * system timer interface226 */227 228struct dummy_systimer_pcm {229	/* ops must be the first item */230	const struct dummy_timer_ops *timer_ops;231	spinlock_t lock;232	struct timer_list timer;233	unsigned long base_time;234	unsigned int frac_pos;	/* fractional sample position (based HZ) */235	unsigned int frac_period_rest;236	unsigned int frac_buffer_size;	/* buffer_size * HZ */237	unsigned int frac_period_size;	/* period_size * HZ */238	unsigned int rate;239	int elapsed;240	struct snd_pcm_substream *substream;241};242 243static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm)244{245	mod_timer(&dpcm->timer, jiffies +246		DIV_ROUND_UP(dpcm->frac_period_rest, dpcm->rate));247}248 249static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm)250{251	unsigned long delta;252 253	delta = jiffies - dpcm->base_time;254	if (!delta)255		return;256	dpcm->base_time += delta;257	delta *= dpcm->rate;258	dpcm->frac_pos += delta;259	while (dpcm->frac_pos >= dpcm->frac_buffer_size)260		dpcm->frac_pos -= dpcm->frac_buffer_size;261	while (dpcm->frac_period_rest <= delta) {262		dpcm->elapsed++;263		dpcm->frac_period_rest += dpcm->frac_period_size;264	}265	dpcm->frac_period_rest -= delta;266}267 268static int dummy_systimer_start(struct snd_pcm_substream *substream)269{270	struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;271	spin_lock(&dpcm->lock);272	dpcm->base_time = jiffies;273	dummy_systimer_rearm(dpcm);274	spin_unlock(&dpcm->lock);275	return 0;276}277 278static int dummy_systimer_stop(struct snd_pcm_substream *substream)279{280	struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;281	spin_lock(&dpcm->lock);282	del_timer(&dpcm->timer);283	spin_unlock(&dpcm->lock);284	return 0;285}286 287static int dummy_systimer_prepare(struct snd_pcm_substream *substream)288{289	struct snd_pcm_runtime *runtime = substream->runtime;290	struct dummy_systimer_pcm *dpcm = runtime->private_data;291 292	dpcm->frac_pos = 0;293	dpcm->rate = runtime->rate;294	dpcm->frac_buffer_size = runtime->buffer_size * HZ;295	dpcm->frac_period_size = runtime->period_size * HZ;296	dpcm->frac_period_rest = dpcm->frac_period_size;297	dpcm->elapsed = 0;298 299	return 0;300}301 302static void dummy_systimer_callback(struct timer_list *t)303{304	struct dummy_systimer_pcm *dpcm = from_timer(dpcm, t, timer);305	unsigned long flags;306	int elapsed = 0;307 308	spin_lock_irqsave(&dpcm->lock, flags);309	dummy_systimer_update(dpcm);310	dummy_systimer_rearm(dpcm);311	elapsed = dpcm->elapsed;312	dpcm->elapsed = 0;313	spin_unlock_irqrestore(&dpcm->lock, flags);314	if (elapsed)315		snd_pcm_period_elapsed(dpcm->substream);316}317 318static snd_pcm_uframes_t319dummy_systimer_pointer(struct snd_pcm_substream *substream)320{321	struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;322	snd_pcm_uframes_t pos;323 324	spin_lock(&dpcm->lock);325	dummy_systimer_update(dpcm);326	pos = dpcm->frac_pos / HZ;327	spin_unlock(&dpcm->lock);328	return pos;329}330 331static int dummy_systimer_create(struct snd_pcm_substream *substream)332{333	struct dummy_systimer_pcm *dpcm;334 335	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);336	if (!dpcm)337		return -ENOMEM;338	substream->runtime->private_data = dpcm;339	timer_setup(&dpcm->timer, dummy_systimer_callback, 0);340	spin_lock_init(&dpcm->lock);341	dpcm->substream = substream;342	return 0;343}344 345static void dummy_systimer_free(struct snd_pcm_substream *substream)346{347	kfree(substream->runtime->private_data);348}349 350static const struct dummy_timer_ops dummy_systimer_ops = {351	.create =	dummy_systimer_create,352	.free =		dummy_systimer_free,353	.prepare =	dummy_systimer_prepare,354	.start =	dummy_systimer_start,355	.stop =		dummy_systimer_stop,356	.pointer =	dummy_systimer_pointer,357};358 359#ifdef CONFIG_HIGH_RES_TIMERS360/*361 * hrtimer interface362 */363 364struct dummy_hrtimer_pcm {365	/* ops must be the first item */366	const struct dummy_timer_ops *timer_ops;367	ktime_t base_time;368	ktime_t period_time;369	atomic_t running;370	struct hrtimer timer;371	struct snd_pcm_substream *substream;372};373 374static enum hrtimer_restart dummy_hrtimer_callback(struct hrtimer *timer)375{376	struct dummy_hrtimer_pcm *dpcm;377 378	dpcm = container_of(timer, struct dummy_hrtimer_pcm, timer);379	if (!atomic_read(&dpcm->running))380		return HRTIMER_NORESTART;381	/*382	 * In cases of XRUN and draining, this calls .trigger to stop PCM383	 * substream.384	 */385	snd_pcm_period_elapsed(dpcm->substream);386	if (!atomic_read(&dpcm->running))387		return HRTIMER_NORESTART;388 389	hrtimer_forward_now(timer, dpcm->period_time);390	return HRTIMER_RESTART;391}392 393static int dummy_hrtimer_start(struct snd_pcm_substream *substream)394{395	struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;396 397	dpcm->base_time = hrtimer_cb_get_time(&dpcm->timer);398	hrtimer_start(&dpcm->timer, dpcm->period_time, HRTIMER_MODE_REL_SOFT);399	atomic_set(&dpcm->running, 1);400	return 0;401}402 403static int dummy_hrtimer_stop(struct snd_pcm_substream *substream)404{405	struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;406 407	atomic_set(&dpcm->running, 0);408	if (!hrtimer_callback_running(&dpcm->timer))409		hrtimer_cancel(&dpcm->timer);410	return 0;411}412 413static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm)414{415	hrtimer_cancel(&dpcm->timer);416}417 418static snd_pcm_uframes_t419dummy_hrtimer_pointer(struct snd_pcm_substream *substream)420{421	struct snd_pcm_runtime *runtime = substream->runtime;422	struct dummy_hrtimer_pcm *dpcm = runtime->private_data;423	u64 delta;424	u32 pos;425 426	delta = ktime_us_delta(hrtimer_cb_get_time(&dpcm->timer),427			       dpcm->base_time);428	delta = div_u64(delta * runtime->rate + 999999, 1000000);429	div_u64_rem(delta, runtime->buffer_size, &pos);430	return pos;431}432 433static int dummy_hrtimer_prepare(struct snd_pcm_substream *substream)434{435	struct snd_pcm_runtime *runtime = substream->runtime;436	struct dummy_hrtimer_pcm *dpcm = runtime->private_data;437	unsigned int period, rate;438	long sec;439	unsigned long nsecs;440 441	dummy_hrtimer_sync(dpcm);442	period = runtime->period_size;443	rate = runtime->rate;444	sec = period / rate;445	period %= rate;446	nsecs = div_u64((u64)period * 1000000000UL + rate - 1, rate);447	dpcm->period_time = ktime_set(sec, nsecs);448 449	return 0;450}451 452static int dummy_hrtimer_create(struct snd_pcm_substream *substream)453{454	struct dummy_hrtimer_pcm *dpcm;455 456	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);457	if (!dpcm)458		return -ENOMEM;459	substream->runtime->private_data = dpcm;460	hrtimer_init(&dpcm->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);461	dpcm->timer.function = dummy_hrtimer_callback;462	dpcm->substream = substream;463	atomic_set(&dpcm->running, 0);464	return 0;465}466 467static void dummy_hrtimer_free(struct snd_pcm_substream *substream)468{469	struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;470	dummy_hrtimer_sync(dpcm);471	kfree(dpcm);472}473 474static const struct dummy_timer_ops dummy_hrtimer_ops = {475	.create =	dummy_hrtimer_create,476	.free =		dummy_hrtimer_free,477	.prepare =	dummy_hrtimer_prepare,478	.start =	dummy_hrtimer_start,479	.stop =		dummy_hrtimer_stop,480	.pointer =	dummy_hrtimer_pointer,481};482 483#endif /* CONFIG_HIGH_RES_TIMERS */484 485/*486 * PCM interface487 */488 489static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)490{491	switch (cmd) {492	case SNDRV_PCM_TRIGGER_START:493	case SNDRV_PCM_TRIGGER_RESUME:494		return get_dummy_ops(substream)->start(substream);495	case SNDRV_PCM_TRIGGER_STOP:496	case SNDRV_PCM_TRIGGER_SUSPEND:497		return get_dummy_ops(substream)->stop(substream);498	}499	return -EINVAL;500}501 502static int dummy_pcm_prepare(struct snd_pcm_substream *substream)503{504	return get_dummy_ops(substream)->prepare(substream);505}506 507static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream)508{509	return get_dummy_ops(substream)->pointer(substream);510}511 512static const struct snd_pcm_hardware dummy_pcm_hardware = {513	.info =			(SNDRV_PCM_INFO_MMAP |514				 SNDRV_PCM_INFO_INTERLEAVED |515				 SNDRV_PCM_INFO_RESUME |516				 SNDRV_PCM_INFO_MMAP_VALID),517	.formats =		USE_FORMATS,518	.rates =		USE_RATE,519	.rate_min =		USE_RATE_MIN,520	.rate_max =		USE_RATE_MAX,521	.channels_min =		USE_CHANNELS_MIN,522	.channels_max =		USE_CHANNELS_MAX,523	.buffer_bytes_max =	MAX_BUFFER_SIZE,524	.period_bytes_min =	MIN_PERIOD_SIZE,525	.period_bytes_max =	MAX_PERIOD_SIZE,526	.periods_min =		USE_PERIODS_MIN,527	.periods_max =		USE_PERIODS_MAX,528	.fifo_size =		0,529};530 531static int dummy_pcm_hw_params(struct snd_pcm_substream *substream,532			       struct snd_pcm_hw_params *hw_params)533{534	if (fake_buffer) {535		/* runtime->dma_bytes has to be set manually to allow mmap */536		substream->runtime->dma_bytes = params_buffer_bytes(hw_params);537		return 0;538	}539	return 0;540}541 542static int dummy_pcm_open(struct snd_pcm_substream *substream)543{544	struct snd_dummy *dummy = snd_pcm_substream_chip(substream);545	const struct dummy_model *model = dummy->model;546	struct snd_pcm_runtime *runtime = substream->runtime;547	const struct dummy_timer_ops *ops;548	int err;549 550	ops = &dummy_systimer_ops;551#ifdef CONFIG_HIGH_RES_TIMERS552	if (hrtimer)553		ops = &dummy_hrtimer_ops;554#endif555 556	err = ops->create(substream);557	if (err < 0)558		return err;559	get_dummy_ops(substream) = ops;560 561	runtime->hw = dummy->pcm_hw;562	if (substream->pcm->device & 1) {563		runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;564		runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;565	}566	if (substream->pcm->device & 2)567		runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |568				      SNDRV_PCM_INFO_MMAP_VALID);569 570	if (model == NULL)571		return 0;572 573	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {574		if (model->playback_constraints)575			err = model->playback_constraints(substream->runtime);576	} else {577		if (model->capture_constraints)578			err = model->capture_constraints(substream->runtime);579	}580	if (err < 0) {581		get_dummy_ops(substream)->free(substream);582		return err;583	}584	return 0;585}586 587static int dummy_pcm_close(struct snd_pcm_substream *substream)588{589	get_dummy_ops(substream)->free(substream);590	return 0;591}592 593/*594 * dummy buffer handling595 */596 597static void *dummy_page[2];598 599static void free_fake_buffer(void)600{601	if (fake_buffer) {602		int i;603		for (i = 0; i < 2; i++)604			if (dummy_page[i]) {605				free_page((unsigned long)dummy_page[i]);606				dummy_page[i] = NULL;607			}608	}609}610 611static int alloc_fake_buffer(void)612{613	int i;614 615	if (!fake_buffer)616		return 0;617	for (i = 0; i < 2; i++) {618		dummy_page[i] = (void *)get_zeroed_page(GFP_KERNEL);619		if (!dummy_page[i]) {620			free_fake_buffer();621			return -ENOMEM;622		}623	}624	return 0;625}626 627static int dummy_pcm_copy(struct snd_pcm_substream *substream,628			  int channel, unsigned long pos,629			  struct iov_iter *iter, unsigned long bytes)630{631	return 0; /* do nothing */632}633 634static int dummy_pcm_silence(struct snd_pcm_substream *substream,635			     int channel, unsigned long pos,636			     unsigned long bytes)637{638	return 0; /* do nothing */639}640 641static struct page *dummy_pcm_page(struct snd_pcm_substream *substream,642				   unsigned long offset)643{644	return virt_to_page(dummy_page[substream->stream]); /* the same page */645}646 647static const struct snd_pcm_ops dummy_pcm_ops = {648	.open =		dummy_pcm_open,649	.close =	dummy_pcm_close,650	.hw_params =	dummy_pcm_hw_params,651	.prepare =	dummy_pcm_prepare,652	.trigger =	dummy_pcm_trigger,653	.pointer =	dummy_pcm_pointer,654};655 656static const struct snd_pcm_ops dummy_pcm_ops_no_buf = {657	.open =		dummy_pcm_open,658	.close =	dummy_pcm_close,659	.hw_params =	dummy_pcm_hw_params,660	.prepare =	dummy_pcm_prepare,661	.trigger =	dummy_pcm_trigger,662	.pointer =	dummy_pcm_pointer,663	.copy =		dummy_pcm_copy,664	.fill_silence =	dummy_pcm_silence,665	.page =		dummy_pcm_page,666};667 668static int snd_card_dummy_pcm(struct snd_dummy *dummy, int device,669			      int substreams)670{671	struct snd_pcm *pcm;672	const struct snd_pcm_ops *ops;673	int err;674 675	err = snd_pcm_new(dummy->card, "Dummy PCM", device,676			       substreams, substreams, &pcm);677	if (err < 0)678		return err;679	dummy->pcm = pcm;680	if (fake_buffer)681		ops = &dummy_pcm_ops_no_buf;682	else683		ops = &dummy_pcm_ops;684	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, ops);685	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, ops);686	pcm->private_data = dummy;687	pcm->info_flags = 0;688	strcpy(pcm->name, "Dummy PCM");689	if (!fake_buffer) {690		snd_pcm_set_managed_buffer_all(pcm,691			SNDRV_DMA_TYPE_CONTINUOUS,692			NULL,693			0, 64*1024);694	}695	return 0;696}697 698/*699 * mixer interface700 */701 702#define DUMMY_VOLUME(xname, xindex, addr) \703{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \704  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \705  .name = xname, .index = xindex, \706  .info = snd_dummy_volume_info, \707  .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \708  .private_value = addr, \709  .tlv = { .p = db_scale_dummy } }710 711static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol,712				 struct snd_ctl_elem_info *uinfo)713{714	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;715	uinfo->count = 2;716	uinfo->value.integer.min = mixer_volume_level_min;717	uinfo->value.integer.max = mixer_volume_level_max;718	return 0;719}720 721static int snd_dummy_volume_get(struct snd_kcontrol *kcontrol,722				struct snd_ctl_elem_value *ucontrol)723{724	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);725	int addr = kcontrol->private_value;726 727	spin_lock_irq(&dummy->mixer_lock);728	ucontrol->value.integer.value[0] = dummy->mixer_volume[addr][0];729	ucontrol->value.integer.value[1] = dummy->mixer_volume[addr][1];730	spin_unlock_irq(&dummy->mixer_lock);731	return 0;732}733 734static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,735				struct snd_ctl_elem_value *ucontrol)736{737	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);738	int change, addr = kcontrol->private_value;739	int left, right;740 741	left = ucontrol->value.integer.value[0];742	if (left < mixer_volume_level_min)743		left = mixer_volume_level_min;744	if (left > mixer_volume_level_max)745		left = mixer_volume_level_max;746	right = ucontrol->value.integer.value[1];747	if (right < mixer_volume_level_min)748		right = mixer_volume_level_min;749	if (right > mixer_volume_level_max)750		right = mixer_volume_level_max;751	spin_lock_irq(&dummy->mixer_lock);752	change = dummy->mixer_volume[addr][0] != left ||753	         dummy->mixer_volume[addr][1] != right;754	dummy->mixer_volume[addr][0] = left;755	dummy->mixer_volume[addr][1] = right;756	spin_unlock_irq(&dummy->mixer_lock);757	return change;758}759 760static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);761 762#define DUMMY_CAPSRC(xname, xindex, addr) \763{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \764  .info = snd_dummy_capsrc_info, \765  .get = snd_dummy_capsrc_get, .put = snd_dummy_capsrc_put, \766  .private_value = addr }767 768#define snd_dummy_capsrc_info	snd_ctl_boolean_stereo_info769 770static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol,771				struct snd_ctl_elem_value *ucontrol)772{773	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);774	int addr = kcontrol->private_value;775 776	spin_lock_irq(&dummy->mixer_lock);777	ucontrol->value.integer.value[0] = dummy->capture_source[addr][0];778	ucontrol->value.integer.value[1] = dummy->capture_source[addr][1];779	spin_unlock_irq(&dummy->mixer_lock);780	return 0;781}782 783static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)784{785	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);786	int change, addr = kcontrol->private_value;787	int left, right;788 789	left = ucontrol->value.integer.value[0] & 1;790	right = ucontrol->value.integer.value[1] & 1;791	spin_lock_irq(&dummy->mixer_lock);792	change = dummy->capture_source[addr][0] != left &&793	         dummy->capture_source[addr][1] != right;794	dummy->capture_source[addr][0] = left;795	dummy->capture_source[addr][1] = right;796	spin_unlock_irq(&dummy->mixer_lock);797	return change;798}799 800static int snd_dummy_iobox_info(struct snd_kcontrol *kcontrol,801				struct snd_ctl_elem_info *info)802{803	static const char *const names[] = { "None", "CD Player" };804 805	return snd_ctl_enum_info(info, 1, 2, names);806}807 808static int snd_dummy_iobox_get(struct snd_kcontrol *kcontrol,809			       struct snd_ctl_elem_value *value)810{811	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);812 813	value->value.enumerated.item[0] = dummy->iobox;814	return 0;815}816 817static int snd_dummy_iobox_put(struct snd_kcontrol *kcontrol,818			       struct snd_ctl_elem_value *value)819{820	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);821	int changed;822 823	if (value->value.enumerated.item[0] > 1)824		return -EINVAL;825 826	changed = value->value.enumerated.item[0] != dummy->iobox;827	if (changed) {828		dummy->iobox = value->value.enumerated.item[0];829 830		if (dummy->iobox) {831			dummy->cd_volume_ctl->vd[0].access &=832				~SNDRV_CTL_ELEM_ACCESS_INACTIVE;833			dummy->cd_switch_ctl->vd[0].access &=834				~SNDRV_CTL_ELEM_ACCESS_INACTIVE;835		} else {836			dummy->cd_volume_ctl->vd[0].access |=837				SNDRV_CTL_ELEM_ACCESS_INACTIVE;838			dummy->cd_switch_ctl->vd[0].access |=839				SNDRV_CTL_ELEM_ACCESS_INACTIVE;840		}841 842		snd_ctl_notify(dummy->card, SNDRV_CTL_EVENT_MASK_INFO,843			       &dummy->cd_volume_ctl->id);844		snd_ctl_notify(dummy->card, SNDRV_CTL_EVENT_MASK_INFO,845			       &dummy->cd_switch_ctl->id);846	}847 848	return changed;849}850 851static const struct snd_kcontrol_new snd_dummy_controls[] = {852DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),853DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),854DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),855DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH),856DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),857DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE),858DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),859DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC),860DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),861DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD),862{863	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,864	.name  = "External I/O Box",865	.info  = snd_dummy_iobox_info,866	.get   = snd_dummy_iobox_get,867	.put   = snd_dummy_iobox_put,868},869};870 871static int snd_card_dummy_new_mixer(struct snd_dummy *dummy)872{873	struct snd_card *card = dummy->card;874	struct snd_kcontrol *kcontrol;875	unsigned int idx;876	int err;877 878	spin_lock_init(&dummy->mixer_lock);879	strcpy(card->mixername, "Dummy Mixer");880	dummy->iobox = 1;881 882	for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) {883		kcontrol = snd_ctl_new1(&snd_dummy_controls[idx], dummy);884		err = snd_ctl_add(card, kcontrol);885		if (err < 0)886			return err;887		if (!strcmp(kcontrol->id.name, "CD Volume"))888			dummy->cd_volume_ctl = kcontrol;889		else if (!strcmp(kcontrol->id.name, "CD Capture Switch"))890			dummy->cd_switch_ctl = kcontrol;891 892	}893	return 0;894}895 896#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_PROC_FS)897/*898 * proc interface899 */900static void print_formats(struct snd_dummy *dummy,901			  struct snd_info_buffer *buffer)902{903	snd_pcm_format_t i;904 905	pcm_for_each_format(i) {906		if (dummy->pcm_hw.formats & pcm_format_to_bits(i))907			snd_iprintf(buffer, " %s", snd_pcm_format_name(i));908	}909}910 911static void print_rates(struct snd_dummy *dummy,912			struct snd_info_buffer *buffer)913{914	static const int rates[] = {915		5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,916		64000, 88200, 96000, 176400, 192000,917	};918	int i;919 920	if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS)921		snd_iprintf(buffer, " continuous");922	if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT)923		snd_iprintf(buffer, " knot");924	for (i = 0; i < ARRAY_SIZE(rates); i++)925		if (dummy->pcm_hw.rates & (1 << i))926			snd_iprintf(buffer, " %d", rates[i]);927}928 929#define get_dummy_int_ptr(dummy, ofs) \930	(unsigned int *)((char *)&((dummy)->pcm_hw) + (ofs))931#define get_dummy_ll_ptr(dummy, ofs) \932	(unsigned long long *)((char *)&((dummy)->pcm_hw) + (ofs))933 934struct dummy_hw_field {935	const char *name;936	const char *format;937	unsigned int offset;938	unsigned int size;939};940#define FIELD_ENTRY(item, fmt) {		   \941	.name = #item,				   \942	.format = fmt,				   \943	.offset = offsetof(struct snd_pcm_hardware, item), \944	.size = sizeof(dummy_pcm_hardware.item) }945 946static const struct dummy_hw_field fields[] = {947	FIELD_ENTRY(formats, "%#llx"),948	FIELD_ENTRY(rates, "%#x"),949	FIELD_ENTRY(rate_min, "%d"),950	FIELD_ENTRY(rate_max, "%d"),951	FIELD_ENTRY(channels_min, "%d"),952	FIELD_ENTRY(channels_max, "%d"),953	FIELD_ENTRY(buffer_bytes_max, "%ld"),954	FIELD_ENTRY(period_bytes_min, "%ld"),955	FIELD_ENTRY(period_bytes_max, "%ld"),956	FIELD_ENTRY(periods_min, "%d"),957	FIELD_ENTRY(periods_max, "%d"),958};959 960static void dummy_proc_read(struct snd_info_entry *entry,961			    struct snd_info_buffer *buffer)962{963	struct snd_dummy *dummy = entry->private_data;964	int i;965 966	for (i = 0; i < ARRAY_SIZE(fields); i++) {967		snd_iprintf(buffer, "%s ", fields[i].name);968		if (fields[i].size == sizeof(int))969			snd_iprintf(buffer, fields[i].format,970				*get_dummy_int_ptr(dummy, fields[i].offset));971		else972			snd_iprintf(buffer, fields[i].format,973				*get_dummy_ll_ptr(dummy, fields[i].offset));974		if (!strcmp(fields[i].name, "formats"))975			print_formats(dummy, buffer);976		else if (!strcmp(fields[i].name, "rates"))977			print_rates(dummy, buffer);978		snd_iprintf(buffer, "\n");979	}980}981 982static void dummy_proc_write(struct snd_info_entry *entry,983			     struct snd_info_buffer *buffer)984{985	struct snd_dummy *dummy = entry->private_data;986	char line[64];987 988	while (!snd_info_get_line(buffer, line, sizeof(line))) {989		char item[20];990		const char *ptr;991		unsigned long long val;992		int i;993 994		ptr = snd_info_get_str(item, line, sizeof(item));995		for (i = 0; i < ARRAY_SIZE(fields); i++) {996			if (!strcmp(item, fields[i].name))997				break;998		}999		if (i >= ARRAY_SIZE(fields))1000			continue;1001		snd_info_get_str(item, ptr, sizeof(item));1002		if (kstrtoull(item, 0, &val))1003			continue;1004		if (fields[i].size == sizeof(int))1005			*get_dummy_int_ptr(dummy, fields[i].offset) = val;1006		else1007			*get_dummy_ll_ptr(dummy, fields[i].offset) = val;1008	}1009}1010 1011static void dummy_proc_init(struct snd_dummy *chip)1012{1013	snd_card_rw_proc_new(chip->card, "dummy_pcm", chip,1014			     dummy_proc_read, dummy_proc_write);1015}1016#else1017#define dummy_proc_init(x)1018#endif /* CONFIG_SND_DEBUG && CONFIG_SND_PROC_FS */1019 1020static int snd_dummy_probe(struct platform_device *devptr)1021{1022	struct snd_card *card;1023	struct snd_dummy *dummy;1024	const struct dummy_model *m = NULL, **mdl;1025	int idx, err;1026	int dev = devptr->id;1027 1028	err = snd_devm_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,1029				sizeof(struct snd_dummy), &card);1030	if (err < 0)1031		return err;1032	dummy = card->private_data;1033	dummy->card = card;1034	for (mdl = dummy_models; *mdl && model[dev]; mdl++) {1035		if (strcmp(model[dev], (*mdl)->name) == 0) {1036			pr_info("snd-dummy: Using model '%s' for card %i\n",1037				(*mdl)->name, card->number);1038			m = dummy->model = *mdl;1039			break;1040		}1041	}1042	for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {1043		if (pcm_substreams[dev] < 1)1044			pcm_substreams[dev] = 1;1045		if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)1046			pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;1047		err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev]);1048		if (err < 0)1049			return err;1050	}1051 1052	dummy->pcm_hw = dummy_pcm_hardware;1053	if (m) {1054		if (m->formats)1055			dummy->pcm_hw.formats = m->formats;1056		if (m->buffer_bytes_max)1057			dummy->pcm_hw.buffer_bytes_max = m->buffer_bytes_max;1058		if (m->period_bytes_min)1059			dummy->pcm_hw.period_bytes_min = m->period_bytes_min;1060		if (m->period_bytes_max)1061			dummy->pcm_hw.period_bytes_max = m->period_bytes_max;1062		if (m->periods_min)1063			dummy->pcm_hw.periods_min = m->periods_min;1064		if (m->periods_max)1065			dummy->pcm_hw.periods_max = m->periods_max;1066		if (m->rates)1067			dummy->pcm_hw.rates = m->rates;1068		if (m->rate_min)1069			dummy->pcm_hw.rate_min = m->rate_min;1070		if (m->rate_max)1071			dummy->pcm_hw.rate_max = m->rate_max;1072		if (m->channels_min)1073			dummy->pcm_hw.channels_min = m->channels_min;1074		if (m->channels_max)1075			dummy->pcm_hw.channels_max = m->channels_max;1076	}1077 1078	if (mixer_volume_level_min > mixer_volume_level_max) {1079		pr_warn("snd-dummy: Invalid mixer volume level: min=%d, max=%d. Fall back to default value.\n",1080		mixer_volume_level_min, mixer_volume_level_max);1081		mixer_volume_level_min = USE_MIXER_VOLUME_LEVEL_MIN;1082		mixer_volume_level_max = USE_MIXER_VOLUME_LEVEL_MAX;1083	}1084	err = snd_card_dummy_new_mixer(dummy);1085	if (err < 0)1086		return err;1087	strcpy(card->driver, "Dummy");1088	strcpy(card->shortname, "Dummy");1089	sprintf(card->longname, "Dummy %i", dev + 1);1090 1091	dummy_proc_init(dummy);1092 1093	err = snd_card_register(card);1094	if (err < 0)1095		return err;1096	platform_set_drvdata(devptr, card);1097	return 0;1098}1099 1100static int snd_dummy_suspend(struct device *pdev)1101{1102	struct snd_card *card = dev_get_drvdata(pdev);1103 1104	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);1105	return 0;1106}1107 1108static int snd_dummy_resume(struct device *pdev)1109{1110	struct snd_card *card = dev_get_drvdata(pdev);1111 1112	snd_power_change_state(card, SNDRV_CTL_POWER_D0);1113	return 0;1114}1115 1116static DEFINE_SIMPLE_DEV_PM_OPS(snd_dummy_pm, snd_dummy_suspend, snd_dummy_resume);1117 1118#define SND_DUMMY_DRIVER	"snd_dummy"1119 1120static struct platform_driver snd_dummy_driver = {1121	.probe		= snd_dummy_probe,1122	.driver		= {1123		.name	= SND_DUMMY_DRIVER,1124		.pm	= &snd_dummy_pm,1125	},1126};1127 1128static void snd_dummy_unregister_all(void)1129{1130	int i;1131 1132	for (i = 0; i < ARRAY_SIZE(devices); ++i)1133		platform_device_unregister(devices[i]);1134	platform_driver_unregister(&snd_dummy_driver);1135	free_fake_buffer();1136}1137 1138static int __init alsa_card_dummy_init(void)1139{1140	int i, cards, err;1141 1142	err = platform_driver_register(&snd_dummy_driver);1143	if (err < 0)1144		return err;1145 1146	err = alloc_fake_buffer();1147	if (err < 0) {1148		platform_driver_unregister(&snd_dummy_driver);1149		return err;1150	}1151 1152	cards = 0;1153	for (i = 0; i < SNDRV_CARDS; i++) {1154		struct platform_device *device;1155		if (! enable[i])1156			continue;1157		device = platform_device_register_simple(SND_DUMMY_DRIVER,1158							 i, NULL, 0);1159		if (IS_ERR(device))1160			continue;1161		if (!platform_get_drvdata(device)) {1162			platform_device_unregister(device);1163			continue;1164		}1165		devices[i] = device;1166		cards++;1167	}1168	if (!cards) {1169#ifdef MODULE1170		pr_err("Dummy soundcard not found or device busy\n");1171#endif1172		snd_dummy_unregister_all();1173		return -ENODEV;1174	}1175	return 0;1176}1177 1178static void __exit alsa_card_dummy_exit(void)1179{1180	snd_dummy_unregister_all();1181}1182 1183module_init(alsa_card_dummy_init)1184module_exit(alsa_card_dummy_exit)1185