1 From a7e31a16c66c5ecd1665250cfee9f3cfb64cfa67 Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Mon, 26 Mar 2012 22:15:50 +0100
4 Subject: [PATCH 09/54] bcm2708: alsa sound driver
6 Signed-off-by: popcornmix <popcornmix@gmail.com>
8 arch/arm/configs/bcmrpi_cutdown_defconfig | 20 +
9 arch/arm/configs/bcmrpi_defconfig | 20 +
10 arch/arm/mach-bcm2708/bcm2708.c | 54 ++
11 sound/arm/Kconfig | 7 +
12 sound/arm/Makefile | 5 +
13 sound/arm/bcm2835-ctl.c | 200 +++++++
14 sound/arm/bcm2835-pcm.c | 409 +++++++++++++++
15 sound/arm/bcm2835-vchiq.c | 844 ++++++++++++++++++++++++++++++
16 sound/arm/bcm2835.c | 413 +++++++++++++++
17 sound/arm/bcm2835.h | 155 ++++++
18 sound/arm/vc_vchi_audioserv_defs.h | 116 ++++
19 11 files changed, 2243 insertions(+)
20 create mode 100755 sound/arm/bcm2835-ctl.c
21 create mode 100755 sound/arm/bcm2835-pcm.c
22 create mode 100755 sound/arm/bcm2835-vchiq.c
23 create mode 100755 sound/arm/bcm2835.c
24 create mode 100755 sound/arm/bcm2835.h
25 create mode 100644 sound/arm/vc_vchi_audioserv_defs.h
27 diff --git a/arch/arm/configs/bcmrpi_cutdown_defconfig b/arch/arm/configs/bcmrpi_cutdown_defconfig
28 index 74f2dc9..e519412 100644
29 --- a/arch/arm/configs/bcmrpi_cutdown_defconfig
30 +++ b/arch/arm/configs/bcmrpi_cutdown_defconfig
31 @@ -208,6 +208,26 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
33 # CONFIG_LOGO_LINUX_MONO is not set
34 # CONFIG_LOGO_LINUX_VGA16 is not set
37 +CONFIG_SND_SEQUENCER=m
38 +CONFIG_SND_SEQ_DUMMY=m
39 +CONFIG_SND_MIXER_OSS=m
41 +CONFIG_SND_SEQUENCER_OSS=y
47 +CONFIG_SND_SERIAL_U16550=m
50 +CONFIG_SND_USB_AUDIO=m
51 +CONFIG_SND_USB_UA101=m
52 +CONFIG_SND_USB_CAIAQ=m
53 +CONFIG_SND_USB_6FIRE=m
58 diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig
59 index 339aabf..df947e5 100644
60 --- a/arch/arm/configs/bcmrpi_defconfig
61 +++ b/arch/arm/configs/bcmrpi_defconfig
62 @@ -225,6 +225,26 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
64 # CONFIG_LOGO_LINUX_MONO is not set
65 # CONFIG_LOGO_LINUX_VGA16 is not set
68 +CONFIG_SND_SEQUENCER=m
69 +CONFIG_SND_SEQ_DUMMY=m
70 +CONFIG_SND_MIXER_OSS=m
72 +CONFIG_SND_SEQUENCER_OSS=y
78 +CONFIG_SND_SERIAL_U16550=m
81 +CONFIG_SND_USB_AUDIO=m
82 +CONFIG_SND_USB_UA101=m
83 +CONFIG_SND_USB_CAIAQ=m
84 +CONFIG_SND_USB_6FIRE=m
89 diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c
90 index a5af6ec..1904066 100644
91 --- a/arch/arm/mach-bcm2708/bcm2708.c
92 +++ b/arch/arm/mach-bcm2708/bcm2708.c
93 @@ -431,6 +431,58 @@ struct platform_device bcm2708_powerman_device = {
94 .coherent_dma_mask = 0xffffffffUL},
98 +static struct platform_device bcm2708_alsa_devices[] = {
100 + .name = "bcm2835_AUD0",
101 + .id = 0, /* first audio device */
103 + .num_resources = 0,
106 + .name = "bcm2835_AUD1",
107 + .id = 1, /* second audio device */
109 + .num_resources = 0,
112 + .name = "bcm2835_AUD2",
113 + .id = 2, /* third audio device */
115 + .num_resources = 0,
118 + .name = "bcm2835_AUD3",
119 + .id = 3, /* forth audio device */
121 + .num_resources = 0,
124 + .name = "bcm2835_AUD4",
125 + .id = 4, /* fifth audio device */
127 + .num_resources = 0,
130 + .name = "bcm2835_AUD5",
131 + .id = 5, /* sixth audio device */
133 + .num_resources = 0,
136 + .name = "bcm2835_AUD6",
137 + .id = 6, /* seventh audio device */
139 + .num_resources = 0,
142 + .name = "bcm2835_AUD7",
143 + .id = 7, /* eighth audio device */
145 + .num_resources = 0,
149 int __init bcm_register_device(struct platform_device *pdev)
152 @@ -539,6 +591,8 @@ void __init bcm2708_init(void)
153 bcm_register_device(&bcm2708_emmc_device);
156 + for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
157 + bcm_register_device(&bcm2708_alsa_devices[i]);
159 for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
160 struct amba_device *d = amba_devs[i];
161 diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
162 index 885683a..f7ceafd 100644
163 --- a/sound/arm/Kconfig
164 +++ b/sound/arm/Kconfig
165 @@ -39,5 +39,12 @@ config SND_PXA2XX_AC97
166 Say Y or M if you want to support any AC97 codec attached to
167 the PXA2xx AC97 interface.
170 + tristate "BCM2835 ALSA driver"
171 + depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND
174 + Say Y or M if you want to support BCM2835 Alsa pcm card driver
178 diff --git a/sound/arm/Makefile b/sound/arm/Makefile
179 index 8c0c851..6796d7f 100644
180 --- a/sound/arm/Makefile
181 +++ b/sound/arm/Makefile
182 @@ -14,3 +14,8 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o
184 obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
185 snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
187 +obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o
188 +snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
190 +ccflags-y += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
191 diff --git a/sound/arm/bcm2835-ctl.c b/sound/arm/bcm2835-ctl.c
193 index 0000000..8c5334a
195 +++ b/sound/arm/bcm2835-ctl.c
197 +/*****************************************************************************
198 +* Copyright 2011 Broadcom Corporation. All rights reserved.
200 +* Unless you and Broadcom execute a separate written software license
201 +* agreement governing use of this software, this software is licensed to you
202 +* under the terms of the GNU General Public License version 2, available at
203 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
205 +* Notwithstanding the above, under no circumstances may you combine this
206 +* software in any way with any other Broadcom software provided under a
207 +* license other than the GPL, without Broadcom's express prior written
209 +*****************************************************************************/
211 +#include <linux/platform_device.h>
212 +#include <linux/init.h>
213 +#include <linux/io.h>
214 +#include <linux/jiffies.h>
215 +#include <linux/slab.h>
216 +#include <linux/time.h>
217 +#include <linux/wait.h>
218 +#include <linux/delay.h>
219 +#include <linux/moduleparam.h>
220 +#include <linux/sched.h>
222 +#include <sound/core.h>
223 +#include <sound/control.h>
224 +#include <sound/pcm.h>
225 +#include <sound/pcm_params.h>
226 +#include <sound/rawmidi.h>
227 +#include <sound/initval.h>
228 +#include <sound/tlv.h>
230 +#include "bcm2835.h"
232 +/* volume maximum and minimum in terms of 0.01dB */
233 +#define CTRL_VOL_MAX 400
234 +#define CTRL_VOL_MIN -10239 /* originally -10240 */
237 +static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
238 + struct snd_ctl_elem_info *uinfo)
240 + audio_info(" ... IN\n");
241 + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
242 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
244 + uinfo->value.integer.min = CTRL_VOL_MIN;
245 + uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
246 + } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
247 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
249 + uinfo->value.integer.min = 0;
250 + uinfo->value.integer.max = 1;
251 + } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
252 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
254 + uinfo->value.integer.min = 0;
255 + uinfo->value.integer.max = AUDIO_DEST_MAX-1;
257 + audio_info(" ... OUT\n");
261 +/* toggles mute on or off depending on the value of nmute, and returns
262 + * 1 if the mute value was changed, otherwise 0
264 +static int toggle_mute(struct bcm2835_chip *chip, int nmute)
266 + /* if settings are ok, just return 0 */
267 + if(chip->mute == nmute)
270 + /* if the sound is muted then we need to unmute */
271 + if(chip->mute == CTRL_VOL_MUTE)
273 + chip->volume = chip->old_volume; /* copy the old volume back */
274 + audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
276 + else /* otherwise we mute */
278 + chip->old_volume = chip->volume;
279 + chip->volume = 26214; /* set volume to minimum level AKA mute */
280 + audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
283 + chip->mute = nmute;
287 +static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
288 + struct snd_ctl_elem_value *ucontrol)
290 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
292 + BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
294 + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
295 + ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
296 + else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
297 + ucontrol->value.integer.value[0] = chip->mute;
298 + else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
299 + ucontrol->value.integer.value[0] = chip->dest;
304 +static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
305 + struct snd_ctl_elem_value *ucontrol)
307 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
310 + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
311 + audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
312 + if (chip->mute == CTRL_VOL_MUTE) {
313 + /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
314 + return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
317 + || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
319 + chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
323 + } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
324 + /* Now implemented */
325 + audio_info(" Mute attempted\n");
326 + changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
328 + } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
329 + if (ucontrol->value.integer.value[0] != chip->dest) {
330 + chip->dest = ucontrol->value.integer.value[0];
336 + if (bcm2835_audio_set_ctls(chip))
337 + printk(KERN_ERR "Failed to set ALSA controls..\n");
343 +static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
345 +static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
347 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
348 + .name = "PCM Playback Volume",
350 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
351 + .private_value = PCM_PLAYBACK_VOLUME,
352 + .info = snd_bcm2835_ctl_info,
353 + .get = snd_bcm2835_ctl_get,
354 + .put = snd_bcm2835_ctl_put,
356 + .tlv = {.p = snd_bcm2835_db_scale}
359 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
360 + .name = "PCM Playback Switch",
362 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
363 + .private_value = PCM_PLAYBACK_MUTE,
364 + .info = snd_bcm2835_ctl_info,
365 + .get = snd_bcm2835_ctl_get,
366 + .put = snd_bcm2835_ctl_put,
370 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
371 + .name = "PCM Playback Route",
373 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
374 + .private_value = PCM_PLAYBACK_DEVICE,
375 + .info = snd_bcm2835_ctl_info,
376 + .get = snd_bcm2835_ctl_get,
377 + .put = snd_bcm2835_ctl_put,
382 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
387 + strcpy(chip->card->mixername, "Broadcom Mixer");
388 + for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
390 + snd_ctl_add(chip->card,
391 + snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
397 diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c
399 index 0000000..2e7d405
401 +++ b/sound/arm/bcm2835-pcm.c
403 +/*****************************************************************************
404 +* Copyright 2011 Broadcom Corporation. All rights reserved.
406 +* Unless you and Broadcom execute a separate written software license
407 +* agreement governing use of this software, this software is licensed to you
408 +* under the terms of the GNU General Public License version 2, available at
409 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
411 +* Notwithstanding the above, under no circumstances may you combine this
412 +* software in any way with any other Broadcom software provided under a
413 +* license other than the GPL, without Broadcom's express prior written
415 +*****************************************************************************/
417 +#include <linux/interrupt.h>
418 +#include <linux/slab.h>
420 +#include "bcm2835.h"
422 +/* hardware definition */
423 +static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
424 + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER),
425 + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
426 + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
431 + .buffer_bytes_max = 128 * 1024,
432 + .period_bytes_min = 1 * 1024,
433 + .period_bytes_max = 128 * 1024,
435 + .periods_max = 128,
438 +static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
440 + audio_info("Freeing up alsa stream here ..\n");
441 + if (runtime->private_data)
442 + kfree(runtime->private_data);
443 + runtime->private_data = NULL;
446 +static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
448 + bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
449 + uint32_t consumed = 0;
450 + int new_period = 0;
452 + audio_info(" .. IN\n");
454 + audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
455 + alsa_stream ? alsa_stream->substream : 0);
457 + if (alsa_stream->open)
458 + consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
460 + /* We get called only if playback was triggered, So, the number of buffers we retrieve in
461 + * each iteration are the buffers that have been played out already
464 + if (alsa_stream->period_size) {
465 + if ((alsa_stream->pos / alsa_stream->period_size) !=
466 + ((alsa_stream->pos + consumed) / alsa_stream->period_size))
469 + audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
472 + alsa_stream->buffer_size,
473 + (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods),
474 + frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
476 + if (alsa_stream->buffer_size) {
477 + alsa_stream->pos += consumed &~ (1<<30);
478 + alsa_stream->pos %= alsa_stream->buffer_size;
481 + if (alsa_stream->substream) {
483 + snd_pcm_period_elapsed(alsa_stream->substream);
485 + audio_warning(" unexpected NULL substream\n");
487 + audio_info(" .. OUT\n");
489 + return IRQ_HANDLED;
493 +static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
495 + bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
496 + struct snd_pcm_runtime *runtime = substream->runtime;
497 + bcm2835_alsa_stream_t *alsa_stream;
501 + audio_info(" .. IN (%d)\n", substream->number);
503 + audio_info("Alsa open (%d)\n", substream->number);
504 + idx = substream->number;
506 + if (idx > MAX_SUBSTREAMS) {
508 + ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
509 + idx, MAX_SUBSTREAMS);
514 + /* Check if we are ready */
515 + if (!(chip->avail_substreams & (1 << idx))) {
516 + /* We are not ready yet */
517 + audio_error("substream(%d) device is not ready yet\n", idx);
522 + alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
523 + if (alsa_stream == NULL) {
527 + /* Initialise alsa_stream */
528 + alsa_stream->chip = chip;
529 + alsa_stream->substream = substream;
530 + alsa_stream->idx = idx;
532 + sema_init(&alsa_stream->buffers_update_sem, 0);
533 + sema_init(&alsa_stream->control_sem, 0);
534 + spin_lock_init(&alsa_stream->lock);
536 + /* Enabled in start trigger, called on each "fifo irq" after that */
537 + alsa_stream->enable_fifo_irq = 0;
538 + alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;
540 + err = bcm2835_audio_open(alsa_stream);
542 + kfree(alsa_stream);
545 + runtime->private_data = alsa_stream;
546 + runtime->private_free = snd_bcm2835_playback_free;
547 + runtime->hw = snd_bcm2835_playback_hw;
548 + /* minimum 16 bytes alignment (for vchiq bulk transfers) */
549 + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
552 + chip->alsa_stream[idx] = alsa_stream;
554 + alsa_stream->open = 1;
555 + alsa_stream->draining = 1;
558 + audio_info(" .. OUT =%d\n", err);
563 +/* close callback */
564 +static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
566 + /* the hardware-specific codes will be here */
568 + struct snd_pcm_runtime *runtime = substream->runtime;
569 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
571 + audio_info(" .. IN\n");
572 + audio_info("Alsa close\n");
575 + * Call stop if it's still running. This happens when app
576 + * is force killed and we don't get a stop trigger.
578 + if (alsa_stream->running) {
580 + err = bcm2835_audio_stop(alsa_stream);
581 + alsa_stream->running = 0;
583 + audio_error(" Failed to STOP alsa device\n");
586 + alsa_stream->period_size = 0;
587 + alsa_stream->buffer_size = 0;
589 + if (alsa_stream->open) {
590 + alsa_stream->open = 0;
591 + bcm2835_audio_close(alsa_stream);
593 + if (alsa_stream->chip)
594 + alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
596 + * Do not free up alsa_stream here, it will be freed up by
597 + * runtime->private_free callback we registered in *_open above
600 + audio_info(" .. OUT\n");
605 +/* hw_params callback */
606 +static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
607 + struct snd_pcm_hw_params *params)
610 + struct snd_pcm_runtime *runtime = substream->runtime;
611 + bcm2835_alsa_stream_t *alsa_stream =
612 + (bcm2835_alsa_stream_t *) runtime->private_data;
614 + audio_info(" .. IN\n");
616 + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
619 + (" pcm_lib_malloc failed to allocated pages for buffers\n");
623 + err = bcm2835_audio_set_params(alsa_stream, params_channels(params),
624 + params_rate(params),
625 + snd_pcm_format_width(params_format
628 + audio_error(" error setting hw params\n");
631 + bcm2835_audio_setup(alsa_stream);
633 + /* in preparation of the stream, set the controls (volume level) of the stream */
634 + bcm2835_audio_set_ctls(alsa_stream->chip);
636 + audio_info(" .. OUT\n");
641 +/* hw_free callback */
642 +static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
644 + audio_info(" .. IN\n");
645 + return snd_pcm_lib_free_pages(substream);
648 +/* prepare callback */
649 +static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
651 + struct snd_pcm_runtime *runtime = substream->runtime;
652 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
654 + audio_info(" .. IN\n");
656 + alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
657 + alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
658 + alsa_stream->pos = 0;
660 + audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
661 + alsa_stream->buffer_size, alsa_stream->period_size,
662 + alsa_stream->pos, runtime->frame_bits);
664 + audio_info(" .. OUT\n");
668 +/* trigger callback */
669 +static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
671 + struct snd_pcm_runtime *runtime = substream->runtime;
672 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
675 + audio_info(" .. IN\n");
678 + case SNDRV_PCM_TRIGGER_START:
679 + audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
680 + alsa_stream->running);
681 + if (!alsa_stream->running) {
682 + err = bcm2835_audio_start(alsa_stream);
684 + alsa_stream->running = 1;
685 + alsa_stream->draining = 1;
687 + audio_error(" Failed to START alsa device (%d)\n", err);
691 + case SNDRV_PCM_TRIGGER_STOP:
693 + ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
694 + alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
695 + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
696 + audio_info("DRAINING\n");
697 + alsa_stream->draining = 1;
699 + audio_info("DROPPING\n");
700 + alsa_stream->draining = 0;
702 + if (alsa_stream->running) {
703 + err = bcm2835_audio_stop(alsa_stream);
705 + audio_error(" Failed to STOP alsa device (%d)\n", err);
706 + alsa_stream->running = 0;
713 + audio_info(" .. OUT\n");
717 +/* pointer callback */
718 +static snd_pcm_uframes_t
719 +snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
721 + struct snd_pcm_runtime *runtime = substream->runtime;
722 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
724 + audio_info(" .. IN\n");
726 + audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
727 + frames_to_bytes(runtime, runtime->status->hw_ptr),
728 + frames_to_bytes(runtime, runtime->control->appl_ptr),
731 + audio_info(" .. OUT\n");
732 + return bytes_to_frames(runtime, alsa_stream->pos);
735 +static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream,
736 + int channel, snd_pcm_uframes_t pos, void *src,
737 + snd_pcm_uframes_t count)
740 + struct snd_pcm_runtime *runtime = substream->runtime;
741 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
743 + audio_info(" .. IN\n");
744 + audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n",
745 + frames_to_bytes(runtime, count), frames_to_bytes(runtime,
749 + frames_to_bytes(runtime, runtime->control->appl_ptr),
752 + bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count),
754 + audio_info(" .. OUT\n");
758 +static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
759 + unsigned int cmd, void *arg)
761 + int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
762 + audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
763 + cmd, arg, arg ? *(unsigned *)arg : 0, ret);
768 +static struct snd_pcm_ops snd_bcm2835_playback_ops = {
769 + .open = snd_bcm2835_playback_open,
770 + .close = snd_bcm2835_playback_close,
771 + .ioctl = snd_bcm2835_pcm_lib_ioctl,
772 + .hw_params = snd_bcm2835_pcm_hw_params,
773 + .hw_free = snd_bcm2835_pcm_hw_free,
774 + .prepare = snd_bcm2835_pcm_prepare,
775 + .trigger = snd_bcm2835_pcm_trigger,
776 + .pointer = snd_bcm2835_pcm_pointer,
777 + .copy = snd_bcm2835_pcm_copy,
780 +/* create a pcm device */
781 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
783 + struct snd_pcm *pcm;
786 + audio_info(" .. IN\n");
788 + snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
791 + pcm->private_data = chip;
792 + strcpy(pcm->name, "bcm2835 ALSA");
794 + chip->dest = AUDIO_DEST_AUTO;
795 + chip->volume = alsa2chip(0);
796 + chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
797 + /* set operators */
798 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
799 + &snd_bcm2835_playback_ops);
801 + /* pre-allocation of buffers */
802 + /* NOTE: this may fail */
803 + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
804 + snd_dma_continuous_data
805 + (GFP_KERNEL), 64 * 1024,
808 + audio_info(" .. OUT\n");
812 diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c
814 index 0000000..b9b4fe8
816 +++ b/sound/arm/bcm2835-vchiq.c
818 +/*****************************************************************************
819 +* Copyright 2011 Broadcom Corporation. All rights reserved.
821 +* Unless you and Broadcom execute a separate written software license
822 +* agreement governing use of this software, this software is licensed to you
823 +* under the terms of the GNU General Public License version 2, available at
824 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
826 +* Notwithstanding the above, under no circumstances may you combine this
827 +* software in any way with any other Broadcom software provided under a
828 +* license other than the GPL, without Broadcom's express prior written
830 +*****************************************************************************/
832 +#include <linux/device.h>
833 +#include <sound/core.h>
834 +#include <sound/initval.h>
835 +#include <sound/pcm.h>
836 +#include <linux/io.h>
837 +#include <linux/interrupt.h>
838 +#include <linux/fs.h>
839 +#include <linux/file.h>
840 +#include <linux/mm.h>
841 +#include <linux/syscalls.h>
842 +#include <asm/uaccess.h>
843 +#include <linux/slab.h>
844 +#include <linux/delay.h>
845 +#include <linux/atomic.h>
846 +#include <linux/module.h>
848 +#include "bcm2835.h"
850 +/* ---- Include Files -------------------------------------------------------- */
852 +#include "interface/vchi/vchi.h"
853 +#include "vc_vchi_audioserv_defs.h"
855 +/* ---- Private Constants and Types ------------------------------------------ */
857 +/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
858 +#ifdef AUDIO_DEBUG_ENABLE
859 + #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
860 + #define LOG_WARN( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
861 + #define LOG_INFO( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
862 + #define LOG_DBG( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
864 + #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
865 + #define LOG_WARN( fmt, arg... )
866 + #define LOG_INFO( fmt, arg... )
867 + #define LOG_DBG( fmt, arg... )
870 +typedef struct opaque_AUDIO_INSTANCE_T {
871 + uint32_t num_connections;
872 + VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
873 + struct semaphore msg_avail_event;
874 + struct mutex vchi_mutex;
875 + bcm2835_alsa_stream_t *alsa_stream;
877 + short peer_version;
880 +bool force_bulk = false;
882 +/* ---- Private Variables ---------------------------------------------------- */
884 +/* ---- Private Function Prototypes ------------------------------------------ */
886 +/* ---- Private Functions ---------------------------------------------------- */
888 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
889 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
892 + struct work_struct my_work;
893 + bcm2835_alsa_stream_t *alsa_stream;
897 +static void my_wq_function(struct work_struct *work)
899 + my_work_t *w = (my_work_t *) work;
901 + LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->x);
904 + ret = bcm2835_audio_start_worker(w->alsa_stream);
907 + ret = bcm2835_audio_stop_worker(w->alsa_stream);
910 + LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->x);
913 + kfree((void *)work);
914 + LOG_DBG(" .. OUT %d\n", ret);
917 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
920 + LOG_DBG(" .. IN\n");
921 + if (alsa_stream->my_wq) {
922 + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
923 + /*--- Queue some work (item 1) ---*/
925 + INIT_WORK((struct work_struct *)work, my_wq_function);
926 + work->alsa_stream = alsa_stream;
929 + (alsa_stream->my_wq, (struct work_struct *)work))
932 + LOG_ERR(" .. Error: NULL work kmalloc\n");
934 + LOG_DBG(" .. OUT %d\n", ret);
938 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
941 + LOG_DBG(" .. IN\n");
942 + if (alsa_stream->my_wq) {
943 + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
944 + /*--- Queue some work (item 1) ---*/
946 + INIT_WORK((struct work_struct *)work, my_wq_function);
947 + work->alsa_stream = alsa_stream;
950 + (alsa_stream->my_wq, (struct work_struct *)work))
953 + LOG_ERR(" .. Error: NULL work kmalloc\n");
955 + LOG_DBG(" .. OUT %d\n", ret);
959 +void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
961 + alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
965 +void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
967 + if (alsa_stream->my_wq) {
968 + flush_workqueue(alsa_stream->my_wq);
969 + destroy_workqueue(alsa_stream->my_wq);
970 + alsa_stream->my_wq = NULL;
975 +static void audio_vchi_callback(void *param,
976 + const VCHI_CALLBACK_REASON_T reason,
979 + AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
983 + bcm2835_alsa_stream_t *alsa_stream = 0;
984 + LOG_DBG(" .. IN instance=%p, param=%p, reason=%d, handle=%p\n",
985 + instance, param, reason, msg_handle);
987 + if (!instance || reason != VCHI_CALLBACK_MSG_AVAILABLE) {
990 + alsa_stream = instance->alsa_stream;
991 + status = vchi_msg_dequeue(instance->vchi_handle[0],
992 + &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
993 + if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
995 + (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
996 + instance, m.u.result.success);
997 + instance->result = m.u.result.success;
998 + up(&instance->msg_avail_event);
999 + } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
1000 + irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
1002 + (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
1003 + instance, m.u.complete.count);
1004 + if (alsa_stream && callback) {
1005 + atomic_add(m.u.complete.count, &alsa_stream->retrieved);
1006 + callback(0, alsa_stream);
1008 + LOG_DBG(" .. unexpected alsa_stream=%p, callback=%p\n",
1009 + alsa_stream, callback);
1012 + LOG_DBG(" .. unexpected m.type=%d\n", m.type);
1014 + LOG_DBG(" .. OUT\n");
1017 +static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
1018 + VCHI_CONNECTION_T **
1020 + uint32_t num_connections)
1023 + AUDIO_INSTANCE_T *instance;
1026 + LOG_DBG("%s: start", __func__);
1028 + if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
1029 + LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
1030 + __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
1034 + /* Allocate memory for this instance */
1035 + instance = kmalloc(sizeof(*instance), GFP_KERNEL);
1037 + memset(instance, 0, sizeof(*instance));
1038 + instance->num_connections = num_connections;
1040 + /* Create a lock for exclusive, serialized VCHI connection access */
1041 + mutex_init(&instance->vchi_mutex);
1042 + /* Open the VCHI service connections */
1043 + for (i = 0; i < num_connections; i++) {
1044 + SERVICE_CREATION_T params = {
1045 + VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
1046 + VC_AUDIO_SERVER_NAME, // 4cc service code
1047 + vchi_connections[i], // passed in fn pointers
1048 + 0, // rx fifo size (unused)
1049 + 0, // tx fifo size (unused)
1050 + audio_vchi_callback, // service callback
1051 + instance, // service callback parameter
1052 + 1, //TODO: remove VCOS_FALSE, // unaligned bulk recieves
1053 + 1, //TODO: remove VCOS_FALSE, // unaligned bulk transmits
1054 + 0 // want crc check on bulk transfers
1057 + status = vchi_service_open(vchi_instance, ¶ms,
1058 + &instance->vchi_handle[i]);
1061 + ("%s: failed to open VCHI service connection (status=%d)\n",
1062 + __func__, status);
1064 + goto err_close_services;
1066 + /* Finished with the service for now */
1067 + vchi_service_release(instance->vchi_handle[i]);
1072 +err_close_services:
1073 + for (i = 0; i < instance->num_connections; i++) {
1074 + vchi_service_close(instance->vchi_handle[i]);
1082 +static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
1086 + LOG_DBG(" .. IN\n");
1088 + if (instance == NULL) {
1089 + LOG_ERR("%s: invalid handle %p\n", __func__, instance);
1094 + LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
1095 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1097 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1101 + /* Close all VCHI service connections */
1102 + for (i = 0; i < instance->num_connections; i++) {
1104 + LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
1105 + vchi_service_use(instance->vchi_handle[i]);
1107 + success = vchi_service_close(instance->vchi_handle[i]);
1108 + if (success != 0) {
1110 + ("%s: failed to close VCHI service connection (status=%d)\n",
1111 + __func__, success);
1115 + mutex_unlock(&instance->vchi_mutex);
1119 + LOG_DBG(" .. OUT\n");
1124 +static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
1126 + static VCHI_INSTANCE_T vchi_instance;
1127 + static VCHI_CONNECTION_T *vchi_connection;
1128 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1130 + LOG_DBG(" .. IN\n");
1132 + LOG_INFO("%s: start", __func__);
1133 + //BUG_ON(instance);
1135 + LOG_ERR("%s: VCHI instance already open (%p)\n",
1136 + __func__, instance);
1137 + instance->alsa_stream = alsa_stream;
1138 + alsa_stream->instance = instance;
1139 + ret = 0; // xxx todo -1;
1140 + goto err_free_mem;
1143 + /* Initialize and create a VCHI connection */
1144 + ret = vchi_initialise(&vchi_instance);
1146 + LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
1150 + goto err_free_mem;
1152 + ret = vchi_connect(NULL, 0, vchi_instance);
1154 + LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
1158 + goto err_free_mem;
1161 + /* Initialize an instance of the audio service */
1162 + instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
1164 + if (instance == NULL /*|| audio_handle != instance */ ) {
1165 + LOG_ERR("%s: failed to initialize audio service\n", __func__);
1168 + goto err_free_mem;
1171 + instance->alsa_stream = alsa_stream;
1172 + alsa_stream->instance = instance;
1174 + LOG_DBG(" success !\n");
1176 + LOG_DBG(" .. OUT\n");
1181 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
1183 + AUDIO_INSTANCE_T *instance;
1187 + LOG_DBG(" .. IN\n");
1189 + my_workqueue_init(alsa_stream);
1191 + ret = bcm2835_audio_open_connection(alsa_stream);
1196 + instance = alsa_stream->instance;
1198 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1200 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1203 + vchi_service_use(instance->vchi_handle[0]);
1205 + m.type = VC_AUDIO_MSG_TYPE_OPEN;
1207 + /* Send the message to the videocore */
1208 + success = vchi_msg_queue(instance->vchi_handle[0],
1210 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1212 + if (success != 0) {
1213 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1214 + __func__, success);
1223 + vchi_service_release(instance->vchi_handle[0]);
1224 + mutex_unlock(&instance->vchi_mutex);
1226 + LOG_DBG(" .. OUT\n");
1230 +static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
1231 + bcm2835_chip_t * chip)
1234 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1237 + LOG_DBG(" .. IN\n");
1240 + (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
1242 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1244 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1247 + vchi_service_use(instance->vchi_handle[0]);
1249 + instance->result = -1;
1251 + m.type = VC_AUDIO_MSG_TYPE_CONTROL;
1252 + m.u.control.dest = chip->dest;
1253 + m.u.control.volume = chip->volume;
1255 + /* Create the message available event */
1256 + sema_init(&instance->msg_avail_event, 0);
1258 + /* Send the message to the videocore */
1259 + success = vchi_msg_queue(instance->vchi_handle[0],
1261 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1263 + if (success != 0) {
1264 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1265 + __func__, success);
1271 + /* We are expecting a reply from the videocore */
1272 + if (down_interruptible(&instance->msg_avail_event)) {
1273 + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1274 + __func__, success);
1280 + if (instance->result != 0) {
1281 + LOG_ERR("%s: result=%d\n", __func__, instance->result);
1290 + vchi_service_release(instance->vchi_handle[0]);
1291 + mutex_unlock(&instance->vchi_mutex);
1293 + LOG_DBG(" .. OUT\n");
1297 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
1301 + LOG_DBG(" .. IN\n");
1303 + /* change ctls for all substreams */
1304 + for (i = 0; i < MAX_SUBSTREAMS; i++) {
1305 + if (chip->avail_substreams & (1 << i)) {
1306 + if (!chip->alsa_stream[i])
1308 + LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
1311 + else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
1312 + (chip->alsa_stream[i], chip) != 0)
1314 + LOG_DBG("Couldn't set the controls for stream %d\n", i);
1317 + else LOG_DBG(" Controls set for stream %d\n", i);
1320 + LOG_DBG(" .. OUT ret=%d\n", ret);
1324 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
1325 + uint32_t channels, uint32_t samplerate,
1329 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1332 + LOG_DBG(" .. IN\n");
1335 + (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
1336 + channels, samplerate, bps);
1338 + /* resend ctls - alsa_stream may not have been open when first send */
1339 + ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
1341 + LOG_ERR(" Alsa controls not supported\n");
1345 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1347 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1350 + vchi_service_use(instance->vchi_handle[0]);
1352 + instance->result = -1;
1354 + m.type = VC_AUDIO_MSG_TYPE_CONFIG;
1355 + m.u.config.channels = channels;
1356 + m.u.config.samplerate = samplerate;
1357 + m.u.config.bps = bps;
1359 + /* Create the message available event */
1360 + sema_init(&instance->msg_avail_event, 0);
1362 + /* Send the message to the videocore */
1363 + success = vchi_msg_queue(instance->vchi_handle[0],
1365 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1367 + if (success != 0) {
1368 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1369 + __func__, success);
1375 + /* We are expecting a reply from the videocore */
1376 + if (down_interruptible(&instance->msg_avail_event)) {
1377 + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1378 + __func__, success);
1384 + if (instance->result != 0) {
1385 + LOG_ERR("%s: result=%d", __func__, instance->result);
1394 + vchi_service_release(instance->vchi_handle[0]);
1395 + mutex_unlock(&instance->vchi_mutex);
1397 + LOG_DBG(" .. OUT\n");
1401 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
1403 + LOG_DBG(" .. IN\n");
1405 + LOG_DBG(" .. OUT\n");
1410 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
1413 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1416 + LOG_DBG(" .. IN\n");
1418 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1420 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1423 + vchi_service_use(instance->vchi_handle[0]);
1425 + m.type = VC_AUDIO_MSG_TYPE_START;
1427 + /* Send the message to the videocore */
1428 + success = vchi_msg_queue(instance->vchi_handle[0],
1430 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1432 + if (success != 0) {
1433 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1434 + __func__, success);
1443 + vchi_service_release(instance->vchi_handle[0]);
1444 + mutex_unlock(&instance->vchi_mutex);
1445 + LOG_DBG(" .. OUT\n");
1449 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
1452 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1455 + LOG_DBG(" .. IN\n");
1457 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1459 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1462 + vchi_service_use(instance->vchi_handle[0]);
1464 + m.type = VC_AUDIO_MSG_TYPE_STOP;
1465 + m.u.stop.draining = alsa_stream->draining;
1467 + /* Send the message to the videocore */
1468 + success = vchi_msg_queue(instance->vchi_handle[0],
1470 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1472 + if (success != 0) {
1473 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1474 + __func__, success);
1483 + vchi_service_release(instance->vchi_handle[0]);
1484 + mutex_unlock(&instance->vchi_mutex);
1485 + LOG_DBG(" .. OUT\n");
1489 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
1492 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1495 + LOG_DBG(" .. IN\n");
1497 + my_workqueue_quit(alsa_stream);
1499 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1501 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1504 + vchi_service_use(instance->vchi_handle[0]);
1506 + m.type = VC_AUDIO_MSG_TYPE_CLOSE;
1508 + /* Create the message available event */
1509 + sema_init(&instance->msg_avail_event, 0);
1511 + /* Send the message to the videocore */
1512 + success = vchi_msg_queue(instance->vchi_handle[0],
1514 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1516 + if (success != 0) {
1517 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1518 + __func__, success);
1522 + if (down_interruptible(&instance->msg_avail_event)) {
1523 + LOG_ERR("%s: failed on waiting for event (status=%d)",
1524 + __func__, success);
1529 + if (instance->result != 0) {
1530 + LOG_ERR("%s: failed result (status=%d)",
1531 + __func__, instance->result);
1540 + vchi_service_release(instance->vchi_handle[0]);
1541 + mutex_unlock(&instance->vchi_mutex);
1543 + /* Stop the audio service */
1545 + vc_vchi_audio_deinit(instance);
1546 + alsa_stream->instance = NULL;
1548 + LOG_DBG(" .. OUT\n");
1552 +int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
1556 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1560 + LOG_DBG(" .. IN\n");
1562 + LOG_INFO(" Writing %d bytes from %p\n", count, src);
1564 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1566 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1569 + vchi_service_use(instance->vchi_handle[0]);
1571 + if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) {
1572 + LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
1574 + m.type = VC_AUDIO_MSG_TYPE_WRITE;
1575 + m.u.write.count = count;
1576 + // old version uses bulk, new version uses control
1577 + m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000;
1578 + m.u.write.callback = alsa_stream->fifo_irq_handler;
1579 + m.u.write.cookie = alsa_stream;
1580 + m.u.write.silence = src == NULL;
1582 + /* Send the message to the videocore */
1583 + success = vchi_msg_queue(instance->vchi_handle[0],
1585 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1587 + if (success != 0) {
1588 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1589 + __func__, success);
1594 + if (!m.u.write.silence) {
1595 + if (m.u.write.max_packet == 0) {
1596 + /* Send the message to the videocore */
1597 + success = vchi_bulk_queue_transmit(instance->vchi_handle[0],
1600 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED
1603 + VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
1606 + while (count > 0) {
1607 + int bytes = min((int)m.u.write.max_packet, (int)count);
1608 + success = vchi_msg_queue(instance->vchi_handle[0],
1610 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1611 + src = (char *)src + bytes;
1615 + if (success != 0) {
1617 + ("%s: failed on vchi_bulk_queue_transmit (status=%d)",
1618 + __func__, success);
1627 + vchi_service_release(instance->vchi_handle[0]);
1628 + mutex_unlock(&instance->vchi_mutex);
1629 + LOG_DBG(" .. OUT\n");
1634 + * Returns all buffers from arm->vc
1636 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
1638 + LOG_DBG(" .. IN\n");
1639 + LOG_DBG(" .. OUT\n");
1644 + * Forces VC to flush(drop) its filled playback buffers and
1645 + * return them the us. (VC->ARM)
1647 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
1649 + LOG_DBG(" .. IN\n");
1650 + LOG_DBG(" .. OUT\n");
1653 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
1655 + uint32_t count = atomic_read(&alsa_stream->retrieved);
1656 + atomic_sub(count, &alsa_stream->retrieved);
1660 +module_param(force_bulk, bool, 0444);
1661 +MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
1662 diff --git a/sound/arm/bcm2835.c b/sound/arm/bcm2835.c
1663 new file mode 100755
1664 index 0000000..317e7d9
1666 +++ b/sound/arm/bcm2835.c
1668 +/*****************************************************************************
1669 +* Copyright 2011 Broadcom Corporation. All rights reserved.
1671 +* Unless you and Broadcom execute a separate written software license
1672 +* agreement governing use of this software, this software is licensed to you
1673 +* under the terms of the GNU General Public License version 2, available at
1674 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
1676 +* Notwithstanding the above, under no circumstances may you combine this
1677 +* software in any way with any other Broadcom software provided under a
1678 +* license other than the GPL, without Broadcom's express prior written
1680 +*****************************************************************************/
1682 +#include <linux/platform_device.h>
1684 +#include <linux/init.h>
1685 +#include <linux/slab.h>
1686 +#include <linux/module.h>
1688 +#include "bcm2835.h"
1690 +/* module parameters (see "Module Parameters") */
1691 +/* SNDRV_CARDS: maximum number of cards supported by this module */
1692 +static int index[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = -1 };
1693 +static char *id[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = NULL };
1694 +static int enable[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = 1 };
1696 +/* HACKY global pointers needed for successive probes to work : ssp
1697 + * But compared against the changes we will have to do in VC audio_ipc code
1698 + * to export 8 audio_ipc devices as a single IPC device and then monitor all
1699 + * four devices in a thread, this gets things done quickly and should be easier
1700 + * to debug if we run into issues
1703 +static struct snd_card *g_card = NULL;
1704 +static bcm2835_chip_t *g_chip = NULL;
1706 +static int snd_bcm2835_free(bcm2835_chip_t * chip)
1712 +/* component-destructor
1713 + * (see "Management of Cards and Components")
1715 +static int snd_bcm2835_dev_free(struct snd_device *device)
1717 + return snd_bcm2835_free(device->device_data);
1720 +/* chip-specific constructor
1721 + * (see "Management of Cards and Components")
1723 +static int snd_bcm2835_create(struct snd_card *card,
1724 + struct platform_device *pdev,
1725 + bcm2835_chip_t ** rchip)
1727 + bcm2835_chip_t *chip;
1729 + static struct snd_device_ops ops = {
1730 + .dev_free = snd_bcm2835_dev_free,
1735 + chip = kzalloc(sizeof(*chip), GFP_KERNEL);
1739 + chip->card = card;
1741 + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
1743 + snd_bcm2835_free(chip);
1751 +static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
1754 + bcm2835_chip_t *chip;
1755 + struct snd_card *card;
1758 + if (dev >= MAX_SUBSTREAMS)
1761 + if (!enable[dev]) {
1767 + goto add_register_map;
1769 + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &g_card);
1773 + snd_card_set_dev(g_card, &pdev->dev);
1774 + strcpy(g_card->driver, "BRCM bcm2835 ALSA Driver");
1775 + strcpy(g_card->shortname, "bcm2835 ALSA");
1776 + sprintf(g_card->longname, "%s", g_card->shortname);
1778 + err = snd_bcm2835_create(g_card, pdev, &chip);
1780 + printk(KERN_ERR "Failed to create bcm2835 chip\n");
1781 + goto out_bcm2835_create;
1785 + err = snd_bcm2835_new_pcm(chip);
1787 + printk(KERN_ERR "Failed to create new BCM2835 pcm device\n");
1788 + goto out_bcm2835_new_pcm;
1791 + err = snd_bcm2835_new_ctl(chip);
1793 + printk(KERN_ERR "Failed to create new BCM2835 ctl\n");
1794 + goto out_bcm2835_new_ctl;
1801 + BUG_ON(!(card && chip));
1803 + chip->avail_substreams |= (1 << dev);
1804 + chip->pdev[dev] = pdev;
1807 + err = snd_card_register(card);
1810 + "Failed to register bcm2835 ALSA card \n");
1811 + goto out_card_register;
1813 + platform_set_drvdata(pdev, card);
1814 + printk(KERN_INFO "bcm2835 ALSA card created!\n");
1816 + printk(KERN_INFO "bcm2835 ALSA chip created!\n");
1817 + platform_set_drvdata(pdev, (void *)dev);
1825 +out_bcm2835_new_ctl:
1826 +out_bcm2835_new_pcm:
1827 +out_bcm2835_create:
1829 + if (snd_card_free(g_card))
1830 + printk(KERN_ERR "Failed to free Registered alsa card\n");
1833 + dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
1834 + printk(KERN_ERR "BCM2835 ALSA Probe failed !!\n");
1838 +static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
1843 + drv_data = platform_get_drvdata(pdev);
1845 + if (drv_data == (void *)g_card) {
1846 + /* This is the card device */
1847 + snd_card_free((struct snd_card *)drv_data);
1851 + idx = (uint32_t) drv_data;
1852 + if (g_card != NULL) {
1854 + /* We pass chip device numbers in audio ipc devices
1855 + * other than the one we registered our card with
1857 + idx = (uint32_t) drv_data;
1858 + BUG_ON(!idx || idx > MAX_SUBSTREAMS);
1859 + g_chip->avail_substreams &= ~(1 << idx);
1860 + /* There should be atleast one substream registered
1861 + * after we are done here, as it wil be removed when
1862 + * the *remove* is called for the card device
1864 + BUG_ON(!g_chip->avail_substreams);
1868 + platform_set_drvdata(pdev, NULL);
1874 +static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
1875 + pm_message_t state)
1880 +static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
1887 +static struct platform_driver bcm2835_alsa0_driver = {
1888 + .probe = snd_bcm2835_alsa_probe,
1889 + .remove = snd_bcm2835_alsa_remove,
1891 + .suspend = snd_bcm2835_alsa_suspend,
1892 + .resume = snd_bcm2835_alsa_resume,
1895 + .name = "bcm2835_AUD0",
1896 + .owner = THIS_MODULE,
1900 +static struct platform_driver bcm2835_alsa1_driver = {
1901 + .probe = snd_bcm2835_alsa_probe,
1902 + .remove = snd_bcm2835_alsa_remove,
1904 + .suspend = snd_bcm2835_alsa_suspend,
1905 + .resume = snd_bcm2835_alsa_resume,
1908 + .name = "bcm2835_AUD1",
1909 + .owner = THIS_MODULE,
1913 +static struct platform_driver bcm2835_alsa2_driver = {
1914 + .probe = snd_bcm2835_alsa_probe,
1915 + .remove = snd_bcm2835_alsa_remove,
1917 + .suspend = snd_bcm2835_alsa_suspend,
1918 + .resume = snd_bcm2835_alsa_resume,
1921 + .name = "bcm2835_AUD2",
1922 + .owner = THIS_MODULE,
1926 +static struct platform_driver bcm2835_alsa3_driver = {
1927 + .probe = snd_bcm2835_alsa_probe,
1928 + .remove = snd_bcm2835_alsa_remove,
1930 + .suspend = snd_bcm2835_alsa_suspend,
1931 + .resume = snd_bcm2835_alsa_resume,
1934 + .name = "bcm2835_AUD3",
1935 + .owner = THIS_MODULE,
1939 +static struct platform_driver bcm2835_alsa4_driver = {
1940 + .probe = snd_bcm2835_alsa_probe,
1941 + .remove = snd_bcm2835_alsa_remove,
1943 + .suspend = snd_bcm2835_alsa_suspend,
1944 + .resume = snd_bcm2835_alsa_resume,
1947 + .name = "bcm2835_AUD4",
1948 + .owner = THIS_MODULE,
1952 +static struct platform_driver bcm2835_alsa5_driver = {
1953 + .probe = snd_bcm2835_alsa_probe,
1954 + .remove = snd_bcm2835_alsa_remove,
1956 + .suspend = snd_bcm2835_alsa_suspend,
1957 + .resume = snd_bcm2835_alsa_resume,
1960 + .name = "bcm2835_AUD5",
1961 + .owner = THIS_MODULE,
1965 +static struct platform_driver bcm2835_alsa6_driver = {
1966 + .probe = snd_bcm2835_alsa_probe,
1967 + .remove = snd_bcm2835_alsa_remove,
1969 + .suspend = snd_bcm2835_alsa_suspend,
1970 + .resume = snd_bcm2835_alsa_resume,
1973 + .name = "bcm2835_AUD6",
1974 + .owner = THIS_MODULE,
1978 +static struct platform_driver bcm2835_alsa7_driver = {
1979 + .probe = snd_bcm2835_alsa_probe,
1980 + .remove = snd_bcm2835_alsa_remove,
1982 + .suspend = snd_bcm2835_alsa_suspend,
1983 + .resume = snd_bcm2835_alsa_resume,
1986 + .name = "bcm2835_AUD7",
1987 + .owner = THIS_MODULE,
1991 +static int bcm2835_alsa_device_init(void)
1994 + err = platform_driver_register(&bcm2835_alsa0_driver);
1996 + printk("Error registering bcm2835_alsa0_driver %d .\n", err);
2000 + err = platform_driver_register(&bcm2835_alsa1_driver);
2002 + printk("Error registering bcm2835_alsa1_driver %d .\n", err);
2003 + goto unregister_0;
2006 + err = platform_driver_register(&bcm2835_alsa2_driver);
2008 + printk("Error registering bcm2835_alsa2_driver %d .\n", err);
2009 + goto unregister_1;
2012 + err = platform_driver_register(&bcm2835_alsa3_driver);
2014 + printk("Error registering bcm2835_alsa3_driver %d .\n", err);
2015 + goto unregister_2;
2018 + err = platform_driver_register(&bcm2835_alsa4_driver);
2020 + printk("Error registering bcm2835_alsa4_driver %d .\n", err);
2021 + goto unregister_3;
2024 + err = platform_driver_register(&bcm2835_alsa5_driver);
2026 + printk("Error registering bcm2835_alsa5_driver %d .\n", err);
2027 + goto unregister_4;
2030 + err = platform_driver_register(&bcm2835_alsa6_driver);
2032 + printk("Error registering bcm2835_alsa6_driver %d .\n", err);
2033 + goto unregister_5;
2036 + err = platform_driver_register(&bcm2835_alsa7_driver);
2038 + printk("Error registering bcm2835_alsa7_driver %d .\n", err);
2039 + goto unregister_6;
2045 + platform_driver_unregister(&bcm2835_alsa6_driver);
2047 + platform_driver_unregister(&bcm2835_alsa5_driver);
2049 + platform_driver_unregister(&bcm2835_alsa4_driver);
2051 + platform_driver_unregister(&bcm2835_alsa3_driver);
2053 + platform_driver_unregister(&bcm2835_alsa2_driver);
2055 + platform_driver_unregister(&bcm2835_alsa1_driver);
2057 + platform_driver_unregister(&bcm2835_alsa0_driver);
2062 +static void bcm2835_alsa_device_exit(void)
2064 + platform_driver_unregister(&bcm2835_alsa0_driver);
2065 + platform_driver_unregister(&bcm2835_alsa1_driver);
2066 + platform_driver_unregister(&bcm2835_alsa2_driver);
2067 + platform_driver_unregister(&bcm2835_alsa3_driver);
2068 + platform_driver_unregister(&bcm2835_alsa4_driver);
2069 + platform_driver_unregister(&bcm2835_alsa5_driver);
2070 + platform_driver_unregister(&bcm2835_alsa6_driver);
2071 + platform_driver_unregister(&bcm2835_alsa7_driver);
2074 +late_initcall(bcm2835_alsa_device_init);
2075 +module_exit(bcm2835_alsa_device_exit);
2077 +MODULE_AUTHOR("Dom Cobley");
2078 +MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
2079 +MODULE_LICENSE("GPL");
2080 +MODULE_ALIAS("platform:bcm2835_alsa");
2081 diff --git a/sound/arm/bcm2835.h b/sound/arm/bcm2835.h
2082 new file mode 100755
2083 index 0000000..080bd5c
2085 +++ b/sound/arm/bcm2835.h
2087 +/*****************************************************************************
2088 +* Copyright 2011 Broadcom Corporation. All rights reserved.
2090 +* Unless you and Broadcom execute a separate written software license
2091 +* agreement governing use of this software, this software is licensed to you
2092 +* under the terms of the GNU General Public License version 2, available at
2093 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2095 +* Notwithstanding the above, under no circumstances may you combine this
2096 +* software in any way with any other Broadcom software provided under a
2097 +* license other than the GPL, without Broadcom's express prior written
2099 +*****************************************************************************/
2101 +#ifndef __SOUND_ARM_BCM2835_H
2102 +#define __SOUND_ARM_BCM2835_H
2104 +#include <linux/device.h>
2105 +#include <linux/list.h>
2106 +#include <linux/interrupt.h>
2107 +#include <linux/wait.h>
2108 +#include <sound/core.h>
2109 +#include <sound/initval.h>
2110 +#include <sound/pcm.h>
2111 +#include <sound/pcm_params.h>
2112 +#include <linux/workqueue.h>
2115 +#define AUDIO_DEBUG_ENABLE
2116 +#define AUDIO_VERBOSE_DEBUG_ENABLE
2121 +#ifdef AUDIO_DEBUG_ENABLE
2122 +#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
2124 +#define audio_debug(fmt, arg...) \
2125 + printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
2127 +#define audio_info(fmt, arg...) \
2128 + printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
2132 +#define audio_debug(fmt, arg...)
2134 +#define audio_info(fmt, arg...)
2136 +#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
2140 +#define audio_debug(fmt, arg...)
2142 +#define audio_info(fmt, arg...)
2144 +#endif /* AUDIO_DEBUG_ENABLE */
2146 +#define audio_error(fmt, arg...) \
2147 + printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
2149 +#define audio_warning(fmt, arg...) \
2150 + printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
2152 +#define audio_alert(fmt, arg...) \
2153 + printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
2155 +#define MAX_SUBSTREAMS (8)
2156 +#define AVAIL_SUBSTREAMS_MASK (0xff)
2162 +/* macros for alsa2chip and chip2alsa, instead of functions */
2164 +#define alsa2chip(vol) (uint)(-((vol << 8) / 100)) /* convert alsa to chip volume (defined as macro rather than function call) */
2165 +#define chip2alsa(vol) -((vol * 100) >> 8) /* convert chip to alsa volume */
2167 +/* Some constants for values .. */
2169 + AUDIO_DEST_AUTO = 0,
2170 + AUDIO_DEST_HEADPHONES = 1,
2171 + AUDIO_DEST_HDMI = 2,
2173 +} SND_BCM2835_ROUTE_T;
2176 + PCM_PLAYBACK_VOLUME,
2177 + PCM_PLAYBACK_MUTE,
2178 + PCM_PLAYBACK_DEVICE,
2179 +} SND_BCM2835_CTRL_T;
2181 +/* definition of the chip-specific record */
2182 +typedef struct bcm2835_chip {
2183 + struct snd_card *card;
2184 + struct snd_pcm *pcm;
2185 + /* Bitmat for valid reg_base and irq numbers */
2186 + uint32_t avail_substreams;
2187 + struct platform_device *pdev[MAX_SUBSTREAMS];
2188 + struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
2191 + int old_volume; /* stores the volume value whist muted */
2196 +typedef struct bcm2835_alsa_stream {
2197 + bcm2835_chip_t *chip;
2198 + struct snd_pcm_substream *substream;
2200 + struct semaphore buffers_update_sem;
2201 + struct semaphore control_sem;
2203 + volatile uint32_t control;
2204 + volatile uint32_t status;
2211 + unsigned int buffer_size;
2212 + unsigned int period_size;
2214 + uint32_t enable_fifo_irq;
2215 + irq_handler_t fifo_irq_handler;
2217 + atomic_t retrieved;
2218 + struct opaque_AUDIO_INSTANCE_T *instance;
2219 + struct workqueue_struct *my_wq;
2221 +} bcm2835_alsa_stream_t;
2223 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
2224 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
2226 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
2227 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
2228 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
2229 + uint32_t channels, uint32_t samplerate,
2231 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream);
2232 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream);
2233 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream);
2234 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip);
2235 +int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
2237 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream);
2238 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream);
2239 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream);
2241 +#endif /* __SOUND_ARM_BCM2835_H */
2242 diff --git a/sound/arm/vc_vchi_audioserv_defs.h b/sound/arm/vc_vchi_audioserv_defs.h
2243 new file mode 100644
2244 index 0000000..af3e6eb
2246 +++ b/sound/arm/vc_vchi_audioserv_defs.h
2248 +/*****************************************************************************
2249 +* Copyright 2011 Broadcom Corporation. All rights reserved.
2251 +* Unless you and Broadcom execute a separate written software license
2252 +* agreement governing use of this software, this software is licensed to you
2253 +* under the terms of the GNU General Public License version 2, available at
2254 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2256 +* Notwithstanding the above, under no circumstances may you combine this
2257 +* software in any way with any other Broadcom software provided under a
2258 +* license other than the GPL, without Broadcom's express prior written
2260 +*****************************************************************************/
2262 +#ifndef _VC_AUDIO_DEFS_H_
2263 +#define _VC_AUDIO_DEFS_H_
2265 +#define VC_AUDIOSERV_MIN_VER 1
2266 +#define VC_AUDIOSERV_VER 2
2268 +// FourCC code used for VCHI connection
2269 +#define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
2271 +// Maximum message length
2272 +#define VC_AUDIO_MAX_MSG_LEN (sizeof( VC_AUDIO_MSG_T ))
2274 +// List of screens that are currently supported
2275 +// All message types supported for HOST->VC direction
2277 + VC_AUDIO_MSG_TYPE_RESULT, // Generic result
2278 + VC_AUDIO_MSG_TYPE_COMPLETE, // Generic result
2279 + VC_AUDIO_MSG_TYPE_CONFIG, // Configure audio
2280 + VC_AUDIO_MSG_TYPE_CONTROL, // Configure audio
2281 + VC_AUDIO_MSG_TYPE_OPEN, // Configure audio
2282 + VC_AUDIO_MSG_TYPE_CLOSE, // Configure audio
2283 + VC_AUDIO_MSG_TYPE_START, // Configure audio
2284 + VC_AUDIO_MSG_TYPE_STOP, // Configure audio
2285 + VC_AUDIO_MSG_TYPE_WRITE, // Configure audio
2286 + VC_AUDIO_MSG_TYPE_MAX
2287 +} VC_AUDIO_MSG_TYPE;
2289 +// configure the audio
2291 + uint32_t channels;
2292 + uint32_t samplerate;
2295 +} VC_AUDIO_CONFIG_T;
2301 +} VC_AUDIO_CONTROL_T;
2313 +} VC_AUDIO_CLOSE_T;
2318 +} VC_AUDIO_START_T;
2321 + uint32_t draining;
2325 +// configure the write audio samples
2327 + uint32_t count; // in bytes
2331 + uint16_t max_packet;
2332 +} VC_AUDIO_WRITE_T;
2334 +// Generic result for a request (VC->HOST)
2336 + int32_t success; // Success value
2338 +} VC_AUDIO_RESULT_T;
2340 +// Generic result for a request (VC->HOST)
2342 + int32_t count; // Success value
2345 +} VC_AUDIO_COMPLETE_T;
2347 +// Message header for all messages in HOST->VC direction
2349 + int32_t type; // Message type (VC_AUDIO_MSG_TYPE)
2351 + VC_AUDIO_CONFIG_T config;
2352 + VC_AUDIO_CONTROL_T control;
2353 + VC_AUDIO_OPEN_T open;
2354 + VC_AUDIO_CLOSE_T close;
2355 + VC_AUDIO_START_T start;
2356 + VC_AUDIO_STOP_T stop;
2357 + VC_AUDIO_WRITE_T write;
2358 + VC_AUDIO_RESULT_T result;
2359 + VC_AUDIO_COMPLETE_T complete;
2363 +#endif // _VC_AUDIO_DEFS_H_