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 	struct snd_pcm_runtime *runtime = substream->runtime;
62 	struct snd_pcm_hardware *hw = &runtime->hw;
63 	struct amdtp_stream *s;
64 	int err;
65 
66 
67 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
68 		substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
69 		s = &dg00x->tx_stream;
70 	} else {
71 		substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
72 		s = &dg00x->rx_stream;
73 	}
74 
75 	hw->channels_min = 10;
76 	hw->channels_max = 18;
77 
78 	hw->rates = SNDRV_PCM_RATE_44100 |
79 		    SNDRV_PCM_RATE_48000 |
80 		    SNDRV_PCM_RATE_88200 |
81 		    SNDRV_PCM_RATE_96000;
82 	snd_pcm_limit_hw_rates(runtime);
83 
84 	err = snd_pcm_hw_rule_add(substream->runtime, 0,
85 				  SNDRV_PCM_HW_PARAM_CHANNELS,
86 				  hw_rule_channels, NULL,
87 				  SNDRV_PCM_HW_PARAM_RATE, -1);
88 	if (err < 0)
89 		return err;
90 
91 	err = snd_pcm_hw_rule_add(substream->runtime, 0,
92 				  SNDRV_PCM_HW_PARAM_RATE,
93 				  hw_rule_rate, NULL,
94 				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
95 	if (err < 0)
96 		return err;
97 
98 	return amdtp_dot_add_pcm_hw_constraints(s, substream->runtime);
99 }
100 
101 static int pcm_open(struct snd_pcm_substream *substream)
102 {
103 	struct snd_dg00x *dg00x = substream->private_data;
104 	enum snd_dg00x_clock clock;
105 	bool detect;
106 	unsigned int rate;
107 	int err;
108 
109 	err = snd_dg00x_stream_lock_try(dg00x);
110 	if (err < 0)
111 		goto end;
112 
113 	err = pcm_init_hw_params(dg00x, substream);
114 	if (err < 0)
115 		goto err_locked;
116 
117 	/* Check current clock source. */
118 	err = snd_dg00x_stream_get_clock(dg00x, &clock);
119 	if (err < 0)
120 		goto err_locked;
121 	if (clock != SND_DG00X_CLOCK_INTERNAL) {
122 		err = snd_dg00x_stream_check_external_clock(dg00x, &detect);
123 		if (err < 0)
124 			goto err_locked;
125 		if (!detect) {
126 			err = -EBUSY;
127 			goto err_locked;
128 		}
129 	}
130 
131 	if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
132 	    amdtp_stream_pcm_running(&dg00x->rx_stream) ||
133 	    amdtp_stream_pcm_running(&dg00x->tx_stream)) {
134 		err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
135 		if (err < 0)
136 			goto err_locked;
137 		substream->runtime->hw.rate_min = rate;
138 		substream->runtime->hw.rate_max = rate;
139 	}
140 
141 	snd_pcm_set_sync(substream);
142 end:
143 	return err;
144 err_locked:
145 	snd_dg00x_stream_lock_release(dg00x);
146 	return err;
147 }
148 
149 static int pcm_close(struct snd_pcm_substream *substream)
150 {
151 	struct snd_dg00x *dg00x = substream->private_data;
152 
153 	snd_dg00x_stream_lock_release(dg00x);
154 
155 	return 0;
156 }
157 
158 static int pcm_hw_params(struct snd_pcm_substream *substream,
159 			 struct snd_pcm_hw_params *hw_params)
160 {
161 	struct snd_dg00x *dg00x = substream->private_data;
162 	int err;
163 
164 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
165 					       params_buffer_bytes(hw_params));
166 	if (err < 0)
167 		return err;
168 
169 	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
170 		unsigned int rate = params_rate(hw_params);
171 
172 		mutex_lock(&dg00x->mutex);
173 		err = snd_dg00x_stream_reserve_duplex(dg00x, rate);
174 		if (err >= 0)
175 			++dg00x->substreams_counter;
176 		mutex_unlock(&dg00x->mutex);
177 	}
178 
179 	return err;
180 }
181 
182 static int pcm_hw_free(struct snd_pcm_substream *substream)
183 {
184 	struct snd_dg00x *dg00x = substream->private_data;
185 
186 	mutex_lock(&dg00x->mutex);
187 
188 	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
189 		--dg00x->substreams_counter;
190 
191 	snd_dg00x_stream_stop_duplex(dg00x);
192 
193 	mutex_unlock(&dg00x->mutex);
194 
195 	return snd_pcm_lib_free_vmalloc_buffer(substream);
196 }
197 
198 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
199 {
200 	struct snd_dg00x *dg00x = substream->private_data;
201 	int err;
202 
203 	mutex_lock(&dg00x->mutex);
204 
205 	err = snd_dg00x_stream_start_duplex(dg00x);
206 	if (err >= 0)
207 		amdtp_stream_pcm_prepare(&dg00x->tx_stream);
208 
209 	mutex_unlock(&dg00x->mutex);
210 
211 	return err;
212 }
213 
214 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
215 {
216 	struct snd_dg00x *dg00x = substream->private_data;
217 	int err;
218 
219 	mutex_lock(&dg00x->mutex);
220 
221 	err = snd_dg00x_stream_start_duplex(dg00x);
222 	if (err >= 0) {
223 		amdtp_stream_pcm_prepare(&dg00x->rx_stream);
224 		amdtp_dot_reset(&dg00x->rx_stream);
225 	}
226 
227 	mutex_unlock(&dg00x->mutex);
228 
229 	return err;
230 }
231 
232 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
233 {
234 	struct snd_dg00x *dg00x = substream->private_data;
235 
236 	switch (cmd) {
237 	case SNDRV_PCM_TRIGGER_START:
238 		amdtp_stream_pcm_trigger(&dg00x->tx_stream, substream);
239 		break;
240 	case SNDRV_PCM_TRIGGER_STOP:
241 		amdtp_stream_pcm_trigger(&dg00x->tx_stream, NULL);
242 		break;
243 	default:
244 		return -EINVAL;
245 	}
246 
247 	return 0;
248 }
249 
250 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
251 {
252 	struct snd_dg00x *dg00x = substream->private_data;
253 
254 	switch (cmd) {
255 	case SNDRV_PCM_TRIGGER_START:
256 		amdtp_stream_pcm_trigger(&dg00x->rx_stream, substream);
257 		break;
258 	case SNDRV_PCM_TRIGGER_STOP:
259 		amdtp_stream_pcm_trigger(&dg00x->rx_stream, NULL);
260 		break;
261 	default:
262 		return -EINVAL;
263 	}
264 
265 	return 0;
266 }
267 
268 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
269 {
270 	struct snd_dg00x *dg00x = sbstrm->private_data;
271 
272 	return amdtp_stream_pcm_pointer(&dg00x->tx_stream);
273 }
274 
275 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
276 {
277 	struct snd_dg00x *dg00x = sbstrm->private_data;
278 
279 	return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
280 }
281 
282 static int pcm_capture_ack(struct snd_pcm_substream *substream)
283 {
284 	struct snd_dg00x *dg00x = substream->private_data;
285 
286 	return amdtp_stream_pcm_ack(&dg00x->tx_stream);
287 }
288 
289 static int pcm_playback_ack(struct snd_pcm_substream *substream)
290 {
291 	struct snd_dg00x *dg00x = substream->private_data;
292 
293 	return amdtp_stream_pcm_ack(&dg00x->rx_stream);
294 }
295 
296 int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
297 {
298 	static const struct snd_pcm_ops capture_ops = {
299 		.open		= pcm_open,
300 		.close		= pcm_close,
301 		.ioctl		= snd_pcm_lib_ioctl,
302 		.hw_params	= pcm_hw_params,
303 		.hw_free	= pcm_hw_free,
304 		.prepare	= pcm_capture_prepare,
305 		.trigger	= pcm_capture_trigger,
306 		.pointer	= pcm_capture_pointer,
307 		.ack		= pcm_capture_ack,
308 		.page		= snd_pcm_lib_get_vmalloc_page,
309 	};
310 	static const struct snd_pcm_ops playback_ops = {
311 		.open		= pcm_open,
312 		.close		= pcm_close,
313 		.ioctl		= snd_pcm_lib_ioctl,
314 		.hw_params	= pcm_hw_params,
315 		.hw_free	= pcm_hw_free,
316 		.prepare	= pcm_playback_prepare,
317 		.trigger	= pcm_playback_trigger,
318 		.pointer	= pcm_playback_pointer,
319 		.ack		= pcm_playback_ack,
320 		.page		= snd_pcm_lib_get_vmalloc_page,
321 	};
322 	struct snd_pcm *pcm;
323 	int err;
324 
325 	err = snd_pcm_new(dg00x->card, dg00x->card->driver, 0, 1, 1, &pcm);
326 	if (err < 0)
327 		return err;
328 
329 	pcm->private_data = dg00x;
330 	snprintf(pcm->name, sizeof(pcm->name),
331 		 "%s PCM", dg00x->card->shortname);
332 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
333 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
334 
335 	return 0;
336 }
337