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_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 		unsigned int rate = params_rate(hw_params);
99 
100 		mutex_lock(&tscm->mutex);
101 		err = snd_tscm_stream_reserve_duplex(tscm, rate);
102 		if (err >= 0)
103 			++tscm->substreams_counter;
104 		mutex_unlock(&tscm->mutex);
105 	}
106 
107 	return err;
108 }
109 
110 static int pcm_hw_free(struct snd_pcm_substream *substream)
111 {
112 	struct snd_tscm *tscm = substream->private_data;
113 
114 	mutex_lock(&tscm->mutex);
115 
116 	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
117 		--tscm->substreams_counter;
118 
119 	snd_tscm_stream_stop_duplex(tscm);
120 
121 	mutex_unlock(&tscm->mutex);
122 
123 	return snd_pcm_lib_free_vmalloc_buffer(substream);
124 }
125 
126 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
127 {
128 	struct snd_tscm *tscm = substream->private_data;
129 	struct snd_pcm_runtime *runtime = substream->runtime;
130 	int err;
131 
132 	mutex_lock(&tscm->mutex);
133 
134 	err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
135 	if (err >= 0)
136 		amdtp_stream_pcm_prepare(&tscm->tx_stream);
137 
138 	mutex_unlock(&tscm->mutex);
139 
140 	return err;
141 }
142 
143 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
144 {
145 	struct snd_tscm *tscm = substream->private_data;
146 	struct snd_pcm_runtime *runtime = substream->runtime;
147 	int err;
148 
149 	mutex_lock(&tscm->mutex);
150 
151 	err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
152 	if (err >= 0)
153 		amdtp_stream_pcm_prepare(&tscm->rx_stream);
154 
155 	mutex_unlock(&tscm->mutex);
156 
157 	return err;
158 }
159 
160 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
161 {
162 	struct snd_tscm *tscm = substream->private_data;
163 
164 	switch (cmd) {
165 	case SNDRV_PCM_TRIGGER_START:
166 		amdtp_stream_pcm_trigger(&tscm->tx_stream, substream);
167 		break;
168 	case SNDRV_PCM_TRIGGER_STOP:
169 		amdtp_stream_pcm_trigger(&tscm->tx_stream, NULL);
170 		break;
171 	default:
172 		return -EINVAL;
173 	}
174 
175 	return 0;
176 }
177 
178 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
179 {
180 	struct snd_tscm *tscm = substream->private_data;
181 
182 	switch (cmd) {
183 	case SNDRV_PCM_TRIGGER_START:
184 		amdtp_stream_pcm_trigger(&tscm->rx_stream, substream);
185 		break;
186 	case SNDRV_PCM_TRIGGER_STOP:
187 		amdtp_stream_pcm_trigger(&tscm->rx_stream, NULL);
188 		break;
189 	default:
190 		return -EINVAL;
191 	}
192 
193 	return 0;
194 }
195 
196 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
197 {
198 	struct snd_tscm *tscm = sbstrm->private_data;
199 
200 	return amdtp_stream_pcm_pointer(&tscm->tx_stream);
201 }
202 
203 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
204 {
205 	struct snd_tscm *tscm = sbstrm->private_data;
206 
207 	return amdtp_stream_pcm_pointer(&tscm->rx_stream);
208 }
209 
210 static int pcm_capture_ack(struct snd_pcm_substream *substream)
211 {
212 	struct snd_tscm *tscm = substream->private_data;
213 
214 	return amdtp_stream_pcm_ack(&tscm->tx_stream);
215 }
216 
217 static int pcm_playback_ack(struct snd_pcm_substream *substream)
218 {
219 	struct snd_tscm *tscm = substream->private_data;
220 
221 	return amdtp_stream_pcm_ack(&tscm->rx_stream);
222 }
223 
224 int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
225 {
226 	static const struct snd_pcm_ops capture_ops = {
227 		.open		= pcm_open,
228 		.close		= pcm_close,
229 		.ioctl		= snd_pcm_lib_ioctl,
230 		.hw_params	= pcm_hw_params,
231 		.hw_free	= pcm_hw_free,
232 		.prepare	= pcm_capture_prepare,
233 		.trigger	= pcm_capture_trigger,
234 		.pointer	= pcm_capture_pointer,
235 		.ack		= pcm_capture_ack,
236 		.page		= snd_pcm_lib_get_vmalloc_page,
237 	};
238 	static const struct snd_pcm_ops playback_ops = {
239 		.open		= pcm_open,
240 		.close		= pcm_close,
241 		.ioctl		= snd_pcm_lib_ioctl,
242 		.hw_params	= pcm_hw_params,
243 		.hw_free	= pcm_hw_free,
244 		.prepare	= pcm_playback_prepare,
245 		.trigger	= pcm_playback_trigger,
246 		.pointer	= pcm_playback_pointer,
247 		.ack		= pcm_playback_ack,
248 		.page		= snd_pcm_lib_get_vmalloc_page,
249 	};
250 	struct snd_pcm *pcm;
251 	int err;
252 
253 	err = snd_pcm_new(tscm->card, tscm->card->driver, 0, 1, 1, &pcm);
254 	if (err < 0)
255 		return err;
256 
257 	pcm->private_data = tscm;
258 	snprintf(pcm->name, sizeof(pcm->name),
259 		 "%s PCM", tscm->card->shortname);
260 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
261 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
262 
263 	return 0;
264 }
265