1 From f99826368eeb17ddaf6b9459f577356c0387f365 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 007/196] 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 | 12 +
11 sound/arm/Kconfig | 7 +
12 sound/arm/Makefile | 6 +
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, 2202 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 64a2783..67f3608 100644
91 --- a/arch/arm/mach-bcm2708/bcm2708.c
92 +++ b/arch/arm/mach-bcm2708/bcm2708.c
93 @@ -424,6 +424,16 @@ 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,
107 int __init bcm_register_device(struct platform_device *pdev)
110 @@ -529,6 +539,8 @@ void __init bcm2708_init(void)
111 bcm_register_device(&bcm2708_emmc_device);
114 + for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
115 + bcm_register_device(&bcm2708_alsa_devices[i]);
117 for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
118 struct amba_device *d = amba_devs[i];
119 diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
120 index 885683a..f7ceafd 100644
121 --- a/sound/arm/Kconfig
122 +++ b/sound/arm/Kconfig
123 @@ -39,5 +39,12 @@ config SND_PXA2XX_AC97
124 Say Y or M if you want to support any AC97 codec attached to
125 the PXA2xx AC97 interface.
128 + tristate "BCM2835 ALSA driver"
129 + depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND
132 + Say Y or M if you want to support BCM2835 Alsa pcm card driver
136 diff --git a/sound/arm/Makefile b/sound/arm/Makefile
137 index 8c0c851..181cb57 100644
138 --- a/sound/arm/Makefile
139 +++ b/sound/arm/Makefile
140 @@ -14,3 +14,9 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o
142 obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
143 snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
145 +obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o
146 +snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
148 +EXTRA_CFLAGS += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
150 diff --git a/sound/arm/bcm2835-ctl.c b/sound/arm/bcm2835-ctl.c
152 index 0000000..c3e0f7a
154 +++ b/sound/arm/bcm2835-ctl.c
156 +/*****************************************************************************
157 +* Copyright 2011 Broadcom Corporation. All rights reserved.
159 +* Unless you and Broadcom execute a separate written software license
160 +* agreement governing use of this software, this software is licensed to you
161 +* under the terms of the GNU General Public License version 2, available at
162 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
164 +* Notwithstanding the above, under no circumstances may you combine this
165 +* software in any way with any other Broadcom software provided under a
166 +* license other than the GPL, without Broadcom's express prior written
168 +*****************************************************************************/
170 +#include <linux/platform_device.h>
171 +#include <linux/init.h>
172 +#include <linux/io.h>
173 +#include <linux/jiffies.h>
174 +#include <linux/slab.h>
175 +#include <linux/time.h>
176 +#include <linux/wait.h>
177 +#include <linux/delay.h>
178 +#include <linux/moduleparam.h>
179 +#include <linux/sched.h>
181 +#include <sound/core.h>
182 +#include <sound/control.h>
183 +#include <sound/pcm.h>
184 +#include <sound/pcm_params.h>
185 +#include <sound/rawmidi.h>
186 +#include <sound/initval.h>
187 +#include <sound/tlv.h>
189 +#include "bcm2835.h"
191 +/* volume maximum and minimum in terms of 0.01dB */
192 +#define CTRL_VOL_MAX 400
193 +#define CTRL_VOL_MIN -10239 /* originally -10240 */
196 +static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
197 + struct snd_ctl_elem_info *uinfo)
199 + audio_info(" ... IN\n");
200 + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
201 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
203 + uinfo->value.integer.min = CTRL_VOL_MIN;
204 + uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
205 + } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
206 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
208 + uinfo->value.integer.min = 0;
209 + uinfo->value.integer.max = 1;
210 + } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
211 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
213 + uinfo->value.integer.min = 0;
214 + uinfo->value.integer.max = AUDIO_DEST_MAX-1;
216 + audio_info(" ... OUT\n");
220 +/* toggles mute on or off depending on the value of nmute, and returns
221 + * 1 if the mute value was changed, otherwise 0
223 +static int toggle_mute(struct bcm2835_chip *chip, int nmute)
225 + /* if settings are ok, just return 0 */
226 + if(chip->mute == nmute)
229 + /* if the sound is muted then we need to unmute */
230 + if(chip->mute == CTRL_VOL_MUTE)
232 + chip->volume = chip->old_volume; /* copy the old volume back */
233 + audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
235 + else /* otherwise we mute */
237 + chip->old_volume = chip->volume;
238 + chip->volume = 26214; /* set volume to minimum level AKA mute */
239 + audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
242 + chip->mute = nmute;
246 +static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
247 + struct snd_ctl_elem_value *ucontrol)
249 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
251 + BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
253 + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
254 + ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
255 + else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
256 + ucontrol->value.integer.value[0] = chip->mute;
257 + else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
258 + ucontrol->value.integer.value[0] = chip->dest;
263 +static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
264 + struct snd_ctl_elem_value *ucontrol)
266 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
269 + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
270 + audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
271 + if (chip->mute == CTRL_VOL_MUTE) {
272 + /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
273 + return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
276 + || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
278 + chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
282 + } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
283 + /* Now implemented */
284 + audio_info(" Mute attempted\n");
285 + changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
287 + } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
288 + if (ucontrol->value.integer.value[0] != chip->dest) {
289 + chip->dest = ucontrol->value.integer.value[0];
295 + if (bcm2835_audio_set_ctls(chip))
296 + printk(KERN_ERR "Failed to set ALSA controls..\n");
302 +static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
304 +static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
306 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
307 + .name = "PCM Playback Volume",
309 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
310 + .private_value = PCM_PLAYBACK_VOLUME,
311 + .info = snd_bcm2835_ctl_info,
312 + .get = snd_bcm2835_ctl_get,
313 + .put = snd_bcm2835_ctl_put,
315 + .tlv = {.p = snd_bcm2835_db_scale}
318 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
319 + .name = "PCM Playback Switch",
321 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
322 + .private_value = PCM_PLAYBACK_MUTE,
323 + .info = snd_bcm2835_ctl_info,
324 + .get = snd_bcm2835_ctl_get,
325 + .put = snd_bcm2835_ctl_put,
329 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
330 + .name = "PCM Playback Route",
332 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
333 + .private_value = PCM_PLAYBACK_DEVICE,
334 + .info = snd_bcm2835_ctl_info,
335 + .get = snd_bcm2835_ctl_get,
336 + .put = snd_bcm2835_ctl_put,
341 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
346 + strcpy(chip->card->mixername, "Broadcom Mixer");
347 + for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
349 + snd_ctl_add(chip->card,
350 + snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
356 diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c
358 index 0000000..4206b7e
360 +++ b/sound/arm/bcm2835-pcm.c
362 +/*****************************************************************************
363 +* Copyright 2011 Broadcom Corporation. All rights reserved.
365 +* Unless you and Broadcom execute a separate written software license
366 +* agreement governing use of this software, this software is licensed to you
367 +* under the terms of the GNU General Public License version 2, available at
368 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
370 +* Notwithstanding the above, under no circumstances may you combine this
371 +* software in any way with any other Broadcom software provided under a
372 +* license other than the GPL, without Broadcom's express prior written
374 +*****************************************************************************/
376 +#include <linux/interrupt.h>
377 +#include <linux/slab.h>
379 +#include "bcm2835.h"
381 +/* hardware definition */
382 +static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
383 + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER),
384 + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
385 + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
390 + .buffer_bytes_max = 128 * 1024,
391 + .period_bytes_min = 1 * 1024,
392 + .period_bytes_max = 128 * 1024,
394 + .periods_max = 128,
397 +static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
399 + audio_info("Freeing up alsa stream here ..\n");
400 + if (runtime->private_data)
401 + kfree(runtime->private_data);
402 + runtime->private_data = NULL;
405 +static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
407 + bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
408 + uint32_t consumed = 0;
409 + int new_period = 0;
411 + audio_info(" .. IN\n");
413 + audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
414 + alsa_stream ? alsa_stream->substream : 0);
416 + if (alsa_stream->open)
417 + consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
419 + /* We get called only if playback was triggered, So, the number of buffers we retrieve in
420 + * each iteration are the buffers that have been played out already
423 + if (alsa_stream->period_size) {
424 + if ((alsa_stream->pos / alsa_stream->period_size) !=
425 + ((alsa_stream->pos + consumed) / alsa_stream->period_size))
428 + audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
431 + alsa_stream->buffer_size,
432 + (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods),
433 + frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
435 + if (alsa_stream->buffer_size) {
436 + alsa_stream->pos += consumed &~ (1<<30);
437 + alsa_stream->pos %= alsa_stream->buffer_size;
440 + if (alsa_stream->substream) {
442 + snd_pcm_period_elapsed(alsa_stream->substream);
444 + audio_warning(" unexpected NULL substream\n");
446 + audio_info(" .. OUT\n");
448 + return IRQ_HANDLED;
452 +static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
454 + bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
455 + struct snd_pcm_runtime *runtime = substream->runtime;
456 + bcm2835_alsa_stream_t *alsa_stream;
460 + audio_info(" .. IN (%d)\n", substream->number);
462 + audio_info("Alsa open (%d)\n", substream->number);
463 + idx = substream->number;
465 + if (idx > MAX_SUBSTREAMS) {
467 + ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
468 + idx, MAX_SUBSTREAMS);
473 + /* Check if we are ready */
474 + if (!(chip->avail_substreams & (1 << idx))) {
475 + /* We are not ready yet */
476 + audio_error("substream(%d) device is not ready yet\n", idx);
481 + alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
482 + if (alsa_stream == NULL) {
486 + /* Initialise alsa_stream */
487 + alsa_stream->chip = chip;
488 + alsa_stream->substream = substream;
489 + alsa_stream->idx = idx;
490 + chip->alsa_stream[idx] = alsa_stream;
492 + sema_init(&alsa_stream->buffers_update_sem, 0);
493 + sema_init(&alsa_stream->control_sem, 0);
494 + spin_lock_init(&alsa_stream->lock);
496 + /* Enabled in start trigger, called on each "fifo irq" after that */
497 + alsa_stream->enable_fifo_irq = 0;
498 + alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;
500 + runtime->private_data = alsa_stream;
501 + runtime->private_free = snd_bcm2835_playback_free;
502 + runtime->hw = snd_bcm2835_playback_hw;
503 + /* minimum 16 bytes alignment (for vchiq bulk transfers) */
504 + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
507 + err = bcm2835_audio_open(alsa_stream);
509 + kfree(alsa_stream);
513 + alsa_stream->open = 1;
514 + alsa_stream->draining = 1;
517 + audio_info(" .. OUT =%d\n", err);
522 +/* close callback */
523 +static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
525 + /* the hardware-specific codes will be here */
527 + struct snd_pcm_runtime *runtime = substream->runtime;
528 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
530 + audio_info(" .. IN\n");
531 + audio_info("Alsa close\n");
534 + * Call stop if it's still running. This happens when app
535 + * is force killed and we don't get a stop trigger.
537 + if (alsa_stream->running) {
539 + err = bcm2835_audio_stop(alsa_stream);
540 + alsa_stream->running = 0;
542 + audio_error(" Failed to STOP alsa device\n");
545 + alsa_stream->period_size = 0;
546 + alsa_stream->buffer_size = 0;
548 + if (alsa_stream->open) {
549 + alsa_stream->open = 0;
550 + bcm2835_audio_close(alsa_stream);
552 + if (alsa_stream->chip)
553 + alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
555 + * Do not free up alsa_stream here, it will be freed up by
556 + * runtime->private_free callback we registered in *_open above
559 + audio_info(" .. OUT\n");
564 +/* hw_params callback */
565 +static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
566 + struct snd_pcm_hw_params *params)
569 + struct snd_pcm_runtime *runtime = substream->runtime;
570 + bcm2835_alsa_stream_t *alsa_stream =
571 + (bcm2835_alsa_stream_t *) runtime->private_data;
573 + audio_info(" .. IN\n");
575 + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
578 + (" pcm_lib_malloc failed to allocated pages for buffers\n");
582 + err = bcm2835_audio_set_params(alsa_stream, params_channels(params),
583 + params_rate(params),
584 + snd_pcm_format_width(params_format
587 + audio_error(" error setting hw params\n");
590 + bcm2835_audio_setup(alsa_stream);
592 + /* in preparation of the stream, set the controls (volume level) of the stream */
593 + bcm2835_audio_set_ctls(alsa_stream->chip);
595 + audio_info(" .. OUT\n");
600 +/* hw_free callback */
601 +static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
603 + audio_info(" .. IN\n");
604 + return snd_pcm_lib_free_pages(substream);
607 +/* prepare callback */
608 +static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
610 + struct snd_pcm_runtime *runtime = substream->runtime;
611 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
613 + audio_info(" .. IN\n");
615 + alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
616 + alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
617 + alsa_stream->pos = 0;
619 + audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
620 + alsa_stream->buffer_size, alsa_stream->period_size,
621 + alsa_stream->pos, runtime->frame_bits);
623 + audio_info(" .. OUT\n");
627 +/* trigger callback */
628 +static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
630 + struct snd_pcm_runtime *runtime = substream->runtime;
631 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
634 + audio_info(" .. IN\n");
637 + case SNDRV_PCM_TRIGGER_START:
638 + audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
639 + alsa_stream->running);
640 + if (!alsa_stream->running) {
641 + err = bcm2835_audio_start(alsa_stream);
643 + alsa_stream->running = 1;
644 + alsa_stream->draining = 1;
646 + audio_error(" Failed to START alsa device (%d)\n", err);
650 + case SNDRV_PCM_TRIGGER_STOP:
652 + ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
653 + alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
654 + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
655 + audio_info("DRAINING\n");
656 + alsa_stream->draining = 1;
658 + audio_info("DROPPING\n");
659 + alsa_stream->draining = 0;
661 + if (alsa_stream->running) {
662 + err = bcm2835_audio_stop(alsa_stream);
664 + audio_error(" Failed to STOP alsa device (%d)\n", err);
665 + alsa_stream->running = 0;
672 + audio_info(" .. OUT\n");
676 +/* pointer callback */
677 +static snd_pcm_uframes_t
678 +snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
680 + struct snd_pcm_runtime *runtime = substream->runtime;
681 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
683 + audio_info(" .. IN\n");
685 + audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
686 + frames_to_bytes(runtime, runtime->status->hw_ptr),
687 + frames_to_bytes(runtime, runtime->control->appl_ptr),
690 + audio_info(" .. OUT\n");
691 + return bytes_to_frames(runtime, alsa_stream->pos);
694 +static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream,
695 + int channel, snd_pcm_uframes_t pos, void *src,
696 + snd_pcm_uframes_t count)
699 + struct snd_pcm_runtime *runtime = substream->runtime;
700 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
702 + audio_info(" .. IN\n");
703 + audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n",
704 + frames_to_bytes(runtime, count), frames_to_bytes(runtime,
708 + frames_to_bytes(runtime, runtime->control->appl_ptr),
711 + bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count),
713 + audio_info(" .. OUT\n");
717 +static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
718 + unsigned int cmd, void *arg)
720 + int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
721 + audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
722 + cmd, arg, arg ? *(unsigned *)arg : 0, ret);
727 +static struct snd_pcm_ops snd_bcm2835_playback_ops = {
728 + .open = snd_bcm2835_playback_open,
729 + .close = snd_bcm2835_playback_close,
730 + .ioctl = snd_bcm2835_pcm_lib_ioctl,
731 + .hw_params = snd_bcm2835_pcm_hw_params,
732 + .hw_free = snd_bcm2835_pcm_hw_free,
733 + .prepare = snd_bcm2835_pcm_prepare,
734 + .trigger = snd_bcm2835_pcm_trigger,
735 + .pointer = snd_bcm2835_pcm_pointer,
736 + .copy = snd_bcm2835_pcm_copy,
739 +/* create a pcm device */
740 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
742 + struct snd_pcm *pcm;
745 + audio_info(" .. IN\n");
747 + snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
750 + pcm->private_data = chip;
751 + strcpy(pcm->name, "bcm2835 ALSA");
753 + chip->dest = AUDIO_DEST_AUTO;
754 + chip->volume = alsa2chip(0);
755 + chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
756 + /* set operators */
757 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
758 + &snd_bcm2835_playback_ops);
760 + /* pre-allocation of buffers */
761 + /* NOTE: this may fail */
762 + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
763 + snd_dma_continuous_data
764 + (GFP_KERNEL), 64 * 1024,
767 + audio_info(" .. OUT\n");
771 diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c
773 index 0000000..9ecb2d6
775 +++ b/sound/arm/bcm2835-vchiq.c
777 +/*****************************************************************************
778 +* Copyright 2011 Broadcom Corporation. All rights reserved.
780 +* Unless you and Broadcom execute a separate written software license
781 +* agreement governing use of this software, this software is licensed to you
782 +* under the terms of the GNU General Public License version 2, available at
783 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
785 +* Notwithstanding the above, under no circumstances may you combine this
786 +* software in any way with any other Broadcom software provided under a
787 +* license other than the GPL, without Broadcom's express prior written
789 +*****************************************************************************/
791 +#include <linux/device.h>
792 +#include <sound/core.h>
793 +#include <sound/initval.h>
794 +#include <sound/pcm.h>
795 +#include <linux/io.h>
796 +#include <linux/interrupt.h>
797 +#include <linux/fs.h>
798 +#include <linux/file.h>
799 +#include <linux/mm.h>
800 +#include <linux/syscalls.h>
801 +#include <asm/uaccess.h>
802 +#include <linux/slab.h>
803 +#include <linux/delay.h>
804 +#include <linux/atomic.h>
805 +#include <linux/module.h>
807 +#include "bcm2835.h"
809 +/* ---- Include Files -------------------------------------------------------- */
811 +#include "interface/vchi/vchi.h"
812 +#include "vc_vchi_audioserv_defs.h"
814 +/* ---- Private Constants and Types ------------------------------------------ */
816 +/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
817 +#ifdef AUDIO_DEBUG_ENABLE
818 + #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
819 + #define LOG_WARN( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
820 + #define LOG_INFO( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
821 + #define LOG_DBG( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
823 + #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
824 + #define LOG_WARN( fmt, arg... )
825 + #define LOG_INFO( fmt, arg... )
826 + #define LOG_DBG( fmt, arg... )
829 +typedef struct opaque_AUDIO_INSTANCE_T {
830 + uint32_t num_connections;
831 + VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
832 + struct semaphore msg_avail_event;
833 + struct mutex vchi_mutex;
834 + bcm2835_alsa_stream_t *alsa_stream;
836 + short peer_version;
839 +bool force_bulk = false;
841 +/* ---- Private Variables ---------------------------------------------------- */
843 +/* ---- Private Function Prototypes ------------------------------------------ */
845 +/* ---- Private Functions ---------------------------------------------------- */
847 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
848 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
851 + struct work_struct my_work;
852 + bcm2835_alsa_stream_t *alsa_stream;
856 +static void my_wq_function(struct work_struct *work)
858 + my_work_t *w = (my_work_t *) work;
860 + LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->x);
863 + ret = bcm2835_audio_start_worker(w->alsa_stream);
866 + ret = bcm2835_audio_stop_worker(w->alsa_stream);
869 + LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->x);
872 + kfree((void *)work);
873 + LOG_DBG(" .. OUT %d\n", ret);
876 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
879 + LOG_DBG(" .. IN\n");
880 + if (alsa_stream->my_wq) {
881 + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
882 + /*--- Queue some work (item 1) ---*/
884 + INIT_WORK((struct work_struct *)work, my_wq_function);
885 + work->alsa_stream = alsa_stream;
888 + (alsa_stream->my_wq, (struct work_struct *)work))
891 + LOG_ERR(" .. Error: NULL work kmalloc\n");
893 + LOG_DBG(" .. OUT %d\n", ret);
897 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
900 + LOG_DBG(" .. IN\n");
901 + if (alsa_stream->my_wq) {
902 + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
903 + /*--- Queue some work (item 1) ---*/
905 + INIT_WORK((struct work_struct *)work, my_wq_function);
906 + work->alsa_stream = alsa_stream;
909 + (alsa_stream->my_wq, (struct work_struct *)work))
912 + LOG_ERR(" .. Error: NULL work kmalloc\n");
914 + LOG_DBG(" .. OUT %d\n", ret);
918 +void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
920 + alsa_stream->my_wq = create_workqueue("my_queue");
924 +void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
926 + if (alsa_stream->my_wq) {
927 + flush_workqueue(alsa_stream->my_wq);
928 + destroy_workqueue(alsa_stream->my_wq);
929 + alsa_stream->my_wq = NULL;
934 +static void audio_vchi_callback(void *param,
935 + const VCHI_CALLBACK_REASON_T reason,
938 + AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
942 + bcm2835_alsa_stream_t *alsa_stream = 0;
943 + LOG_DBG(" .. IN instance=%p, param=%p, reason=%d, handle=%p\n",
944 + instance, param, reason, msg_handle);
946 + if (!instance || reason != VCHI_CALLBACK_MSG_AVAILABLE) {
949 + alsa_stream = instance->alsa_stream;
950 + status = vchi_msg_dequeue(instance->vchi_handle[0],
951 + &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
952 + if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
954 + (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
955 + instance, m.u.result.success);
956 + instance->result = m.u.result.success;
957 + up(&instance->msg_avail_event);
958 + } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
959 + irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
961 + (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
962 + instance, m.u.complete.count);
963 + if (alsa_stream && callback) {
964 + atomic_add(m.u.complete.count, &alsa_stream->retrieved);
965 + callback(0, alsa_stream);
967 + LOG_DBG(" .. unexpected alsa_stream=%p, callback=%p\n",
968 + alsa_stream, callback);
971 + LOG_DBG(" .. unexpected m.type=%d\n", m.type);
973 + LOG_DBG(" .. OUT\n");
976 +static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
977 + VCHI_CONNECTION_T **
979 + uint32_t num_connections)
982 + AUDIO_INSTANCE_T *instance;
985 + LOG_DBG("%s: start", __func__);
987 + if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
988 + LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
989 + __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
993 + /* Allocate memory for this instance */
994 + instance = kmalloc(sizeof(*instance), GFP_KERNEL);
996 + memset(instance, 0, sizeof(*instance));
997 + instance->num_connections = num_connections;
999 + /* Create a lock for exclusive, serialized VCHI connection access */
1000 + mutex_init(&instance->vchi_mutex);
1001 + /* Open the VCHI service connections */
1002 + for (i = 0; i < num_connections; i++) {
1003 + SERVICE_CREATION_T params = {
1004 + VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
1005 + VC_AUDIO_SERVER_NAME, // 4cc service code
1006 + vchi_connections[i], // passed in fn pointers
1007 + 0, // rx fifo size (unused)
1008 + 0, // tx fifo size (unused)
1009 + audio_vchi_callback, // service callback
1010 + instance, // service callback parameter
1011 + 1, //TODO: remove VCOS_FALSE, // unaligned bulk recieves
1012 + 1, //TODO: remove VCOS_FALSE, // unaligned bulk transmits
1013 + 0 // want crc check on bulk transfers
1016 + status = vchi_service_open(vchi_instance, ¶ms,
1017 + &instance->vchi_handle[i]);
1020 + ("%s: failed to open VCHI service connection (status=%d)\n",
1021 + __func__, status);
1023 + goto err_close_services;
1025 + /* Finished with the service for now */
1026 + vchi_service_release(instance->vchi_handle[i]);
1031 +err_close_services:
1032 + for (i = 0; i < instance->num_connections; i++) {
1033 + vchi_service_close(instance->vchi_handle[i]);
1041 +static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
1045 + LOG_DBG(" .. IN\n");
1047 + if (instance == NULL) {
1048 + LOG_ERR("%s: invalid handle %p\n", __func__, instance);
1053 + LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
1054 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1056 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1060 + /* Close all VCHI service connections */
1061 + for (i = 0; i < instance->num_connections; i++) {
1063 + LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
1064 + vchi_service_use(instance->vchi_handle[i]);
1066 + success = vchi_service_close(instance->vchi_handle[i]);
1067 + if (success != 0) {
1069 + ("%s: failed to close VCHI service connection (status=%d)\n",
1070 + __func__, success);
1074 + mutex_unlock(&instance->vchi_mutex);
1078 + LOG_DBG(" .. OUT\n");
1083 +static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
1085 + static VCHI_INSTANCE_T vchi_instance;
1086 + static VCHI_CONNECTION_T *vchi_connection;
1087 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1089 + LOG_DBG(" .. IN\n");
1091 + LOG_INFO("%s: start", __func__);
1092 + //BUG_ON(instance);
1094 + LOG_ERR("%s: VCHI instance already open (%p)\n",
1095 + __func__, instance);
1096 + instance->alsa_stream = alsa_stream;
1097 + alsa_stream->instance = instance;
1098 + ret = 0; // xxx todo -1;
1099 + goto err_free_mem;
1102 + /* Initialize and create a VCHI connection */
1103 + ret = vchi_initialise(&vchi_instance);
1105 + LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
1109 + goto err_free_mem;
1111 + ret = vchi_connect(NULL, 0, vchi_instance);
1113 + LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
1117 + goto err_free_mem;
1120 + /* Initialize an instance of the audio service */
1121 + instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
1123 + if (instance == NULL /*|| audio_handle != instance */ ) {
1124 + LOG_ERR("%s: failed to initialize audio service\n", __func__);
1127 + goto err_free_mem;
1130 + instance->alsa_stream = alsa_stream;
1131 + alsa_stream->instance = instance;
1133 + LOG_DBG(" success !\n");
1135 + LOG_DBG(" .. OUT\n");
1140 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
1142 + AUDIO_INSTANCE_T *instance;
1146 + LOG_DBG(" .. IN\n");
1148 + my_workqueue_init(alsa_stream);
1150 + ret = bcm2835_audio_open_connection(alsa_stream);
1155 + instance = alsa_stream->instance;
1157 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1159 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1162 + vchi_service_use(instance->vchi_handle[0]);
1164 + m.type = VC_AUDIO_MSG_TYPE_OPEN;
1166 + /* Send the message to the videocore */
1167 + success = vchi_msg_queue(instance->vchi_handle[0],
1169 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1171 + if (success != 0) {
1172 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1173 + __func__, success);
1182 + vchi_service_release(instance->vchi_handle[0]);
1183 + mutex_unlock(&instance->vchi_mutex);
1185 + LOG_DBG(" .. OUT\n");
1189 +static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
1190 + bcm2835_chip_t * chip)
1193 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1196 + LOG_DBG(" .. IN\n");
1199 + (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
1201 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1203 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1206 + vchi_service_use(instance->vchi_handle[0]);
1208 + instance->result = -1;
1210 + m.type = VC_AUDIO_MSG_TYPE_CONTROL;
1211 + m.u.control.dest = chip->dest;
1212 + m.u.control.volume = chip->volume;
1214 + /* Create the message available event */
1215 + sema_init(&instance->msg_avail_event, 0);
1217 + /* Send the message to the videocore */
1218 + success = vchi_msg_queue(instance->vchi_handle[0],
1220 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1222 + if (success != 0) {
1223 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1224 + __func__, success);
1230 + /* We are expecting a reply from the videocore */
1231 + if (down_interruptible(&instance->msg_avail_event)) {
1232 + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1233 + __func__, success);
1239 + if (instance->result != 0) {
1240 + LOG_ERR("%s: result=%d\n", __func__, instance->result);
1249 + vchi_service_release(instance->vchi_handle[0]);
1250 + mutex_unlock(&instance->vchi_mutex);
1252 + LOG_DBG(" .. OUT\n");
1256 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
1260 + LOG_DBG(" .. IN\n");
1262 + /* change ctls for all substreams */
1263 + for (i = 0; i < MAX_SUBSTREAMS; i++) {
1264 + if (chip->avail_substreams & (1 << i)) {
1265 + if (!chip->alsa_stream[i])
1267 + LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
1270 + else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
1271 + (chip->alsa_stream[i], chip) != 0)
1273 + LOG_DBG("Couldn't set the controls for stream %d\n", i);
1276 + else LOG_DBG(" Controls set for stream %d\n", i);
1279 + LOG_DBG(" .. OUT ret=%d\n", ret);
1283 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
1284 + uint32_t channels, uint32_t samplerate,
1288 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1291 + LOG_DBG(" .. IN\n");
1294 + (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
1295 + channels, samplerate, bps);
1297 + /* resend ctls - alsa_stream may not have been open when first send */
1298 + ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
1300 + LOG_ERR(" Alsa controls not supported\n");
1304 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1306 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1309 + vchi_service_use(instance->vchi_handle[0]);
1311 + instance->result = -1;
1313 + m.type = VC_AUDIO_MSG_TYPE_CONFIG;
1314 + m.u.config.channels = channels;
1315 + m.u.config.samplerate = samplerate;
1316 + m.u.config.bps = bps;
1318 + /* Create the message available event */
1319 + sema_init(&instance->msg_avail_event, 0);
1321 + /* Send the message to the videocore */
1322 + success = vchi_msg_queue(instance->vchi_handle[0],
1324 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1326 + if (success != 0) {
1327 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1328 + __func__, success);
1334 + /* We are expecting a reply from the videocore */
1335 + if (down_interruptible(&instance->msg_avail_event)) {
1336 + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1337 + __func__, success);
1343 + if (instance->result != 0) {
1344 + LOG_ERR("%s: result=%d", __func__, instance->result);
1353 + vchi_service_release(instance->vchi_handle[0]);
1354 + mutex_unlock(&instance->vchi_mutex);
1356 + LOG_DBG(" .. OUT\n");
1360 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
1362 + LOG_DBG(" .. IN\n");
1364 + LOG_DBG(" .. OUT\n");
1369 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
1372 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1375 + LOG_DBG(" .. IN\n");
1377 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1379 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1382 + vchi_service_use(instance->vchi_handle[0]);
1384 + m.type = VC_AUDIO_MSG_TYPE_START;
1386 + /* Send the message to the videocore */
1387 + success = vchi_msg_queue(instance->vchi_handle[0],
1389 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1391 + if (success != 0) {
1392 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1393 + __func__, success);
1402 + vchi_service_release(instance->vchi_handle[0]);
1403 + mutex_unlock(&instance->vchi_mutex);
1404 + LOG_DBG(" .. OUT\n");
1408 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
1411 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1414 + LOG_DBG(" .. IN\n");
1416 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1418 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1421 + vchi_service_use(instance->vchi_handle[0]);
1423 + m.type = VC_AUDIO_MSG_TYPE_STOP;
1424 + m.u.stop.draining = alsa_stream->draining;
1426 + /* Send the message to the videocore */
1427 + success = vchi_msg_queue(instance->vchi_handle[0],
1429 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1431 + if (success != 0) {
1432 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1433 + __func__, success);
1442 + vchi_service_release(instance->vchi_handle[0]);
1443 + mutex_unlock(&instance->vchi_mutex);
1444 + LOG_DBG(" .. OUT\n");
1448 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
1451 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1454 + LOG_DBG(" .. IN\n");
1456 + my_workqueue_quit(alsa_stream);
1458 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1460 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1463 + vchi_service_use(instance->vchi_handle[0]);
1465 + m.type = VC_AUDIO_MSG_TYPE_CLOSE;
1467 + /* Create the message available event */
1468 + sema_init(&instance->msg_avail_event, 0);
1470 + /* Send the message to the videocore */
1471 + success = vchi_msg_queue(instance->vchi_handle[0],
1473 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1475 + if (success != 0) {
1476 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1477 + __func__, success);
1481 + if (down_interruptible(&instance->msg_avail_event)) {
1482 + LOG_ERR("%s: failed on waiting for event (status=%d)",
1483 + __func__, success);
1488 + if (instance->result != 0) {
1489 + LOG_ERR("%s: failed result (status=%d)",
1490 + __func__, instance->result);
1499 + vchi_service_release(instance->vchi_handle[0]);
1500 + mutex_unlock(&instance->vchi_mutex);
1502 + /* Stop the audio service */
1504 + vc_vchi_audio_deinit(instance);
1505 + alsa_stream->instance = NULL;
1507 + LOG_DBG(" .. OUT\n");
1511 +int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
1515 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1519 + LOG_DBG(" .. IN\n");
1521 + LOG_INFO(" Writing %d bytes from %p\n", count, src);
1523 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1525 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1528 + vchi_service_use(instance->vchi_handle[0]);
1530 + if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) {
1531 + LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
1533 + m.type = VC_AUDIO_MSG_TYPE_WRITE;
1534 + m.u.write.count = count;
1535 + // old version uses bulk, new version uses control
1536 + m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000;
1537 + m.u.write.callback = alsa_stream->fifo_irq_handler;
1538 + m.u.write.cookie = alsa_stream;
1539 + m.u.write.silence = src == NULL;
1541 + /* Send the message to the videocore */
1542 + success = vchi_msg_queue(instance->vchi_handle[0],
1544 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1546 + if (success != 0) {
1547 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1548 + __func__, success);
1553 + if (!m.u.write.silence) {
1554 + if (m.u.write.max_packet == 0) {
1555 + /* Send the message to the videocore */
1556 + success = vchi_bulk_queue_transmit(instance->vchi_handle[0],
1559 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED
1562 + VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
1565 + while (count > 0) {
1566 + int bytes = min((int)m.u.write.max_packet, (int)count);
1567 + success = vchi_msg_queue(instance->vchi_handle[0],
1569 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1570 + src = (char *)src + bytes;
1574 + if (success != 0) {
1576 + ("%s: failed on vchi_bulk_queue_transmit (status=%d)",
1577 + __func__, success);
1586 + vchi_service_release(instance->vchi_handle[0]);
1587 + mutex_unlock(&instance->vchi_mutex);
1588 + LOG_DBG(" .. OUT\n");
1593 + * Returns all buffers from arm->vc
1595 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
1597 + LOG_DBG(" .. IN\n");
1598 + LOG_DBG(" .. OUT\n");
1603 + * Forces VC to flush(drop) its filled playback buffers and
1604 + * return them the us. (VC->ARM)
1606 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
1608 + LOG_DBG(" .. IN\n");
1609 + LOG_DBG(" .. OUT\n");
1612 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
1614 + uint32_t count = atomic_read(&alsa_stream->retrieved);
1615 + atomic_sub(count, &alsa_stream->retrieved);
1619 +module_param(force_bulk, bool, 0444);
1620 +MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
1621 diff --git a/sound/arm/bcm2835.c b/sound/arm/bcm2835.c
1622 new file mode 100755
1623 index 0000000..e5ac894
1625 +++ b/sound/arm/bcm2835.c
1627 +/*****************************************************************************
1628 +* Copyright 2011 Broadcom Corporation. All rights reserved.
1630 +* Unless you and Broadcom execute a separate written software license
1631 +* agreement governing use of this software, this software is licensed to you
1632 +* under the terms of the GNU General Public License version 2, available at
1633 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
1635 +* Notwithstanding the above, under no circumstances may you combine this
1636 +* software in any way with any other Broadcom software provided under a
1637 +* license other than the GPL, without Broadcom's express prior written
1639 +*****************************************************************************/
1641 +#include <linux/platform_device.h>
1643 +#include <linux/init.h>
1644 +#include <linux/slab.h>
1645 +#include <linux/module.h>
1647 +#include "bcm2835.h"
1649 +/* module parameters (see "Module Parameters") */
1650 +/* SNDRV_CARDS: maximum number of cards supported by this module */
1651 +static int index[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = -1 };
1652 +static char *id[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = NULL };
1653 +static int enable[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = 1 };
1655 +/* HACKY global pointers needed for successive probes to work : ssp
1656 + * But compared against the changes we will have to do in VC audio_ipc code
1657 + * to export 8 audio_ipc devices as a single IPC device and then monitor all
1658 + * four devices in a thread, this gets things done quickly and should be easier
1659 + * to debug if we run into issues
1662 +static struct snd_card *g_card = NULL;
1663 +static bcm2835_chip_t *g_chip = NULL;
1665 +static int snd_bcm2835_free(bcm2835_chip_t * chip)
1671 +/* component-destructor
1672 + * (see "Management of Cards and Components")
1674 +static int snd_bcm2835_dev_free(struct snd_device *device)
1676 + return snd_bcm2835_free(device->device_data);
1679 +/* chip-specific constructor
1680 + * (see "Management of Cards and Components")
1682 +static int snd_bcm2835_create(struct snd_card *card,
1683 + struct platform_device *pdev,
1684 + bcm2835_chip_t ** rchip)
1686 + bcm2835_chip_t *chip;
1688 + static struct snd_device_ops ops = {
1689 + .dev_free = snd_bcm2835_dev_free,
1694 + chip = kzalloc(sizeof(*chip), GFP_KERNEL);
1698 + chip->card = card;
1700 + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
1702 + snd_bcm2835_free(chip);
1710 +static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
1713 + bcm2835_chip_t *chip;
1714 + struct snd_card *card;
1717 + if (dev >= MAX_SUBSTREAMS)
1720 + if (!enable[dev]) {
1726 + goto add_register_map;
1728 + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &g_card);
1732 + snd_card_set_dev(g_card, &pdev->dev);
1733 + strcpy(g_card->driver, "BRCM bcm2835 ALSA Driver");
1734 + strcpy(g_card->shortname, "bcm2835 ALSA");
1735 + sprintf(g_card->longname, "%s", g_card->shortname);
1737 + err = snd_bcm2835_create(g_card, pdev, &chip);
1739 + printk(KERN_ERR "Failed to create bcm2835 chip\n");
1740 + goto out_bcm2835_create;
1744 + err = snd_bcm2835_new_pcm(chip);
1746 + printk(KERN_ERR "Failed to create new BCM2835 pcm device\n");
1747 + goto out_bcm2835_new_pcm;
1750 + err = snd_bcm2835_new_ctl(chip);
1752 + printk(KERN_ERR "Failed to create new BCM2835 ctl\n");
1753 + goto out_bcm2835_new_ctl;
1760 + BUG_ON(!(card && chip));
1762 + chip->avail_substreams |= (1 << dev);
1763 + chip->pdev[dev] = pdev;
1766 + err = snd_card_register(card);
1769 + "Failed to register bcm2835 ALSA card \n");
1770 + goto out_card_register;
1772 + platform_set_drvdata(pdev, card);
1773 + printk(KERN_INFO "bcm2835 ALSA card created!\n");
1775 + printk(KERN_INFO "bcm2835 ALSA chip created!\n");
1776 + platform_set_drvdata(pdev, (void *)dev);
1784 +out_bcm2835_new_ctl:
1785 +out_bcm2835_new_pcm:
1786 +out_bcm2835_create:
1788 + if (snd_card_free(g_card))
1789 + printk(KERN_ERR "Failed to free Registered alsa card\n");
1792 + dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
1793 + printk(KERN_ERR "BCM2835 ALSA Probe failed !!\n");
1797 +static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
1802 + drv_data = platform_get_drvdata(pdev);
1804 + if (drv_data == (void *)g_card) {
1805 + /* This is the card device */
1806 + snd_card_free((struct snd_card *)drv_data);
1810 + idx = (uint32_t) drv_data;
1811 + if (g_card != NULL) {
1813 + /* We pass chip device numbers in audio ipc devices
1814 + * other than the one we registered our card with
1816 + idx = (uint32_t) drv_data;
1817 + BUG_ON(!idx || idx > MAX_SUBSTREAMS);
1818 + g_chip->avail_substreams &= ~(1 << idx);
1819 + /* There should be atleast one substream registered
1820 + * after we are done here, as it wil be removed when
1821 + * the *remove* is called for the card device
1823 + BUG_ON(!g_chip->avail_substreams);
1827 + platform_set_drvdata(pdev, NULL);
1833 +static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
1834 + pm_message_t state)
1839 +static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
1846 +static struct platform_driver bcm2835_alsa0_driver = {
1847 + .probe = snd_bcm2835_alsa_probe,
1848 + .remove = snd_bcm2835_alsa_remove,
1850 + .suspend = snd_bcm2835_alsa_suspend,
1851 + .resume = snd_bcm2835_alsa_resume,
1854 + .name = "bcm2835_AUD0",
1855 + .owner = THIS_MODULE,
1859 +static struct platform_driver bcm2835_alsa1_driver = {
1860 + .probe = snd_bcm2835_alsa_probe,
1861 + .remove = snd_bcm2835_alsa_remove,
1863 + .suspend = snd_bcm2835_alsa_suspend,
1864 + .resume = snd_bcm2835_alsa_resume,
1867 + .name = "bcm2835_AUD1",
1868 + .owner = THIS_MODULE,
1872 +static struct platform_driver bcm2835_alsa2_driver = {
1873 + .probe = snd_bcm2835_alsa_probe,
1874 + .remove = snd_bcm2835_alsa_remove,
1876 + .suspend = snd_bcm2835_alsa_suspend,
1877 + .resume = snd_bcm2835_alsa_resume,
1880 + .name = "bcm2835_AUD2",
1881 + .owner = THIS_MODULE,
1885 +static struct platform_driver bcm2835_alsa3_driver = {
1886 + .probe = snd_bcm2835_alsa_probe,
1887 + .remove = snd_bcm2835_alsa_remove,
1889 + .suspend = snd_bcm2835_alsa_suspend,
1890 + .resume = snd_bcm2835_alsa_resume,
1893 + .name = "bcm2835_AUD3",
1894 + .owner = THIS_MODULE,
1898 +static struct platform_driver bcm2835_alsa4_driver = {
1899 + .probe = snd_bcm2835_alsa_probe,
1900 + .remove = snd_bcm2835_alsa_remove,
1902 + .suspend = snd_bcm2835_alsa_suspend,
1903 + .resume = snd_bcm2835_alsa_resume,
1906 + .name = "bcm2835_AUD4",
1907 + .owner = THIS_MODULE,
1911 +static struct platform_driver bcm2835_alsa5_driver = {
1912 + .probe = snd_bcm2835_alsa_probe,
1913 + .remove = snd_bcm2835_alsa_remove,
1915 + .suspend = snd_bcm2835_alsa_suspend,
1916 + .resume = snd_bcm2835_alsa_resume,
1919 + .name = "bcm2835_AUD5",
1920 + .owner = THIS_MODULE,
1924 +static struct platform_driver bcm2835_alsa6_driver = {
1925 + .probe = snd_bcm2835_alsa_probe,
1926 + .remove = snd_bcm2835_alsa_remove,
1928 + .suspend = snd_bcm2835_alsa_suspend,
1929 + .resume = snd_bcm2835_alsa_resume,
1932 + .name = "bcm2835_AUD6",
1933 + .owner = THIS_MODULE,
1937 +static struct platform_driver bcm2835_alsa7_driver = {
1938 + .probe = snd_bcm2835_alsa_probe,
1939 + .remove = snd_bcm2835_alsa_remove,
1941 + .suspend = snd_bcm2835_alsa_suspend,
1942 + .resume = snd_bcm2835_alsa_resume,
1945 + .name = "bcm2835_AUD7",
1946 + .owner = THIS_MODULE,
1950 +static int bcm2835_alsa_device_init(void)
1953 + err = platform_driver_register(&bcm2835_alsa0_driver);
1955 + printk("Error registering bcm2835_alsa0_driver %d .\n", err);
1959 + err = platform_driver_register(&bcm2835_alsa1_driver);
1961 + printk("Error registering bcm2835_alsa1_driver %d .\n", err);
1962 + goto unregister_0;
1965 + err = platform_driver_register(&bcm2835_alsa2_driver);
1967 + printk("Error registering bcm2835_alsa2_driver %d .\n", err);
1968 + goto unregister_1;
1971 + err = platform_driver_register(&bcm2835_alsa3_driver);
1973 + printk("Error registering bcm2835_alsa3_driver %d .\n", err);
1974 + goto unregister_2;
1977 + err = platform_driver_register(&bcm2835_alsa4_driver);
1979 + printk("Error registering bcm2835_alsa4_driver %d .\n", err);
1980 + goto unregister_3;
1983 + err = platform_driver_register(&bcm2835_alsa5_driver);
1985 + printk("Error registering bcm2835_alsa5_driver %d .\n", err);
1986 + goto unregister_4;
1989 + err = platform_driver_register(&bcm2835_alsa6_driver);
1991 + printk("Error registering bcm2835_alsa6_driver %d .\n", err);
1992 + goto unregister_5;
1995 + err = platform_driver_register(&bcm2835_alsa7_driver);
1997 + printk("Error registering bcm2835_alsa7_driver %d .\n", err);
1998 + goto unregister_6;
2004 + platform_driver_unregister(&bcm2835_alsa6_driver);
2006 + platform_driver_unregister(&bcm2835_alsa5_driver);
2008 + platform_driver_unregister(&bcm2835_alsa4_driver);
2010 + platform_driver_unregister(&bcm2835_alsa3_driver);
2012 + platform_driver_unregister(&bcm2835_alsa2_driver);
2014 + platform_driver_unregister(&bcm2835_alsa1_driver);
2016 + platform_driver_unregister(&bcm2835_alsa0_driver);
2021 +static void bcm2835_alsa_device_exit(void)
2023 + platform_driver_unregister(&bcm2835_alsa0_driver);
2024 + platform_driver_unregister(&bcm2835_alsa1_driver);
2025 + platform_driver_unregister(&bcm2835_alsa2_driver);
2026 + platform_driver_unregister(&bcm2835_alsa3_driver);
2027 + platform_driver_unregister(&bcm2835_alsa4_driver);
2028 + platform_driver_unregister(&bcm2835_alsa5_driver);
2029 + platform_driver_unregister(&bcm2835_alsa6_driver);
2030 + platform_driver_unregister(&bcm2835_alsa7_driver);
2033 +late_initcall(bcm2835_alsa_device_init);
2034 +module_exit(bcm2835_alsa_device_exit);
2036 +MODULE_AUTHOR("Dom Cobley");
2037 +MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
2038 +MODULE_LICENSE("GPL");
2039 +MODULE_ALIAS("platform:bcm2835_alsa");
2040 diff --git a/sound/arm/bcm2835.h b/sound/arm/bcm2835.h
2041 new file mode 100755
2042 index 0000000..b966e28
2044 +++ b/sound/arm/bcm2835.h
2046 +/*****************************************************************************
2047 +* Copyright 2011 Broadcom Corporation. All rights reserved.
2049 +* Unless you and Broadcom execute a separate written software license
2050 +* agreement governing use of this software, this software is licensed to you
2051 +* under the terms of the GNU General Public License version 2, available at
2052 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2054 +* Notwithstanding the above, under no circumstances may you combine this
2055 +* software in any way with any other Broadcom software provided under a
2056 +* license other than the GPL, without Broadcom's express prior written
2058 +*****************************************************************************/
2060 +#ifndef __SOUND_ARM_BCM2835_H
2061 +#define __SOUND_ARM_BCM2835_H
2063 +#include <linux/device.h>
2064 +#include <linux/list.h>
2065 +#include <linux/interrupt.h>
2066 +#include <linux/wait.h>
2067 +#include <sound/core.h>
2068 +#include <sound/initval.h>
2069 +#include <sound/pcm.h>
2070 +#include <sound/pcm_params.h>
2071 +#include <linux/workqueue.h>
2074 +#define AUDIO_DEBUG_ENABLE
2075 +#define AUDIO_VERBOSE_DEBUG_ENABLE
2080 +#ifdef AUDIO_DEBUG_ENABLE
2081 +#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
2083 +#define audio_debug(fmt, arg...) \
2084 + printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
2086 +#define audio_info(fmt, arg...) \
2087 + printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
2091 +#define audio_debug(fmt, arg...)
2093 +#define audio_info(fmt, arg...)
2095 +#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
2099 +#define audio_debug(fmt, arg...)
2101 +#define audio_info(fmt, arg...)
2103 +#endif /* AUDIO_DEBUG_ENABLE */
2105 +#define audio_error(fmt, arg...) \
2106 + printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
2108 +#define audio_warning(fmt, arg...) \
2109 + printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
2111 +#define audio_alert(fmt, arg...) \
2112 + printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
2114 +#define MAX_SUBSTREAMS (8)
2115 +#define AVAIL_SUBSTREAMS_MASK (0xff)
2121 +/* macros for alsa2chip and chip2alsa, instead of functions */
2123 +#define alsa2chip(vol) (uint)(-((vol << 8) / 100)) /* convert alsa to chip volume (defined as macro rather than function call) */
2124 +#define chip2alsa(vol) -((vol * 100) >> 8) /* convert chip to alsa volume */
2126 +/* Some constants for values .. */
2128 + AUDIO_DEST_AUTO = 0,
2129 + AUDIO_DEST_HEADPHONES = 1,
2130 + AUDIO_DEST_HDMI = 2,
2132 +} SND_BCM2835_ROUTE_T;
2135 + PCM_PLAYBACK_VOLUME,
2136 + PCM_PLAYBACK_MUTE,
2137 + PCM_PLAYBACK_DEVICE,
2138 +} SND_BCM2835_CTRL_T;
2140 +/* definition of the chip-specific record */
2141 +typedef struct bcm2835_chip {
2142 + struct snd_card *card;
2143 + struct snd_pcm *pcm;
2144 + /* Bitmat for valid reg_base and irq numbers */
2145 + uint32_t avail_substreams;
2146 + struct platform_device *pdev[MAX_SUBSTREAMS];
2147 + struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
2150 + int old_volume; /* stores the volume value whist muted */
2155 +typedef struct bcm2835_alsa_stream {
2156 + bcm2835_chip_t *chip;
2157 + struct snd_pcm_substream *substream;
2159 + struct semaphore buffers_update_sem;
2160 + struct semaphore control_sem;
2162 + volatile uint32_t control;
2163 + volatile uint32_t status;
2170 + unsigned int buffer_size;
2171 + unsigned int period_size;
2173 + uint32_t enable_fifo_irq;
2174 + irq_handler_t fifo_irq_handler;
2176 + atomic_t retrieved;
2177 + struct opaque_AUDIO_INSTANCE_T *instance;
2178 + struct workqueue_struct *my_wq;
2180 +} bcm2835_alsa_stream_t;
2182 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
2183 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
2185 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
2186 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
2187 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
2188 + uint32_t channels, uint32_t samplerate,
2190 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream);
2191 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream);
2192 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream);
2193 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip);
2194 +int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
2196 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream);
2197 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream);
2198 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream);
2200 +#endif /* __SOUND_ARM_BCM2835_H */
2201 diff --git a/sound/arm/vc_vchi_audioserv_defs.h b/sound/arm/vc_vchi_audioserv_defs.h
2202 new file mode 100644
2203 index 0000000..af3e6eb
2205 +++ b/sound/arm/vc_vchi_audioserv_defs.h
2207 +/*****************************************************************************
2208 +* Copyright 2011 Broadcom Corporation. All rights reserved.
2210 +* Unless you and Broadcom execute a separate written software license
2211 +* agreement governing use of this software, this software is licensed to you
2212 +* under the terms of the GNU General Public License version 2, available at
2213 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2215 +* Notwithstanding the above, under no circumstances may you combine this
2216 +* software in any way with any other Broadcom software provided under a
2217 +* license other than the GPL, without Broadcom's express prior written
2219 +*****************************************************************************/
2221 +#ifndef _VC_AUDIO_DEFS_H_
2222 +#define _VC_AUDIO_DEFS_H_
2224 +#define VC_AUDIOSERV_MIN_VER 1
2225 +#define VC_AUDIOSERV_VER 2
2227 +// FourCC code used for VCHI connection
2228 +#define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
2230 +// Maximum message length
2231 +#define VC_AUDIO_MAX_MSG_LEN (sizeof( VC_AUDIO_MSG_T ))
2233 +// List of screens that are currently supported
2234 +// All message types supported for HOST->VC direction
2236 + VC_AUDIO_MSG_TYPE_RESULT, // Generic result
2237 + VC_AUDIO_MSG_TYPE_COMPLETE, // Generic result
2238 + VC_AUDIO_MSG_TYPE_CONFIG, // Configure audio
2239 + VC_AUDIO_MSG_TYPE_CONTROL, // Configure audio
2240 + VC_AUDIO_MSG_TYPE_OPEN, // Configure audio
2241 + VC_AUDIO_MSG_TYPE_CLOSE, // Configure audio
2242 + VC_AUDIO_MSG_TYPE_START, // Configure audio
2243 + VC_AUDIO_MSG_TYPE_STOP, // Configure audio
2244 + VC_AUDIO_MSG_TYPE_WRITE, // Configure audio
2245 + VC_AUDIO_MSG_TYPE_MAX
2246 +} VC_AUDIO_MSG_TYPE;
2248 +// configure the audio
2250 + uint32_t channels;
2251 + uint32_t samplerate;
2254 +} VC_AUDIO_CONFIG_T;
2260 +} VC_AUDIO_CONTROL_T;
2272 +} VC_AUDIO_CLOSE_T;
2277 +} VC_AUDIO_START_T;
2280 + uint32_t draining;
2284 +// configure the write audio samples
2286 + uint32_t count; // in bytes
2290 + uint16_t max_packet;
2291 +} VC_AUDIO_WRITE_T;
2293 +// Generic result for a request (VC->HOST)
2295 + int32_t success; // Success value
2297 +} VC_AUDIO_RESULT_T;
2299 +// Generic result for a request (VC->HOST)
2301 + int32_t count; // Success value
2304 +} VC_AUDIO_COMPLETE_T;
2306 +// Message header for all messages in HOST->VC direction
2308 + int32_t type; // Message type (VC_AUDIO_MSG_TYPE)
2310 + VC_AUDIO_CONFIG_T config;
2311 + VC_AUDIO_CONTROL_T control;
2312 + VC_AUDIO_OPEN_T open;
2313 + VC_AUDIO_CLOSE_T close;
2314 + VC_AUDIO_START_T start;
2315 + VC_AUDIO_STOP_T stop;
2316 + VC_AUDIO_WRITE_T write;
2317 + VC_AUDIO_RESULT_T result;
2318 + VC_AUDIO_COMPLETE_T complete;
2322 +#endif // _VC_AUDIO_DEFS_H_