xref: /openbmc/linux/sound/firewire/dice/dice-pcm.c (revision 82e6fdd6)
1 /*
2  * dice_pcm.c - a part of driver for DICE based devices
3  *
4  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5  * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6  *
7  * Licensed under the terms of the GNU General Public License, version 2.
8  */
9 
10 #include "dice.h"
11 
12 static int limit_channels_and_rates(struct snd_dice *dice,
13 				    struct snd_pcm_runtime *runtime,
14 				    enum amdtp_stream_direction dir,
15 				    unsigned int index, unsigned int size)
16 {
17 	struct snd_pcm_hardware *hw = &runtime->hw;
18 	struct amdtp_stream *stream;
19 	unsigned int rate;
20 	__be32 reg;
21 	int err;
22 
23 	/*
24 	 * Retrieve current Multi Bit Linear Audio data channel and limit to
25 	 * it.
26 	 */
27 	if (dir == AMDTP_IN_STREAM) {
28 		stream = &dice->tx_stream[index];
29 		err = snd_dice_transaction_read_tx(dice,
30 				size * index + TX_NUMBER_AUDIO,
31 				&reg, sizeof(reg));
32 	} else {
33 		stream = &dice->rx_stream[index];
34 		err = snd_dice_transaction_read_rx(dice,
35 				size * index + RX_NUMBER_AUDIO,
36 				&reg, sizeof(reg));
37 	}
38 	if (err < 0)
39 		return err;
40 
41 	hw->channels_min = hw->channels_max = be32_to_cpu(reg);
42 
43 	/* Retrieve current sampling transfer frequency and limit to it. */
44 	err = snd_dice_transaction_get_rate(dice, &rate);
45 	if (err < 0)
46 		return err;
47 
48 	hw->rates = snd_pcm_rate_to_rate_bit(rate);
49 	snd_pcm_limit_hw_rates(runtime);
50 
51 	return 0;
52 }
53 
54 static int init_hw_info(struct snd_dice *dice,
55 			struct snd_pcm_substream *substream)
56 {
57 	struct snd_pcm_runtime *runtime = substream->runtime;
58 	struct snd_pcm_hardware *hw = &runtime->hw;
59 	enum amdtp_stream_direction dir;
60 	struct amdtp_stream *stream;
61 	__be32 reg[2];
62 	unsigned int count, size;
63 	int err;
64 
65 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
66 		hw->formats = AM824_IN_PCM_FORMAT_BITS;
67 		dir = AMDTP_IN_STREAM;
68 		stream = &dice->tx_stream[substream->pcm->device];
69 		err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg,
70 						   sizeof(reg));
71 	} else {
72 		hw->formats = AM824_OUT_PCM_FORMAT_BITS;
73 		dir = AMDTP_OUT_STREAM;
74 		stream = &dice->rx_stream[substream->pcm->device];
75 		err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg,
76 						   sizeof(reg));
77 	}
78 
79 	if (err < 0)
80 		return err;
81 
82 	count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
83 	if (substream->pcm->device >= count)
84 		return -ENXIO;
85 
86 	size = be32_to_cpu(reg[1]) * 4;
87 	err = limit_channels_and_rates(dice, substream->runtime, dir,
88 				       substream->pcm->device, size);
89 	if (err < 0)
90 		return err;
91 
92 	return amdtp_am824_add_pcm_hw_constraints(stream, runtime);
93 }
94 
95 static int pcm_open(struct snd_pcm_substream *substream)
96 {
97 	struct snd_dice *dice = substream->private_data;
98 	int err;
99 
100 	err = snd_dice_stream_lock_try(dice);
101 	if (err < 0)
102 		goto end;
103 
104 	err = init_hw_info(dice, substream);
105 	if (err < 0)
106 		goto err_locked;
107 
108 	snd_pcm_set_sync(substream);
109 end:
110 	return err;
111 err_locked:
112 	snd_dice_stream_lock_release(dice);
113 	return err;
114 }
115 
116 static int pcm_close(struct snd_pcm_substream *substream)
117 {
118 	struct snd_dice *dice = substream->private_data;
119 
120 	snd_dice_stream_lock_release(dice);
121 
122 	return 0;
123 }
124 
125 static int capture_hw_params(struct snd_pcm_substream *substream,
126 			     struct snd_pcm_hw_params *hw_params)
127 {
128 	struct snd_dice *dice = substream->private_data;
129 	int err;
130 
131 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
132 					       params_buffer_bytes(hw_params));
133 	if (err < 0)
134 		return err;
135 
136 	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
137 		mutex_lock(&dice->mutex);
138 		dice->substreams_counter++;
139 		mutex_unlock(&dice->mutex);
140 	}
141 
142 	return 0;
143 }
144 static int playback_hw_params(struct snd_pcm_substream *substream,
145 			      struct snd_pcm_hw_params *hw_params)
146 {
147 	struct snd_dice *dice = substream->private_data;
148 	int err;
149 
150 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
151 					       params_buffer_bytes(hw_params));
152 	if (err < 0)
153 		return err;
154 
155 	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
156 		mutex_lock(&dice->mutex);
157 		dice->substreams_counter++;
158 		mutex_unlock(&dice->mutex);
159 	}
160 
161 	return 0;
162 }
163 
164 static int capture_hw_free(struct snd_pcm_substream *substream)
165 {
166 	struct snd_dice *dice = substream->private_data;
167 
168 	mutex_lock(&dice->mutex);
169 
170 	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
171 		dice->substreams_counter--;
172 
173 	snd_dice_stream_stop_duplex(dice);
174 
175 	mutex_unlock(&dice->mutex);
176 
177 	return snd_pcm_lib_free_vmalloc_buffer(substream);
178 }
179 
180 static int playback_hw_free(struct snd_pcm_substream *substream)
181 {
182 	struct snd_dice *dice = substream->private_data;
183 
184 	mutex_lock(&dice->mutex);
185 
186 	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
187 		dice->substreams_counter--;
188 
189 	snd_dice_stream_stop_duplex(dice);
190 
191 	mutex_unlock(&dice->mutex);
192 
193 	return snd_pcm_lib_free_vmalloc_buffer(substream);
194 }
195 
196 static int capture_prepare(struct snd_pcm_substream *substream)
197 {
198 	struct snd_dice *dice = substream->private_data;
199 	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
200 	int err;
201 
202 	mutex_lock(&dice->mutex);
203 	err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
204 	mutex_unlock(&dice->mutex);
205 	if (err >= 0)
206 		amdtp_stream_pcm_prepare(stream);
207 
208 	return 0;
209 }
210 static int playback_prepare(struct snd_pcm_substream *substream)
211 {
212 	struct snd_dice *dice = substream->private_data;
213 	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
214 	int err;
215 
216 	mutex_lock(&dice->mutex);
217 	err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
218 	mutex_unlock(&dice->mutex);
219 	if (err >= 0)
220 		amdtp_stream_pcm_prepare(stream);
221 
222 	return err;
223 }
224 
225 static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
226 {
227 	struct snd_dice *dice = substream->private_data;
228 	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
229 
230 	switch (cmd) {
231 	case SNDRV_PCM_TRIGGER_START:
232 		amdtp_stream_pcm_trigger(stream, substream);
233 		break;
234 	case SNDRV_PCM_TRIGGER_STOP:
235 		amdtp_stream_pcm_trigger(stream, NULL);
236 		break;
237 	default:
238 		return -EINVAL;
239 	}
240 
241 	return 0;
242 }
243 static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
244 {
245 	struct snd_dice *dice = substream->private_data;
246 	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
247 
248 	switch (cmd) {
249 	case SNDRV_PCM_TRIGGER_START:
250 		amdtp_stream_pcm_trigger(stream, substream);
251 		break;
252 	case SNDRV_PCM_TRIGGER_STOP:
253 		amdtp_stream_pcm_trigger(stream, NULL);
254 		break;
255 	default:
256 		return -EINVAL;
257 	}
258 
259 	return 0;
260 }
261 
262 static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
263 {
264 	struct snd_dice *dice = substream->private_data;
265 	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
266 
267 	return amdtp_stream_pcm_pointer(stream);
268 }
269 static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
270 {
271 	struct snd_dice *dice = substream->private_data;
272 	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
273 
274 	return amdtp_stream_pcm_pointer(stream);
275 }
276 
277 static int capture_ack(struct snd_pcm_substream *substream)
278 {
279 	struct snd_dice *dice = substream->private_data;
280 	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
281 
282 	return amdtp_stream_pcm_ack(stream);
283 }
284 
285 static int playback_ack(struct snd_pcm_substream *substream)
286 {
287 	struct snd_dice *dice = substream->private_data;
288 	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
289 
290 	return amdtp_stream_pcm_ack(stream);
291 }
292 
293 int snd_dice_create_pcm(struct snd_dice *dice)
294 {
295 	static const struct snd_pcm_ops capture_ops = {
296 		.open      = pcm_open,
297 		.close     = pcm_close,
298 		.ioctl     = snd_pcm_lib_ioctl,
299 		.hw_params = capture_hw_params,
300 		.hw_free   = capture_hw_free,
301 		.prepare   = capture_prepare,
302 		.trigger   = capture_trigger,
303 		.pointer   = capture_pointer,
304 		.ack       = capture_ack,
305 		.page      = snd_pcm_lib_get_vmalloc_page,
306 		.mmap      = snd_pcm_lib_mmap_vmalloc,
307 	};
308 	static const struct snd_pcm_ops playback_ops = {
309 		.open      = pcm_open,
310 		.close     = pcm_close,
311 		.ioctl     = snd_pcm_lib_ioctl,
312 		.hw_params = playback_hw_params,
313 		.hw_free   = playback_hw_free,
314 		.prepare   = playback_prepare,
315 		.trigger   = playback_trigger,
316 		.pointer   = playback_pointer,
317 		.ack       = playback_ack,
318 		.page      = snd_pcm_lib_get_vmalloc_page,
319 		.mmap      = snd_pcm_lib_mmap_vmalloc,
320 	};
321 	__be32 reg;
322 	struct snd_pcm *pcm;
323 	unsigned int i, max_capture, max_playback, capture, playback;
324 	int err;
325 
326 	/* Check whether PCM substreams are required. */
327 	if (dice->force_two_pcms) {
328 		max_capture = max_playback = 2;
329 	} else {
330 		max_capture = max_playback = 0;
331 		err = snd_dice_transaction_read_tx(dice, TX_NUMBER, &reg,
332 						   sizeof(reg));
333 		if (err < 0)
334 			return err;
335 		max_capture = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
336 
337 		err = snd_dice_transaction_read_rx(dice, RX_NUMBER, &reg,
338 						   sizeof(reg));
339 		if (err < 0)
340 			return err;
341 		max_playback = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
342 	}
343 
344 	for (i = 0; i < MAX_STREAMS; i++) {
345 		capture = playback = 0;
346 		if (i < max_capture)
347 			capture = 1;
348 		if (i < max_playback)
349 			playback = 1;
350 		if (capture == 0 && playback == 0)
351 			break;
352 
353 		err = snd_pcm_new(dice->card, "DICE", i, playback, capture,
354 				  &pcm);
355 		if (err < 0)
356 			return err;
357 		pcm->private_data = dice;
358 		strcpy(pcm->name, dice->card->shortname);
359 
360 		if (capture > 0)
361 			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
362 					&capture_ops);
363 
364 		if (playback > 0)
365 			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
366 					&playback_ops);
367 	}
368 
369 	return 0;
370 }
371