xref: /openbmc/linux/sound/firewire/dice/dice-pcm.c (revision 4f6cce39)
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 void limit_period_and_buffer(struct snd_pcm_hardware *hw)
55 {
56 	hw->periods_min = 2;			/* SNDRV_PCM_INFO_BATCH */
57 	hw->periods_max = UINT_MAX;
58 
59 	hw->period_bytes_min = 4 * hw->channels_max;    /* byte for a frame */
60 
61 	/* Just to prevent from allocating much pages. */
62 	hw->period_bytes_max = hw->period_bytes_min * 2048;
63 	hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
64 }
65 
66 static int init_hw_info(struct snd_dice *dice,
67 			struct snd_pcm_substream *substream)
68 {
69 	struct snd_pcm_runtime *runtime = substream->runtime;
70 	struct snd_pcm_hardware *hw = &runtime->hw;
71 	enum amdtp_stream_direction dir;
72 	struct amdtp_stream *stream;
73 	__be32 reg[2];
74 	unsigned int count, size;
75 	int err;
76 
77 	hw->info = SNDRV_PCM_INFO_MMAP |
78 		   SNDRV_PCM_INFO_MMAP_VALID |
79 		   SNDRV_PCM_INFO_BATCH |
80 		   SNDRV_PCM_INFO_INTERLEAVED |
81 		   SNDRV_PCM_INFO_JOINT_DUPLEX |
82 		   SNDRV_PCM_INFO_BLOCK_TRANSFER;
83 
84 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
85 		hw->formats = AM824_IN_PCM_FORMAT_BITS;
86 		dir = AMDTP_IN_STREAM;
87 		stream = &dice->tx_stream[substream->pcm->device];
88 		err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg,
89 						   sizeof(reg));
90 	} else {
91 		hw->formats = AM824_OUT_PCM_FORMAT_BITS;
92 		dir = AMDTP_OUT_STREAM;
93 		stream = &dice->rx_stream[substream->pcm->device];
94 		err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg,
95 						   sizeof(reg));
96 	}
97 
98 	if (err < 0)
99 		return err;
100 
101 	count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
102 	if (substream->pcm->device >= count)
103 		return -ENXIO;
104 
105 	size = be32_to_cpu(reg[1]) * 4;
106 	err = limit_channels_and_rates(dice, substream->runtime, dir,
107 				       substream->pcm->device, size);
108 	if (err < 0)
109 		return err;
110 	limit_period_and_buffer(hw);
111 
112 	return amdtp_am824_add_pcm_hw_constraints(stream, runtime);
113 }
114 
115 static int pcm_open(struct snd_pcm_substream *substream)
116 {
117 	struct snd_dice *dice = substream->private_data;
118 	int err;
119 
120 	err = snd_dice_stream_lock_try(dice);
121 	if (err < 0)
122 		goto end;
123 
124 	err = init_hw_info(dice, substream);
125 	if (err < 0)
126 		goto err_locked;
127 
128 	snd_pcm_set_sync(substream);
129 end:
130 	return err;
131 err_locked:
132 	snd_dice_stream_lock_release(dice);
133 	return err;
134 }
135 
136 static int pcm_close(struct snd_pcm_substream *substream)
137 {
138 	struct snd_dice *dice = substream->private_data;
139 
140 	snd_dice_stream_lock_release(dice);
141 
142 	return 0;
143 }
144 
145 static int capture_hw_params(struct snd_pcm_substream *substream,
146 			     struct snd_pcm_hw_params *hw_params)
147 {
148 	struct snd_dice *dice = substream->private_data;
149 	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
150 	int err;
151 
152 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
153 					       params_buffer_bytes(hw_params));
154 	if (err < 0)
155 		return err;
156 
157 	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
158 		mutex_lock(&dice->mutex);
159 		dice->substreams_counter++;
160 		mutex_unlock(&dice->mutex);
161 	}
162 
163 	amdtp_am824_set_pcm_format(stream, params_format(hw_params));
164 
165 	return 0;
166 }
167 static int playback_hw_params(struct snd_pcm_substream *substream,
168 			      struct snd_pcm_hw_params *hw_params)
169 {
170 	struct snd_dice *dice = substream->private_data;
171 	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
172 	int err;
173 
174 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
175 					       params_buffer_bytes(hw_params));
176 	if (err < 0)
177 		return err;
178 
179 	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
180 		mutex_lock(&dice->mutex);
181 		dice->substreams_counter++;
182 		mutex_unlock(&dice->mutex);
183 	}
184 
185 	amdtp_am824_set_pcm_format(stream, params_format(hw_params));
186 
187 	return 0;
188 }
189 
190 static int capture_hw_free(struct snd_pcm_substream *substream)
191 {
192 	struct snd_dice *dice = substream->private_data;
193 
194 	mutex_lock(&dice->mutex);
195 
196 	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
197 		dice->substreams_counter--;
198 
199 	snd_dice_stream_stop_duplex(dice);
200 
201 	mutex_unlock(&dice->mutex);
202 
203 	return snd_pcm_lib_free_vmalloc_buffer(substream);
204 }
205 
206 static int playback_hw_free(struct snd_pcm_substream *substream)
207 {
208 	struct snd_dice *dice = substream->private_data;
209 
210 	mutex_lock(&dice->mutex);
211 
212 	if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
213 		dice->substreams_counter--;
214 
215 	snd_dice_stream_stop_duplex(dice);
216 
217 	mutex_unlock(&dice->mutex);
218 
219 	return snd_pcm_lib_free_vmalloc_buffer(substream);
220 }
221 
222 static int capture_prepare(struct snd_pcm_substream *substream)
223 {
224 	struct snd_dice *dice = substream->private_data;
225 	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
226 	int err;
227 
228 	mutex_lock(&dice->mutex);
229 	err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
230 	mutex_unlock(&dice->mutex);
231 	if (err >= 0)
232 		amdtp_stream_pcm_prepare(stream);
233 
234 	return 0;
235 }
236 static int playback_prepare(struct snd_pcm_substream *substream)
237 {
238 	struct snd_dice *dice = substream->private_data;
239 	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
240 	int err;
241 
242 	mutex_lock(&dice->mutex);
243 	err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
244 	mutex_unlock(&dice->mutex);
245 	if (err >= 0)
246 		amdtp_stream_pcm_prepare(stream);
247 
248 	return err;
249 }
250 
251 static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
252 {
253 	struct snd_dice *dice = substream->private_data;
254 	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
255 
256 	switch (cmd) {
257 	case SNDRV_PCM_TRIGGER_START:
258 		amdtp_stream_pcm_trigger(stream, substream);
259 		break;
260 	case SNDRV_PCM_TRIGGER_STOP:
261 		amdtp_stream_pcm_trigger(stream, NULL);
262 		break;
263 	default:
264 		return -EINVAL;
265 	}
266 
267 	return 0;
268 }
269 static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
270 {
271 	struct snd_dice *dice = substream->private_data;
272 	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
273 
274 	switch (cmd) {
275 	case SNDRV_PCM_TRIGGER_START:
276 		amdtp_stream_pcm_trigger(stream, substream);
277 		break;
278 	case SNDRV_PCM_TRIGGER_STOP:
279 		amdtp_stream_pcm_trigger(stream, NULL);
280 		break;
281 	default:
282 		return -EINVAL;
283 	}
284 
285 	return 0;
286 }
287 
288 static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
289 {
290 	struct snd_dice *dice = substream->private_data;
291 	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
292 
293 	return amdtp_stream_pcm_pointer(stream);
294 }
295 static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
296 {
297 	struct snd_dice *dice = substream->private_data;
298 	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
299 
300 	return amdtp_stream_pcm_pointer(stream);
301 }
302 
303 int snd_dice_create_pcm(struct snd_dice *dice)
304 {
305 	static const struct snd_pcm_ops capture_ops = {
306 		.open      = pcm_open,
307 		.close     = pcm_close,
308 		.ioctl     = snd_pcm_lib_ioctl,
309 		.hw_params = capture_hw_params,
310 		.hw_free   = capture_hw_free,
311 		.prepare   = capture_prepare,
312 		.trigger   = capture_trigger,
313 		.pointer   = capture_pointer,
314 		.page      = snd_pcm_lib_get_vmalloc_page,
315 		.mmap      = snd_pcm_lib_mmap_vmalloc,
316 	};
317 	static const struct snd_pcm_ops playback_ops = {
318 		.open      = pcm_open,
319 		.close     = pcm_close,
320 		.ioctl     = snd_pcm_lib_ioctl,
321 		.hw_params = playback_hw_params,
322 		.hw_free   = playback_hw_free,
323 		.prepare   = playback_prepare,
324 		.trigger   = playback_trigger,
325 		.pointer   = playback_pointer,
326 		.page      = snd_pcm_lib_get_vmalloc_page,
327 		.mmap      = snd_pcm_lib_mmap_vmalloc,
328 	};
329 	__be32 reg;
330 	struct snd_pcm *pcm;
331 	unsigned int i, max_capture, max_playback, capture, playback;
332 	int err;
333 
334 	/* Check whether PCM substreams are required. */
335 	if (dice->force_two_pcms) {
336 		max_capture = max_playback = 2;
337 	} else {
338 		max_capture = max_playback = 0;
339 		err = snd_dice_transaction_read_tx(dice, TX_NUMBER, &reg,
340 						   sizeof(reg));
341 		if (err < 0)
342 			return err;
343 		max_capture = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
344 
345 		err = snd_dice_transaction_read_rx(dice, RX_NUMBER, &reg,
346 						   sizeof(reg));
347 		if (err < 0)
348 			return err;
349 		max_playback = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
350 	}
351 
352 	for (i = 0; i < MAX_STREAMS; i++) {
353 		capture = playback = 0;
354 		if (i < max_capture)
355 			capture = 1;
356 		if (i < max_playback)
357 			playback = 1;
358 		if (capture == 0 && playback == 0)
359 			break;
360 
361 		err = snd_pcm_new(dice->card, "DICE", i, playback, capture,
362 				  &pcm);
363 		if (err < 0)
364 			return err;
365 		pcm->private_data = dice;
366 		strcpy(pcm->name, dice->card->shortname);
367 
368 		if (capture > 0)
369 			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
370 					&capture_ops);
371 
372 		if (playback > 0)
373 			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
374 					&playback_ops);
375 	}
376 
377 	return 0;
378 }
379