blob: 4aa0249826fd1378661d76a75cbb59a9b96ba8db [file] [log] [blame]
Takashi Sakamotoc50fb912014-11-29 00:59:15 +09001/*
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
Takashi Sakamoto0d5ee192016-02-08 22:54:15 +090012static int limit_channels_and_rates(struct snd_dice *dice,
13 struct snd_pcm_runtime *runtime,
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +090014 enum amdtp_stream_direction dir,
15 unsigned int index, unsigned int size)
Takashi Sakamotoc50fb912014-11-29 00:59:15 +090016{
Takashi Sakamoto2c2416c2014-11-29 00:59:18 +090017 struct snd_pcm_hardware *hw = &runtime->hw;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +090018 struct amdtp_stream *stream;
Takashi Sakamoto0d5ee192016-02-08 22:54:15 +090019 unsigned int rate;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +090020 __be32 reg;
Takashi Sakamoto0d5ee192016-02-08 22:54:15 +090021 int err;
Takashi Sakamotoc50fb912014-11-29 00:59:15 +090022
Takashi Sakamoto0d5ee192016-02-08 22:54:15 +090023 /*
24 * Retrieve current Multi Bit Linear Audio data channel and limit to
25 * it.
26 */
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +090027 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));
Takashi Sakamoto0d5ee192016-02-08 22:54:15 +090032 } else {
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +090033 stream = &dice->rx_stream[index];
34 err = snd_dice_transaction_read_rx(dice,
35 size * index + RX_NUMBER_AUDIO,
36 &reg, sizeof(reg));
Takashi Sakamotoc50fb912014-11-29 00:59:15 +090037 }
Takashi Sakamoto0d5ee192016-02-08 22:54:15 +090038 if (err < 0)
39 return err;
Takashi Sakamotoc50fb912014-11-29 00:59:15 +090040
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +090041 hw->channels_min = hw->channels_max = be32_to_cpu(reg);
Takashi Sakamoto0d5ee192016-02-08 22:54:15 +090042
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);
Takashi Sakamoto2c2416c2014-11-29 00:59:18 +090049 snd_pcm_limit_hw_rates(runtime);
Takashi Sakamoto0d5ee192016-02-08 22:54:15 +090050
51 return 0;
Takashi Sakamoto2c2416c2014-11-29 00:59:18 +090052}
53
54static 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
66static 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;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +090071 enum amdtp_stream_direction dir;
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +090072 struct amdtp_stream *stream;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +090073 __be32 reg[2];
74 unsigned int count, size;
Takashi Sakamoto2c2416c2014-11-29 00:59:18 +090075 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 |
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +090081 SNDRV_PCM_INFO_JOINT_DUPLEX |
Takashi Sakamoto2c2416c2014-11-29 00:59:18 +090082 SNDRV_PCM_INFO_BLOCK_TRANSFER;
Takashi Sakamoto2c2416c2014-11-29 00:59:18 +090083
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +090084 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
Takashi Sakamoto49c7b3f2015-09-19 11:22:01 +090085 hw->formats = AM824_IN_PCM_FORMAT_BITS;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +090086 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));
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +090090 } else {
Takashi Sakamoto49c7b3f2015-09-19 11:22:01 +090091 hw->formats = AM824_OUT_PCM_FORMAT_BITS;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +090092 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));
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +090096 }
97
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +090098 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);
Takashi Sakamoto0d5ee192016-02-08 22:54:15 +0900108 if (err < 0)
109 return err;
Takashi Sakamoto2c2416c2014-11-29 00:59:18 +0900110 limit_period_and_buffer(hw);
111
Takashi Sakamoto0d5ee192016-02-08 22:54:15 +0900112 return amdtp_am824_add_pcm_hw_constraints(stream, runtime);
Takashi Sakamoto2c2416c2014-11-29 00:59:18 +0900113}
114
115static 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);
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900121 if (err < 0)
Takashi Sakamoto2c2416c2014-11-29 00:59:18 +0900122 goto end;
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900123
Takashi Sakamoto2c2416c2014-11-29 00:59:18 +0900124 err = init_hw_info(dice, substream);
125 if (err < 0)
126 goto err_locked;
Takashi Sakamoto8fc01fc2014-12-09 00:10:37 +0900127
Takashi Sakamoto8fc01fc2014-12-09 00:10:37 +0900128 snd_pcm_set_sync(substream);
Takashi Sakamoto2c2416c2014-11-29 00:59:18 +0900129end:
130 return err;
131err_locked:
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900132 snd_dice_stream_lock_release(dice);
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900133 return err;
134}
135
136static 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
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900145static 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;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900149 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
Takashi Sakamoto22c103c2015-08-29 10:38:46 +0900150 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;
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900156
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
Takashi Sakamoto8ae25b762016-03-07 22:35:42 +0900163 amdtp_am824_set_pcm_format(stream, params_format(hw_params));
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900164
Takashi Sakamoto22c103c2015-08-29 10:38:46 +0900165 return 0;
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900166}
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900167static 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;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900171 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
Takashi Sakamoto22c103c2015-08-29 10:38:46 +0900172 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;
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900178
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
Takashi Sakamoto8ae25b762016-03-07 22:35:42 +0900185 amdtp_am824_set_pcm_format(stream, params_format(hw_params));
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900186
Takashi Sakamoto22c103c2015-08-29 10:38:46 +0900187 return 0;
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900188}
189
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900190static int capture_hw_free(struct snd_pcm_substream *substream)
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900191{
192 struct snd_dice *dice = substream->private_data;
193
194 mutex_lock(&dice->mutex);
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900195
196 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
197 dice->substreams_counter--;
198
Takashi Sakamoto9a028432014-12-09 00:10:36 +0900199 snd_dice_stream_stop_duplex(dice);
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900200
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900201 mutex_unlock(&dice->mutex);
202
203 return snd_pcm_lib_free_vmalloc_buffer(substream);
204}
205
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900206static 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
222static int capture_prepare(struct snd_pcm_substream *substream)
223{
224 struct snd_dice *dice = substream->private_data;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900225 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900226 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)
Takashi Sakamoto8ae25b762016-03-07 22:35:42 +0900232 amdtp_stream_pcm_prepare(stream);
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900233
234 return 0;
235}
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900236static int playback_prepare(struct snd_pcm_substream *substream)
237{
238 struct snd_dice *dice = substream->private_data;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900239 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900240 int err;
241
242 mutex_lock(&dice->mutex);
Takashi Sakamoto9a028432014-12-09 00:10:36 +0900243 err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900244 mutex_unlock(&dice->mutex);
Takashi Sakamoto288a8d02014-12-09 00:10:35 +0900245 if (err >= 0)
Takashi Sakamoto8ae25b762016-03-07 22:35:42 +0900246 amdtp_stream_pcm_prepare(stream);
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900247
Takashi Sakamoto288a8d02014-12-09 00:10:35 +0900248 return err;
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900249}
250
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900251static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
252{
253 struct snd_dice *dice = substream->private_data;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900254 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900255
256 switch (cmd) {
257 case SNDRV_PCM_TRIGGER_START:
Takashi Sakamoto8ae25b762016-03-07 22:35:42 +0900258 amdtp_stream_pcm_trigger(stream, substream);
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900259 break;
260 case SNDRV_PCM_TRIGGER_STOP:
Takashi Sakamoto8ae25b762016-03-07 22:35:42 +0900261 amdtp_stream_pcm_trigger(stream, NULL);
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900262 break;
263 default:
264 return -EINVAL;
265 }
266
267 return 0;
268}
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900269static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
270{
271 struct snd_dice *dice = substream->private_data;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900272 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900273
274 switch (cmd) {
275 case SNDRV_PCM_TRIGGER_START:
Takashi Sakamoto8ae25b762016-03-07 22:35:42 +0900276 amdtp_stream_pcm_trigger(stream, substream);
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900277 break;
278 case SNDRV_PCM_TRIGGER_STOP:
Takashi Sakamoto8ae25b762016-03-07 22:35:42 +0900279 amdtp_stream_pcm_trigger(stream, NULL);
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900280 break;
281 default:
282 return -EINVAL;
283 }
284
285 return 0;
286}
287
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900288static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
289{
290 struct snd_dice *dice = substream->private_data;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900291 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900292
Takashi Sakamoto8ae25b762016-03-07 22:35:42 +0900293 return amdtp_stream_pcm_pointer(stream);
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900294}
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900295static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
296{
297 struct snd_dice *dice = substream->private_data;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900298 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900299
Takashi Sakamoto8ae25b762016-03-07 22:35:42 +0900300 return amdtp_stream_pcm_pointer(stream);
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900301}
302
303int snd_dice_create_pcm(struct snd_dice *dice)
304{
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900305 static 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 };
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900317 static 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 };
Takashi Sakamotoc3007652016-02-08 22:54:18 +0900329 __be32 reg;
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900330 struct snd_pcm *pcm;
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900331 unsigned int i, max_capture, max_playback, capture, playback;
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900332 int err;
333
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900334 /* Check whether PCM substreams are required. */
Takashi Sakamoto7cafc652016-03-07 22:35:45 +0900335 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);
Takashi Sakamotoc3007652016-02-08 22:54:18 +0900344
Takashi Sakamoto7cafc652016-03-07 22:35:45 +0900345 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 }
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900351
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900352 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;
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900360
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900361 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);
Takashi Sakamoto69dcf3e2014-12-09 00:10:38 +0900367
Takashi Sakamoto4bdc4952016-03-07 22:35:44 +0900368 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 }
Takashi Sakamotoc50fb912014-11-29 00:59:15 +0900376
377 return 0;
378}