1 /*
2  * digi00x-pcm.c - a part of driver for Digidesign Digi 002/003 family
3  *
4  * Copyright (c) 2014-2015 Takashi Sakamoto
5  *
6  * Licensed under the terms of the GNU General Public License, version 2.
7  */
8 
9 #include "digi00x.h"
10 
11 static int hw_rule_rate(struct snd_pcm_hw_params *params,
12 			struct snd_pcm_hw_rule *rule)
13 {
14 	struct snd_interval *r =
15 		hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
16 	const struct snd_interval *c =
17 		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
18 	struct snd_interval t = {
19 		.min = UINT_MAX, .max = 0, .integer = 1,
20 	};
21 	unsigned int i;
22 
23 	for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
24 		if (!snd_interval_test(c,
25 				       snd_dg00x_stream_pcm_channels[i]))
26 			continue;
27 
28 		t.min = min(t.min, snd_dg00x_stream_rates[i]);
29 		t.max = max(t.max, snd_dg00x_stream_rates[i]);
30 	}
31 
32 	return snd_interval_refine(r, &t);
33 }
34 
35 static int hw_rule_channels(struct snd_pcm_hw_params *params,
36 			    struct snd_pcm_hw_rule *rule)
37 {
38 	struct snd_interval *c =
39 		hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
40 	const struct snd_interval *r =
41 		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
42 	struct snd_interval t = {
43 		.min = UINT_MAX, .max = 0, .integer = 1,
44 	};
45 	unsigned int i;
46 
47 	for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
48 		if (!snd_interval_test(r, snd_dg00x_stream_rates[i]))
49 			continue;
50 
51 		t.min = min(t.min, snd_dg00x_stream_pcm_channels[i]);
52 		t.max = max(t.max, snd_dg00x_stream_pcm_channels[i]);
53 	}
54 
55 	return snd_interval_refine(c, &t);
56 }
57 
58 static int pcm_init_hw_params(struct snd_dg00x *dg00x,
59 			      struct snd_pcm_substream *substream)
60 {
61 	static const struct snd_pcm_hardware hardware = {
62 		.info = SNDRV_PCM_INFO_BATCH |
63 			SNDRV_PCM_INFO_BLOCK_TRANSFER |
64 			SNDRV_PCM_INFO_INTERLEAVED |
65 			SNDRV_PCM_INFO_JOINT_DUPLEX |
66 			SNDRV_PCM_INFO_MMAP |
67 			SNDRV_PCM_INFO_MMAP_VALID,
68 		.rates = SNDRV_PCM_RATE_44100 |
69 			 SNDRV_PCM_RATE_48000 |
70 			 SNDRV_PCM_RATE_88200 |
71 			 SNDRV_PCM_RATE_96000,
72 		.rate_min = 44100,
73 		.rate_max = 96000,
74 		.channels_min = 10,
75 		.channels_max = 18,
76 		.period_bytes_min = 4 * 18,
77 		.period_bytes_max = 4 * 18 * 2048,
78 		.buffer_bytes_max = 4 * 18 * 2048 * 2,
79 		.periods_min = 2,
80 		.periods_max = UINT_MAX,
81 	};
82 	struct amdtp_stream *s;
83 	int err;
84 
85 	substream->runtime->hw = hardware;
86 
87 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
88 		substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
89 		s = &dg00x->tx_stream;
90 	} else {
91 		substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S16 |
92 						 SNDRV_PCM_FMTBIT_S32;
93 		s = &dg00x->rx_stream;
94 	}
95 
96 	err = snd_pcm_hw_rule_add(substream->runtime, 0,
97 				  SNDRV_PCM_HW_PARAM_CHANNELS,
98 				  hw_rule_channels, NULL,
99 				  SNDRV_PCM_HW_PARAM_RATE, -1);
100 	if (err < 0)
101 		return err;
102 
103 	err = snd_pcm_hw_rule_add(substream->runtime, 0,
104 				  SNDRV_PCM_HW_PARAM_RATE,
105 				  hw_rule_rate, NULL,
106 				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
107 	if (err < 0)
108 		return err;
109 
110 	return amdtp_dot_add_pcm_hw_constraints(s, substream->runtime);
111 }
112 
113 static int pcm_open(struct snd_pcm_substream *substream)
114 {
115 	struct snd_dg00x *dg00x = substream->private_data;
116 	enum snd_dg00x_clock clock;
117 	bool detect;
118 	unsigned int rate;
119 	int err;
120 
121 	err = snd_dg00x_stream_lock_try(dg00x);
122 	if (err < 0)
123 		goto end;
124 
125 	err = pcm_init_hw_params(dg00x, substream);
126 	if (err < 0)
127 		goto err_locked;
128 
129 	/* Check current clock source. */
130 	err = snd_dg00x_stream_get_clock(dg00x, &clock);
131 	if (err < 0)
132 		goto err_locked;
133 	if (clock != SND_DG00X_CLOCK_INTERNAL) {
134 		err = snd_dg00x_stream_check_external_clock(dg00x, &detect);
135 		if (err < 0)
136 			goto err_locked;
137 		if (!detect) {
138 			err = -EBUSY;
139 			goto err_locked;
140 		}
141 	}
142 
143 	if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
144 	    amdtp_stream_pcm_running(&dg00x->rx_stream) ||
145 	    amdtp_stream_pcm_running(&dg00x->tx_stream)) {
146 		err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
147 		if (err < 0)
148 			goto err_locked;
149 		substream->runtime->hw.rate_min = rate;
150 		substream->runtime->hw.rate_max = rate;
151 	}
152 
153 	snd_pcm_set_sync(substream);
154 end:
155 	return err;
156 err_locked:
157 	snd_dg00x_stream_lock_release(dg00x);
158 	return err;
159 }
160 
161 static int pcm_close(struct snd_pcm_substream *substream)
162 {
163 	struct snd_dg00x *dg00x = substream->private_data;
164 
165 	snd_dg00x_stream_lock_release(dg00x);
166 
167 	return 0;
168 }
169 
170 static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
171 				 struct snd_pcm_hw_params *hw_params)
172 {
173 	struct snd_dg00x *dg00x = substream->private_data;
174 	int err;
175 
176 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
177 					       params_buffer_bytes(hw_params));
178 	if (err < 0)
179 		return err;
180 
181 	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
182 		mutex_lock(&dg00x->mutex);
183 		dg00x->substreams_counter++;
184 		mutex_unlock(&dg00x->mutex);
185 	}
186 
187 	amdtp_dot_set_pcm_format(&dg00x->tx_stream, params_format(hw_params));
188 
189 	return 0;
190 }
191 
192 static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
193 				  struct snd_pcm_hw_params *hw_params)
194 {
195 	struct snd_dg00x *dg00x = substream->private_data;
196 	int err;
197 
198 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
199 					       params_buffer_bytes(hw_params));
200 	if (err < 0)
201 		return err;
202 
203 	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
204 		mutex_lock(&dg00x->mutex);
205 		dg00x->substreams_counter++;
206 		mutex_unlock(&dg00x->mutex);
207 	}
208 
209 	amdtp_dot_set_pcm_format(&dg00x->rx_stream, params_format(hw_params));
210 
211 	return 0;
212 }
213 
214 static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
215 {
216 	struct snd_dg00x *dg00x = substream->private_data;
217 
218 	mutex_lock(&dg00x->mutex);
219 
220 	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
221 		dg00x->substreams_counter--;
222 
223 	snd_dg00x_stream_stop_duplex(dg00x);
224 
225 	mutex_unlock(&dg00x->mutex);
226 
227 	return snd_pcm_lib_free_vmalloc_buffer(substream);
228 }
229 
230 static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
231 {
232 	struct snd_dg00x *dg00x = substream->private_data;
233 
234 	mutex_lock(&dg00x->mutex);
235 
236 	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
237 		dg00x->substreams_counter--;
238 
239 	snd_dg00x_stream_stop_duplex(dg00x);
240 
241 	mutex_unlock(&dg00x->mutex);
242 
243 	return snd_pcm_lib_free_vmalloc_buffer(substream);
244 }
245 
246 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
247 {
248 	struct snd_dg00x *dg00x = substream->private_data;
249 	struct snd_pcm_runtime *runtime = substream->runtime;
250 	int err;
251 
252 	mutex_lock(&dg00x->mutex);
253 
254 	err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
255 	if (err >= 0)
256 		amdtp_stream_pcm_prepare(&dg00x->tx_stream);
257 
258 	mutex_unlock(&dg00x->mutex);
259 
260 	return err;
261 }
262 
263 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
264 {
265 	struct snd_dg00x *dg00x = substream->private_data;
266 	struct snd_pcm_runtime *runtime = substream->runtime;
267 	int err;
268 
269 	mutex_lock(&dg00x->mutex);
270 
271 	err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
272 	if (err >= 0) {
273 		amdtp_stream_pcm_prepare(&dg00x->rx_stream);
274 		amdtp_dot_reset(&dg00x->rx_stream);
275 	}
276 
277 	mutex_unlock(&dg00x->mutex);
278 
279 	return err;
280 }
281 
282 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
283 {
284 	struct snd_dg00x *dg00x = substream->private_data;
285 
286 	switch (cmd) {
287 	case SNDRV_PCM_TRIGGER_START:
288 		amdtp_stream_pcm_trigger(&dg00x->tx_stream, substream);
289 		break;
290 	case SNDRV_PCM_TRIGGER_STOP:
291 		amdtp_stream_pcm_trigger(&dg00x->tx_stream, NULL);
292 		break;
293 	default:
294 		return -EINVAL;
295 	}
296 
297 	return 0;
298 }
299 
300 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
301 {
302 	struct snd_dg00x *dg00x = substream->private_data;
303 
304 	switch (cmd) {
305 	case SNDRV_PCM_TRIGGER_START:
306 		amdtp_stream_pcm_trigger(&dg00x->rx_stream, substream);
307 		break;
308 	case SNDRV_PCM_TRIGGER_STOP:
309 		amdtp_stream_pcm_trigger(&dg00x->rx_stream, NULL);
310 		break;
311 	default:
312 		return -EINVAL;
313 	}
314 
315 	return 0;
316 }
317 
318 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
319 {
320 	struct snd_dg00x *dg00x = sbstrm->private_data;
321 
322 	return amdtp_stream_pcm_pointer(&dg00x->tx_stream);
323 }
324 
325 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
326 {
327 	struct snd_dg00x *dg00x = sbstrm->private_data;
328 
329 	return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
330 }
331 
332 int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
333 {
334 	static const struct snd_pcm_ops capture_ops = {
335 		.open		= pcm_open,
336 		.close		= pcm_close,
337 		.ioctl		= snd_pcm_lib_ioctl,
338 		.hw_params	= pcm_capture_hw_params,
339 		.hw_free	= pcm_capture_hw_free,
340 		.prepare	= pcm_capture_prepare,
341 		.trigger	= pcm_capture_trigger,
342 		.pointer	= pcm_capture_pointer,
343 		.page		= snd_pcm_lib_get_vmalloc_page,
344 	};
345 	static const struct snd_pcm_ops playback_ops = {
346 		.open		= pcm_open,
347 		.close		= pcm_close,
348 		.ioctl		= snd_pcm_lib_ioctl,
349 		.hw_params	= pcm_playback_hw_params,
350 		.hw_free	= pcm_playback_hw_free,
351 		.prepare	= pcm_playback_prepare,
352 		.trigger	= pcm_playback_trigger,
353 		.pointer	= pcm_playback_pointer,
354 		.page		= snd_pcm_lib_get_vmalloc_page,
355 		.mmap		= snd_pcm_lib_mmap_vmalloc,
356 	};
357 	struct snd_pcm *pcm;
358 	int err;
359 
360 	err = snd_pcm_new(dg00x->card, dg00x->card->driver, 0, 1, 1, &pcm);
361 	if (err < 0)
362 		return err;
363 
364 	pcm->private_data = dg00x;
365 	snprintf(pcm->name, sizeof(pcm->name),
366 		 "%s PCM", dg00x->card->shortname);
367 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
368 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
369 
370 	return 0;
371 }
372