1 /*
2  * tascam-pcm.c - a part of driver for TASCAM FireWire series
3  *
4  * Copyright (c) 2015 Takashi Sakamoto
5  *
6  * Licensed under the terms of the GNU General Public License, version 2.
7  */
8 
9 #include "tascam.h"
10 
11 static void set_buffer_params(struct snd_pcm_hardware *hw)
12 {
13 	hw->period_bytes_min = 4 * hw->channels_min;
14 	hw->period_bytes_max = hw->period_bytes_min * 2048;
15 	hw->buffer_bytes_max = hw->period_bytes_max * 2;
16 
17 	hw->periods_min = 2;
18 	hw->periods_max = UINT_MAX;
19 }
20 
21 static int pcm_init_hw_params(struct snd_tscm *tscm,
22 			      struct snd_pcm_substream *substream)
23 {
24 	static const struct snd_pcm_hardware hardware = {
25 		.info = SNDRV_PCM_INFO_BATCH |
26 			SNDRV_PCM_INFO_BLOCK_TRANSFER |
27 			SNDRV_PCM_INFO_INTERLEAVED |
28 			SNDRV_PCM_INFO_JOINT_DUPLEX |
29 			SNDRV_PCM_INFO_MMAP |
30 			SNDRV_PCM_INFO_MMAP_VALID,
31 		.rates = SNDRV_PCM_RATE_44100 |
32 			 SNDRV_PCM_RATE_48000 |
33 			 SNDRV_PCM_RATE_88200 |
34 			 SNDRV_PCM_RATE_96000,
35 		.rate_min = 44100,
36 		.rate_max = 96000,
37 		.channels_min = 10,
38 		.channels_max = 18,
39 	};
40 	struct snd_pcm_runtime *runtime = substream->runtime;
41 	struct amdtp_stream *stream;
42 	unsigned int pcm_channels;
43 
44 	runtime->hw = hardware;
45 
46 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
47 		runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
48 		stream = &tscm->tx_stream;
49 		pcm_channels = tscm->spec->pcm_capture_analog_channels;
50 	} else {
51 		runtime->hw.formats =
52 				SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S32;
53 		stream = &tscm->rx_stream;
54 		pcm_channels = tscm->spec->pcm_playback_analog_channels;
55 	}
56 
57 	if (tscm->spec->has_adat)
58 		pcm_channels += 8;
59 	if (tscm->spec->has_spdif)
60 		pcm_channels += 2;
61 	runtime->hw.channels_min = runtime->hw.channels_max = pcm_channels;
62 
63 	set_buffer_params(&runtime->hw);
64 
65 	return amdtp_tscm_add_pcm_hw_constraints(stream, runtime);
66 }
67 
68 static int pcm_open(struct snd_pcm_substream *substream)
69 {
70 	struct snd_tscm *tscm = substream->private_data;
71 	enum snd_tscm_clock clock;
72 	unsigned int rate;
73 	int err;
74 
75 	err = snd_tscm_stream_lock_try(tscm);
76 	if (err < 0)
77 		goto end;
78 
79 	err = pcm_init_hw_params(tscm, substream);
80 	if (err < 0)
81 		goto err_locked;
82 
83 	err = snd_tscm_stream_get_clock(tscm, &clock);
84 	if (clock != SND_TSCM_CLOCK_INTERNAL ||
85 	    amdtp_stream_pcm_running(&tscm->rx_stream) ||
86 	    amdtp_stream_pcm_running(&tscm->tx_stream)) {
87 		err = snd_tscm_stream_get_rate(tscm, &rate);
88 		if (err < 0)
89 			goto err_locked;
90 		substream->runtime->hw.rate_min = rate;
91 		substream->runtime->hw.rate_max = rate;
92 	}
93 
94 	snd_pcm_set_sync(substream);
95 end:
96 	return err;
97 err_locked:
98 	snd_tscm_stream_lock_release(tscm);
99 	return err;
100 }
101 
102 static int pcm_close(struct snd_pcm_substream *substream)
103 {
104 	struct snd_tscm *tscm = substream->private_data;
105 
106 	snd_tscm_stream_lock_release(tscm);
107 
108 	return 0;
109 }
110 
111 static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
112 				 struct snd_pcm_hw_params *hw_params)
113 {
114 	struct snd_tscm *tscm = substream->private_data;
115 	int err;
116 
117 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
118 					       params_buffer_bytes(hw_params));
119 	if (err < 0)
120 		return err;
121 
122 	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
123 		mutex_lock(&tscm->mutex);
124 		tscm->substreams_counter++;
125 		mutex_unlock(&tscm->mutex);
126 	}
127 
128 	amdtp_tscm_set_pcm_format(&tscm->tx_stream, params_format(hw_params));
129 
130 	return 0;
131 }
132 
133 static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
134 				  struct snd_pcm_hw_params *hw_params)
135 {
136 	struct snd_tscm *tscm = substream->private_data;
137 	int err;
138 
139 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
140 					       params_buffer_bytes(hw_params));
141 	if (err < 0)
142 		return err;
143 
144 	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
145 		mutex_lock(&tscm->mutex);
146 		tscm->substreams_counter++;
147 		mutex_unlock(&tscm->mutex);
148 	}
149 
150 	amdtp_tscm_set_pcm_format(&tscm->rx_stream, params_format(hw_params));
151 
152 	return 0;
153 }
154 
155 static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
156 {
157 	struct snd_tscm *tscm = substream->private_data;
158 
159 	mutex_lock(&tscm->mutex);
160 
161 	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
162 		tscm->substreams_counter--;
163 
164 	snd_tscm_stream_stop_duplex(tscm);
165 
166 	mutex_unlock(&tscm->mutex);
167 
168 	return snd_pcm_lib_free_vmalloc_buffer(substream);
169 }
170 
171 static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
172 {
173 	struct snd_tscm *tscm = substream->private_data;
174 
175 	mutex_lock(&tscm->mutex);
176 
177 	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
178 		tscm->substreams_counter--;
179 
180 	snd_tscm_stream_stop_duplex(tscm);
181 
182 	mutex_unlock(&tscm->mutex);
183 
184 	return snd_pcm_lib_free_vmalloc_buffer(substream);
185 }
186 
187 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
188 {
189 	struct snd_tscm *tscm = substream->private_data;
190 	struct snd_pcm_runtime *runtime = substream->runtime;
191 	int err;
192 
193 	mutex_lock(&tscm->mutex);
194 
195 	err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
196 	if (err >= 0)
197 		amdtp_stream_pcm_prepare(&tscm->tx_stream);
198 
199 	mutex_unlock(&tscm->mutex);
200 
201 	return err;
202 }
203 
204 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
205 {
206 	struct snd_tscm *tscm = substream->private_data;
207 	struct snd_pcm_runtime *runtime = substream->runtime;
208 	int err;
209 
210 	mutex_lock(&tscm->mutex);
211 
212 	err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
213 	if (err >= 0)
214 		amdtp_stream_pcm_prepare(&tscm->rx_stream);
215 
216 	mutex_unlock(&tscm->mutex);
217 
218 	return err;
219 }
220 
221 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
222 {
223 	struct snd_tscm *tscm = substream->private_data;
224 
225 	switch (cmd) {
226 	case SNDRV_PCM_TRIGGER_START:
227 		amdtp_stream_pcm_trigger(&tscm->tx_stream, substream);
228 		break;
229 	case SNDRV_PCM_TRIGGER_STOP:
230 		amdtp_stream_pcm_trigger(&tscm->tx_stream, NULL);
231 		break;
232 	default:
233 		return -EINVAL;
234 	}
235 
236 	return 0;
237 }
238 
239 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
240 {
241 	struct snd_tscm *tscm = substream->private_data;
242 
243 	switch (cmd) {
244 	case SNDRV_PCM_TRIGGER_START:
245 		amdtp_stream_pcm_trigger(&tscm->rx_stream, substream);
246 		break;
247 	case SNDRV_PCM_TRIGGER_STOP:
248 		amdtp_stream_pcm_trigger(&tscm->rx_stream, NULL);
249 		break;
250 	default:
251 		return -EINVAL;
252 	}
253 
254 	return 0;
255 }
256 
257 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
258 {
259 	struct snd_tscm *tscm = sbstrm->private_data;
260 
261 	return amdtp_stream_pcm_pointer(&tscm->tx_stream);
262 }
263 
264 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
265 {
266 	struct snd_tscm *tscm = sbstrm->private_data;
267 
268 	return amdtp_stream_pcm_pointer(&tscm->rx_stream);
269 }
270 
271 static const struct snd_pcm_ops pcm_capture_ops = {
272 	.open		= pcm_open,
273 	.close		= pcm_close,
274 	.ioctl		= snd_pcm_lib_ioctl,
275 	.hw_params	= pcm_capture_hw_params,
276 	.hw_free	= pcm_capture_hw_free,
277 	.prepare	= pcm_capture_prepare,
278 	.trigger	= pcm_capture_trigger,
279 	.pointer	= pcm_capture_pointer,
280 	.page		= snd_pcm_lib_get_vmalloc_page,
281 };
282 
283 static const struct snd_pcm_ops pcm_playback_ops = {
284 	.open		= pcm_open,
285 	.close		= pcm_close,
286 	.ioctl		= snd_pcm_lib_ioctl,
287 	.hw_params	= pcm_playback_hw_params,
288 	.hw_free	= pcm_playback_hw_free,
289 	.prepare	= pcm_playback_prepare,
290 	.trigger	= pcm_playback_trigger,
291 	.pointer	= pcm_playback_pointer,
292 	.page		= snd_pcm_lib_get_vmalloc_page,
293 	.mmap		= snd_pcm_lib_mmap_vmalloc,
294 };
295 
296 int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
297 {
298 	struct snd_pcm *pcm;
299 	int err;
300 
301 	err = snd_pcm_new(tscm->card, tscm->card->driver, 0, 1, 1, &pcm);
302 	if (err < 0)
303 		return err;
304 
305 	pcm->private_data = tscm;
306 	snprintf(pcm->name, sizeof(pcm->name),
307 		 "%s PCM", tscm->card->shortname);
308 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
309 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
310 
311 	return 0;
312 }
313