ALSA: dice: handle whole available isochronous streams
[cascardo/linux.git] / sound / firewire / dice / dice-pcm.c
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                                     struct amdtp_stream *stream)
15 {
16         struct snd_pcm_hardware *hw = &runtime->hw;
17         unsigned int rate;
18         __be32 reg[2];
19         int err;
20
21         /*
22          * Retrieve current Multi Bit Linear Audio data channel and limit to
23          * it.
24          */
25         if (stream == &dice->tx_stream[0]) {
26                 err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
27                                                    reg, sizeof(reg));
28         } else {
29                 err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
30                                                    reg, sizeof(reg));
31         }
32         if (err < 0)
33                 return err;
34
35         hw->channels_min = hw->channels_max = be32_to_cpu(reg[0]);
36
37         /* Retrieve current sampling transfer frequency and limit to it. */
38         err = snd_dice_transaction_get_rate(dice, &rate);
39         if (err < 0)
40                 return err;
41
42         hw->rates = snd_pcm_rate_to_rate_bit(rate);
43         snd_pcm_limit_hw_rates(runtime);
44
45         return 0;
46 }
47
48 static void limit_period_and_buffer(struct snd_pcm_hardware *hw)
49 {
50         hw->periods_min = 2;                    /* SNDRV_PCM_INFO_BATCH */
51         hw->periods_max = UINT_MAX;
52
53         hw->period_bytes_min = 4 * hw->channels_max;    /* byte for a frame */
54
55         /* Just to prevent from allocating much pages. */
56         hw->period_bytes_max = hw->period_bytes_min * 2048;
57         hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
58 }
59
60 static int init_hw_info(struct snd_dice *dice,
61                         struct snd_pcm_substream *substream)
62 {
63         struct snd_pcm_runtime *runtime = substream->runtime;
64         struct snd_pcm_hardware *hw = &runtime->hw;
65         struct amdtp_stream *stream;
66         int err;
67
68         hw->info = SNDRV_PCM_INFO_MMAP |
69                    SNDRV_PCM_INFO_MMAP_VALID |
70                    SNDRV_PCM_INFO_BATCH |
71                    SNDRV_PCM_INFO_INTERLEAVED |
72                    SNDRV_PCM_INFO_JOINT_DUPLEX |
73                    SNDRV_PCM_INFO_BLOCK_TRANSFER;
74
75         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
76                 hw->formats = AM824_IN_PCM_FORMAT_BITS;
77                 stream = &dice->tx_stream[0];
78         } else {
79                 hw->formats = AM824_OUT_PCM_FORMAT_BITS;
80                 stream = &dice->rx_stream[0];
81         }
82
83         err = limit_channels_and_rates(dice, runtime, stream);
84         if (err < 0)
85                 return err;
86         limit_period_and_buffer(hw);
87
88         return amdtp_am824_add_pcm_hw_constraints(stream, runtime);
89 }
90
91 static int pcm_open(struct snd_pcm_substream *substream)
92 {
93         struct snd_dice *dice = substream->private_data;
94         int err;
95
96         err = snd_dice_stream_lock_try(dice);
97         if (err < 0)
98                 goto end;
99
100         err = init_hw_info(dice, substream);
101         if (err < 0)
102                 goto err_locked;
103
104         snd_pcm_set_sync(substream);
105 end:
106         return err;
107 err_locked:
108         snd_dice_stream_lock_release(dice);
109         return err;
110 }
111
112 static int pcm_close(struct snd_pcm_substream *substream)
113 {
114         struct snd_dice *dice = substream->private_data;
115
116         snd_dice_stream_lock_release(dice);
117
118         return 0;
119 }
120
121 static int capture_hw_params(struct snd_pcm_substream *substream,
122                              struct snd_pcm_hw_params *hw_params)
123 {
124         struct snd_dice *dice = substream->private_data;
125         struct amdtp_stream *stream = &dice->tx_stream[0];
126         int err;
127
128         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
129                                                params_buffer_bytes(hw_params));
130         if (err < 0)
131                 return err;
132
133         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
134                 mutex_lock(&dice->mutex);
135                 dice->substreams_counter++;
136                 mutex_unlock(&dice->mutex);
137         }
138
139         amdtp_am824_set_pcm_format(stream, params_format(hw_params));
140
141         return 0;
142 }
143 static int playback_hw_params(struct snd_pcm_substream *substream,
144                               struct snd_pcm_hw_params *hw_params)
145 {
146         struct snd_dice *dice = substream->private_data;
147         struct amdtp_stream *stream = &dice->rx_stream[0];
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         amdtp_am824_set_pcm_format(stream, params_format(hw_params));
162
163         return 0;
164 }
165
166 static int capture_hw_free(struct snd_pcm_substream *substream)
167 {
168         struct snd_dice *dice = substream->private_data;
169
170         mutex_lock(&dice->mutex);
171
172         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
173                 dice->substreams_counter--;
174
175         snd_dice_stream_stop_duplex(dice);
176
177         mutex_unlock(&dice->mutex);
178
179         return snd_pcm_lib_free_vmalloc_buffer(substream);
180 }
181
182 static int playback_hw_free(struct snd_pcm_substream *substream)
183 {
184         struct snd_dice *dice = substream->private_data;
185
186         mutex_lock(&dice->mutex);
187
188         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
189                 dice->substreams_counter--;
190
191         snd_dice_stream_stop_duplex(dice);
192
193         mutex_unlock(&dice->mutex);
194
195         return snd_pcm_lib_free_vmalloc_buffer(substream);
196 }
197
198 static int capture_prepare(struct snd_pcm_substream *substream)
199 {
200         struct snd_dice *dice = substream->private_data;
201         struct amdtp_stream *stream = &dice->tx_stream[0];
202         int err;
203
204         mutex_lock(&dice->mutex);
205         err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
206         mutex_unlock(&dice->mutex);
207         if (err >= 0)
208                 amdtp_stream_pcm_prepare(stream);
209
210         return 0;
211 }
212 static int playback_prepare(struct snd_pcm_substream *substream)
213 {
214         struct snd_dice *dice = substream->private_data;
215         struct amdtp_stream *stream = &dice->rx_stream[0];
216         int err;
217
218         mutex_lock(&dice->mutex);
219         err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
220         mutex_unlock(&dice->mutex);
221         if (err >= 0)
222                 amdtp_stream_pcm_prepare(stream);
223
224         return err;
225 }
226
227 static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
228 {
229         struct snd_dice *dice = substream->private_data;
230         struct amdtp_stream *stream = &dice->tx_stream[0];
231
232         switch (cmd) {
233         case SNDRV_PCM_TRIGGER_START:
234                 amdtp_stream_pcm_trigger(stream, substream);
235                 break;
236         case SNDRV_PCM_TRIGGER_STOP:
237                 amdtp_stream_pcm_trigger(stream, NULL);
238                 break;
239         default:
240                 return -EINVAL;
241         }
242
243         return 0;
244 }
245 static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
246 {
247         struct snd_dice *dice = substream->private_data;
248         struct amdtp_stream *stream = &dice->rx_stream[0];
249
250         switch (cmd) {
251         case SNDRV_PCM_TRIGGER_START:
252                 amdtp_stream_pcm_trigger(stream, substream);
253                 break;
254         case SNDRV_PCM_TRIGGER_STOP:
255                 amdtp_stream_pcm_trigger(stream, NULL);
256                 break;
257         default:
258                 return -EINVAL;
259         }
260
261         return 0;
262 }
263
264 static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
265 {
266         struct snd_dice *dice = substream->private_data;
267         struct amdtp_stream *stream = &dice->tx_stream[0];
268
269         return amdtp_stream_pcm_pointer(stream);
270 }
271 static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
272 {
273         struct snd_dice *dice = substream->private_data;
274         struct amdtp_stream *stream = &dice->rx_stream[0];
275
276         return amdtp_stream_pcm_pointer(stream);
277 }
278
279 int snd_dice_create_pcm(struct snd_dice *dice)
280 {
281         static struct snd_pcm_ops capture_ops = {
282                 .open      = pcm_open,
283                 .close     = pcm_close,
284                 .ioctl     = snd_pcm_lib_ioctl,
285                 .hw_params = capture_hw_params,
286                 .hw_free   = capture_hw_free,
287                 .prepare   = capture_prepare,
288                 .trigger   = capture_trigger,
289                 .pointer   = capture_pointer,
290                 .page      = snd_pcm_lib_get_vmalloc_page,
291                 .mmap      = snd_pcm_lib_mmap_vmalloc,
292         };
293         static struct snd_pcm_ops playback_ops = {
294                 .open      = pcm_open,
295                 .close     = pcm_close,
296                 .ioctl     = snd_pcm_lib_ioctl,
297                 .hw_params = playback_hw_params,
298                 .hw_free   = playback_hw_free,
299                 .prepare   = playback_prepare,
300                 .trigger   = playback_trigger,
301                 .pointer   = playback_pointer,
302                 .page      = snd_pcm_lib_get_vmalloc_page,
303                 .mmap      = snd_pcm_lib_mmap_vmalloc,
304         };
305         __be32 reg;
306         struct snd_pcm *pcm;
307         unsigned int capture, playback;
308         int err;
309
310         /*
311          * Check whether PCM substreams are required.
312          *
313          * TODO: in the case that any PCM substreams are not avail at a certain
314          * sampling transfer frequency?
315          */
316         err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
317                                            &reg, sizeof(reg));
318         if (err < 0)
319                 return err;
320         if (be32_to_cpu(reg) > 0)
321                 capture = 1;
322
323         err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
324                                            &reg, sizeof(reg));
325         if (err < 0)
326                 return err;
327         if (be32_to_cpu(reg) > 0)
328                 playback = 1;
329
330         err = snd_pcm_new(dice->card, "DICE", 0, playback, capture, &pcm);
331         if (err < 0)
332                 return err;
333         pcm->private_data = dice;
334         strcpy(pcm->name, dice->card->shortname);
335
336         if (capture > 0)
337                 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
338
339         if (playback > 0)
340                 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
341
342         return 0;
343 }