xref: /openbmc/linux/sound/pci/echoaudio/echoaudio.c (revision dd7b254d8dd3a9528f423ac3bf875e6f0c8da561)
1*dd7b254dSGiuliano Pochini /*
2*dd7b254dSGiuliano Pochini  *  ALSA driver for Echoaudio soundcards.
3*dd7b254dSGiuliano Pochini  *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it>
4*dd7b254dSGiuliano Pochini  *
5*dd7b254dSGiuliano Pochini  *  This program is free software; you can redistribute it and/or modify
6*dd7b254dSGiuliano Pochini  *  it under the terms of the GNU General Public License as published by
7*dd7b254dSGiuliano Pochini  *  the Free Software Foundation; version 2 of the License.
8*dd7b254dSGiuliano Pochini  *
9*dd7b254dSGiuliano Pochini  *  This program is distributed in the hope that it will be useful,
10*dd7b254dSGiuliano Pochini  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11*dd7b254dSGiuliano Pochini  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*dd7b254dSGiuliano Pochini  *  GNU General Public License for more details.
13*dd7b254dSGiuliano Pochini  *
14*dd7b254dSGiuliano Pochini  *  You should have received a copy of the GNU General Public License
15*dd7b254dSGiuliano Pochini  *  along with this program; if not, write to the Free Software
16*dd7b254dSGiuliano Pochini  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17*dd7b254dSGiuliano Pochini  */
18*dd7b254dSGiuliano Pochini 
19*dd7b254dSGiuliano Pochini MODULE_AUTHOR("Giuliano Pochini <pochini@shiny.it>");
20*dd7b254dSGiuliano Pochini MODULE_LICENSE("GPL v2");
21*dd7b254dSGiuliano Pochini MODULE_DESCRIPTION("Echoaudio " ECHOCARD_NAME " soundcards driver");
22*dd7b254dSGiuliano Pochini MODULE_SUPPORTED_DEVICE("{{Echoaudio," ECHOCARD_NAME "}}");
23*dd7b254dSGiuliano Pochini MODULE_DEVICE_TABLE(pci, snd_echo_ids);
24*dd7b254dSGiuliano Pochini 
25*dd7b254dSGiuliano Pochini static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
26*dd7b254dSGiuliano Pochini static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
27*dd7b254dSGiuliano Pochini static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
28*dd7b254dSGiuliano Pochini 
29*dd7b254dSGiuliano Pochini module_param_array(index, int, NULL, 0444);
30*dd7b254dSGiuliano Pochini MODULE_PARM_DESC(index, "Index value for " ECHOCARD_NAME " soundcard.");
31*dd7b254dSGiuliano Pochini module_param_array(id, charp, NULL, 0444);
32*dd7b254dSGiuliano Pochini MODULE_PARM_DESC(id, "ID string for " ECHOCARD_NAME " soundcard.");
33*dd7b254dSGiuliano Pochini module_param_array(enable, bool, NULL, 0444);
34*dd7b254dSGiuliano Pochini MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard.");
35*dd7b254dSGiuliano Pochini 
36*dd7b254dSGiuliano Pochini static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999};
37*dd7b254dSGiuliano Pochini 
38*dd7b254dSGiuliano Pochini static int get_firmware(const struct firmware **fw_entry,
39*dd7b254dSGiuliano Pochini 			const struct firmware *frm, struct echoaudio *chip)
40*dd7b254dSGiuliano Pochini {
41*dd7b254dSGiuliano Pochini 	int err;
42*dd7b254dSGiuliano Pochini 	char name[30];
43*dd7b254dSGiuliano Pochini 	DE_ACT(("firmware requested: %s\n", frm->data));
44*dd7b254dSGiuliano Pochini 	snprintf(name, sizeof(name), "ea/%s", frm->data);
45*dd7b254dSGiuliano Pochini 	if ((err = request_firmware(fw_entry, name, pci_device(chip))) < 0)
46*dd7b254dSGiuliano Pochini 		snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
47*dd7b254dSGiuliano Pochini 	return err;
48*dd7b254dSGiuliano Pochini }
49*dd7b254dSGiuliano Pochini 
50*dd7b254dSGiuliano Pochini static void free_firmware(const struct firmware *fw_entry)
51*dd7b254dSGiuliano Pochini {
52*dd7b254dSGiuliano Pochini 	release_firmware(fw_entry);
53*dd7b254dSGiuliano Pochini 	DE_ACT(("firmware released\n"));
54*dd7b254dSGiuliano Pochini }
55*dd7b254dSGiuliano Pochini 
56*dd7b254dSGiuliano Pochini 
57*dd7b254dSGiuliano Pochini 
58*dd7b254dSGiuliano Pochini /******************************************************************************
59*dd7b254dSGiuliano Pochini 	PCM interface
60*dd7b254dSGiuliano Pochini ******************************************************************************/
61*dd7b254dSGiuliano Pochini 
62*dd7b254dSGiuliano Pochini static void audiopipe_free(struct snd_pcm_runtime *runtime)
63*dd7b254dSGiuliano Pochini {
64*dd7b254dSGiuliano Pochini 	struct audiopipe *pipe = runtime->private_data;
65*dd7b254dSGiuliano Pochini 
66*dd7b254dSGiuliano Pochini 	if (pipe->sgpage.area)
67*dd7b254dSGiuliano Pochini 		snd_dma_free_pages(&pipe->sgpage);
68*dd7b254dSGiuliano Pochini 	kfree(pipe);
69*dd7b254dSGiuliano Pochini }
70*dd7b254dSGiuliano Pochini 
71*dd7b254dSGiuliano Pochini 
72*dd7b254dSGiuliano Pochini 
73*dd7b254dSGiuliano Pochini static int hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params,
74*dd7b254dSGiuliano Pochini 					      struct snd_pcm_hw_rule *rule)
75*dd7b254dSGiuliano Pochini {
76*dd7b254dSGiuliano Pochini 	struct snd_interval *c = hw_param_interval(params,
77*dd7b254dSGiuliano Pochini 						   SNDRV_PCM_HW_PARAM_CHANNELS);
78*dd7b254dSGiuliano Pochini 	struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
79*dd7b254dSGiuliano Pochini 	struct snd_mask fmt;
80*dd7b254dSGiuliano Pochini 
81*dd7b254dSGiuliano Pochini 	snd_mask_any(&fmt);
82*dd7b254dSGiuliano Pochini 
83*dd7b254dSGiuliano Pochini #ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
84*dd7b254dSGiuliano Pochini 	/* >=2 channels cannot be S32_BE */
85*dd7b254dSGiuliano Pochini 	if (c->min == 2) {
86*dd7b254dSGiuliano Pochini 		fmt.bits[0] &= ~SNDRV_PCM_FMTBIT_S32_BE;
87*dd7b254dSGiuliano Pochini 		return snd_mask_refine(f, &fmt);
88*dd7b254dSGiuliano Pochini 	}
89*dd7b254dSGiuliano Pochini #endif
90*dd7b254dSGiuliano Pochini 	/* > 2 channels cannot be U8 and S32_BE */
91*dd7b254dSGiuliano Pochini 	if (c->min > 2) {
92*dd7b254dSGiuliano Pochini 		fmt.bits[0] &= ~(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_BE);
93*dd7b254dSGiuliano Pochini 		return snd_mask_refine(f, &fmt);
94*dd7b254dSGiuliano Pochini 	}
95*dd7b254dSGiuliano Pochini 	/* Mono is ok with any format */
96*dd7b254dSGiuliano Pochini 	return 0;
97*dd7b254dSGiuliano Pochini }
98*dd7b254dSGiuliano Pochini 
99*dd7b254dSGiuliano Pochini 
100*dd7b254dSGiuliano Pochini 
101*dd7b254dSGiuliano Pochini static int hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params,
102*dd7b254dSGiuliano Pochini 					      struct snd_pcm_hw_rule *rule)
103*dd7b254dSGiuliano Pochini {
104*dd7b254dSGiuliano Pochini 	struct snd_interval *c = hw_param_interval(params,
105*dd7b254dSGiuliano Pochini 						   SNDRV_PCM_HW_PARAM_CHANNELS);
106*dd7b254dSGiuliano Pochini 	struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
107*dd7b254dSGiuliano Pochini 	struct snd_interval ch;
108*dd7b254dSGiuliano Pochini 
109*dd7b254dSGiuliano Pochini 	snd_interval_any(&ch);
110*dd7b254dSGiuliano Pochini 
111*dd7b254dSGiuliano Pochini 	/* S32_BE is mono (and stereo) only */
112*dd7b254dSGiuliano Pochini 	if (f->bits[0] == SNDRV_PCM_FMTBIT_S32_BE) {
113*dd7b254dSGiuliano Pochini 		ch.min = 1;
114*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
115*dd7b254dSGiuliano Pochini 		ch.max = 2;
116*dd7b254dSGiuliano Pochini #else
117*dd7b254dSGiuliano Pochini 		ch.max = 1;
118*dd7b254dSGiuliano Pochini #endif
119*dd7b254dSGiuliano Pochini 		ch.integer = 1;
120*dd7b254dSGiuliano Pochini 		return snd_interval_refine(c, &ch);
121*dd7b254dSGiuliano Pochini 	}
122*dd7b254dSGiuliano Pochini 	/* U8 can be only mono or stereo */
123*dd7b254dSGiuliano Pochini 	if (f->bits[0] == SNDRV_PCM_FMTBIT_U8) {
124*dd7b254dSGiuliano Pochini 		ch.min = 1;
125*dd7b254dSGiuliano Pochini 		ch.max = 2;
126*dd7b254dSGiuliano Pochini 		ch.integer = 1;
127*dd7b254dSGiuliano Pochini 		return snd_interval_refine(c, &ch);
128*dd7b254dSGiuliano Pochini 	}
129*dd7b254dSGiuliano Pochini 	/* S16_LE, S24_3LE and S32_LE support any number of channels. */
130*dd7b254dSGiuliano Pochini 	return 0;
131*dd7b254dSGiuliano Pochini }
132*dd7b254dSGiuliano Pochini 
133*dd7b254dSGiuliano Pochini 
134*dd7b254dSGiuliano Pochini 
135*dd7b254dSGiuliano Pochini static int hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params,
136*dd7b254dSGiuliano Pochini 					       struct snd_pcm_hw_rule *rule)
137*dd7b254dSGiuliano Pochini {
138*dd7b254dSGiuliano Pochini 	struct snd_interval *c = hw_param_interval(params,
139*dd7b254dSGiuliano Pochini 						   SNDRV_PCM_HW_PARAM_CHANNELS);
140*dd7b254dSGiuliano Pochini 	struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
141*dd7b254dSGiuliano Pochini 	struct snd_mask fmt;
142*dd7b254dSGiuliano Pochini 	u64 fmask;
143*dd7b254dSGiuliano Pochini 	snd_mask_any(&fmt);
144*dd7b254dSGiuliano Pochini 
145*dd7b254dSGiuliano Pochini 	fmask = fmt.bits[0] + ((u64)fmt.bits[1] << 32);
146*dd7b254dSGiuliano Pochini 
147*dd7b254dSGiuliano Pochini 	/* >2 channels must be S16_LE, S24_3LE or S32_LE */
148*dd7b254dSGiuliano Pochini 	if (c->min > 2) {
149*dd7b254dSGiuliano Pochini 		fmask &= SNDRV_PCM_FMTBIT_S16_LE |
150*dd7b254dSGiuliano Pochini 			 SNDRV_PCM_FMTBIT_S24_3LE |
151*dd7b254dSGiuliano Pochini 			 SNDRV_PCM_FMTBIT_S32_LE;
152*dd7b254dSGiuliano Pochini 	/* 1 channel must be S32_BE or S32_LE */
153*dd7b254dSGiuliano Pochini 	} else if (c->max == 1)
154*dd7b254dSGiuliano Pochini 		fmask &= SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE;
155*dd7b254dSGiuliano Pochini #ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
156*dd7b254dSGiuliano Pochini 	/* 2 channels cannot be S32_BE */
157*dd7b254dSGiuliano Pochini 	else if (c->min == 2 && c->max == 2)
158*dd7b254dSGiuliano Pochini 		fmask &= ~SNDRV_PCM_FMTBIT_S32_BE;
159*dd7b254dSGiuliano Pochini #endif
160*dd7b254dSGiuliano Pochini 	else
161*dd7b254dSGiuliano Pochini 		return 0;
162*dd7b254dSGiuliano Pochini 
163*dd7b254dSGiuliano Pochini 	fmt.bits[0] &= (u32)fmask;
164*dd7b254dSGiuliano Pochini 	fmt.bits[1] &= (u32)(fmask >> 32);
165*dd7b254dSGiuliano Pochini 	return snd_mask_refine(f, &fmt);
166*dd7b254dSGiuliano Pochini }
167*dd7b254dSGiuliano Pochini 
168*dd7b254dSGiuliano Pochini 
169*dd7b254dSGiuliano Pochini 
170*dd7b254dSGiuliano Pochini static int hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,
171*dd7b254dSGiuliano Pochini 					       struct snd_pcm_hw_rule *rule)
172*dd7b254dSGiuliano Pochini {
173*dd7b254dSGiuliano Pochini 	struct snd_interval *c = hw_param_interval(params,
174*dd7b254dSGiuliano Pochini 						   SNDRV_PCM_HW_PARAM_CHANNELS);
175*dd7b254dSGiuliano Pochini 	struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
176*dd7b254dSGiuliano Pochini 	struct snd_interval ch;
177*dd7b254dSGiuliano Pochini 	u64 fmask;
178*dd7b254dSGiuliano Pochini 
179*dd7b254dSGiuliano Pochini 	snd_interval_any(&ch);
180*dd7b254dSGiuliano Pochini 	ch.integer = 1;
181*dd7b254dSGiuliano Pochini 	fmask = f->bits[0] + ((u64)f->bits[1] << 32);
182*dd7b254dSGiuliano Pochini 
183*dd7b254dSGiuliano Pochini 	/* S32_BE is mono (and stereo) only */
184*dd7b254dSGiuliano Pochini 	if (fmask == SNDRV_PCM_FMTBIT_S32_BE) {
185*dd7b254dSGiuliano Pochini 		ch.min = 1;
186*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32
187*dd7b254dSGiuliano Pochini 		ch.max = 2;
188*dd7b254dSGiuliano Pochini #else
189*dd7b254dSGiuliano Pochini 		ch.max = 1;
190*dd7b254dSGiuliano Pochini #endif
191*dd7b254dSGiuliano Pochini 	/* U8 is stereo only */
192*dd7b254dSGiuliano Pochini 	} else if (fmask == SNDRV_PCM_FMTBIT_U8)
193*dd7b254dSGiuliano Pochini 		ch.min = ch.max = 2;
194*dd7b254dSGiuliano Pochini 	/* S16_LE and S24_3LE must be at least stereo */
195*dd7b254dSGiuliano Pochini 	else if (!(fmask & ~(SNDRV_PCM_FMTBIT_S16_LE |
196*dd7b254dSGiuliano Pochini 			       SNDRV_PCM_FMTBIT_S24_3LE)))
197*dd7b254dSGiuliano Pochini 		ch.min = 2;
198*dd7b254dSGiuliano Pochini 	else
199*dd7b254dSGiuliano Pochini 		return 0;
200*dd7b254dSGiuliano Pochini 
201*dd7b254dSGiuliano Pochini 	return snd_interval_refine(c, &ch);
202*dd7b254dSGiuliano Pochini }
203*dd7b254dSGiuliano Pochini 
204*dd7b254dSGiuliano Pochini 
205*dd7b254dSGiuliano Pochini 
206*dd7b254dSGiuliano Pochini /* Since the sample rate is a global setting, do allow the user to change the
207*dd7b254dSGiuliano Pochini sample rate only if there is only one pcm device open. */
208*dd7b254dSGiuliano Pochini static int hw_rule_sample_rate(struct snd_pcm_hw_params *params,
209*dd7b254dSGiuliano Pochini 			       struct snd_pcm_hw_rule *rule)
210*dd7b254dSGiuliano Pochini {
211*dd7b254dSGiuliano Pochini 	struct snd_interval *rate = hw_param_interval(params,
212*dd7b254dSGiuliano Pochini 						      SNDRV_PCM_HW_PARAM_RATE);
213*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = rule->private;
214*dd7b254dSGiuliano Pochini 	struct snd_interval fixed;
215*dd7b254dSGiuliano Pochini 
216*dd7b254dSGiuliano Pochini 	if (!chip->can_set_rate) {
217*dd7b254dSGiuliano Pochini 		snd_interval_any(&fixed);
218*dd7b254dSGiuliano Pochini 		fixed.min = fixed.max = chip->sample_rate;
219*dd7b254dSGiuliano Pochini 		return snd_interval_refine(rate, &fixed);
220*dd7b254dSGiuliano Pochini 	}
221*dd7b254dSGiuliano Pochini 	return 0;
222*dd7b254dSGiuliano Pochini }
223*dd7b254dSGiuliano Pochini 
224*dd7b254dSGiuliano Pochini 
225*dd7b254dSGiuliano Pochini static int pcm_open(struct snd_pcm_substream *substream,
226*dd7b254dSGiuliano Pochini 		    signed char max_channels)
227*dd7b254dSGiuliano Pochini {
228*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
229*dd7b254dSGiuliano Pochini 	struct snd_pcm_runtime *runtime;
230*dd7b254dSGiuliano Pochini 	struct audiopipe *pipe;
231*dd7b254dSGiuliano Pochini 	int err, i;
232*dd7b254dSGiuliano Pochini 
233*dd7b254dSGiuliano Pochini 	if (max_channels <= 0)
234*dd7b254dSGiuliano Pochini 		return -EAGAIN;
235*dd7b254dSGiuliano Pochini 
236*dd7b254dSGiuliano Pochini 	chip = snd_pcm_substream_chip(substream);
237*dd7b254dSGiuliano Pochini 	runtime = substream->runtime;
238*dd7b254dSGiuliano Pochini 
239*dd7b254dSGiuliano Pochini 	if (!(pipe = kmalloc(sizeof(struct audiopipe), GFP_KERNEL)))
240*dd7b254dSGiuliano Pochini 		return -ENOMEM;
241*dd7b254dSGiuliano Pochini 	memset(pipe, 0, sizeof(struct audiopipe));
242*dd7b254dSGiuliano Pochini 	pipe->index = -1;		/* Not configured yet */
243*dd7b254dSGiuliano Pochini 
244*dd7b254dSGiuliano Pochini 	/* Set up hw capabilities and contraints */
245*dd7b254dSGiuliano Pochini 	memcpy(&pipe->hw, &pcm_hardware_skel, sizeof(struct snd_pcm_hardware));
246*dd7b254dSGiuliano Pochini 	DE_HWP(("max_channels=%d\n", max_channels));
247*dd7b254dSGiuliano Pochini 	pipe->constr.list = channels_list;
248*dd7b254dSGiuliano Pochini 	pipe->constr.mask = 0;
249*dd7b254dSGiuliano Pochini 	for (i = 0; channels_list[i] <= max_channels; i++);
250*dd7b254dSGiuliano Pochini 	pipe->constr.count = i;
251*dd7b254dSGiuliano Pochini 	if (pipe->hw.channels_max > max_channels)
252*dd7b254dSGiuliano Pochini 		pipe->hw.channels_max = max_channels;
253*dd7b254dSGiuliano Pochini 	if (chip->digital_mode == DIGITAL_MODE_ADAT) {
254*dd7b254dSGiuliano Pochini 		pipe->hw.rate_max = 48000;
255*dd7b254dSGiuliano Pochini 		pipe->hw.rates &= SNDRV_PCM_RATE_8000_48000;
256*dd7b254dSGiuliano Pochini 	}
257*dd7b254dSGiuliano Pochini 
258*dd7b254dSGiuliano Pochini 	runtime->hw = pipe->hw;
259*dd7b254dSGiuliano Pochini 	runtime->private_data = pipe;
260*dd7b254dSGiuliano Pochini 	runtime->private_free = audiopipe_free;
261*dd7b254dSGiuliano Pochini 	snd_pcm_set_sync(substream);
262*dd7b254dSGiuliano Pochini 
263*dd7b254dSGiuliano Pochini 	/* Only mono and any even number of channels are allowed */
264*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_constraint_list(runtime, 0,
265*dd7b254dSGiuliano Pochini 					      SNDRV_PCM_HW_PARAM_CHANNELS,
266*dd7b254dSGiuliano Pochini 					      &pipe->constr)) < 0)
267*dd7b254dSGiuliano Pochini 		return err;
268*dd7b254dSGiuliano Pochini 
269*dd7b254dSGiuliano Pochini 	/* All periods should have the same size */
270*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_constraint_integer(runtime,
271*dd7b254dSGiuliano Pochini 						 SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
272*dd7b254dSGiuliano Pochini 		return err;
273*dd7b254dSGiuliano Pochini 
274*dd7b254dSGiuliano Pochini 	/* The hw accesses memory in chunks 32 frames long and they should be
275*dd7b254dSGiuliano Pochini 	32-bytes-aligned. It's not a requirement, but it seems that IRQs are
276*dd7b254dSGiuliano Pochini 	generated with a resolution of 32 frames. Thus we need the following */
277*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_constraint_step(runtime, 0,
278*dd7b254dSGiuliano Pochini 					      SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
279*dd7b254dSGiuliano Pochini 					      32)) < 0)
280*dd7b254dSGiuliano Pochini 		return err;
281*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_constraint_step(runtime, 0,
282*dd7b254dSGiuliano Pochini 					      SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
283*dd7b254dSGiuliano Pochini 					      32)) < 0)
284*dd7b254dSGiuliano Pochini 		return err;
285*dd7b254dSGiuliano Pochini 
286*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
287*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_RATE,
288*dd7b254dSGiuliano Pochini 					hw_rule_sample_rate, chip,
289*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_RATE, -1)) < 0)
290*dd7b254dSGiuliano Pochini 		return err;
291*dd7b254dSGiuliano Pochini 
292*dd7b254dSGiuliano Pochini 	/* Finally allocate a page for the scatter-gather list */
293*dd7b254dSGiuliano Pochini 	if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
294*dd7b254dSGiuliano Pochini 				       snd_dma_pci_data(chip->pci),
295*dd7b254dSGiuliano Pochini 				       PAGE_SIZE, &pipe->sgpage)) < 0) {
296*dd7b254dSGiuliano Pochini 		DE_HWP(("s-g list allocation failed\n"));
297*dd7b254dSGiuliano Pochini 		return err;
298*dd7b254dSGiuliano Pochini 	}
299*dd7b254dSGiuliano Pochini 
300*dd7b254dSGiuliano Pochini 	return 0;
301*dd7b254dSGiuliano Pochini }
302*dd7b254dSGiuliano Pochini 
303*dd7b254dSGiuliano Pochini 
304*dd7b254dSGiuliano Pochini 
305*dd7b254dSGiuliano Pochini static int pcm_analog_in_open(struct snd_pcm_substream *substream)
306*dd7b254dSGiuliano Pochini {
307*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_pcm_substream_chip(substream);
308*dd7b254dSGiuliano Pochini 	int err;
309*dd7b254dSGiuliano Pochini 
310*dd7b254dSGiuliano Pochini 	DE_ACT(("pcm_analog_in_open\n"));
311*dd7b254dSGiuliano Pochini 	if ((err = pcm_open(substream, num_analog_busses_in(chip) -
312*dd7b254dSGiuliano Pochini 			    substream->number)) < 0)
313*dd7b254dSGiuliano Pochini 		return err;
314*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
315*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_CHANNELS,
316*dd7b254dSGiuliano Pochini 				       hw_rule_capture_channels_by_format, NULL,
317*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
318*dd7b254dSGiuliano Pochini 		return err;
319*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
320*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_FORMAT,
321*dd7b254dSGiuliano Pochini 				       hw_rule_capture_format_by_channels, NULL,
322*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
323*dd7b254dSGiuliano Pochini 		return err;
324*dd7b254dSGiuliano Pochini 	atomic_inc(&chip->opencount);
325*dd7b254dSGiuliano Pochini 	if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
326*dd7b254dSGiuliano Pochini 		chip->can_set_rate=0;
327*dd7b254dSGiuliano Pochini 	DE_HWP(("pcm_analog_in_open  cs=%d  oc=%d  r=%d\n",
328*dd7b254dSGiuliano Pochini 		chip->can_set_rate, atomic_read(&chip->opencount),
329*dd7b254dSGiuliano Pochini 		chip->sample_rate));
330*dd7b254dSGiuliano Pochini 	return 0;
331*dd7b254dSGiuliano Pochini }
332*dd7b254dSGiuliano Pochini 
333*dd7b254dSGiuliano Pochini 
334*dd7b254dSGiuliano Pochini 
335*dd7b254dSGiuliano Pochini static int pcm_analog_out_open(struct snd_pcm_substream *substream)
336*dd7b254dSGiuliano Pochini {
337*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_pcm_substream_chip(substream);
338*dd7b254dSGiuliano Pochini 	int max_channels, err;
339*dd7b254dSGiuliano Pochini 
340*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_VMIXER
341*dd7b254dSGiuliano Pochini 	max_channels = num_pipes_out(chip);
342*dd7b254dSGiuliano Pochini #else
343*dd7b254dSGiuliano Pochini 	max_channels = num_analog_busses_out(chip);
344*dd7b254dSGiuliano Pochini #endif
345*dd7b254dSGiuliano Pochini 	DE_ACT(("pcm_analog_out_open\n"));
346*dd7b254dSGiuliano Pochini 	if ((err = pcm_open(substream, max_channels - substream->number)) < 0)
347*dd7b254dSGiuliano Pochini 		return err;
348*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
349*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_CHANNELS,
350*dd7b254dSGiuliano Pochini 				       hw_rule_playback_channels_by_format,
351*dd7b254dSGiuliano Pochini 				       NULL,
352*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
353*dd7b254dSGiuliano Pochini 		return err;
354*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
355*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_FORMAT,
356*dd7b254dSGiuliano Pochini 				       hw_rule_playback_format_by_channels,
357*dd7b254dSGiuliano Pochini 				       NULL,
358*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
359*dd7b254dSGiuliano Pochini 		return err;
360*dd7b254dSGiuliano Pochini 	atomic_inc(&chip->opencount);
361*dd7b254dSGiuliano Pochini 	if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
362*dd7b254dSGiuliano Pochini 		chip->can_set_rate=0;
363*dd7b254dSGiuliano Pochini 	DE_HWP(("pcm_analog_out_open  cs=%d  oc=%d  r=%d\n",
364*dd7b254dSGiuliano Pochini 		chip->can_set_rate, atomic_read(&chip->opencount),
365*dd7b254dSGiuliano Pochini 		chip->sample_rate));
366*dd7b254dSGiuliano Pochini 	return 0;
367*dd7b254dSGiuliano Pochini }
368*dd7b254dSGiuliano Pochini 
369*dd7b254dSGiuliano Pochini 
370*dd7b254dSGiuliano Pochini 
371*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_DIGITAL_IO
372*dd7b254dSGiuliano Pochini 
373*dd7b254dSGiuliano Pochini static int pcm_digital_in_open(struct snd_pcm_substream *substream)
374*dd7b254dSGiuliano Pochini {
375*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_pcm_substream_chip(substream);
376*dd7b254dSGiuliano Pochini 	int err, max_channels;
377*dd7b254dSGiuliano Pochini 
378*dd7b254dSGiuliano Pochini 	DE_ACT(("pcm_digital_in_open\n"));
379*dd7b254dSGiuliano Pochini 	max_channels = num_digital_busses_in(chip) - substream->number;
380*dd7b254dSGiuliano Pochini 	down(&chip->mode_mutex);
381*dd7b254dSGiuliano Pochini 	if (chip->digital_mode == DIGITAL_MODE_ADAT)
382*dd7b254dSGiuliano Pochini 		err = pcm_open(substream, max_channels);
383*dd7b254dSGiuliano Pochini 	else	/* If the card has ADAT, subtract the 6 channels
384*dd7b254dSGiuliano Pochini 		 * that S/PDIF doesn't have
385*dd7b254dSGiuliano Pochini 		 */
386*dd7b254dSGiuliano Pochini 		err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT);
387*dd7b254dSGiuliano Pochini 
388*dd7b254dSGiuliano Pochini 	if (err < 0)
389*dd7b254dSGiuliano Pochini 		goto din_exit;
390*dd7b254dSGiuliano Pochini 
391*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
392*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_CHANNELS,
393*dd7b254dSGiuliano Pochini 				       hw_rule_capture_channels_by_format, NULL,
394*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0)
395*dd7b254dSGiuliano Pochini 		goto din_exit;
396*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
397*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_FORMAT,
398*dd7b254dSGiuliano Pochini 				       hw_rule_capture_format_by_channels, NULL,
399*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0)
400*dd7b254dSGiuliano Pochini 		goto din_exit;
401*dd7b254dSGiuliano Pochini 
402*dd7b254dSGiuliano Pochini 	atomic_inc(&chip->opencount);
403*dd7b254dSGiuliano Pochini 	if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
404*dd7b254dSGiuliano Pochini 		chip->can_set_rate=0;
405*dd7b254dSGiuliano Pochini 
406*dd7b254dSGiuliano Pochini din_exit:
407*dd7b254dSGiuliano Pochini 	up(&chip->mode_mutex);
408*dd7b254dSGiuliano Pochini 	return err;
409*dd7b254dSGiuliano Pochini }
410*dd7b254dSGiuliano Pochini 
411*dd7b254dSGiuliano Pochini 
412*dd7b254dSGiuliano Pochini 
413*dd7b254dSGiuliano Pochini #ifndef ECHOCARD_HAS_VMIXER	/* See the note in snd_echo_new_pcm() */
414*dd7b254dSGiuliano Pochini 
415*dd7b254dSGiuliano Pochini static int pcm_digital_out_open(struct snd_pcm_substream *substream)
416*dd7b254dSGiuliano Pochini {
417*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_pcm_substream_chip(substream);
418*dd7b254dSGiuliano Pochini 	int err, max_channels;
419*dd7b254dSGiuliano Pochini 
420*dd7b254dSGiuliano Pochini 	DE_ACT(("pcm_digital_out_open\n"));
421*dd7b254dSGiuliano Pochini 	max_channels = num_digital_busses_out(chip) - substream->number;
422*dd7b254dSGiuliano Pochini 	down(&chip->mode_mutex);
423*dd7b254dSGiuliano Pochini 	if (chip->digital_mode == DIGITAL_MODE_ADAT)
424*dd7b254dSGiuliano Pochini 		err = pcm_open(substream, max_channels);
425*dd7b254dSGiuliano Pochini 	else	/* If the card has ADAT, subtract the 6 channels
426*dd7b254dSGiuliano Pochini 		 * that S/PDIF doesn't have
427*dd7b254dSGiuliano Pochini 		 */
428*dd7b254dSGiuliano Pochini 		err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT);
429*dd7b254dSGiuliano Pochini 
430*dd7b254dSGiuliano Pochini 	if (err < 0)
431*dd7b254dSGiuliano Pochini 		goto dout_exit;
432*dd7b254dSGiuliano Pochini 
433*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
434*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_CHANNELS,
435*dd7b254dSGiuliano Pochini 				       hw_rule_playback_channels_by_format,
436*dd7b254dSGiuliano Pochini 				       NULL, SNDRV_PCM_HW_PARAM_FORMAT,
437*dd7b254dSGiuliano Pochini 				       -1)) < 0)
438*dd7b254dSGiuliano Pochini 		goto dout_exit;
439*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
440*dd7b254dSGiuliano Pochini 				       SNDRV_PCM_HW_PARAM_FORMAT,
441*dd7b254dSGiuliano Pochini 				       hw_rule_playback_format_by_channels,
442*dd7b254dSGiuliano Pochini 				       NULL, SNDRV_PCM_HW_PARAM_CHANNELS,
443*dd7b254dSGiuliano Pochini 				       -1)) < 0)
444*dd7b254dSGiuliano Pochini 		goto dout_exit;
445*dd7b254dSGiuliano Pochini 	atomic_inc(&chip->opencount);
446*dd7b254dSGiuliano Pochini 	if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
447*dd7b254dSGiuliano Pochini 		chip->can_set_rate=0;
448*dd7b254dSGiuliano Pochini dout_exit:
449*dd7b254dSGiuliano Pochini 	up(&chip->mode_mutex);
450*dd7b254dSGiuliano Pochini 	return err;
451*dd7b254dSGiuliano Pochini }
452*dd7b254dSGiuliano Pochini 
453*dd7b254dSGiuliano Pochini #endif /* !ECHOCARD_HAS_VMIXER */
454*dd7b254dSGiuliano Pochini 
455*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_DIGITAL_IO */
456*dd7b254dSGiuliano Pochini 
457*dd7b254dSGiuliano Pochini 
458*dd7b254dSGiuliano Pochini 
459*dd7b254dSGiuliano Pochini static int pcm_close(struct snd_pcm_substream *substream)
460*dd7b254dSGiuliano Pochini {
461*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_pcm_substream_chip(substream);
462*dd7b254dSGiuliano Pochini 	int oc;
463*dd7b254dSGiuliano Pochini 
464*dd7b254dSGiuliano Pochini 	/* Nothing to do here. Audio is already off and pipe will be
465*dd7b254dSGiuliano Pochini 	 * freed by its callback
466*dd7b254dSGiuliano Pochini 	 */
467*dd7b254dSGiuliano Pochini 	DE_ACT(("pcm_close\n"));
468*dd7b254dSGiuliano Pochini 
469*dd7b254dSGiuliano Pochini 	atomic_dec(&chip->opencount);
470*dd7b254dSGiuliano Pochini 	oc = atomic_read(&chip->opencount);
471*dd7b254dSGiuliano Pochini 	DE_ACT(("pcm_close  oc=%d  cs=%d  rs=%d\n", oc,
472*dd7b254dSGiuliano Pochini 		chip->can_set_rate, chip->rate_set));
473*dd7b254dSGiuliano Pochini 	if (oc < 2)
474*dd7b254dSGiuliano Pochini 		chip->can_set_rate = 1;
475*dd7b254dSGiuliano Pochini 	if (oc == 0)
476*dd7b254dSGiuliano Pochini 		chip->rate_set = 0;
477*dd7b254dSGiuliano Pochini 	DE_ACT(("pcm_close2 oc=%d  cs=%d  rs=%d\n", oc,
478*dd7b254dSGiuliano Pochini 		chip->can_set_rate,chip->rate_set));
479*dd7b254dSGiuliano Pochini 
480*dd7b254dSGiuliano Pochini 	return 0;
481*dd7b254dSGiuliano Pochini }
482*dd7b254dSGiuliano Pochini 
483*dd7b254dSGiuliano Pochini 
484*dd7b254dSGiuliano Pochini 
485*dd7b254dSGiuliano Pochini /* Channel allocation and scatter-gather list setup */
486*dd7b254dSGiuliano Pochini static int init_engine(struct snd_pcm_substream *substream,
487*dd7b254dSGiuliano Pochini 		       struct snd_pcm_hw_params *hw_params,
488*dd7b254dSGiuliano Pochini 		       int pipe_index, int interleave)
489*dd7b254dSGiuliano Pochini {
490*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
491*dd7b254dSGiuliano Pochini 	int err, per, rest, page, edge, offs;
492*dd7b254dSGiuliano Pochini 	struct snd_sg_buf *sgbuf;
493*dd7b254dSGiuliano Pochini 	struct audiopipe *pipe;
494*dd7b254dSGiuliano Pochini 
495*dd7b254dSGiuliano Pochini 	chip = snd_pcm_substream_chip(substream);
496*dd7b254dSGiuliano Pochini 	pipe = (struct audiopipe *) substream->runtime->private_data;
497*dd7b254dSGiuliano Pochini 
498*dd7b254dSGiuliano Pochini 	/* Sets up che hardware. If it's already initialized, reset and
499*dd7b254dSGiuliano Pochini 	 * redo with the new parameters
500*dd7b254dSGiuliano Pochini 	 */
501*dd7b254dSGiuliano Pochini 	spin_lock_irq(&chip->lock);
502*dd7b254dSGiuliano Pochini 	if (pipe->index >= 0) {
503*dd7b254dSGiuliano Pochini 		DE_HWP(("hwp_ie free(%d)\n", pipe->index));
504*dd7b254dSGiuliano Pochini 		err = free_pipes(chip, pipe);
505*dd7b254dSGiuliano Pochini 		snd_assert(!err);
506*dd7b254dSGiuliano Pochini 		chip->substream[pipe->index] = NULL;
507*dd7b254dSGiuliano Pochini 	}
508*dd7b254dSGiuliano Pochini 
509*dd7b254dSGiuliano Pochini 	err = allocate_pipes(chip, pipe, pipe_index, interleave);
510*dd7b254dSGiuliano Pochini 	if (err < 0) {
511*dd7b254dSGiuliano Pochini 		spin_unlock_irq(&chip->lock);
512*dd7b254dSGiuliano Pochini 		DE_ACT((KERN_NOTICE "allocate_pipes(%d) err=%d\n",
513*dd7b254dSGiuliano Pochini 			pipe_index, err));
514*dd7b254dSGiuliano Pochini 		return err;
515*dd7b254dSGiuliano Pochini 	}
516*dd7b254dSGiuliano Pochini 	spin_unlock_irq(&chip->lock);
517*dd7b254dSGiuliano Pochini 	DE_ACT((KERN_NOTICE "allocate_pipes()=%d\n", pipe_index));
518*dd7b254dSGiuliano Pochini 
519*dd7b254dSGiuliano Pochini 	DE_HWP(("pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n",
520*dd7b254dSGiuliano Pochini 		params_buffer_bytes(hw_params), params_periods(hw_params),
521*dd7b254dSGiuliano Pochini 		params_period_bytes(hw_params)));
522*dd7b254dSGiuliano Pochini 	err = snd_pcm_lib_malloc_pages(substream,
523*dd7b254dSGiuliano Pochini 				       params_buffer_bytes(hw_params));
524*dd7b254dSGiuliano Pochini 	if (err < 0) {
525*dd7b254dSGiuliano Pochini 		snd_printk(KERN_ERR "malloc_pages err=%d\n", err);
526*dd7b254dSGiuliano Pochini 		spin_lock_irq(&chip->lock);
527*dd7b254dSGiuliano Pochini 		free_pipes(chip, pipe);
528*dd7b254dSGiuliano Pochini 		spin_unlock_irq(&chip->lock);
529*dd7b254dSGiuliano Pochini 		pipe->index = -1;
530*dd7b254dSGiuliano Pochini 		return err;
531*dd7b254dSGiuliano Pochini 	}
532*dd7b254dSGiuliano Pochini 
533*dd7b254dSGiuliano Pochini 	sgbuf = snd_pcm_substream_sgbuf(substream);
534*dd7b254dSGiuliano Pochini 
535*dd7b254dSGiuliano Pochini 	DE_HWP(("pcm_hw_params table size=%d pages=%d\n",
536*dd7b254dSGiuliano Pochini 		sgbuf->size, sgbuf->pages));
537*dd7b254dSGiuliano Pochini 	sglist_init(chip, pipe);
538*dd7b254dSGiuliano Pochini 	edge = PAGE_SIZE;
539*dd7b254dSGiuliano Pochini 	for (offs = page = per = 0; offs < params_buffer_bytes(hw_params);
540*dd7b254dSGiuliano Pochini 	     per++) {
541*dd7b254dSGiuliano Pochini 		rest = params_period_bytes(hw_params);
542*dd7b254dSGiuliano Pochini 		if (offs + rest > params_buffer_bytes(hw_params))
543*dd7b254dSGiuliano Pochini 			rest = params_buffer_bytes(hw_params) - offs;
544*dd7b254dSGiuliano Pochini 		while (rest) {
545*dd7b254dSGiuliano Pochini 			if (rest <= edge - offs) {
546*dd7b254dSGiuliano Pochini 				sglist_add_mapping(chip, pipe,
547*dd7b254dSGiuliano Pochini 						   snd_sgbuf_get_addr(sgbuf, offs),
548*dd7b254dSGiuliano Pochini 						   rest);
549*dd7b254dSGiuliano Pochini 				sglist_add_irq(chip, pipe);
550*dd7b254dSGiuliano Pochini 				offs += rest;
551*dd7b254dSGiuliano Pochini 				rest = 0;
552*dd7b254dSGiuliano Pochini 			} else {
553*dd7b254dSGiuliano Pochini 				sglist_add_mapping(chip, pipe,
554*dd7b254dSGiuliano Pochini 						   snd_sgbuf_get_addr(sgbuf, offs),
555*dd7b254dSGiuliano Pochini 						   edge - offs);
556*dd7b254dSGiuliano Pochini 				rest -= edge - offs;
557*dd7b254dSGiuliano Pochini 				offs = edge;
558*dd7b254dSGiuliano Pochini 			}
559*dd7b254dSGiuliano Pochini 			if (offs == edge) {
560*dd7b254dSGiuliano Pochini 				edge += PAGE_SIZE;
561*dd7b254dSGiuliano Pochini 				page++;
562*dd7b254dSGiuliano Pochini 			}
563*dd7b254dSGiuliano Pochini 		}
564*dd7b254dSGiuliano Pochini 	}
565*dd7b254dSGiuliano Pochini 
566*dd7b254dSGiuliano Pochini 	/* Close the ring buffer */
567*dd7b254dSGiuliano Pochini 	sglist_wrap(chip, pipe);
568*dd7b254dSGiuliano Pochini 
569*dd7b254dSGiuliano Pochini 	/* This stuff is used by the irq handler, so it must be
570*dd7b254dSGiuliano Pochini 	 * initialized before chip->substream
571*dd7b254dSGiuliano Pochini 	 */
572*dd7b254dSGiuliano Pochini 	chip->last_period[pipe_index] = 0;
573*dd7b254dSGiuliano Pochini 	pipe->last_counter = 0;
574*dd7b254dSGiuliano Pochini 	pipe->position = 0;
575*dd7b254dSGiuliano Pochini 	smp_wmb();
576*dd7b254dSGiuliano Pochini 	chip->substream[pipe_index] = substream;
577*dd7b254dSGiuliano Pochini 	chip->rate_set = 1;
578*dd7b254dSGiuliano Pochini 	spin_lock_irq(&chip->lock);
579*dd7b254dSGiuliano Pochini 	set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den);
580*dd7b254dSGiuliano Pochini 	spin_unlock_irq(&chip->lock);
581*dd7b254dSGiuliano Pochini 	DE_HWP(("pcm_hw_params ok\n"));
582*dd7b254dSGiuliano Pochini 	return 0;
583*dd7b254dSGiuliano Pochini }
584*dd7b254dSGiuliano Pochini 
585*dd7b254dSGiuliano Pochini 
586*dd7b254dSGiuliano Pochini 
587*dd7b254dSGiuliano Pochini static int pcm_analog_in_hw_params(struct snd_pcm_substream *substream,
588*dd7b254dSGiuliano Pochini 				   struct snd_pcm_hw_params *hw_params)
589*dd7b254dSGiuliano Pochini {
590*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_pcm_substream_chip(substream);
591*dd7b254dSGiuliano Pochini 
592*dd7b254dSGiuliano Pochini 	return init_engine(substream, hw_params, px_analog_in(chip) +
593*dd7b254dSGiuliano Pochini 			substream->number, params_channels(hw_params));
594*dd7b254dSGiuliano Pochini }
595*dd7b254dSGiuliano Pochini 
596*dd7b254dSGiuliano Pochini 
597*dd7b254dSGiuliano Pochini 
598*dd7b254dSGiuliano Pochini static int pcm_analog_out_hw_params(struct snd_pcm_substream *substream,
599*dd7b254dSGiuliano Pochini 				    struct snd_pcm_hw_params *hw_params)
600*dd7b254dSGiuliano Pochini {
601*dd7b254dSGiuliano Pochini 	return init_engine(substream, hw_params, substream->number,
602*dd7b254dSGiuliano Pochini 			   params_channels(hw_params));
603*dd7b254dSGiuliano Pochini }
604*dd7b254dSGiuliano Pochini 
605*dd7b254dSGiuliano Pochini 
606*dd7b254dSGiuliano Pochini 
607*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_DIGITAL_IO
608*dd7b254dSGiuliano Pochini 
609*dd7b254dSGiuliano Pochini static int pcm_digital_in_hw_params(struct snd_pcm_substream *substream,
610*dd7b254dSGiuliano Pochini 				    struct snd_pcm_hw_params *hw_params)
611*dd7b254dSGiuliano Pochini {
612*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_pcm_substream_chip(substream);
613*dd7b254dSGiuliano Pochini 
614*dd7b254dSGiuliano Pochini 	return init_engine(substream, hw_params, px_digital_in(chip) +
615*dd7b254dSGiuliano Pochini 			substream->number, params_channels(hw_params));
616*dd7b254dSGiuliano Pochini }
617*dd7b254dSGiuliano Pochini 
618*dd7b254dSGiuliano Pochini 
619*dd7b254dSGiuliano Pochini 
620*dd7b254dSGiuliano Pochini #ifndef ECHOCARD_HAS_VMIXER	/* See the note in snd_echo_new_pcm() */
621*dd7b254dSGiuliano Pochini static int pcm_digital_out_hw_params(struct snd_pcm_substream *substream,
622*dd7b254dSGiuliano Pochini 				     struct snd_pcm_hw_params *hw_params)
623*dd7b254dSGiuliano Pochini {
624*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_pcm_substream_chip(substream);
625*dd7b254dSGiuliano Pochini 
626*dd7b254dSGiuliano Pochini 	return init_engine(substream, hw_params, px_digital_out(chip) +
627*dd7b254dSGiuliano Pochini 			substream->number, params_channels(hw_params));
628*dd7b254dSGiuliano Pochini }
629*dd7b254dSGiuliano Pochini #endif /* !ECHOCARD_HAS_VMIXER */
630*dd7b254dSGiuliano Pochini 
631*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_DIGITAL_IO */
632*dd7b254dSGiuliano Pochini 
633*dd7b254dSGiuliano Pochini 
634*dd7b254dSGiuliano Pochini 
635*dd7b254dSGiuliano Pochini static int pcm_hw_free(struct snd_pcm_substream *substream)
636*dd7b254dSGiuliano Pochini {
637*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
638*dd7b254dSGiuliano Pochini 	struct audiopipe *pipe;
639*dd7b254dSGiuliano Pochini 
640*dd7b254dSGiuliano Pochini 	chip = snd_pcm_substream_chip(substream);
641*dd7b254dSGiuliano Pochini 	pipe = (struct audiopipe *) substream->runtime->private_data;
642*dd7b254dSGiuliano Pochini 
643*dd7b254dSGiuliano Pochini 	spin_lock_irq(&chip->lock);
644*dd7b254dSGiuliano Pochini 	if (pipe->index >= 0) {
645*dd7b254dSGiuliano Pochini 		DE_HWP(("pcm_hw_free(%d)\n", pipe->index));
646*dd7b254dSGiuliano Pochini 		free_pipes(chip, pipe);
647*dd7b254dSGiuliano Pochini 		chip->substream[pipe->index] = NULL;
648*dd7b254dSGiuliano Pochini 		pipe->index = -1;
649*dd7b254dSGiuliano Pochini 	}
650*dd7b254dSGiuliano Pochini 	spin_unlock_irq(&chip->lock);
651*dd7b254dSGiuliano Pochini 
652*dd7b254dSGiuliano Pochini 	DE_HWP(("pcm_hw_freed\n"));
653*dd7b254dSGiuliano Pochini 	snd_pcm_lib_free_pages(substream);
654*dd7b254dSGiuliano Pochini 	return 0;
655*dd7b254dSGiuliano Pochini }
656*dd7b254dSGiuliano Pochini 
657*dd7b254dSGiuliano Pochini 
658*dd7b254dSGiuliano Pochini 
659*dd7b254dSGiuliano Pochini static int pcm_prepare(struct snd_pcm_substream *substream)
660*dd7b254dSGiuliano Pochini {
661*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_pcm_substream_chip(substream);
662*dd7b254dSGiuliano Pochini 	struct snd_pcm_runtime *runtime = substream->runtime;
663*dd7b254dSGiuliano Pochini 	struct audioformat format;
664*dd7b254dSGiuliano Pochini 	int pipe_index = ((struct audiopipe *)runtime->private_data)->index;
665*dd7b254dSGiuliano Pochini 
666*dd7b254dSGiuliano Pochini 	DE_HWP(("Prepare rate=%d format=%d channels=%d\n",
667*dd7b254dSGiuliano Pochini 		runtime->rate, runtime->format, runtime->channels));
668*dd7b254dSGiuliano Pochini 	format.interleave = runtime->channels;
669*dd7b254dSGiuliano Pochini 	format.data_are_bigendian = 0;
670*dd7b254dSGiuliano Pochini 	format.mono_to_stereo = 0;
671*dd7b254dSGiuliano Pochini 	switch (runtime->format) {
672*dd7b254dSGiuliano Pochini 	case SNDRV_PCM_FORMAT_U8:
673*dd7b254dSGiuliano Pochini 		format.bits_per_sample = 8;
674*dd7b254dSGiuliano Pochini 		break;
675*dd7b254dSGiuliano Pochini 	case SNDRV_PCM_FORMAT_S16_LE:
676*dd7b254dSGiuliano Pochini 		format.bits_per_sample = 16;
677*dd7b254dSGiuliano Pochini 		break;
678*dd7b254dSGiuliano Pochini 	case SNDRV_PCM_FORMAT_S24_3LE:
679*dd7b254dSGiuliano Pochini 		format.bits_per_sample = 24;
680*dd7b254dSGiuliano Pochini 		break;
681*dd7b254dSGiuliano Pochini 	case SNDRV_PCM_FORMAT_S32_BE:
682*dd7b254dSGiuliano Pochini 		format.data_are_bigendian = 1;
683*dd7b254dSGiuliano Pochini 	case SNDRV_PCM_FORMAT_S32_LE:
684*dd7b254dSGiuliano Pochini 		format.bits_per_sample = 32;
685*dd7b254dSGiuliano Pochini 		break;
686*dd7b254dSGiuliano Pochini 	default:
687*dd7b254dSGiuliano Pochini 		DE_HWP(("Prepare error: unsupported format %d\n",
688*dd7b254dSGiuliano Pochini 			runtime->format));
689*dd7b254dSGiuliano Pochini 		return -EINVAL;
690*dd7b254dSGiuliano Pochini 	}
691*dd7b254dSGiuliano Pochini 
692*dd7b254dSGiuliano Pochini 	snd_assert(pipe_index < px_num(chip), return -EINVAL);
693*dd7b254dSGiuliano Pochini 	snd_assert(is_pipe_allocated(chip, pipe_index), return -EINVAL);
694*dd7b254dSGiuliano Pochini 	set_audio_format(chip, pipe_index, &format);
695*dd7b254dSGiuliano Pochini 	return 0;
696*dd7b254dSGiuliano Pochini }
697*dd7b254dSGiuliano Pochini 
698*dd7b254dSGiuliano Pochini 
699*dd7b254dSGiuliano Pochini 
700*dd7b254dSGiuliano Pochini static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
701*dd7b254dSGiuliano Pochini {
702*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_pcm_substream_chip(substream);
703*dd7b254dSGiuliano Pochini 	struct snd_pcm_runtime *runtime = substream->runtime;
704*dd7b254dSGiuliano Pochini 	struct audiopipe *pipe = runtime->private_data;
705*dd7b254dSGiuliano Pochini 	int i, err;
706*dd7b254dSGiuliano Pochini 	u32 channelmask = 0;
707*dd7b254dSGiuliano Pochini 	struct list_head *pos;
708*dd7b254dSGiuliano Pochini 	struct snd_pcm_substream *s;
709*dd7b254dSGiuliano Pochini 
710*dd7b254dSGiuliano Pochini 	snd_pcm_group_for_each(pos, substream) {
711*dd7b254dSGiuliano Pochini 		s = snd_pcm_group_substream_entry(pos);
712*dd7b254dSGiuliano Pochini 		for (i = 0; i < DSP_MAXPIPES; i++) {
713*dd7b254dSGiuliano Pochini 			if (s == chip->substream[i]) {
714*dd7b254dSGiuliano Pochini 				channelmask |= 1 << i;
715*dd7b254dSGiuliano Pochini 				snd_pcm_trigger_done(s, substream);
716*dd7b254dSGiuliano Pochini 			}
717*dd7b254dSGiuliano Pochini 		}
718*dd7b254dSGiuliano Pochini 	}
719*dd7b254dSGiuliano Pochini 
720*dd7b254dSGiuliano Pochini 	spin_lock(&chip->lock);
721*dd7b254dSGiuliano Pochini 	switch (cmd) {
722*dd7b254dSGiuliano Pochini 	case SNDRV_PCM_TRIGGER_START:
723*dd7b254dSGiuliano Pochini 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
724*dd7b254dSGiuliano Pochini 		DE_ACT(("pcm_trigger start\n"));
725*dd7b254dSGiuliano Pochini 		for (i = 0; i < DSP_MAXPIPES; i++) {
726*dd7b254dSGiuliano Pochini 			if (channelmask & (1 << i)) {
727*dd7b254dSGiuliano Pochini 				pipe = chip->substream[i]->runtime->private_data;
728*dd7b254dSGiuliano Pochini 				switch (pipe->state) {
729*dd7b254dSGiuliano Pochini 				case PIPE_STATE_STOPPED:
730*dd7b254dSGiuliano Pochini 					chip->last_period[i] = 0;
731*dd7b254dSGiuliano Pochini 					pipe->last_counter = 0;
732*dd7b254dSGiuliano Pochini 					pipe->position = 0;
733*dd7b254dSGiuliano Pochini 					*pipe->dma_counter = 0;
734*dd7b254dSGiuliano Pochini 				case PIPE_STATE_PAUSED:
735*dd7b254dSGiuliano Pochini 					pipe->state = PIPE_STATE_STARTED;
736*dd7b254dSGiuliano Pochini 					break;
737*dd7b254dSGiuliano Pochini 				case PIPE_STATE_STARTED:
738*dd7b254dSGiuliano Pochini 					break;
739*dd7b254dSGiuliano Pochini 				}
740*dd7b254dSGiuliano Pochini 			}
741*dd7b254dSGiuliano Pochini 		}
742*dd7b254dSGiuliano Pochini 		err = start_transport(chip, channelmask,
743*dd7b254dSGiuliano Pochini 				      chip->pipe_cyclic_mask);
744*dd7b254dSGiuliano Pochini 		break;
745*dd7b254dSGiuliano Pochini 	case SNDRV_PCM_TRIGGER_STOP:
746*dd7b254dSGiuliano Pochini 		DE_ACT(("pcm_trigger stop\n"));
747*dd7b254dSGiuliano Pochini 		for (i = 0; i < DSP_MAXPIPES; i++) {
748*dd7b254dSGiuliano Pochini 			if (channelmask & (1 << i)) {
749*dd7b254dSGiuliano Pochini 				pipe = chip->substream[i]->runtime->private_data;
750*dd7b254dSGiuliano Pochini 				pipe->state = PIPE_STATE_STOPPED;
751*dd7b254dSGiuliano Pochini 			}
752*dd7b254dSGiuliano Pochini 		}
753*dd7b254dSGiuliano Pochini 		err = stop_transport(chip, channelmask);
754*dd7b254dSGiuliano Pochini 		break;
755*dd7b254dSGiuliano Pochini 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
756*dd7b254dSGiuliano Pochini 		DE_ACT(("pcm_trigger pause\n"));
757*dd7b254dSGiuliano Pochini 		for (i = 0; i < DSP_MAXPIPES; i++) {
758*dd7b254dSGiuliano Pochini 			if (channelmask & (1 << i)) {
759*dd7b254dSGiuliano Pochini 				pipe = chip->substream[i]->runtime->private_data;
760*dd7b254dSGiuliano Pochini 				pipe->state = PIPE_STATE_PAUSED;
761*dd7b254dSGiuliano Pochini 			}
762*dd7b254dSGiuliano Pochini 		}
763*dd7b254dSGiuliano Pochini 		err = pause_transport(chip, channelmask);
764*dd7b254dSGiuliano Pochini 		break;
765*dd7b254dSGiuliano Pochini 	default:
766*dd7b254dSGiuliano Pochini 		err = -EINVAL;
767*dd7b254dSGiuliano Pochini 	}
768*dd7b254dSGiuliano Pochini 	spin_unlock(&chip->lock);
769*dd7b254dSGiuliano Pochini 	return err;
770*dd7b254dSGiuliano Pochini }
771*dd7b254dSGiuliano Pochini 
772*dd7b254dSGiuliano Pochini 
773*dd7b254dSGiuliano Pochini 
774*dd7b254dSGiuliano Pochini static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream)
775*dd7b254dSGiuliano Pochini {
776*dd7b254dSGiuliano Pochini 	struct snd_pcm_runtime *runtime = substream->runtime;
777*dd7b254dSGiuliano Pochini 	struct audiopipe *pipe = runtime->private_data;
778*dd7b254dSGiuliano Pochini 	size_t cnt, bufsize, pos;
779*dd7b254dSGiuliano Pochini 
780*dd7b254dSGiuliano Pochini 	cnt = le32_to_cpu(*pipe->dma_counter);
781*dd7b254dSGiuliano Pochini 	pipe->position += cnt - pipe->last_counter;
782*dd7b254dSGiuliano Pochini 	pipe->last_counter = cnt;
783*dd7b254dSGiuliano Pochini 	bufsize = substream->runtime->buffer_size;
784*dd7b254dSGiuliano Pochini 	pos = bytes_to_frames(substream->runtime, pipe->position);
785*dd7b254dSGiuliano Pochini 
786*dd7b254dSGiuliano Pochini 	while (pos >= bufsize) {
787*dd7b254dSGiuliano Pochini 		pipe->position -= frames_to_bytes(substream->runtime, bufsize);
788*dd7b254dSGiuliano Pochini 		pos -= bufsize;
789*dd7b254dSGiuliano Pochini 	}
790*dd7b254dSGiuliano Pochini 	return pos;
791*dd7b254dSGiuliano Pochini }
792*dd7b254dSGiuliano Pochini 
793*dd7b254dSGiuliano Pochini 
794*dd7b254dSGiuliano Pochini 
795*dd7b254dSGiuliano Pochini /* pcm *_ops structures */
796*dd7b254dSGiuliano Pochini static struct snd_pcm_ops analog_playback_ops = {
797*dd7b254dSGiuliano Pochini 	.open = pcm_analog_out_open,
798*dd7b254dSGiuliano Pochini 	.close = pcm_close,
799*dd7b254dSGiuliano Pochini 	.ioctl = snd_pcm_lib_ioctl,
800*dd7b254dSGiuliano Pochini 	.hw_params = pcm_analog_out_hw_params,
801*dd7b254dSGiuliano Pochini 	.hw_free = pcm_hw_free,
802*dd7b254dSGiuliano Pochini 	.prepare = pcm_prepare,
803*dd7b254dSGiuliano Pochini 	.trigger = pcm_trigger,
804*dd7b254dSGiuliano Pochini 	.pointer = pcm_pointer,
805*dd7b254dSGiuliano Pochini 	.page = snd_pcm_sgbuf_ops_page,
806*dd7b254dSGiuliano Pochini };
807*dd7b254dSGiuliano Pochini static struct snd_pcm_ops analog_capture_ops = {
808*dd7b254dSGiuliano Pochini 	.open = pcm_analog_in_open,
809*dd7b254dSGiuliano Pochini 	.close = pcm_close,
810*dd7b254dSGiuliano Pochini 	.ioctl = snd_pcm_lib_ioctl,
811*dd7b254dSGiuliano Pochini 	.hw_params = pcm_analog_in_hw_params,
812*dd7b254dSGiuliano Pochini 	.hw_free = pcm_hw_free,
813*dd7b254dSGiuliano Pochini 	.prepare = pcm_prepare,
814*dd7b254dSGiuliano Pochini 	.trigger = pcm_trigger,
815*dd7b254dSGiuliano Pochini 	.pointer = pcm_pointer,
816*dd7b254dSGiuliano Pochini 	.page = snd_pcm_sgbuf_ops_page,
817*dd7b254dSGiuliano Pochini };
818*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_DIGITAL_IO
819*dd7b254dSGiuliano Pochini #ifndef ECHOCARD_HAS_VMIXER
820*dd7b254dSGiuliano Pochini static struct snd_pcm_ops digital_playback_ops = {
821*dd7b254dSGiuliano Pochini 	.open = pcm_digital_out_open,
822*dd7b254dSGiuliano Pochini 	.close = pcm_close,
823*dd7b254dSGiuliano Pochini 	.ioctl = snd_pcm_lib_ioctl,
824*dd7b254dSGiuliano Pochini 	.hw_params = pcm_digital_out_hw_params,
825*dd7b254dSGiuliano Pochini 	.hw_free = pcm_hw_free,
826*dd7b254dSGiuliano Pochini 	.prepare = pcm_prepare,
827*dd7b254dSGiuliano Pochini 	.trigger = pcm_trigger,
828*dd7b254dSGiuliano Pochini 	.pointer = pcm_pointer,
829*dd7b254dSGiuliano Pochini 	.page = snd_pcm_sgbuf_ops_page,
830*dd7b254dSGiuliano Pochini };
831*dd7b254dSGiuliano Pochini #endif /* !ECHOCARD_HAS_VMIXER */
832*dd7b254dSGiuliano Pochini static struct snd_pcm_ops digital_capture_ops = {
833*dd7b254dSGiuliano Pochini 	.open = pcm_digital_in_open,
834*dd7b254dSGiuliano Pochini 	.close = pcm_close,
835*dd7b254dSGiuliano Pochini 	.ioctl = snd_pcm_lib_ioctl,
836*dd7b254dSGiuliano Pochini 	.hw_params = pcm_digital_in_hw_params,
837*dd7b254dSGiuliano Pochini 	.hw_free = pcm_hw_free,
838*dd7b254dSGiuliano Pochini 	.prepare = pcm_prepare,
839*dd7b254dSGiuliano Pochini 	.trigger = pcm_trigger,
840*dd7b254dSGiuliano Pochini 	.pointer = pcm_pointer,
841*dd7b254dSGiuliano Pochini 	.page = snd_pcm_sgbuf_ops_page,
842*dd7b254dSGiuliano Pochini };
843*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_DIGITAL_IO */
844*dd7b254dSGiuliano Pochini 
845*dd7b254dSGiuliano Pochini 
846*dd7b254dSGiuliano Pochini 
847*dd7b254dSGiuliano Pochini /* Preallocate memory only for the first substream because it's the most
848*dd7b254dSGiuliano Pochini  * used one
849*dd7b254dSGiuliano Pochini  */
850*dd7b254dSGiuliano Pochini static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev)
851*dd7b254dSGiuliano Pochini {
852*dd7b254dSGiuliano Pochini 	struct snd_pcm_substream *ss;
853*dd7b254dSGiuliano Pochini 	int stream, err;
854*dd7b254dSGiuliano Pochini 
855*dd7b254dSGiuliano Pochini 	for (stream = 0; stream < 2; stream++)
856*dd7b254dSGiuliano Pochini 		for (ss = pcm->streams[stream].substream; ss; ss = ss->next) {
857*dd7b254dSGiuliano Pochini 			err = snd_pcm_lib_preallocate_pages(ss, SNDRV_DMA_TYPE_DEV_SG,
858*dd7b254dSGiuliano Pochini 							    dev,
859*dd7b254dSGiuliano Pochini 							    ss->number ? 0 : 128<<10,
860*dd7b254dSGiuliano Pochini 							    256<<10);
861*dd7b254dSGiuliano Pochini 			if (err < 0)
862*dd7b254dSGiuliano Pochini 				return err;
863*dd7b254dSGiuliano Pochini 		}
864*dd7b254dSGiuliano Pochini 	return 0;
865*dd7b254dSGiuliano Pochini }
866*dd7b254dSGiuliano Pochini 
867*dd7b254dSGiuliano Pochini 
868*dd7b254dSGiuliano Pochini 
869*dd7b254dSGiuliano Pochini /*<--snd_echo_probe() */
870*dd7b254dSGiuliano Pochini static int __devinit snd_echo_new_pcm(struct echoaudio *chip)
871*dd7b254dSGiuliano Pochini {
872*dd7b254dSGiuliano Pochini 	struct snd_pcm *pcm;
873*dd7b254dSGiuliano Pochini 	int err;
874*dd7b254dSGiuliano Pochini 
875*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_VMIXER
876*dd7b254dSGiuliano Pochini 	/* This card has a Vmixer, that is there is no direct mapping from PCM
877*dd7b254dSGiuliano Pochini 	streams to physical outputs. The user can mix the streams as he wishes
878*dd7b254dSGiuliano Pochini 	via control interface and it's possible to send any stream to any
879*dd7b254dSGiuliano Pochini 	output, thus it makes no sense to keep analog and digital outputs
880*dd7b254dSGiuliano Pochini 	separated */
881*dd7b254dSGiuliano Pochini 
882*dd7b254dSGiuliano Pochini 	/* PCM#0 Virtual outputs and analog inputs */
883*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_new(chip->card, "PCM", 0, num_pipes_out(chip),
884*dd7b254dSGiuliano Pochini 				num_analog_busses_in(chip), &pcm)) < 0)
885*dd7b254dSGiuliano Pochini 		return err;
886*dd7b254dSGiuliano Pochini 	pcm->private_data = chip;
887*dd7b254dSGiuliano Pochini 	chip->analog_pcm = pcm;
888*dd7b254dSGiuliano Pochini 	strcpy(pcm->name, chip->card->shortname);
889*dd7b254dSGiuliano Pochini 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
890*dd7b254dSGiuliano Pochini 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
891*dd7b254dSGiuliano Pochini 	if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
892*dd7b254dSGiuliano Pochini 		return err;
893*dd7b254dSGiuliano Pochini 	DE_INIT(("Analog PCM ok\n"));
894*dd7b254dSGiuliano Pochini 
895*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_DIGITAL_IO
896*dd7b254dSGiuliano Pochini 	/* PCM#1 Digital inputs, no outputs */
897*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_new(chip->card, "Digital PCM", 1, 0,
898*dd7b254dSGiuliano Pochini 			       num_digital_busses_in(chip), &pcm)) < 0)
899*dd7b254dSGiuliano Pochini 		return err;
900*dd7b254dSGiuliano Pochini 	pcm->private_data = chip;
901*dd7b254dSGiuliano Pochini 	chip->digital_pcm = pcm;
902*dd7b254dSGiuliano Pochini 	strcpy(pcm->name, chip->card->shortname);
903*dd7b254dSGiuliano Pochini 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
904*dd7b254dSGiuliano Pochini 	if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
905*dd7b254dSGiuliano Pochini 		return err;
906*dd7b254dSGiuliano Pochini 	DE_INIT(("Digital PCM ok\n"));
907*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_DIGITAL_IO */
908*dd7b254dSGiuliano Pochini 
909*dd7b254dSGiuliano Pochini #else /* ECHOCARD_HAS_VMIXER */
910*dd7b254dSGiuliano Pochini 
911*dd7b254dSGiuliano Pochini 	/* The card can manage substreams formed by analog and digital channels
912*dd7b254dSGiuliano Pochini 	at the same time, but I prefer to keep analog and digital channels
913*dd7b254dSGiuliano Pochini 	separated, because that mixed thing is confusing and useless. So we
914*dd7b254dSGiuliano Pochini 	register two PCM devices: */
915*dd7b254dSGiuliano Pochini 
916*dd7b254dSGiuliano Pochini 	/* PCM#0 Analog i/o */
917*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_new(chip->card, "Analog PCM", 0,
918*dd7b254dSGiuliano Pochini 			       num_analog_busses_out(chip),
919*dd7b254dSGiuliano Pochini 			       num_analog_busses_in(chip), &pcm)) < 0)
920*dd7b254dSGiuliano Pochini 		return err;
921*dd7b254dSGiuliano Pochini 	pcm->private_data = chip;
922*dd7b254dSGiuliano Pochini 	chip->analog_pcm = pcm;
923*dd7b254dSGiuliano Pochini 	strcpy(pcm->name, chip->card->shortname);
924*dd7b254dSGiuliano Pochini 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops);
925*dd7b254dSGiuliano Pochini 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
926*dd7b254dSGiuliano Pochini 	if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
927*dd7b254dSGiuliano Pochini 		return err;
928*dd7b254dSGiuliano Pochini 	DE_INIT(("Analog PCM ok\n"));
929*dd7b254dSGiuliano Pochini 
930*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_DIGITAL_IO
931*dd7b254dSGiuliano Pochini 	/* PCM#1 Digital i/o */
932*dd7b254dSGiuliano Pochini 	if ((err = snd_pcm_new(chip->card, "Digital PCM", 1,
933*dd7b254dSGiuliano Pochini 			       num_digital_busses_out(chip),
934*dd7b254dSGiuliano Pochini 			       num_digital_busses_in(chip), &pcm)) < 0)
935*dd7b254dSGiuliano Pochini 		return err;
936*dd7b254dSGiuliano Pochini 	pcm->private_data = chip;
937*dd7b254dSGiuliano Pochini 	chip->digital_pcm = pcm;
938*dd7b254dSGiuliano Pochini 	strcpy(pcm->name, chip->card->shortname);
939*dd7b254dSGiuliano Pochini 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &digital_playback_ops);
940*dd7b254dSGiuliano Pochini 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
941*dd7b254dSGiuliano Pochini 	if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
942*dd7b254dSGiuliano Pochini 		return err;
943*dd7b254dSGiuliano Pochini 	DE_INIT(("Digital PCM ok\n"));
944*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_DIGITAL_IO */
945*dd7b254dSGiuliano Pochini 
946*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_VMIXER */
947*dd7b254dSGiuliano Pochini 
948*dd7b254dSGiuliano Pochini 	return 0;
949*dd7b254dSGiuliano Pochini }
950*dd7b254dSGiuliano Pochini 
951*dd7b254dSGiuliano Pochini 
952*dd7b254dSGiuliano Pochini 
953*dd7b254dSGiuliano Pochini 
954*dd7b254dSGiuliano Pochini /******************************************************************************
955*dd7b254dSGiuliano Pochini 	Control interface
956*dd7b254dSGiuliano Pochini ******************************************************************************/
957*dd7b254dSGiuliano Pochini 
958*dd7b254dSGiuliano Pochini /******************* PCM output volume *******************/
959*dd7b254dSGiuliano Pochini static int snd_echo_output_gain_info(struct snd_kcontrol *kcontrol,
960*dd7b254dSGiuliano Pochini 				     struct snd_ctl_elem_info *uinfo)
961*dd7b254dSGiuliano Pochini {
962*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
963*dd7b254dSGiuliano Pochini 
964*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
965*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
966*dd7b254dSGiuliano Pochini 	uinfo->count = num_busses_out(chip);
967*dd7b254dSGiuliano Pochini 	uinfo->value.integer.min = ECHOGAIN_MINOUT;
968*dd7b254dSGiuliano Pochini 	uinfo->value.integer.max = ECHOGAIN_MAXOUT;
969*dd7b254dSGiuliano Pochini 	return 0;
970*dd7b254dSGiuliano Pochini }
971*dd7b254dSGiuliano Pochini 
972*dd7b254dSGiuliano Pochini static int snd_echo_output_gain_get(struct snd_kcontrol *kcontrol,
973*dd7b254dSGiuliano Pochini 				    struct snd_ctl_elem_value *ucontrol)
974*dd7b254dSGiuliano Pochini {
975*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
976*dd7b254dSGiuliano Pochini 	int c;
977*dd7b254dSGiuliano Pochini 
978*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
979*dd7b254dSGiuliano Pochini 	for (c = 0; c < num_busses_out(chip); c++)
980*dd7b254dSGiuliano Pochini 		ucontrol->value.integer.value[c] = chip->output_gain[c];
981*dd7b254dSGiuliano Pochini 	return 0;
982*dd7b254dSGiuliano Pochini }
983*dd7b254dSGiuliano Pochini 
984*dd7b254dSGiuliano Pochini static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
985*dd7b254dSGiuliano Pochini 				    struct snd_ctl_elem_value *ucontrol)
986*dd7b254dSGiuliano Pochini {
987*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
988*dd7b254dSGiuliano Pochini 	int c, changed, gain;
989*dd7b254dSGiuliano Pochini 
990*dd7b254dSGiuliano Pochini 	changed = 0;
991*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
992*dd7b254dSGiuliano Pochini 	spin_lock_irq(&chip->lock);
993*dd7b254dSGiuliano Pochini 	for (c = 0; c < num_busses_out(chip); c++) {
994*dd7b254dSGiuliano Pochini 		gain = ucontrol->value.integer.value[c];
995*dd7b254dSGiuliano Pochini 		/* Ignore out of range values */
996*dd7b254dSGiuliano Pochini 		if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
997*dd7b254dSGiuliano Pochini 			continue;
998*dd7b254dSGiuliano Pochini 		if (chip->output_gain[c] != gain) {
999*dd7b254dSGiuliano Pochini 			set_output_gain(chip, c, gain);
1000*dd7b254dSGiuliano Pochini 			changed = 1;
1001*dd7b254dSGiuliano Pochini 		}
1002*dd7b254dSGiuliano Pochini 	}
1003*dd7b254dSGiuliano Pochini 	if (changed)
1004*dd7b254dSGiuliano Pochini 		update_output_line_level(chip);
1005*dd7b254dSGiuliano Pochini 	spin_unlock_irq(&chip->lock);
1006*dd7b254dSGiuliano Pochini 	return changed;
1007*dd7b254dSGiuliano Pochini }
1008*dd7b254dSGiuliano Pochini 
1009*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_VMIXER
1010*dd7b254dSGiuliano Pochini /* On Vmixer cards this one controls the line-out volume */
1011*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = {
1012*dd7b254dSGiuliano Pochini 	.name = "Line Playback Volume",
1013*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1014*dd7b254dSGiuliano Pochini 	.info = snd_echo_output_gain_info,
1015*dd7b254dSGiuliano Pochini 	.get = snd_echo_output_gain_get,
1016*dd7b254dSGiuliano Pochini 	.put = snd_echo_output_gain_put,
1017*dd7b254dSGiuliano Pochini };
1018*dd7b254dSGiuliano Pochini #else
1019*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
1020*dd7b254dSGiuliano Pochini 	.name = "PCM Playback Volume",
1021*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1022*dd7b254dSGiuliano Pochini 	.info = snd_echo_output_gain_info,
1023*dd7b254dSGiuliano Pochini 	.get = snd_echo_output_gain_get,
1024*dd7b254dSGiuliano Pochini 	.put = snd_echo_output_gain_put,
1025*dd7b254dSGiuliano Pochini };
1026*dd7b254dSGiuliano Pochini #endif
1027*dd7b254dSGiuliano Pochini 
1028*dd7b254dSGiuliano Pochini 
1029*dd7b254dSGiuliano Pochini 
1030*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_INPUT_GAIN
1031*dd7b254dSGiuliano Pochini 
1032*dd7b254dSGiuliano Pochini /******************* Analog input volume *******************/
1033*dd7b254dSGiuliano Pochini static int snd_echo_input_gain_info(struct snd_kcontrol *kcontrol,
1034*dd7b254dSGiuliano Pochini 				    struct snd_ctl_elem_info *uinfo)
1035*dd7b254dSGiuliano Pochini {
1036*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1037*dd7b254dSGiuliano Pochini 
1038*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1039*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1040*dd7b254dSGiuliano Pochini 	uinfo->count = num_analog_busses_in(chip);
1041*dd7b254dSGiuliano Pochini 	uinfo->value.integer.min = ECHOGAIN_MININP;
1042*dd7b254dSGiuliano Pochini 	uinfo->value.integer.max = ECHOGAIN_MAXINP;
1043*dd7b254dSGiuliano Pochini 	return 0;
1044*dd7b254dSGiuliano Pochini }
1045*dd7b254dSGiuliano Pochini 
1046*dd7b254dSGiuliano Pochini static int snd_echo_input_gain_get(struct snd_kcontrol *kcontrol,
1047*dd7b254dSGiuliano Pochini 				   struct snd_ctl_elem_value *ucontrol)
1048*dd7b254dSGiuliano Pochini {
1049*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1050*dd7b254dSGiuliano Pochini 	int c;
1051*dd7b254dSGiuliano Pochini 
1052*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1053*dd7b254dSGiuliano Pochini 	for (c = 0; c < num_analog_busses_in(chip); c++)
1054*dd7b254dSGiuliano Pochini 		ucontrol->value.integer.value[c] = chip->input_gain[c];
1055*dd7b254dSGiuliano Pochini 	return 0;
1056*dd7b254dSGiuliano Pochini }
1057*dd7b254dSGiuliano Pochini 
1058*dd7b254dSGiuliano Pochini static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
1059*dd7b254dSGiuliano Pochini 				   struct snd_ctl_elem_value *ucontrol)
1060*dd7b254dSGiuliano Pochini {
1061*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1062*dd7b254dSGiuliano Pochini 	int c, gain, changed;
1063*dd7b254dSGiuliano Pochini 
1064*dd7b254dSGiuliano Pochini 	changed = 0;
1065*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1066*dd7b254dSGiuliano Pochini 	spin_lock_irq(&chip->lock);
1067*dd7b254dSGiuliano Pochini 	for (c = 0; c < num_analog_busses_in(chip); c++) {
1068*dd7b254dSGiuliano Pochini 		gain = ucontrol->value.integer.value[c];
1069*dd7b254dSGiuliano Pochini 		/* Ignore out of range values */
1070*dd7b254dSGiuliano Pochini 		if (gain < ECHOGAIN_MININP || gain > ECHOGAIN_MAXINP)
1071*dd7b254dSGiuliano Pochini 			continue;
1072*dd7b254dSGiuliano Pochini 		if (chip->input_gain[c] != gain) {
1073*dd7b254dSGiuliano Pochini 			set_input_gain(chip, c, gain);
1074*dd7b254dSGiuliano Pochini 			changed = 1;
1075*dd7b254dSGiuliano Pochini 		}
1076*dd7b254dSGiuliano Pochini 	}
1077*dd7b254dSGiuliano Pochini 	if (changed)
1078*dd7b254dSGiuliano Pochini 		update_input_line_level(chip);
1079*dd7b254dSGiuliano Pochini 	spin_unlock_irq(&chip->lock);
1080*dd7b254dSGiuliano Pochini 	return changed;
1081*dd7b254dSGiuliano Pochini }
1082*dd7b254dSGiuliano Pochini 
1083*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = {
1084*dd7b254dSGiuliano Pochini 	.name = "Line Capture Volume",
1085*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1086*dd7b254dSGiuliano Pochini 	.info = snd_echo_input_gain_info,
1087*dd7b254dSGiuliano Pochini 	.get = snd_echo_input_gain_get,
1088*dd7b254dSGiuliano Pochini 	.put = snd_echo_input_gain_put,
1089*dd7b254dSGiuliano Pochini };
1090*dd7b254dSGiuliano Pochini 
1091*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_INPUT_GAIN */
1092*dd7b254dSGiuliano Pochini 
1093*dd7b254dSGiuliano Pochini 
1094*dd7b254dSGiuliano Pochini 
1095*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
1096*dd7b254dSGiuliano Pochini 
1097*dd7b254dSGiuliano Pochini /************ Analog output nominal level (+4dBu / -10dBV) ***************/
1098*dd7b254dSGiuliano Pochini static int snd_echo_output_nominal_info (struct snd_kcontrol *kcontrol,
1099*dd7b254dSGiuliano Pochini 					 struct snd_ctl_elem_info *uinfo)
1100*dd7b254dSGiuliano Pochini {
1101*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1102*dd7b254dSGiuliano Pochini 
1103*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1104*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1105*dd7b254dSGiuliano Pochini 	uinfo->count = num_analog_busses_out(chip);
1106*dd7b254dSGiuliano Pochini 	uinfo->value.integer.min = 0;
1107*dd7b254dSGiuliano Pochini 	uinfo->value.integer.max = 1;
1108*dd7b254dSGiuliano Pochini 	return 0;
1109*dd7b254dSGiuliano Pochini }
1110*dd7b254dSGiuliano Pochini 
1111*dd7b254dSGiuliano Pochini static int snd_echo_output_nominal_get(struct snd_kcontrol *kcontrol,
1112*dd7b254dSGiuliano Pochini 				       struct snd_ctl_elem_value *ucontrol)
1113*dd7b254dSGiuliano Pochini {
1114*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1115*dd7b254dSGiuliano Pochini 	int c;
1116*dd7b254dSGiuliano Pochini 
1117*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1118*dd7b254dSGiuliano Pochini 	for (c = 0; c < num_analog_busses_out(chip); c++)
1119*dd7b254dSGiuliano Pochini 		ucontrol->value.integer.value[c] = chip->nominal_level[c];
1120*dd7b254dSGiuliano Pochini 	return 0;
1121*dd7b254dSGiuliano Pochini }
1122*dd7b254dSGiuliano Pochini 
1123*dd7b254dSGiuliano Pochini static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol,
1124*dd7b254dSGiuliano Pochini 				       struct snd_ctl_elem_value *ucontrol)
1125*dd7b254dSGiuliano Pochini {
1126*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1127*dd7b254dSGiuliano Pochini 	int c, changed;
1128*dd7b254dSGiuliano Pochini 
1129*dd7b254dSGiuliano Pochini 	changed = 0;
1130*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1131*dd7b254dSGiuliano Pochini 	spin_lock_irq(&chip->lock);
1132*dd7b254dSGiuliano Pochini 	for (c = 0; c < num_analog_busses_out(chip); c++) {
1133*dd7b254dSGiuliano Pochini 		if (chip->nominal_level[c] != ucontrol->value.integer.value[c]) {
1134*dd7b254dSGiuliano Pochini 			set_nominal_level(chip, c,
1135*dd7b254dSGiuliano Pochini 					  ucontrol->value.integer.value[c]);
1136*dd7b254dSGiuliano Pochini 			changed = 1;
1137*dd7b254dSGiuliano Pochini 		}
1138*dd7b254dSGiuliano Pochini 	}
1139*dd7b254dSGiuliano Pochini 	if (changed)
1140*dd7b254dSGiuliano Pochini 		update_output_line_level(chip);
1141*dd7b254dSGiuliano Pochini 	spin_unlock_irq(&chip->lock);
1142*dd7b254dSGiuliano Pochini 	return changed;
1143*dd7b254dSGiuliano Pochini }
1144*dd7b254dSGiuliano Pochini 
1145*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_output_nominal_level __devinitdata = {
1146*dd7b254dSGiuliano Pochini 	.name = "Line Playback Switch (-10dBV)",
1147*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1148*dd7b254dSGiuliano Pochini 	.info = snd_echo_output_nominal_info,
1149*dd7b254dSGiuliano Pochini 	.get = snd_echo_output_nominal_get,
1150*dd7b254dSGiuliano Pochini 	.put = snd_echo_output_nominal_put,
1151*dd7b254dSGiuliano Pochini };
1152*dd7b254dSGiuliano Pochini 
1153*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL */
1154*dd7b254dSGiuliano Pochini 
1155*dd7b254dSGiuliano Pochini 
1156*dd7b254dSGiuliano Pochini 
1157*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
1158*dd7b254dSGiuliano Pochini 
1159*dd7b254dSGiuliano Pochini /*************** Analog input nominal level (+4dBu / -10dBV) ***************/
1160*dd7b254dSGiuliano Pochini static int snd_echo_input_nominal_info(struct snd_kcontrol *kcontrol,
1161*dd7b254dSGiuliano Pochini 				       struct snd_ctl_elem_info *uinfo)
1162*dd7b254dSGiuliano Pochini {
1163*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1164*dd7b254dSGiuliano Pochini 
1165*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1166*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1167*dd7b254dSGiuliano Pochini 	uinfo->count = num_analog_busses_in(chip);
1168*dd7b254dSGiuliano Pochini 	uinfo->value.integer.min = 0;
1169*dd7b254dSGiuliano Pochini 	uinfo->value.integer.max = 1;
1170*dd7b254dSGiuliano Pochini 	return 0;
1171*dd7b254dSGiuliano Pochini }
1172*dd7b254dSGiuliano Pochini 
1173*dd7b254dSGiuliano Pochini static int snd_echo_input_nominal_get(struct snd_kcontrol *kcontrol,
1174*dd7b254dSGiuliano Pochini 				      struct snd_ctl_elem_value *ucontrol)
1175*dd7b254dSGiuliano Pochini {
1176*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1177*dd7b254dSGiuliano Pochini 	int c;
1178*dd7b254dSGiuliano Pochini 
1179*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1180*dd7b254dSGiuliano Pochini 	for (c = 0; c < num_analog_busses_in(chip); c++)
1181*dd7b254dSGiuliano Pochini 		ucontrol->value.integer.value[c] =
1182*dd7b254dSGiuliano Pochini 			chip->nominal_level[bx_analog_in(chip) + c];
1183*dd7b254dSGiuliano Pochini 	return 0;
1184*dd7b254dSGiuliano Pochini }
1185*dd7b254dSGiuliano Pochini 
1186*dd7b254dSGiuliano Pochini static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol,
1187*dd7b254dSGiuliano Pochini 				      struct snd_ctl_elem_value *ucontrol)
1188*dd7b254dSGiuliano Pochini {
1189*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1190*dd7b254dSGiuliano Pochini 	int c, changed;
1191*dd7b254dSGiuliano Pochini 
1192*dd7b254dSGiuliano Pochini 	changed = 0;
1193*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1194*dd7b254dSGiuliano Pochini 	spin_lock_irq(&chip->lock);
1195*dd7b254dSGiuliano Pochini 	for (c = 0; c < num_analog_busses_in(chip); c++) {
1196*dd7b254dSGiuliano Pochini 		if (chip->nominal_level[bx_analog_in(chip) + c] !=
1197*dd7b254dSGiuliano Pochini 		    ucontrol->value.integer.value[c]) {
1198*dd7b254dSGiuliano Pochini 			set_nominal_level(chip, bx_analog_in(chip) + c,
1199*dd7b254dSGiuliano Pochini 					  ucontrol->value.integer.value[c]);
1200*dd7b254dSGiuliano Pochini 			changed = 1;
1201*dd7b254dSGiuliano Pochini 		}
1202*dd7b254dSGiuliano Pochini 	}
1203*dd7b254dSGiuliano Pochini 	if (changed)
1204*dd7b254dSGiuliano Pochini 		update_output_line_level(chip);	/* "Output" is not a mistake
1205*dd7b254dSGiuliano Pochini 						 * here.
1206*dd7b254dSGiuliano Pochini 						 */
1207*dd7b254dSGiuliano Pochini 	spin_unlock_irq(&chip->lock);
1208*dd7b254dSGiuliano Pochini 	return changed;
1209*dd7b254dSGiuliano Pochini }
1210*dd7b254dSGiuliano Pochini 
1211*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_intput_nominal_level __devinitdata = {
1212*dd7b254dSGiuliano Pochini 	.name = "Line Capture Switch (-10dBV)",
1213*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1214*dd7b254dSGiuliano Pochini 	.info = snd_echo_input_nominal_info,
1215*dd7b254dSGiuliano Pochini 	.get = snd_echo_input_nominal_get,
1216*dd7b254dSGiuliano Pochini 	.put = snd_echo_input_nominal_put,
1217*dd7b254dSGiuliano Pochini };
1218*dd7b254dSGiuliano Pochini 
1219*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_INPUT_NOMINAL_LEVEL */
1220*dd7b254dSGiuliano Pochini 
1221*dd7b254dSGiuliano Pochini 
1222*dd7b254dSGiuliano Pochini 
1223*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_MONITOR
1224*dd7b254dSGiuliano Pochini 
1225*dd7b254dSGiuliano Pochini /******************* Monitor mixer *******************/
1226*dd7b254dSGiuliano Pochini static int snd_echo_mixer_info(struct snd_kcontrol *kcontrol,
1227*dd7b254dSGiuliano Pochini 			       struct snd_ctl_elem_info *uinfo)
1228*dd7b254dSGiuliano Pochini {
1229*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1230*dd7b254dSGiuliano Pochini 
1231*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1232*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1233*dd7b254dSGiuliano Pochini 	uinfo->count = 1;
1234*dd7b254dSGiuliano Pochini 	uinfo->value.integer.min = ECHOGAIN_MINOUT;
1235*dd7b254dSGiuliano Pochini 	uinfo->value.integer.max = ECHOGAIN_MAXOUT;
1236*dd7b254dSGiuliano Pochini 	uinfo->dimen.d[0] = num_busses_out(chip);
1237*dd7b254dSGiuliano Pochini 	uinfo->dimen.d[1] = num_busses_in(chip);
1238*dd7b254dSGiuliano Pochini 	return 0;
1239*dd7b254dSGiuliano Pochini }
1240*dd7b254dSGiuliano Pochini 
1241*dd7b254dSGiuliano Pochini static int snd_echo_mixer_get(struct snd_kcontrol *kcontrol,
1242*dd7b254dSGiuliano Pochini 			      struct snd_ctl_elem_value *ucontrol)
1243*dd7b254dSGiuliano Pochini {
1244*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1245*dd7b254dSGiuliano Pochini 
1246*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1247*dd7b254dSGiuliano Pochini 	ucontrol->value.integer.value[0] =
1248*dd7b254dSGiuliano Pochini 		chip->monitor_gain[ucontrol->id.index / num_busses_in(chip)]
1249*dd7b254dSGiuliano Pochini 			[ucontrol->id.index % num_busses_in(chip)];
1250*dd7b254dSGiuliano Pochini 	return 0;
1251*dd7b254dSGiuliano Pochini }
1252*dd7b254dSGiuliano Pochini 
1253*dd7b254dSGiuliano Pochini static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol,
1254*dd7b254dSGiuliano Pochini 			      struct snd_ctl_elem_value *ucontrol)
1255*dd7b254dSGiuliano Pochini {
1256*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1257*dd7b254dSGiuliano Pochini 	int changed,  gain;
1258*dd7b254dSGiuliano Pochini 	short out, in;
1259*dd7b254dSGiuliano Pochini 
1260*dd7b254dSGiuliano Pochini 	changed = 0;
1261*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1262*dd7b254dSGiuliano Pochini 	out = ucontrol->id.index / num_busses_in(chip);
1263*dd7b254dSGiuliano Pochini 	in = ucontrol->id.index % num_busses_in(chip);
1264*dd7b254dSGiuliano Pochini 	gain = ucontrol->value.integer.value[0];
1265*dd7b254dSGiuliano Pochini 	if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
1266*dd7b254dSGiuliano Pochini 		return -EINVAL;
1267*dd7b254dSGiuliano Pochini 	if (chip->monitor_gain[out][in] != gain) {
1268*dd7b254dSGiuliano Pochini 		spin_lock_irq(&chip->lock);
1269*dd7b254dSGiuliano Pochini 		set_monitor_gain(chip, out, in, gain);
1270*dd7b254dSGiuliano Pochini 		update_output_line_level(chip);
1271*dd7b254dSGiuliano Pochini 		spin_unlock_irq(&chip->lock);
1272*dd7b254dSGiuliano Pochini 		changed = 1;
1273*dd7b254dSGiuliano Pochini 	}
1274*dd7b254dSGiuliano Pochini 	return changed;
1275*dd7b254dSGiuliano Pochini }
1276*dd7b254dSGiuliano Pochini 
1277*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = {
1278*dd7b254dSGiuliano Pochini 	.name = "Monitor Mixer Volume",
1279*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1280*dd7b254dSGiuliano Pochini 	.info = snd_echo_mixer_info,
1281*dd7b254dSGiuliano Pochini 	.get = snd_echo_mixer_get,
1282*dd7b254dSGiuliano Pochini 	.put = snd_echo_mixer_put,
1283*dd7b254dSGiuliano Pochini };
1284*dd7b254dSGiuliano Pochini 
1285*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_MONITOR */
1286*dd7b254dSGiuliano Pochini 
1287*dd7b254dSGiuliano Pochini 
1288*dd7b254dSGiuliano Pochini 
1289*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_VMIXER
1290*dd7b254dSGiuliano Pochini 
1291*dd7b254dSGiuliano Pochini /******************* Vmixer *******************/
1292*dd7b254dSGiuliano Pochini static int snd_echo_vmixer_info(struct snd_kcontrol *kcontrol,
1293*dd7b254dSGiuliano Pochini 				struct snd_ctl_elem_info *uinfo)
1294*dd7b254dSGiuliano Pochini {
1295*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1296*dd7b254dSGiuliano Pochini 
1297*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1298*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1299*dd7b254dSGiuliano Pochini 	uinfo->count = 1;
1300*dd7b254dSGiuliano Pochini 	uinfo->value.integer.min = ECHOGAIN_MINOUT;
1301*dd7b254dSGiuliano Pochini 	uinfo->value.integer.max = ECHOGAIN_MAXOUT;
1302*dd7b254dSGiuliano Pochini 	uinfo->dimen.d[0] = num_busses_out(chip);
1303*dd7b254dSGiuliano Pochini 	uinfo->dimen.d[1] = num_pipes_out(chip);
1304*dd7b254dSGiuliano Pochini 	return 0;
1305*dd7b254dSGiuliano Pochini }
1306*dd7b254dSGiuliano Pochini 
1307*dd7b254dSGiuliano Pochini static int snd_echo_vmixer_get(struct snd_kcontrol *kcontrol,
1308*dd7b254dSGiuliano Pochini 			       struct snd_ctl_elem_value *ucontrol)
1309*dd7b254dSGiuliano Pochini {
1310*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1311*dd7b254dSGiuliano Pochini 
1312*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1313*dd7b254dSGiuliano Pochini 	ucontrol->value.integer.value[0] =
1314*dd7b254dSGiuliano Pochini 		chip->vmixer_gain[ucontrol->id.index / num_pipes_out(chip)]
1315*dd7b254dSGiuliano Pochini 			[ucontrol->id.index % num_pipes_out(chip)];
1316*dd7b254dSGiuliano Pochini 	return 0;
1317*dd7b254dSGiuliano Pochini }
1318*dd7b254dSGiuliano Pochini 
1319*dd7b254dSGiuliano Pochini static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol,
1320*dd7b254dSGiuliano Pochini 			       struct snd_ctl_elem_value *ucontrol)
1321*dd7b254dSGiuliano Pochini {
1322*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1323*dd7b254dSGiuliano Pochini 	int gain, changed;
1324*dd7b254dSGiuliano Pochini 	short vch, out;
1325*dd7b254dSGiuliano Pochini 
1326*dd7b254dSGiuliano Pochini 	changed = 0;
1327*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1328*dd7b254dSGiuliano Pochini 	out = ucontrol->id.index / num_pipes_out(chip);
1329*dd7b254dSGiuliano Pochini 	vch = ucontrol->id.index % num_pipes_out(chip);
1330*dd7b254dSGiuliano Pochini 	gain = ucontrol->value.integer.value[0];
1331*dd7b254dSGiuliano Pochini 	if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT)
1332*dd7b254dSGiuliano Pochini 		return -EINVAL;
1333*dd7b254dSGiuliano Pochini 	if (chip->vmixer_gain[out][vch] != ucontrol->value.integer.value[0]) {
1334*dd7b254dSGiuliano Pochini 		spin_lock_irq(&chip->lock);
1335*dd7b254dSGiuliano Pochini 		set_vmixer_gain(chip, out, vch, ucontrol->value.integer.value[0]);
1336*dd7b254dSGiuliano Pochini 		update_vmixer_level(chip);
1337*dd7b254dSGiuliano Pochini 		spin_unlock_irq(&chip->lock);
1338*dd7b254dSGiuliano Pochini 		changed = 1;
1339*dd7b254dSGiuliano Pochini 	}
1340*dd7b254dSGiuliano Pochini 	return changed;
1341*dd7b254dSGiuliano Pochini }
1342*dd7b254dSGiuliano Pochini 
1343*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = {
1344*dd7b254dSGiuliano Pochini 	.name = "VMixer Volume",
1345*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1346*dd7b254dSGiuliano Pochini 	.info = snd_echo_vmixer_info,
1347*dd7b254dSGiuliano Pochini 	.get = snd_echo_vmixer_get,
1348*dd7b254dSGiuliano Pochini 	.put = snd_echo_vmixer_put,
1349*dd7b254dSGiuliano Pochini };
1350*dd7b254dSGiuliano Pochini 
1351*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_VMIXER */
1352*dd7b254dSGiuliano Pochini 
1353*dd7b254dSGiuliano Pochini 
1354*dd7b254dSGiuliano Pochini 
1355*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH
1356*dd7b254dSGiuliano Pochini 
1357*dd7b254dSGiuliano Pochini /******************* Digital mode switch *******************/
1358*dd7b254dSGiuliano Pochini static int snd_echo_digital_mode_info(struct snd_kcontrol *kcontrol,
1359*dd7b254dSGiuliano Pochini 				      struct snd_ctl_elem_info *uinfo)
1360*dd7b254dSGiuliano Pochini {
1361*dd7b254dSGiuliano Pochini 	static char *names[4] = {
1362*dd7b254dSGiuliano Pochini 		"S/PDIF Coaxial", "S/PDIF Optical", "ADAT Optical",
1363*dd7b254dSGiuliano Pochini 		"S/PDIF Cdrom"
1364*dd7b254dSGiuliano Pochini 	};
1365*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1366*dd7b254dSGiuliano Pochini 
1367*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1368*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1369*dd7b254dSGiuliano Pochini 	uinfo->value.enumerated.items = chip->num_digital_modes;
1370*dd7b254dSGiuliano Pochini 	uinfo->count = 1;
1371*dd7b254dSGiuliano Pochini 	if (uinfo->value.enumerated.item >= chip->num_digital_modes)
1372*dd7b254dSGiuliano Pochini 		uinfo->value.enumerated.item = chip->num_digital_modes - 1;
1373*dd7b254dSGiuliano Pochini 	strcpy(uinfo->value.enumerated.name, names[
1374*dd7b254dSGiuliano Pochini 			chip->digital_mode_list[uinfo->value.enumerated.item]]);
1375*dd7b254dSGiuliano Pochini 	return 0;
1376*dd7b254dSGiuliano Pochini }
1377*dd7b254dSGiuliano Pochini 
1378*dd7b254dSGiuliano Pochini static int snd_echo_digital_mode_get(struct snd_kcontrol *kcontrol,
1379*dd7b254dSGiuliano Pochini 				     struct snd_ctl_elem_value *ucontrol)
1380*dd7b254dSGiuliano Pochini {
1381*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1382*dd7b254dSGiuliano Pochini 	int i, mode;
1383*dd7b254dSGiuliano Pochini 
1384*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1385*dd7b254dSGiuliano Pochini 	mode = chip->digital_mode;
1386*dd7b254dSGiuliano Pochini 	for (i = chip->num_digital_modes - 1; i >= 0; i--)
1387*dd7b254dSGiuliano Pochini 		if (mode == chip->digital_mode_list[i]) {
1388*dd7b254dSGiuliano Pochini 			ucontrol->value.enumerated.item[0] = i;
1389*dd7b254dSGiuliano Pochini 			break;
1390*dd7b254dSGiuliano Pochini 		}
1391*dd7b254dSGiuliano Pochini 	return 0;
1392*dd7b254dSGiuliano Pochini }
1393*dd7b254dSGiuliano Pochini 
1394*dd7b254dSGiuliano Pochini static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
1395*dd7b254dSGiuliano Pochini 				     struct snd_ctl_elem_value *ucontrol)
1396*dd7b254dSGiuliano Pochini {
1397*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1398*dd7b254dSGiuliano Pochini 	int changed;
1399*dd7b254dSGiuliano Pochini 	unsigned short emode, dmode;
1400*dd7b254dSGiuliano Pochini 
1401*dd7b254dSGiuliano Pochini 	changed = 0;
1402*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1403*dd7b254dSGiuliano Pochini 
1404*dd7b254dSGiuliano Pochini 	emode = ucontrol->value.enumerated.item[0];
1405*dd7b254dSGiuliano Pochini 	if (emode >= chip->num_digital_modes)
1406*dd7b254dSGiuliano Pochini 		return -EINVAL;
1407*dd7b254dSGiuliano Pochini 	dmode = chip->digital_mode_list[emode];
1408*dd7b254dSGiuliano Pochini 
1409*dd7b254dSGiuliano Pochini 	if (dmode != chip->digital_mode) {
1410*dd7b254dSGiuliano Pochini 		/* mode_mutex is required to make this operation atomic wrt
1411*dd7b254dSGiuliano Pochini 		pcm_digital_*_open() and set_input_clock() functions. */
1412*dd7b254dSGiuliano Pochini 		down(&chip->mode_mutex);
1413*dd7b254dSGiuliano Pochini 
1414*dd7b254dSGiuliano Pochini 		/* Do not allow the user to change the digital mode when a pcm
1415*dd7b254dSGiuliano Pochini 		device is open because it also changes the number of channels
1416*dd7b254dSGiuliano Pochini 		and the allowed sample rates */
1417*dd7b254dSGiuliano Pochini 		if (atomic_read(&chip->opencount)) {
1418*dd7b254dSGiuliano Pochini 			changed = -EAGAIN;
1419*dd7b254dSGiuliano Pochini 		} else {
1420*dd7b254dSGiuliano Pochini 			changed = set_digital_mode(chip, dmode);
1421*dd7b254dSGiuliano Pochini 			/* If we had to change the clock source, report it */
1422*dd7b254dSGiuliano Pochini 			if (changed > 0 && chip->clock_src_ctl) {
1423*dd7b254dSGiuliano Pochini 				snd_ctl_notify(chip->card,
1424*dd7b254dSGiuliano Pochini 					       SNDRV_CTL_EVENT_MASK_VALUE,
1425*dd7b254dSGiuliano Pochini 					       &chip->clock_src_ctl->id);
1426*dd7b254dSGiuliano Pochini 				DE_ACT(("SDM() =%d\n", changed));
1427*dd7b254dSGiuliano Pochini 			}
1428*dd7b254dSGiuliano Pochini 			if (changed >= 0)
1429*dd7b254dSGiuliano Pochini 				changed = 1;	/* No errors */
1430*dd7b254dSGiuliano Pochini 		}
1431*dd7b254dSGiuliano Pochini 		up(&chip->mode_mutex);
1432*dd7b254dSGiuliano Pochini 	}
1433*dd7b254dSGiuliano Pochini 	return changed;
1434*dd7b254dSGiuliano Pochini }
1435*dd7b254dSGiuliano Pochini 
1436*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_digital_mode_switch __devinitdata = {
1437*dd7b254dSGiuliano Pochini 	.name = "Digital mode Switch",
1438*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
1439*dd7b254dSGiuliano Pochini 	.info = snd_echo_digital_mode_info,
1440*dd7b254dSGiuliano Pochini 	.get = snd_echo_digital_mode_get,
1441*dd7b254dSGiuliano Pochini 	.put = snd_echo_digital_mode_put,
1442*dd7b254dSGiuliano Pochini };
1443*dd7b254dSGiuliano Pochini 
1444*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */
1445*dd7b254dSGiuliano Pochini 
1446*dd7b254dSGiuliano Pochini 
1447*dd7b254dSGiuliano Pochini 
1448*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_DIGITAL_IO
1449*dd7b254dSGiuliano Pochini 
1450*dd7b254dSGiuliano Pochini /******************* S/PDIF mode switch *******************/
1451*dd7b254dSGiuliano Pochini static int snd_echo_spdif_mode_info(struct snd_kcontrol *kcontrol,
1452*dd7b254dSGiuliano Pochini 				    struct snd_ctl_elem_info *uinfo)
1453*dd7b254dSGiuliano Pochini {
1454*dd7b254dSGiuliano Pochini 	static char *names[2] = {"Consumer", "Professional"};
1455*dd7b254dSGiuliano Pochini 
1456*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1457*dd7b254dSGiuliano Pochini 	uinfo->value.enumerated.items = 2;
1458*dd7b254dSGiuliano Pochini 	uinfo->count = 1;
1459*dd7b254dSGiuliano Pochini 	if (uinfo->value.enumerated.item)
1460*dd7b254dSGiuliano Pochini 		uinfo->value.enumerated.item = 1;
1461*dd7b254dSGiuliano Pochini 	strcpy(uinfo->value.enumerated.name,
1462*dd7b254dSGiuliano Pochini 	       names[uinfo->value.enumerated.item]);
1463*dd7b254dSGiuliano Pochini 	return 0;
1464*dd7b254dSGiuliano Pochini }
1465*dd7b254dSGiuliano Pochini 
1466*dd7b254dSGiuliano Pochini static int snd_echo_spdif_mode_get(struct snd_kcontrol *kcontrol,
1467*dd7b254dSGiuliano Pochini 				   struct snd_ctl_elem_value *ucontrol)
1468*dd7b254dSGiuliano Pochini {
1469*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1470*dd7b254dSGiuliano Pochini 
1471*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1472*dd7b254dSGiuliano Pochini 	ucontrol->value.enumerated.item[0] = !!chip->professional_spdif;
1473*dd7b254dSGiuliano Pochini 	return 0;
1474*dd7b254dSGiuliano Pochini }
1475*dd7b254dSGiuliano Pochini 
1476*dd7b254dSGiuliano Pochini static int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol,
1477*dd7b254dSGiuliano Pochini 				   struct snd_ctl_elem_value *ucontrol)
1478*dd7b254dSGiuliano Pochini {
1479*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1480*dd7b254dSGiuliano Pochini 	int mode;
1481*dd7b254dSGiuliano Pochini 
1482*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1483*dd7b254dSGiuliano Pochini 	mode = !!ucontrol->value.enumerated.item[0];
1484*dd7b254dSGiuliano Pochini 	if (mode != chip->professional_spdif) {
1485*dd7b254dSGiuliano Pochini 		spin_lock_irq(&chip->lock);
1486*dd7b254dSGiuliano Pochini 		set_professional_spdif(chip, mode);
1487*dd7b254dSGiuliano Pochini 		spin_unlock_irq(&chip->lock);
1488*dd7b254dSGiuliano Pochini 		return 1;
1489*dd7b254dSGiuliano Pochini 	}
1490*dd7b254dSGiuliano Pochini 	return 0;
1491*dd7b254dSGiuliano Pochini }
1492*dd7b254dSGiuliano Pochini 
1493*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_spdif_mode_switch __devinitdata = {
1494*dd7b254dSGiuliano Pochini 	.name = "S/PDIF mode Switch",
1495*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
1496*dd7b254dSGiuliano Pochini 	.info = snd_echo_spdif_mode_info,
1497*dd7b254dSGiuliano Pochini 	.get = snd_echo_spdif_mode_get,
1498*dd7b254dSGiuliano Pochini 	.put = snd_echo_spdif_mode_put,
1499*dd7b254dSGiuliano Pochini };
1500*dd7b254dSGiuliano Pochini 
1501*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_DIGITAL_IO */
1502*dd7b254dSGiuliano Pochini 
1503*dd7b254dSGiuliano Pochini 
1504*dd7b254dSGiuliano Pochini 
1505*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
1506*dd7b254dSGiuliano Pochini 
1507*dd7b254dSGiuliano Pochini /******************* Select input clock source *******************/
1508*dd7b254dSGiuliano Pochini static int snd_echo_clock_source_info(struct snd_kcontrol *kcontrol,
1509*dd7b254dSGiuliano Pochini 				      struct snd_ctl_elem_info *uinfo)
1510*dd7b254dSGiuliano Pochini {
1511*dd7b254dSGiuliano Pochini 	static char *names[8] = {
1512*dd7b254dSGiuliano Pochini 		"Internal", "Word", "Super", "S/PDIF", "ADAT", "ESync",
1513*dd7b254dSGiuliano Pochini 		"ESync96", "MTC"
1514*dd7b254dSGiuliano Pochini 	};
1515*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1516*dd7b254dSGiuliano Pochini 
1517*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1518*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1519*dd7b254dSGiuliano Pochini 	uinfo->value.enumerated.items = chip->num_clock_sources;
1520*dd7b254dSGiuliano Pochini 	uinfo->count = 1;
1521*dd7b254dSGiuliano Pochini 	if (uinfo->value.enumerated.item >= chip->num_clock_sources)
1522*dd7b254dSGiuliano Pochini 		uinfo->value.enumerated.item = chip->num_clock_sources - 1;
1523*dd7b254dSGiuliano Pochini 	strcpy(uinfo->value.enumerated.name, names[
1524*dd7b254dSGiuliano Pochini 			chip->clock_source_list[uinfo->value.enumerated.item]]);
1525*dd7b254dSGiuliano Pochini 	return 0;
1526*dd7b254dSGiuliano Pochini }
1527*dd7b254dSGiuliano Pochini 
1528*dd7b254dSGiuliano Pochini static int snd_echo_clock_source_get(struct snd_kcontrol *kcontrol,
1529*dd7b254dSGiuliano Pochini 				     struct snd_ctl_elem_value *ucontrol)
1530*dd7b254dSGiuliano Pochini {
1531*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1532*dd7b254dSGiuliano Pochini 	int i, clock;
1533*dd7b254dSGiuliano Pochini 
1534*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1535*dd7b254dSGiuliano Pochini 	clock = chip->input_clock;
1536*dd7b254dSGiuliano Pochini 
1537*dd7b254dSGiuliano Pochini 	for (i = 0; i < chip->num_clock_sources; i++)
1538*dd7b254dSGiuliano Pochini 		if (clock == chip->clock_source_list[i])
1539*dd7b254dSGiuliano Pochini 			ucontrol->value.enumerated.item[0] = i;
1540*dd7b254dSGiuliano Pochini 
1541*dd7b254dSGiuliano Pochini 	return 0;
1542*dd7b254dSGiuliano Pochini }
1543*dd7b254dSGiuliano Pochini 
1544*dd7b254dSGiuliano Pochini static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol,
1545*dd7b254dSGiuliano Pochini 				     struct snd_ctl_elem_value *ucontrol)
1546*dd7b254dSGiuliano Pochini {
1547*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1548*dd7b254dSGiuliano Pochini 	int changed;
1549*dd7b254dSGiuliano Pochini 	unsigned int eclock, dclock;
1550*dd7b254dSGiuliano Pochini 
1551*dd7b254dSGiuliano Pochini 	changed = 0;
1552*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1553*dd7b254dSGiuliano Pochini 	eclock = ucontrol->value.enumerated.item[0];
1554*dd7b254dSGiuliano Pochini 	if (eclock >= chip->input_clock_types)
1555*dd7b254dSGiuliano Pochini 		return -EINVAL;
1556*dd7b254dSGiuliano Pochini 	dclock = chip->clock_source_list[eclock];
1557*dd7b254dSGiuliano Pochini 	if (chip->input_clock != dclock) {
1558*dd7b254dSGiuliano Pochini 		down(&chip->mode_mutex);
1559*dd7b254dSGiuliano Pochini 		spin_lock_irq(&chip->lock);
1560*dd7b254dSGiuliano Pochini 		if ((changed = set_input_clock(chip, dclock)) == 0)
1561*dd7b254dSGiuliano Pochini 			changed = 1;	/* no errors */
1562*dd7b254dSGiuliano Pochini 		spin_unlock_irq(&chip->lock);
1563*dd7b254dSGiuliano Pochini 		up(&chip->mode_mutex);
1564*dd7b254dSGiuliano Pochini 	}
1565*dd7b254dSGiuliano Pochini 
1566*dd7b254dSGiuliano Pochini 	if (changed < 0)
1567*dd7b254dSGiuliano Pochini 		DE_ACT(("seticlk val%d err 0x%x\n", dclock, changed));
1568*dd7b254dSGiuliano Pochini 
1569*dd7b254dSGiuliano Pochini 	return changed;
1570*dd7b254dSGiuliano Pochini }
1571*dd7b254dSGiuliano Pochini 
1572*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_clock_source_switch __devinitdata = {
1573*dd7b254dSGiuliano Pochini 	.name = "Sample Clock Source",
1574*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
1575*dd7b254dSGiuliano Pochini 	.info = snd_echo_clock_source_info,
1576*dd7b254dSGiuliano Pochini 	.get = snd_echo_clock_source_get,
1577*dd7b254dSGiuliano Pochini 	.put = snd_echo_clock_source_put,
1578*dd7b254dSGiuliano Pochini };
1579*dd7b254dSGiuliano Pochini 
1580*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */
1581*dd7b254dSGiuliano Pochini 
1582*dd7b254dSGiuliano Pochini 
1583*dd7b254dSGiuliano Pochini 
1584*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_PHANTOM_POWER
1585*dd7b254dSGiuliano Pochini 
1586*dd7b254dSGiuliano Pochini /******************* Phantom power switch *******************/
1587*dd7b254dSGiuliano Pochini static int snd_echo_phantom_power_info(struct snd_kcontrol *kcontrol,
1588*dd7b254dSGiuliano Pochini 				       struct snd_ctl_elem_info *uinfo)
1589*dd7b254dSGiuliano Pochini {
1590*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1591*dd7b254dSGiuliano Pochini 	uinfo->count = 1;
1592*dd7b254dSGiuliano Pochini 	uinfo->value.integer.min = 0;
1593*dd7b254dSGiuliano Pochini 	uinfo->value.integer.max = 1;
1594*dd7b254dSGiuliano Pochini 	return 0;
1595*dd7b254dSGiuliano Pochini }
1596*dd7b254dSGiuliano Pochini 
1597*dd7b254dSGiuliano Pochini static int snd_echo_phantom_power_get(struct snd_kcontrol *kcontrol,
1598*dd7b254dSGiuliano Pochini 				      struct snd_ctl_elem_value *ucontrol)
1599*dd7b254dSGiuliano Pochini {
1600*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
1601*dd7b254dSGiuliano Pochini 
1602*dd7b254dSGiuliano Pochini 	ucontrol->value.integer.value[0] = chip->phantom_power;
1603*dd7b254dSGiuliano Pochini 	return 0;
1604*dd7b254dSGiuliano Pochini }
1605*dd7b254dSGiuliano Pochini 
1606*dd7b254dSGiuliano Pochini static int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol,
1607*dd7b254dSGiuliano Pochini 				      struct snd_ctl_elem_value *ucontrol)
1608*dd7b254dSGiuliano Pochini {
1609*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
1610*dd7b254dSGiuliano Pochini 	int power, changed = 0;
1611*dd7b254dSGiuliano Pochini 
1612*dd7b254dSGiuliano Pochini 	power = !!ucontrol->value.integer.value[0];
1613*dd7b254dSGiuliano Pochini 	if (chip->phantom_power != power) {
1614*dd7b254dSGiuliano Pochini 		spin_lock_irq(&chip->lock);
1615*dd7b254dSGiuliano Pochini 		changed = set_phantom_power(chip, power);
1616*dd7b254dSGiuliano Pochini 		spin_unlock_irq(&chip->lock);
1617*dd7b254dSGiuliano Pochini 		if (changed == 0)
1618*dd7b254dSGiuliano Pochini 			changed = 1;	/* no errors */
1619*dd7b254dSGiuliano Pochini 	}
1620*dd7b254dSGiuliano Pochini 	return changed;
1621*dd7b254dSGiuliano Pochini }
1622*dd7b254dSGiuliano Pochini 
1623*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_phantom_power_switch __devinitdata = {
1624*dd7b254dSGiuliano Pochini 	.name = "Phantom power Switch",
1625*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
1626*dd7b254dSGiuliano Pochini 	.info = snd_echo_phantom_power_info,
1627*dd7b254dSGiuliano Pochini 	.get = snd_echo_phantom_power_get,
1628*dd7b254dSGiuliano Pochini 	.put = snd_echo_phantom_power_put,
1629*dd7b254dSGiuliano Pochini };
1630*dd7b254dSGiuliano Pochini 
1631*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_PHANTOM_POWER */
1632*dd7b254dSGiuliano Pochini 
1633*dd7b254dSGiuliano Pochini 
1634*dd7b254dSGiuliano Pochini 
1635*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
1636*dd7b254dSGiuliano Pochini 
1637*dd7b254dSGiuliano Pochini /******************* Digital input automute switch *******************/
1638*dd7b254dSGiuliano Pochini static int snd_echo_automute_info(struct snd_kcontrol *kcontrol,
1639*dd7b254dSGiuliano Pochini 				  struct snd_ctl_elem_info *uinfo)
1640*dd7b254dSGiuliano Pochini {
1641*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1642*dd7b254dSGiuliano Pochini 	uinfo->count = 1;
1643*dd7b254dSGiuliano Pochini 	uinfo->value.integer.min = 0;
1644*dd7b254dSGiuliano Pochini 	uinfo->value.integer.max = 1;
1645*dd7b254dSGiuliano Pochini 	return 0;
1646*dd7b254dSGiuliano Pochini }
1647*dd7b254dSGiuliano Pochini 
1648*dd7b254dSGiuliano Pochini static int snd_echo_automute_get(struct snd_kcontrol *kcontrol,
1649*dd7b254dSGiuliano Pochini 				 struct snd_ctl_elem_value *ucontrol)
1650*dd7b254dSGiuliano Pochini {
1651*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
1652*dd7b254dSGiuliano Pochini 
1653*dd7b254dSGiuliano Pochini 	ucontrol->value.integer.value[0] = chip->digital_in_automute;
1654*dd7b254dSGiuliano Pochini 	return 0;
1655*dd7b254dSGiuliano Pochini }
1656*dd7b254dSGiuliano Pochini 
1657*dd7b254dSGiuliano Pochini static int snd_echo_automute_put(struct snd_kcontrol *kcontrol,
1658*dd7b254dSGiuliano Pochini 				 struct snd_ctl_elem_value *ucontrol)
1659*dd7b254dSGiuliano Pochini {
1660*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = snd_kcontrol_chip(kcontrol);
1661*dd7b254dSGiuliano Pochini 	int automute, changed = 0;
1662*dd7b254dSGiuliano Pochini 
1663*dd7b254dSGiuliano Pochini 	automute = !!ucontrol->value.integer.value[0];
1664*dd7b254dSGiuliano Pochini 	if (chip->digital_in_automute != automute) {
1665*dd7b254dSGiuliano Pochini 		spin_lock_irq(&chip->lock);
1666*dd7b254dSGiuliano Pochini 		changed = set_input_auto_mute(chip, automute);
1667*dd7b254dSGiuliano Pochini 		spin_unlock_irq(&chip->lock);
1668*dd7b254dSGiuliano Pochini 		if (changed == 0)
1669*dd7b254dSGiuliano Pochini 			changed = 1;	/* no errors */
1670*dd7b254dSGiuliano Pochini 	}
1671*dd7b254dSGiuliano Pochini 	return changed;
1672*dd7b254dSGiuliano Pochini }
1673*dd7b254dSGiuliano Pochini 
1674*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_automute_switch __devinitdata = {
1675*dd7b254dSGiuliano Pochini 	.name = "Digital Capture Switch (automute)",
1676*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
1677*dd7b254dSGiuliano Pochini 	.info = snd_echo_automute_info,
1678*dd7b254dSGiuliano Pochini 	.get = snd_echo_automute_get,
1679*dd7b254dSGiuliano Pochini 	.put = snd_echo_automute_put,
1680*dd7b254dSGiuliano Pochini };
1681*dd7b254dSGiuliano Pochini 
1682*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE */
1683*dd7b254dSGiuliano Pochini 
1684*dd7b254dSGiuliano Pochini 
1685*dd7b254dSGiuliano Pochini 
1686*dd7b254dSGiuliano Pochini /******************* VU-meters switch *******************/
1687*dd7b254dSGiuliano Pochini static int snd_echo_vumeters_switch_info(struct snd_kcontrol *kcontrol,
1688*dd7b254dSGiuliano Pochini 					 struct snd_ctl_elem_info *uinfo)
1689*dd7b254dSGiuliano Pochini {
1690*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1691*dd7b254dSGiuliano Pochini 
1692*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1693*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1694*dd7b254dSGiuliano Pochini 	uinfo->count = 1;
1695*dd7b254dSGiuliano Pochini 	uinfo->value.integer.min = 0;
1696*dd7b254dSGiuliano Pochini 	uinfo->value.integer.max = 1;
1697*dd7b254dSGiuliano Pochini 	return 0;
1698*dd7b254dSGiuliano Pochini }
1699*dd7b254dSGiuliano Pochini 
1700*dd7b254dSGiuliano Pochini static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol,
1701*dd7b254dSGiuliano Pochini 					struct snd_ctl_elem_value *ucontrol)
1702*dd7b254dSGiuliano Pochini {
1703*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1704*dd7b254dSGiuliano Pochini 
1705*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1706*dd7b254dSGiuliano Pochini 	spin_lock_irq(&chip->lock);
1707*dd7b254dSGiuliano Pochini 	set_meters_on(chip, ucontrol->value.integer.value[0]);
1708*dd7b254dSGiuliano Pochini 	spin_unlock_irq(&chip->lock);
1709*dd7b254dSGiuliano Pochini 	return 1;
1710*dd7b254dSGiuliano Pochini }
1711*dd7b254dSGiuliano Pochini 
1712*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_vumeters_switch __devinitdata = {
1713*dd7b254dSGiuliano Pochini 	.name = "VU-meters Switch",
1714*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
1715*dd7b254dSGiuliano Pochini 	.access = SNDRV_CTL_ELEM_ACCESS_WRITE,
1716*dd7b254dSGiuliano Pochini 	.info = snd_echo_vumeters_switch_info,
1717*dd7b254dSGiuliano Pochini 	.put = snd_echo_vumeters_switch_put,
1718*dd7b254dSGiuliano Pochini };
1719*dd7b254dSGiuliano Pochini 
1720*dd7b254dSGiuliano Pochini 
1721*dd7b254dSGiuliano Pochini 
1722*dd7b254dSGiuliano Pochini /***** Read VU-meters (input, output, analog and digital together) *****/
1723*dd7b254dSGiuliano Pochini static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol,
1724*dd7b254dSGiuliano Pochini 				  struct snd_ctl_elem_info *uinfo)
1725*dd7b254dSGiuliano Pochini {
1726*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1727*dd7b254dSGiuliano Pochini 
1728*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1729*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1730*dd7b254dSGiuliano Pochini 	uinfo->count = 96;
1731*dd7b254dSGiuliano Pochini 	uinfo->value.integer.min = ECHOGAIN_MINOUT;
1732*dd7b254dSGiuliano Pochini 	uinfo->value.integer.max = 0;
1733*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_VMIXER
1734*dd7b254dSGiuliano Pochini 	uinfo->dimen.d[0] = 3;	/* Out, In, Virt */
1735*dd7b254dSGiuliano Pochini #else
1736*dd7b254dSGiuliano Pochini 	uinfo->dimen.d[0] = 2;	/* Out, In */
1737*dd7b254dSGiuliano Pochini #endif
1738*dd7b254dSGiuliano Pochini 	uinfo->dimen.d[1] = 16;	/* 16 channels */
1739*dd7b254dSGiuliano Pochini 	uinfo->dimen.d[2] = 2;	/* 0=level, 1=peak */
1740*dd7b254dSGiuliano Pochini 	return 0;
1741*dd7b254dSGiuliano Pochini }
1742*dd7b254dSGiuliano Pochini 
1743*dd7b254dSGiuliano Pochini static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol,
1744*dd7b254dSGiuliano Pochini 				 struct snd_ctl_elem_value *ucontrol)
1745*dd7b254dSGiuliano Pochini {
1746*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1747*dd7b254dSGiuliano Pochini 
1748*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1749*dd7b254dSGiuliano Pochini 	get_audio_meters(chip, ucontrol->value.integer.value);
1750*dd7b254dSGiuliano Pochini 	return 0;
1751*dd7b254dSGiuliano Pochini }
1752*dd7b254dSGiuliano Pochini 
1753*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = {
1754*dd7b254dSGiuliano Pochini 	.name = "VU-meters",
1755*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1756*dd7b254dSGiuliano Pochini 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1757*dd7b254dSGiuliano Pochini 	.info = snd_echo_vumeters_info,
1758*dd7b254dSGiuliano Pochini 	.get = snd_echo_vumeters_get,
1759*dd7b254dSGiuliano Pochini };
1760*dd7b254dSGiuliano Pochini 
1761*dd7b254dSGiuliano Pochini 
1762*dd7b254dSGiuliano Pochini 
1763*dd7b254dSGiuliano Pochini /*** Channels info - it exports informations about the number of channels ***/
1764*dd7b254dSGiuliano Pochini static int snd_echo_channels_info_info(struct snd_kcontrol *kcontrol,
1765*dd7b254dSGiuliano Pochini 				       struct snd_ctl_elem_info *uinfo)
1766*dd7b254dSGiuliano Pochini {
1767*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1768*dd7b254dSGiuliano Pochini 
1769*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1770*dd7b254dSGiuliano Pochini 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1771*dd7b254dSGiuliano Pochini 	uinfo->count = 6;
1772*dd7b254dSGiuliano Pochini 	uinfo->value.integer.min = 0;
1773*dd7b254dSGiuliano Pochini 	uinfo->value.integer.max = 1 << ECHO_CLOCK_NUMBER;
1774*dd7b254dSGiuliano Pochini 	return 0;
1775*dd7b254dSGiuliano Pochini }
1776*dd7b254dSGiuliano Pochini 
1777*dd7b254dSGiuliano Pochini static int snd_echo_channels_info_get(struct snd_kcontrol *kcontrol,
1778*dd7b254dSGiuliano Pochini 				      struct snd_ctl_elem_value *ucontrol)
1779*dd7b254dSGiuliano Pochini {
1780*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1781*dd7b254dSGiuliano Pochini 	int detected, clocks, bit, src;
1782*dd7b254dSGiuliano Pochini 
1783*dd7b254dSGiuliano Pochini 	chip = snd_kcontrol_chip(kcontrol);
1784*dd7b254dSGiuliano Pochini 	ucontrol->value.integer.value[0] = num_busses_in(chip);
1785*dd7b254dSGiuliano Pochini 	ucontrol->value.integer.value[1] = num_analog_busses_in(chip);
1786*dd7b254dSGiuliano Pochini 	ucontrol->value.integer.value[2] = num_busses_out(chip);
1787*dd7b254dSGiuliano Pochini 	ucontrol->value.integer.value[3] = num_analog_busses_out(chip);
1788*dd7b254dSGiuliano Pochini 	ucontrol->value.integer.value[4] = num_pipes_out(chip);
1789*dd7b254dSGiuliano Pochini 
1790*dd7b254dSGiuliano Pochini 	/* Compute the bitmask of the currently valid input clocks */
1791*dd7b254dSGiuliano Pochini 	detected = detect_input_clocks(chip);
1792*dd7b254dSGiuliano Pochini 	clocks = 0;
1793*dd7b254dSGiuliano Pochini 	src = chip->num_clock_sources - 1;
1794*dd7b254dSGiuliano Pochini 	for (bit = ECHO_CLOCK_NUMBER - 1; bit >= 0; bit--)
1795*dd7b254dSGiuliano Pochini 		if (detected & (1 << bit))
1796*dd7b254dSGiuliano Pochini 			for (; src >= 0; src--)
1797*dd7b254dSGiuliano Pochini 				if (bit == chip->clock_source_list[src]) {
1798*dd7b254dSGiuliano Pochini 					clocks |= 1 << src;
1799*dd7b254dSGiuliano Pochini 					break;
1800*dd7b254dSGiuliano Pochini 				}
1801*dd7b254dSGiuliano Pochini 	ucontrol->value.integer.value[5] = clocks;
1802*dd7b254dSGiuliano Pochini 
1803*dd7b254dSGiuliano Pochini 	return 0;
1804*dd7b254dSGiuliano Pochini }
1805*dd7b254dSGiuliano Pochini 
1806*dd7b254dSGiuliano Pochini static struct snd_kcontrol_new snd_echo_channels_info __devinitdata = {
1807*dd7b254dSGiuliano Pochini 	.name = "Channels info",
1808*dd7b254dSGiuliano Pochini 	.iface = SNDRV_CTL_ELEM_IFACE_HWDEP,
1809*dd7b254dSGiuliano Pochini 	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1810*dd7b254dSGiuliano Pochini 	.info = snd_echo_channels_info_info,
1811*dd7b254dSGiuliano Pochini 	.get = snd_echo_channels_info_get,
1812*dd7b254dSGiuliano Pochini };
1813*dd7b254dSGiuliano Pochini 
1814*dd7b254dSGiuliano Pochini 
1815*dd7b254dSGiuliano Pochini 
1816*dd7b254dSGiuliano Pochini 
1817*dd7b254dSGiuliano Pochini /******************************************************************************
1818*dd7b254dSGiuliano Pochini 	IRQ Handler
1819*dd7b254dSGiuliano Pochini ******************************************************************************/
1820*dd7b254dSGiuliano Pochini 
1821*dd7b254dSGiuliano Pochini static irqreturn_t snd_echo_interrupt(int irq, void *dev_id,
1822*dd7b254dSGiuliano Pochini 				      struct pt_regs *regs)
1823*dd7b254dSGiuliano Pochini {
1824*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = dev_id;
1825*dd7b254dSGiuliano Pochini 	struct snd_pcm_substream *substream;
1826*dd7b254dSGiuliano Pochini 	int period, ss, st;
1827*dd7b254dSGiuliano Pochini 
1828*dd7b254dSGiuliano Pochini 	spin_lock(&chip->lock);
1829*dd7b254dSGiuliano Pochini 	st = service_irq(chip);
1830*dd7b254dSGiuliano Pochini 	if (st < 0) {
1831*dd7b254dSGiuliano Pochini 		spin_unlock(&chip->lock);
1832*dd7b254dSGiuliano Pochini 		return IRQ_NONE;
1833*dd7b254dSGiuliano Pochini 	}
1834*dd7b254dSGiuliano Pochini 	/* The hardware doesn't tell us which substream caused the irq,
1835*dd7b254dSGiuliano Pochini 	thus we have to check all running substreams. */
1836*dd7b254dSGiuliano Pochini 	for (ss = 0; ss < DSP_MAXPIPES; ss++) {
1837*dd7b254dSGiuliano Pochini 		if ((substream = chip->substream[ss])) {
1838*dd7b254dSGiuliano Pochini 			period = pcm_pointer(substream) /
1839*dd7b254dSGiuliano Pochini 				substream->runtime->period_size;
1840*dd7b254dSGiuliano Pochini 			if (period != chip->last_period[ss]) {
1841*dd7b254dSGiuliano Pochini 				chip->last_period[ss] = period;
1842*dd7b254dSGiuliano Pochini 				spin_unlock(&chip->lock);
1843*dd7b254dSGiuliano Pochini 				snd_pcm_period_elapsed(substream);
1844*dd7b254dSGiuliano Pochini 				spin_lock(&chip->lock);
1845*dd7b254dSGiuliano Pochini 			}
1846*dd7b254dSGiuliano Pochini 		}
1847*dd7b254dSGiuliano Pochini 	}
1848*dd7b254dSGiuliano Pochini 	spin_unlock(&chip->lock);
1849*dd7b254dSGiuliano Pochini 
1850*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_MIDI
1851*dd7b254dSGiuliano Pochini 	if (st > 0 && chip->midi_in) {
1852*dd7b254dSGiuliano Pochini 		snd_rawmidi_receive(chip->midi_in, chip->midi_buffer, st);
1853*dd7b254dSGiuliano Pochini 		DE_MID(("rawmidi_iread=%d\n", st));
1854*dd7b254dSGiuliano Pochini 	}
1855*dd7b254dSGiuliano Pochini #endif
1856*dd7b254dSGiuliano Pochini 	return IRQ_HANDLED;
1857*dd7b254dSGiuliano Pochini }
1858*dd7b254dSGiuliano Pochini 
1859*dd7b254dSGiuliano Pochini 
1860*dd7b254dSGiuliano Pochini 
1861*dd7b254dSGiuliano Pochini 
1862*dd7b254dSGiuliano Pochini /******************************************************************************
1863*dd7b254dSGiuliano Pochini 	Module construction / destruction
1864*dd7b254dSGiuliano Pochini ******************************************************************************/
1865*dd7b254dSGiuliano Pochini 
1866*dd7b254dSGiuliano Pochini static int snd_echo_free(struct echoaudio *chip)
1867*dd7b254dSGiuliano Pochini {
1868*dd7b254dSGiuliano Pochini 	DE_INIT(("Stop DSP...\n"));
1869*dd7b254dSGiuliano Pochini 	if (chip->comm_page) {
1870*dd7b254dSGiuliano Pochini 		rest_in_peace(chip);
1871*dd7b254dSGiuliano Pochini 		snd_dma_free_pages(&chip->commpage_dma_buf);
1872*dd7b254dSGiuliano Pochini 	}
1873*dd7b254dSGiuliano Pochini 	DE_INIT(("Stopped.\n"));
1874*dd7b254dSGiuliano Pochini 
1875*dd7b254dSGiuliano Pochini 	if (chip->irq >= 0)
1876*dd7b254dSGiuliano Pochini 		free_irq(chip->irq, (void *)chip);
1877*dd7b254dSGiuliano Pochini 
1878*dd7b254dSGiuliano Pochini 	if (chip->dsp_registers)
1879*dd7b254dSGiuliano Pochini 		iounmap(chip->dsp_registers);
1880*dd7b254dSGiuliano Pochini 
1881*dd7b254dSGiuliano Pochini 	if (chip->iores) {
1882*dd7b254dSGiuliano Pochini 		release_resource(chip->iores);
1883*dd7b254dSGiuliano Pochini 		kfree_nocheck(chip->iores);
1884*dd7b254dSGiuliano Pochini 	}
1885*dd7b254dSGiuliano Pochini 	DE_INIT(("MMIO freed.\n"));
1886*dd7b254dSGiuliano Pochini 
1887*dd7b254dSGiuliano Pochini 	pci_disable_device(chip->pci);
1888*dd7b254dSGiuliano Pochini 
1889*dd7b254dSGiuliano Pochini 	/* release chip data */
1890*dd7b254dSGiuliano Pochini 	kfree(chip);
1891*dd7b254dSGiuliano Pochini 	DE_INIT(("Chip freed.\n"));
1892*dd7b254dSGiuliano Pochini 	return 0;
1893*dd7b254dSGiuliano Pochini }
1894*dd7b254dSGiuliano Pochini 
1895*dd7b254dSGiuliano Pochini 
1896*dd7b254dSGiuliano Pochini 
1897*dd7b254dSGiuliano Pochini static int snd_echo_dev_free(struct snd_device *device)
1898*dd7b254dSGiuliano Pochini {
1899*dd7b254dSGiuliano Pochini 	struct echoaudio *chip = device->device_data;
1900*dd7b254dSGiuliano Pochini 
1901*dd7b254dSGiuliano Pochini 	DE_INIT(("snd_echo_dev_free()...\n"));
1902*dd7b254dSGiuliano Pochini 	return snd_echo_free(chip);
1903*dd7b254dSGiuliano Pochini }
1904*dd7b254dSGiuliano Pochini 
1905*dd7b254dSGiuliano Pochini 
1906*dd7b254dSGiuliano Pochini 
1907*dd7b254dSGiuliano Pochini /* <--snd_echo_probe() */
1908*dd7b254dSGiuliano Pochini static __devinit int snd_echo_create(struct snd_card *card,
1909*dd7b254dSGiuliano Pochini 				     struct pci_dev *pci,
1910*dd7b254dSGiuliano Pochini 				     struct echoaudio **rchip)
1911*dd7b254dSGiuliano Pochini {
1912*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
1913*dd7b254dSGiuliano Pochini 	int err;
1914*dd7b254dSGiuliano Pochini 	size_t sz;
1915*dd7b254dSGiuliano Pochini 	static struct snd_device_ops ops = {
1916*dd7b254dSGiuliano Pochini 		.dev_free = snd_echo_dev_free,
1917*dd7b254dSGiuliano Pochini 	};
1918*dd7b254dSGiuliano Pochini 
1919*dd7b254dSGiuliano Pochini 	*rchip = NULL;
1920*dd7b254dSGiuliano Pochini 
1921*dd7b254dSGiuliano Pochini 	pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0xC0);
1922*dd7b254dSGiuliano Pochini 
1923*dd7b254dSGiuliano Pochini 	if ((err = pci_enable_device(pci)) < 0)
1924*dd7b254dSGiuliano Pochini 		return err;
1925*dd7b254dSGiuliano Pochini 	pci_set_master(pci);
1926*dd7b254dSGiuliano Pochini 
1927*dd7b254dSGiuliano Pochini 	/* allocate a chip-specific data */
1928*dd7b254dSGiuliano Pochini 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
1929*dd7b254dSGiuliano Pochini 	if (!chip) {
1930*dd7b254dSGiuliano Pochini 		pci_disable_device(pci);
1931*dd7b254dSGiuliano Pochini 		return -ENOMEM;
1932*dd7b254dSGiuliano Pochini 	}
1933*dd7b254dSGiuliano Pochini 	DE_INIT(("chip=%p\n", chip));
1934*dd7b254dSGiuliano Pochini 
1935*dd7b254dSGiuliano Pochini 	spin_lock_init(&chip->lock);
1936*dd7b254dSGiuliano Pochini 	chip->card = card;
1937*dd7b254dSGiuliano Pochini 	chip->pci = pci;
1938*dd7b254dSGiuliano Pochini 	chip->irq = -1;
1939*dd7b254dSGiuliano Pochini 
1940*dd7b254dSGiuliano Pochini 	/* PCI resource allocation */
1941*dd7b254dSGiuliano Pochini 	chip->dsp_registers_phys = pci_resource_start(pci, 0);
1942*dd7b254dSGiuliano Pochini 	sz = pci_resource_len(pci, 0);
1943*dd7b254dSGiuliano Pochini 	if (sz > PAGE_SIZE)
1944*dd7b254dSGiuliano Pochini 		sz = PAGE_SIZE;		/* We map only the required part */
1945*dd7b254dSGiuliano Pochini 
1946*dd7b254dSGiuliano Pochini 	if ((chip->iores = request_mem_region(chip->dsp_registers_phys, sz,
1947*dd7b254dSGiuliano Pochini 					      ECHOCARD_NAME)) == NULL) {
1948*dd7b254dSGiuliano Pochini 		snd_echo_free(chip);
1949*dd7b254dSGiuliano Pochini 		snd_printk(KERN_ERR "cannot get memory region\n");
1950*dd7b254dSGiuliano Pochini 		return -EBUSY;
1951*dd7b254dSGiuliano Pochini 	}
1952*dd7b254dSGiuliano Pochini 	chip->dsp_registers = (volatile u32 __iomem *)
1953*dd7b254dSGiuliano Pochini 		ioremap_nocache(chip->dsp_registers_phys, sz);
1954*dd7b254dSGiuliano Pochini 
1955*dd7b254dSGiuliano Pochini 	if (request_irq(pci->irq, snd_echo_interrupt, SA_INTERRUPT | SA_SHIRQ,
1956*dd7b254dSGiuliano Pochini 						ECHOCARD_NAME, (void *)chip)) {
1957*dd7b254dSGiuliano Pochini 		snd_echo_free(chip);
1958*dd7b254dSGiuliano Pochini 		snd_printk(KERN_ERR "cannot grab irq\n");
1959*dd7b254dSGiuliano Pochini 		return -EBUSY;
1960*dd7b254dSGiuliano Pochini 	}
1961*dd7b254dSGiuliano Pochini 	chip->irq = pci->irq;
1962*dd7b254dSGiuliano Pochini 	DE_INIT(("pci=%p irq=%d subdev=%04x Init hardware...\n",
1963*dd7b254dSGiuliano Pochini 		 chip->pci, chip->irq, chip->pci->subsystem_device));
1964*dd7b254dSGiuliano Pochini 
1965*dd7b254dSGiuliano Pochini 	/* Create the DSP comm page - this is the area of memory used for most
1966*dd7b254dSGiuliano Pochini 	of the communication with the DSP, which accesses it via bus mastering */
1967*dd7b254dSGiuliano Pochini 	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
1968*dd7b254dSGiuliano Pochini 				sizeof(struct comm_page),
1969*dd7b254dSGiuliano Pochini 				&chip->commpage_dma_buf) < 0) {
1970*dd7b254dSGiuliano Pochini 		snd_echo_free(chip);
1971*dd7b254dSGiuliano Pochini 		snd_printk(KERN_ERR "cannot allocate the comm page\n");
1972*dd7b254dSGiuliano Pochini 		return -ENOMEM;
1973*dd7b254dSGiuliano Pochini 	}
1974*dd7b254dSGiuliano Pochini 	chip->comm_page_phys = chip->commpage_dma_buf.addr;
1975*dd7b254dSGiuliano Pochini 	chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area;
1976*dd7b254dSGiuliano Pochini 
1977*dd7b254dSGiuliano Pochini 	err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
1978*dd7b254dSGiuliano Pochini 	if (err) {
1979*dd7b254dSGiuliano Pochini 		DE_INIT(("init_hw err=%d\n", err));
1980*dd7b254dSGiuliano Pochini 		snd_echo_free(chip);
1981*dd7b254dSGiuliano Pochini 		return err;
1982*dd7b254dSGiuliano Pochini 	}
1983*dd7b254dSGiuliano Pochini 	DE_INIT(("Card init OK\n"));
1984*dd7b254dSGiuliano Pochini 
1985*dd7b254dSGiuliano Pochini 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
1986*dd7b254dSGiuliano Pochini 		snd_echo_free(chip);
1987*dd7b254dSGiuliano Pochini 		return err;
1988*dd7b254dSGiuliano Pochini 	}
1989*dd7b254dSGiuliano Pochini 	atomic_set(&chip->opencount, 0);
1990*dd7b254dSGiuliano Pochini 	init_MUTEX(&chip->mode_mutex);
1991*dd7b254dSGiuliano Pochini 	chip->can_set_rate = 1;
1992*dd7b254dSGiuliano Pochini 	*rchip = chip;
1993*dd7b254dSGiuliano Pochini 	/* Init done ! */
1994*dd7b254dSGiuliano Pochini 	return 0;
1995*dd7b254dSGiuliano Pochini }
1996*dd7b254dSGiuliano Pochini 
1997*dd7b254dSGiuliano Pochini 
1998*dd7b254dSGiuliano Pochini 
1999*dd7b254dSGiuliano Pochini /* constructor */
2000*dd7b254dSGiuliano Pochini static int __devinit snd_echo_probe(struct pci_dev *pci,
2001*dd7b254dSGiuliano Pochini 				    const struct pci_device_id *pci_id)
2002*dd7b254dSGiuliano Pochini {
2003*dd7b254dSGiuliano Pochini 	static int dev;
2004*dd7b254dSGiuliano Pochini 	struct snd_card *card;
2005*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
2006*dd7b254dSGiuliano Pochini 	char *dsp;
2007*dd7b254dSGiuliano Pochini 	int i, err;
2008*dd7b254dSGiuliano Pochini 
2009*dd7b254dSGiuliano Pochini 	if (dev >= SNDRV_CARDS)
2010*dd7b254dSGiuliano Pochini 		return -ENODEV;
2011*dd7b254dSGiuliano Pochini 	if (!enable[dev]) {
2012*dd7b254dSGiuliano Pochini 		dev++;
2013*dd7b254dSGiuliano Pochini 		return -ENOENT;
2014*dd7b254dSGiuliano Pochini 	}
2015*dd7b254dSGiuliano Pochini 
2016*dd7b254dSGiuliano Pochini 	DE_INIT(("Echoaudio driver starting...\n"));
2017*dd7b254dSGiuliano Pochini 	i = 0;
2018*dd7b254dSGiuliano Pochini 	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
2019*dd7b254dSGiuliano Pochini 	if (card == NULL)
2020*dd7b254dSGiuliano Pochini 		return -ENOMEM;
2021*dd7b254dSGiuliano Pochini 
2022*dd7b254dSGiuliano Pochini 	if ((err = snd_echo_create(card, pci, &chip)) < 0) {
2023*dd7b254dSGiuliano Pochini 		snd_card_free(card);
2024*dd7b254dSGiuliano Pochini 		return err;
2025*dd7b254dSGiuliano Pochini 	}
2026*dd7b254dSGiuliano Pochini 
2027*dd7b254dSGiuliano Pochini 	strcpy(card->driver, "Echo_" ECHOCARD_NAME);
2028*dd7b254dSGiuliano Pochini 	strcpy(card->shortname, chip->card_name);
2029*dd7b254dSGiuliano Pochini 
2030*dd7b254dSGiuliano Pochini 	dsp = "56301";
2031*dd7b254dSGiuliano Pochini 	if (pci_id->device == 0x3410)
2032*dd7b254dSGiuliano Pochini 		dsp = "56361";
2033*dd7b254dSGiuliano Pochini 
2034*dd7b254dSGiuliano Pochini 	sprintf(card->longname, "%s rev.%d (DSP%s) at 0x%lx irq %i",
2035*dd7b254dSGiuliano Pochini 		card->shortname, pci_id->subdevice & 0x000f, dsp,
2036*dd7b254dSGiuliano Pochini 		chip->dsp_registers_phys, chip->irq);
2037*dd7b254dSGiuliano Pochini 
2038*dd7b254dSGiuliano Pochini 	if ((err = snd_echo_new_pcm(chip)) < 0) {
2039*dd7b254dSGiuliano Pochini 		snd_printk(KERN_ERR "new pcm error %d\n", err);
2040*dd7b254dSGiuliano Pochini 		snd_card_free(card);
2041*dd7b254dSGiuliano Pochini 		return err;
2042*dd7b254dSGiuliano Pochini 	}
2043*dd7b254dSGiuliano Pochini 
2044*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_MIDI
2045*dd7b254dSGiuliano Pochini 	if (chip->has_midi) {	/* Some Mia's do not have midi */
2046*dd7b254dSGiuliano Pochini 		if ((err = snd_echo_midi_create(card, chip)) < 0) {
2047*dd7b254dSGiuliano Pochini 			snd_printk(KERN_ERR "new midi error %d\n", err);
2048*dd7b254dSGiuliano Pochini 			snd_card_free(card);
2049*dd7b254dSGiuliano Pochini 			return err;
2050*dd7b254dSGiuliano Pochini 		}
2051*dd7b254dSGiuliano Pochini 	}
2052*dd7b254dSGiuliano Pochini #endif
2053*dd7b254dSGiuliano Pochini 
2054*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_VMIXER
2055*dd7b254dSGiuliano Pochini 	snd_echo_vmixer.count = num_pipes_out(chip) * num_busses_out(chip);
2056*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_output_gain, chip))) < 0)
2057*dd7b254dSGiuliano Pochini 		goto ctl_error;
2058*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip))) < 0)
2059*dd7b254dSGiuliano Pochini 		goto ctl_error;
2060*dd7b254dSGiuliano Pochini #else
2061*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_pcm_output_gain, chip))) < 0)
2062*dd7b254dSGiuliano Pochini 		goto ctl_error;
2063*dd7b254dSGiuliano Pochini #endif
2064*dd7b254dSGiuliano Pochini 
2065*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_INPUT_GAIN
2066*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_input_gain, chip))) < 0)
2067*dd7b254dSGiuliano Pochini 		goto ctl_error;
2068*dd7b254dSGiuliano Pochini #endif
2069*dd7b254dSGiuliano Pochini 
2070*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL
2071*dd7b254dSGiuliano Pochini 	if (!chip->hasnt_input_nominal_level)
2072*dd7b254dSGiuliano Pochini 		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_intput_nominal_level, chip))) < 0)
2073*dd7b254dSGiuliano Pochini 			goto ctl_error;
2074*dd7b254dSGiuliano Pochini #endif
2075*dd7b254dSGiuliano Pochini 
2076*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL
2077*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_output_nominal_level, chip))) < 0)
2078*dd7b254dSGiuliano Pochini 		goto ctl_error;
2079*dd7b254dSGiuliano Pochini #endif
2080*dd7b254dSGiuliano Pochini 
2081*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters_switch, chip))) < 0)
2082*dd7b254dSGiuliano Pochini 		goto ctl_error;
2083*dd7b254dSGiuliano Pochini 
2084*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters, chip))) < 0)
2085*dd7b254dSGiuliano Pochini 		goto ctl_error;
2086*dd7b254dSGiuliano Pochini 
2087*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_MONITOR
2088*dd7b254dSGiuliano Pochini 	snd_echo_monitor_mixer.count = num_busses_in(chip) * num_busses_out(chip);
2089*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_monitor_mixer, chip))) < 0)
2090*dd7b254dSGiuliano Pochini 		goto ctl_error;
2091*dd7b254dSGiuliano Pochini #endif
2092*dd7b254dSGiuliano Pochini 
2093*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE
2094*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_automute_switch, chip))) < 0)
2095*dd7b254dSGiuliano Pochini 		goto ctl_error;
2096*dd7b254dSGiuliano Pochini #endif
2097*dd7b254dSGiuliano Pochini 
2098*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_channels_info, chip))) < 0)
2099*dd7b254dSGiuliano Pochini 		goto ctl_error;
2100*dd7b254dSGiuliano Pochini 
2101*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH
2102*dd7b254dSGiuliano Pochini 	/* Creates a list of available digital modes */
2103*dd7b254dSGiuliano Pochini 	chip->num_digital_modes = 0;
2104*dd7b254dSGiuliano Pochini 	for (i = 0; i < 6; i++)
2105*dd7b254dSGiuliano Pochini 		if (chip->digital_modes & (1 << i))
2106*dd7b254dSGiuliano Pochini 			chip->digital_mode_list[chip->num_digital_modes++] = i;
2107*dd7b254dSGiuliano Pochini 
2108*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_digital_mode_switch, chip))) < 0)
2109*dd7b254dSGiuliano Pochini 		goto ctl_error;
2110*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */
2111*dd7b254dSGiuliano Pochini 
2112*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
2113*dd7b254dSGiuliano Pochini 	/* Creates a list of available clock sources */
2114*dd7b254dSGiuliano Pochini 	chip->num_clock_sources = 0;
2115*dd7b254dSGiuliano Pochini 	for (i = 0; i < 10; i++)
2116*dd7b254dSGiuliano Pochini 		if (chip->input_clock_types & (1 << i))
2117*dd7b254dSGiuliano Pochini 			chip->clock_source_list[chip->num_clock_sources++] = i;
2118*dd7b254dSGiuliano Pochini 
2119*dd7b254dSGiuliano Pochini 	if (chip->num_clock_sources > 1) {
2120*dd7b254dSGiuliano Pochini 		chip->clock_src_ctl = snd_ctl_new1(&snd_echo_clock_source_switch, chip);
2121*dd7b254dSGiuliano Pochini 		if ((err = snd_ctl_add(chip->card, chip->clock_src_ctl)) < 0)
2122*dd7b254dSGiuliano Pochini 			goto ctl_error;
2123*dd7b254dSGiuliano Pochini 	}
2124*dd7b254dSGiuliano Pochini #endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */
2125*dd7b254dSGiuliano Pochini 
2126*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_DIGITAL_IO
2127*dd7b254dSGiuliano Pochini 	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_spdif_mode_switch, chip))) < 0)
2128*dd7b254dSGiuliano Pochini 		goto ctl_error;
2129*dd7b254dSGiuliano Pochini #endif
2130*dd7b254dSGiuliano Pochini 
2131*dd7b254dSGiuliano Pochini #ifdef ECHOCARD_HAS_PHANTOM_POWER
2132*dd7b254dSGiuliano Pochini 	if (chip->has_phantom_power)
2133*dd7b254dSGiuliano Pochini 		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_phantom_power_switch, chip))) < 0)
2134*dd7b254dSGiuliano Pochini 			goto ctl_error;
2135*dd7b254dSGiuliano Pochini #endif
2136*dd7b254dSGiuliano Pochini 
2137*dd7b254dSGiuliano Pochini 	if ((err = snd_card_register(card)) < 0) {
2138*dd7b254dSGiuliano Pochini 		snd_card_free(card);
2139*dd7b254dSGiuliano Pochini 		goto ctl_error;
2140*dd7b254dSGiuliano Pochini 	}
2141*dd7b254dSGiuliano Pochini 	snd_printk(KERN_INFO "Card registered: %s\n", card->longname);
2142*dd7b254dSGiuliano Pochini 
2143*dd7b254dSGiuliano Pochini 	pci_set_drvdata(pci, chip);
2144*dd7b254dSGiuliano Pochini 	dev++;
2145*dd7b254dSGiuliano Pochini 	return 0;
2146*dd7b254dSGiuliano Pochini 
2147*dd7b254dSGiuliano Pochini ctl_error:
2148*dd7b254dSGiuliano Pochini 	snd_printk(KERN_ERR "new control error %d\n", err);
2149*dd7b254dSGiuliano Pochini 	snd_card_free(card);
2150*dd7b254dSGiuliano Pochini 	return err;
2151*dd7b254dSGiuliano Pochini }
2152*dd7b254dSGiuliano Pochini 
2153*dd7b254dSGiuliano Pochini 
2154*dd7b254dSGiuliano Pochini 
2155*dd7b254dSGiuliano Pochini static void __devexit snd_echo_remove(struct pci_dev *pci)
2156*dd7b254dSGiuliano Pochini {
2157*dd7b254dSGiuliano Pochini 	struct echoaudio *chip;
2158*dd7b254dSGiuliano Pochini 
2159*dd7b254dSGiuliano Pochini 	chip = pci_get_drvdata(pci);
2160*dd7b254dSGiuliano Pochini 	if (chip)
2161*dd7b254dSGiuliano Pochini 		snd_card_free(chip->card);
2162*dd7b254dSGiuliano Pochini 	pci_set_drvdata(pci, NULL);
2163*dd7b254dSGiuliano Pochini }
2164*dd7b254dSGiuliano Pochini 
2165*dd7b254dSGiuliano Pochini 
2166*dd7b254dSGiuliano Pochini 
2167*dd7b254dSGiuliano Pochini /******************************************************************************
2168*dd7b254dSGiuliano Pochini 	Everything starts and ends here
2169*dd7b254dSGiuliano Pochini ******************************************************************************/
2170*dd7b254dSGiuliano Pochini 
2171*dd7b254dSGiuliano Pochini /* pci_driver definition */
2172*dd7b254dSGiuliano Pochini static struct pci_driver driver = {
2173*dd7b254dSGiuliano Pochini 	.name = "Echoaudio " ECHOCARD_NAME,
2174*dd7b254dSGiuliano Pochini 	.id_table = snd_echo_ids,
2175*dd7b254dSGiuliano Pochini 	.probe = snd_echo_probe,
2176*dd7b254dSGiuliano Pochini 	.remove = __devexit_p(snd_echo_remove),
2177*dd7b254dSGiuliano Pochini };
2178*dd7b254dSGiuliano Pochini 
2179*dd7b254dSGiuliano Pochini 
2180*dd7b254dSGiuliano Pochini 
2181*dd7b254dSGiuliano Pochini /* initialization of the module */
2182*dd7b254dSGiuliano Pochini static int __init alsa_card_echo_init(void)
2183*dd7b254dSGiuliano Pochini {
2184*dd7b254dSGiuliano Pochini 	return pci_register_driver(&driver);
2185*dd7b254dSGiuliano Pochini }
2186*dd7b254dSGiuliano Pochini 
2187*dd7b254dSGiuliano Pochini 
2188*dd7b254dSGiuliano Pochini 
2189*dd7b254dSGiuliano Pochini /* clean up the module */
2190*dd7b254dSGiuliano Pochini static void __exit alsa_card_echo_exit(void)
2191*dd7b254dSGiuliano Pochini {
2192*dd7b254dSGiuliano Pochini 	pci_unregister_driver(&driver);
2193*dd7b254dSGiuliano Pochini }
2194*dd7b254dSGiuliano Pochini 
2195*dd7b254dSGiuliano Pochini 
2196*dd7b254dSGiuliano Pochini module_init(alsa_card_echo_init)
2197*dd7b254dSGiuliano Pochini module_exit(alsa_card_echo_exit)
2198