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