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