]>
Commit | Line | Data |
---|---|---|
23b028c8 MZ |
1 | /***************************************************************************** |
2 | * Copyright 2011 Broadcom Corporation. All rights reserved. | |
3 | * | |
4 | * Unless you and Broadcom execute a separate written software license | |
5 | * agreement governing use of this software, this software is licensed to you | |
6 | * under the terms of the GNU General Public License version 2, available at | |
7 | * http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). | |
8 | * | |
9 | * Notwithstanding the above, under no circumstances may you combine this | |
10 | * software in any way with any other Broadcom software provided under a | |
11 | * license other than the GPL, without Broadcom's express prior written | |
12 | * consent. | |
13 | *****************************************************************************/ | |
14 | ||
15 | #include <linux/interrupt.h> | |
16 | #include <linux/slab.h> | |
17 | ||
18 | #include <sound/asoundef.h> | |
19 | ||
20 | #include "bcm2835.h" | |
21 | ||
22 | /* hardware definition */ | |
23 | static struct snd_pcm_hardware snd_bcm2835_playback_hw = { | |
24 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | |
25 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), | |
26 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, | |
27 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, | |
28 | .rate_min = 8000, | |
29 | .rate_max = 48000, | |
30 | .channels_min = 1, | |
31 | .channels_max = 2, | |
32 | .buffer_bytes_max = 128 * 1024, | |
33 | .period_bytes_min = 1 * 1024, | |
34 | .period_bytes_max = 128 * 1024, | |
35 | .periods_min = 1, | |
36 | .periods_max = 128, | |
37 | }; | |
38 | ||
39 | static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = { | |
40 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | |
41 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), | |
42 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
43 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 | | |
44 | SNDRV_PCM_RATE_48000, | |
45 | .rate_min = 44100, | |
46 | .rate_max = 48000, | |
47 | .channels_min = 2, | |
48 | .channels_max = 2, | |
49 | .buffer_bytes_max = 128 * 1024, | |
50 | .period_bytes_min = 1 * 1024, | |
51 | .period_bytes_max = 128 * 1024, | |
52 | .periods_min = 1, | |
53 | .periods_max = 128, | |
54 | }; | |
55 | ||
56 | static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime) | |
57 | { | |
58 | audio_info("Freeing up alsa stream here ..\n"); | |
ac3c5ec8 | 59 | kfree(runtime->private_data); |
23b028c8 MZ |
60 | runtime->private_data = NULL; |
61 | } | |
62 | ||
0cec463e | 63 | void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream) |
23b028c8 | 64 | { |
23b028c8 MZ |
65 | unsigned int consumed = 0; |
66 | int new_period = 0; | |
67 | ||
23b028c8 MZ |
68 | |
69 | audio_info("alsa_stream=%p substream=%p\n", alsa_stream, | |
70 | alsa_stream ? alsa_stream->substream : 0); | |
71 | ||
72 | if (alsa_stream->open) | |
73 | consumed = bcm2835_audio_retrieve_buffers(alsa_stream); | |
74 | ||
75 | /* We get called only if playback was triggered, So, the number of buffers we retrieve in | |
76 | * each iteration are the buffers that have been played out already | |
77 | */ | |
78 | ||
79 | if (alsa_stream->period_size) { | |
80 | if ((alsa_stream->pos / alsa_stream->period_size) != | |
81 | ((alsa_stream->pos + consumed) / alsa_stream->period_size)) | |
82 | new_period = 1; | |
83 | } | |
84 | audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n", | |
85 | alsa_stream->pos, | |
86 | consumed, | |
87 | alsa_stream->buffer_size, | |
88 | (int) (alsa_stream->period_size * alsa_stream->substream->runtime->periods), | |
89 | frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr), | |
90 | new_period); | |
91 | if (alsa_stream->buffer_size) { | |
15411ed5 | 92 | alsa_stream->pos += consumed & ~(1 << 30); |
23b028c8 MZ |
93 | alsa_stream->pos %= alsa_stream->buffer_size; |
94 | } | |
95 | ||
96 | if (alsa_stream->substream) { | |
97 | if (new_period) | |
98 | snd_pcm_period_elapsed(alsa_stream->substream); | |
99 | } else { | |
100 | audio_warning(" unexpected NULL substream\n"); | |
101 | } | |
23b028c8 MZ |
102 | } |
103 | ||
104 | /* open callback */ | |
105 | static int snd_bcm2835_playback_open_generic( | |
106 | struct snd_pcm_substream *substream, int spdif) | |
107 | { | |
108 | struct bcm2835_chip *chip = snd_pcm_substream_chip(substream); | |
109 | struct snd_pcm_runtime *runtime = substream->runtime; | |
110 | struct bcm2835_alsa_stream *alsa_stream; | |
111 | int idx; | |
112 | int err; | |
113 | ||
23b028c8 MZ |
114 | |
115 | if (mutex_lock_interruptible(&chip->audio_mutex)) { | |
116 | audio_error("Interrupted whilst waiting for lock\n"); | |
117 | return -EINTR; | |
118 | } | |
119 | audio_info("Alsa open (%d)\n", substream->number); | |
120 | idx = substream->number; | |
121 | ||
122 | if (spdif && chip->opened) { | |
123 | err = -EBUSY; | |
124 | goto out; | |
125 | } else if (!spdif && (chip->opened & (1 << idx))) { | |
126 | err = -EBUSY; | |
127 | goto out; | |
128 | } | |
84472ecd | 129 | if (idx >= MAX_SUBSTREAMS) { |
23b028c8 MZ |
130 | audio_error |
131 | ("substream(%d) device doesn't exist max(%d) substreams allowed\n", | |
132 | idx, MAX_SUBSTREAMS); | |
133 | err = -ENODEV; | |
134 | goto out; | |
135 | } | |
136 | ||
137 | /* Check if we are ready */ | |
138 | if (!(chip->avail_substreams & (1 << idx))) { | |
139 | /* We are not ready yet */ | |
140 | audio_error("substream(%d) device is not ready yet\n", idx); | |
141 | err = -EAGAIN; | |
142 | goto out; | |
143 | } | |
144 | ||
145 | alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL); | |
146 | if (!alsa_stream) { | |
147 | err = -ENOMEM; | |
148 | goto out; | |
149 | } | |
150 | ||
151 | /* Initialise alsa_stream */ | |
152 | alsa_stream->chip = chip; | |
153 | alsa_stream->substream = substream; | |
154 | alsa_stream->idx = idx; | |
155 | ||
23b028c8 MZ |
156 | spin_lock_init(&alsa_stream->lock); |
157 | ||
23b028c8 MZ |
158 | err = bcm2835_audio_open(alsa_stream); |
159 | if (err) { | |
160 | kfree(alsa_stream); | |
161 | goto out; | |
162 | } | |
163 | runtime->private_data = alsa_stream; | |
164 | runtime->private_free = snd_bcm2835_playback_free; | |
165 | if (spdif) { | |
166 | runtime->hw = snd_bcm2835_playback_spdif_hw; | |
167 | } else { | |
168 | /* clear spdif status, as we are not in spdif mode */ | |
169 | chip->spdif_status = 0; | |
170 | runtime->hw = snd_bcm2835_playback_hw; | |
171 | } | |
172 | /* minimum 16 bytes alignment (for vchiq bulk transfers) */ | |
173 | snd_pcm_hw_constraint_step(runtime, | |
174 | 0, | |
175 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | |
176 | 16); | |
177 | ||
178 | chip->alsa_stream[idx] = alsa_stream; | |
179 | ||
180 | chip->opened |= (1 << idx); | |
181 | alsa_stream->open = 1; | |
182 | alsa_stream->draining = 1; | |
183 | ||
184 | out: | |
185 | mutex_unlock(&chip->audio_mutex); | |
186 | ||
23b028c8 MZ |
187 | |
188 | return err; | |
189 | } | |
190 | ||
191 | static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) | |
192 | { | |
193 | return snd_bcm2835_playback_open_generic(substream, 0); | |
194 | } | |
195 | ||
196 | static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream) | |
197 | { | |
198 | return snd_bcm2835_playback_open_generic(substream, 1); | |
199 | } | |
200 | ||
201 | /* close callback */ | |
202 | static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) | |
203 | { | |
204 | /* the hardware-specific codes will be here */ | |
205 | ||
206 | struct bcm2835_chip *chip; | |
207 | struct snd_pcm_runtime *runtime; | |
208 | struct bcm2835_alsa_stream *alsa_stream; | |
209 | ||
23b028c8 MZ |
210 | |
211 | chip = snd_pcm_substream_chip(substream); | |
212 | if (mutex_lock_interruptible(&chip->audio_mutex)) { | |
213 | audio_error("Interrupted whilst waiting for lock\n"); | |
214 | return -EINTR; | |
215 | } | |
216 | runtime = substream->runtime; | |
217 | alsa_stream = runtime->private_data; | |
218 | ||
219 | audio_info("Alsa close\n"); | |
220 | ||
221 | /* | |
222 | * Call stop if it's still running. This happens when app | |
223 | * is force killed and we don't get a stop trigger. | |
224 | */ | |
225 | if (alsa_stream->running) { | |
226 | int err; | |
227 | err = bcm2835_audio_stop(alsa_stream); | |
228 | alsa_stream->running = 0; | |
229 | if (err) | |
230 | audio_error(" Failed to STOP alsa device\n"); | |
231 | } | |
232 | ||
233 | alsa_stream->period_size = 0; | |
234 | alsa_stream->buffer_size = 0; | |
235 | ||
236 | if (alsa_stream->open) { | |
237 | alsa_stream->open = 0; | |
238 | bcm2835_audio_close(alsa_stream); | |
239 | } | |
240 | if (alsa_stream->chip) | |
241 | alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL; | |
242 | /* | |
243 | * Do not free up alsa_stream here, it will be freed up by | |
244 | * runtime->private_free callback we registered in *_open above | |
245 | */ | |
246 | ||
247 | chip->opened &= ~(1 << substream->number); | |
248 | ||
249 | mutex_unlock(&chip->audio_mutex); | |
23b028c8 MZ |
250 | |
251 | return 0; | |
252 | } | |
253 | ||
254 | /* hw_params callback */ | |
255 | static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream, | |
256 | struct snd_pcm_hw_params *params) | |
257 | { | |
258 | struct snd_pcm_runtime *runtime = substream->runtime; | |
259 | struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; | |
260 | int err; | |
261 | ||
23b028c8 MZ |
262 | |
263 | err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | |
264 | if (err < 0) { | |
265 | audio_error | |
266 | (" pcm_lib_malloc failed to allocated pages for buffers\n"); | |
267 | return err; | |
268 | } | |
269 | ||
270 | alsa_stream->channels = params_channels(params); | |
271 | alsa_stream->params_rate = params_rate(params); | |
272 | alsa_stream->pcm_format_width = snd_pcm_format_width(params_format(params)); | |
23b028c8 MZ |
273 | |
274 | return err; | |
275 | } | |
276 | ||
277 | /* hw_free callback */ | |
278 | static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream) | |
279 | { | |
23b028c8 MZ |
280 | return snd_pcm_lib_free_pages(substream); |
281 | } | |
282 | ||
283 | /* prepare callback */ | |
284 | static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) | |
285 | { | |
286 | struct bcm2835_chip *chip = snd_pcm_substream_chip(substream); | |
287 | struct snd_pcm_runtime *runtime = substream->runtime; | |
288 | struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; | |
289 | int channels; | |
290 | int err; | |
291 | ||
23b028c8 MZ |
292 | |
293 | if (mutex_lock_interruptible(&chip->audio_mutex)) | |
294 | return -EINTR; | |
295 | ||
296 | /* notify the vchiq that it should enter spdif passthrough mode by | |
297 | * setting channels=0 (see | |
298 | * https://github.com/raspberrypi/linux/issues/528) */ | |
299 | if (chip->spdif_status & IEC958_AES0_NONAUDIO) | |
300 | channels = 0; | |
301 | else | |
302 | channels = alsa_stream->channels; | |
303 | ||
304 | err = bcm2835_audio_set_params(alsa_stream, channels, | |
305 | alsa_stream->params_rate, | |
306 | alsa_stream->pcm_format_width); | |
a17b3703 | 307 | if (err < 0) |
23b028c8 | 308 | audio_error(" error setting hw params\n"); |
a17b3703 | 309 | |
23b028c8 MZ |
310 | |
311 | bcm2835_audio_setup(alsa_stream); | |
312 | ||
313 | /* in preparation of the stream, set the controls (volume level) of the stream */ | |
314 | bcm2835_audio_set_ctls(alsa_stream->chip); | |
315 | ||
316 | ||
317 | memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect)); | |
318 | ||
319 | alsa_stream->pcm_indirect.hw_buffer_size = | |
320 | alsa_stream->pcm_indirect.sw_buffer_size = | |
321 | snd_pcm_lib_buffer_bytes(substream); | |
322 | ||
323 | alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); | |
324 | alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); | |
325 | alsa_stream->pos = 0; | |
326 | ||
327 | audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n", | |
328 | alsa_stream->buffer_size, alsa_stream->period_size, | |
329 | alsa_stream->pos, runtime->frame_bits); | |
330 | ||
331 | mutex_unlock(&chip->audio_mutex); | |
23b028c8 MZ |
332 | return 0; |
333 | } | |
334 | ||
335 | static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream, | |
336 | struct snd_pcm_indirect *rec, size_t bytes) | |
337 | { | |
338 | struct snd_pcm_runtime *runtime = substream->runtime; | |
339 | struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; | |
340 | void *src = (void *) (substream->runtime->dma_area + rec->sw_data); | |
341 | int err; | |
342 | ||
343 | err = bcm2835_audio_write(alsa_stream, bytes, src); | |
344 | if (err) | |
345 | audio_error(" Failed to transfer to alsa device (%d)\n", err); | |
346 | ||
347 | } | |
348 | ||
349 | static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream) | |
350 | { | |
351 | struct snd_pcm_runtime *runtime = substream->runtime; | |
352 | struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; | |
353 | struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect; | |
354 | ||
355 | pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max; | |
9ce7b9cf TI |
356 | return snd_pcm_indirect_playback_transfer(substream, pcm_indirect, |
357 | snd_bcm2835_pcm_transfer); | |
23b028c8 MZ |
358 | } |
359 | ||
360 | /* trigger callback */ | |
361 | static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |
362 | { | |
363 | struct snd_pcm_runtime *runtime = substream->runtime; | |
364 | struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; | |
365 | int err = 0; | |
366 | ||
23b028c8 MZ |
367 | |
368 | switch (cmd) { | |
369 | case SNDRV_PCM_TRIGGER_START: | |
370 | audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n", | |
371 | alsa_stream->running); | |
372 | if (!alsa_stream->running) { | |
373 | err = bcm2835_audio_start(alsa_stream); | |
374 | if (!err) { | |
375 | alsa_stream->pcm_indirect.hw_io = | |
376 | alsa_stream->pcm_indirect.hw_data = | |
377 | bytes_to_frames(runtime, | |
378 | alsa_stream->pos); | |
379 | substream->ops->ack(substream); | |
380 | alsa_stream->running = 1; | |
381 | alsa_stream->draining = 1; | |
382 | } else { | |
383 | audio_error(" Failed to START alsa device (%d)\n", err); | |
384 | } | |
385 | } | |
386 | break; | |
387 | case SNDRV_PCM_TRIGGER_STOP: | |
388 | audio_debug | |
389 | ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n", | |
390 | alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING); | |
391 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { | |
392 | audio_info("DRAINING\n"); | |
393 | alsa_stream->draining = 1; | |
394 | } else { | |
395 | audio_info("DROPPING\n"); | |
396 | alsa_stream->draining = 0; | |
397 | } | |
398 | if (alsa_stream->running) { | |
399 | err = bcm2835_audio_stop(alsa_stream); | |
400 | if (err != 0) | |
401 | audio_error(" Failed to STOP alsa device (%d)\n", err); | |
402 | alsa_stream->running = 0; | |
403 | } | |
404 | break; | |
405 | default: | |
406 | err = -EINVAL; | |
407 | } | |
408 | ||
23b028c8 MZ |
409 | return err; |
410 | } | |
411 | ||
412 | /* pointer callback */ | |
413 | static snd_pcm_uframes_t | |
414 | snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream) | |
415 | { | |
416 | struct snd_pcm_runtime *runtime = substream->runtime; | |
417 | struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; | |
418 | ||
23b028c8 MZ |
419 | |
420 | audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0, | |
421 | frames_to_bytes(runtime, runtime->status->hw_ptr), | |
422 | frames_to_bytes(runtime, runtime->control->appl_ptr), | |
423 | alsa_stream->pos); | |
424 | ||
23b028c8 MZ |
425 | return snd_pcm_indirect_playback_pointer(substream, |
426 | &alsa_stream->pcm_indirect, | |
427 | alsa_stream->pos); | |
428 | } | |
429 | ||
430 | static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream, | |
431 | unsigned int cmd, void *arg) | |
432 | { | |
433 | int ret = snd_pcm_lib_ioctl(substream, cmd, arg); | |
cd3d9ece | 434 | |
23b028c8 MZ |
435 | audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream, |
436 | cmd, arg, arg ? *(unsigned *) arg : 0, ret); | |
437 | return ret; | |
438 | } | |
439 | ||
440 | /* operators */ | |
a4400dfd | 441 | static const struct snd_pcm_ops snd_bcm2835_playback_ops = { |
23b028c8 MZ |
442 | .open = snd_bcm2835_playback_open, |
443 | .close = snd_bcm2835_playback_close, | |
444 | .ioctl = snd_bcm2835_pcm_lib_ioctl, | |
445 | .hw_params = snd_bcm2835_pcm_hw_params, | |
446 | .hw_free = snd_bcm2835_pcm_hw_free, | |
447 | .prepare = snd_bcm2835_pcm_prepare, | |
448 | .trigger = snd_bcm2835_pcm_trigger, | |
449 | .pointer = snd_bcm2835_pcm_pointer, | |
450 | .ack = snd_bcm2835_pcm_ack, | |
451 | }; | |
452 | ||
a4400dfd | 453 | static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = { |
23b028c8 MZ |
454 | .open = snd_bcm2835_playback_spdif_open, |
455 | .close = snd_bcm2835_playback_close, | |
456 | .ioctl = snd_bcm2835_pcm_lib_ioctl, | |
457 | .hw_params = snd_bcm2835_pcm_hw_params, | |
458 | .hw_free = snd_bcm2835_pcm_hw_free, | |
459 | .prepare = snd_bcm2835_pcm_prepare, | |
460 | .trigger = snd_bcm2835_pcm_trigger, | |
461 | .pointer = snd_bcm2835_pcm_pointer, | |
462 | .ack = snd_bcm2835_pcm_ack, | |
463 | }; | |
464 | ||
465 | /* create a pcm device */ | |
325b5b6c | 466 | int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, u32 numchannels) |
23b028c8 MZ |
467 | { |
468 | struct snd_pcm *pcm; | |
469 | int err; | |
470 | ||
23b028c8 MZ |
471 | mutex_init(&chip->audio_mutex); |
472 | if (mutex_lock_interruptible(&chip->audio_mutex)) { | |
473 | audio_error("Interrupted whilst waiting for lock\n"); | |
474 | return -EINTR; | |
475 | } | |
325b5b6c | 476 | err = snd_pcm_new(chip->card, "bcm2835 ALSA", 0, numchannels, 0, &pcm); |
23b028c8 MZ |
477 | if (err < 0) |
478 | goto out; | |
479 | pcm->private_data = chip; | |
480 | strcpy(pcm->name, "bcm2835 ALSA"); | |
481 | chip->pcm = pcm; | |
482 | chip->dest = AUDIO_DEST_AUTO; | |
483 | chip->volume = alsa2chip(0); | |
484 | chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */ | |
485 | /* set operators */ | |
486 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | |
487 | &snd_bcm2835_playback_ops); | |
488 | ||
489 | /* pre-allocation of buffers */ | |
490 | /* NOTE: this may fail */ | |
491 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, | |
492 | snd_dma_continuous_data(GFP_KERNEL), | |
493 | snd_bcm2835_playback_hw.buffer_bytes_max, | |
494 | snd_bcm2835_playback_hw.buffer_bytes_max); | |
495 | ||
496 | ||
497 | out: | |
498 | mutex_unlock(&chip->audio_mutex); | |
23b028c8 MZ |
499 | |
500 | return 0; | |
501 | } | |
502 | ||
503 | int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip) | |
504 | { | |
505 | struct snd_pcm *pcm; | |
506 | int err; | |
507 | ||
23b028c8 MZ |
508 | if (mutex_lock_interruptible(&chip->audio_mutex)) { |
509 | audio_error("Interrupted whilst waiting for lock\n"); | |
510 | return -EINTR; | |
511 | } | |
512 | err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm); | |
513 | if (err < 0) | |
514 | goto out; | |
515 | ||
516 | pcm->private_data = chip; | |
517 | strcpy(pcm->name, "bcm2835 IEC958/HDMI"); | |
518 | chip->pcm_spdif = pcm; | |
519 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | |
520 | &snd_bcm2835_playback_spdif_ops); | |
521 | ||
522 | /* pre-allocation of buffers */ | |
523 | /* NOTE: this may fail */ | |
524 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, | |
525 | snd_dma_continuous_data(GFP_KERNEL), | |
526 | snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max); | |
527 | out: | |
528 | mutex_unlock(&chip->audio_mutex); | |
23b028c8 MZ |
529 | |
530 | return 0; | |
531 | } | |
325b5b6c MZ |
532 | |
533 | int snd_bcm2835_new_simple_pcm(struct bcm2835_chip *chip, | |
534 | const char *name, | |
535 | enum snd_bcm2835_route route, | |
536 | u32 numchannels) | |
537 | { | |
538 | struct snd_pcm *pcm; | |
539 | int err; | |
540 | ||
541 | mutex_init(&chip->audio_mutex); | |
542 | ||
543 | err = snd_pcm_new(chip->card, name, 0, numchannels, | |
544 | 0, &pcm); | |
545 | if (err) | |
546 | return err; | |
547 | ||
548 | pcm->private_data = chip; | |
549 | strcpy(pcm->name, name); | |
550 | chip->pcm = pcm; | |
551 | chip->dest = route; | |
552 | chip->volume = alsa2chip(0); | |
553 | chip->mute = CTRL_VOL_UNMUTE; | |
554 | ||
555 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | |
556 | &snd_bcm2835_playback_ops); | |
557 | ||
558 | snd_pcm_lib_preallocate_pages_for_all( | |
559 | pcm, | |
560 | SNDRV_DMA_TYPE_CONTINUOUS, | |
561 | snd_dma_continuous_data(GFP_KERNEL), | |
562 | snd_bcm2835_playback_hw.buffer_bytes_max, | |
563 | snd_bcm2835_playback_hw.buffer_bytes_max); | |
564 | ||
565 | return 0; | |
566 | } | |
567 |