brcm2708: remove 3.14 support
[openwrt/svn-archive/archive.git] / target / linux / brcm2708 / patches-3.14 / 0009-bcm2708-alsa-sound-driver.patch
diff --git a/target/linux/brcm2708/patches-3.14/0009-bcm2708-alsa-sound-driver.patch b/target/linux/brcm2708/patches-3.14/0009-bcm2708-alsa-sound-driver.patch
deleted file mode 100644 (file)
index 8f1af0c..0000000
+++ /dev/null
@@ -1,2335 +0,0 @@
-From a7e31a16c66c5ecd1665250cfee9f3cfb64cfa67 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Mon, 26 Mar 2012 22:15:50 +0100
-Subject: [PATCH 09/54] bcm2708: alsa sound driver
-
-    Signed-off-by: popcornmix <popcornmix@gmail.com>
----
- arch/arm/configs/bcmrpi_cutdown_defconfig |  20 +
- arch/arm/configs/bcmrpi_defconfig         |  20 +
- arch/arm/mach-bcm2708/bcm2708.c           |  54 ++
- sound/arm/Kconfig                         |   7 +
- sound/arm/Makefile                        |   5 +
- sound/arm/bcm2835-ctl.c                   | 200 +++++++
- sound/arm/bcm2835-pcm.c                   | 409 +++++++++++++++
- sound/arm/bcm2835-vchiq.c                 | 844 ++++++++++++++++++++++++++++++
- sound/arm/bcm2835.c                       | 413 +++++++++++++++
- sound/arm/bcm2835.h                       | 155 ++++++
- sound/arm/vc_vchi_audioserv_defs.h        | 116 ++++
- 11 files changed, 2243 insertions(+)
- create mode 100755 sound/arm/bcm2835-ctl.c
- create mode 100755 sound/arm/bcm2835-pcm.c
- create mode 100755 sound/arm/bcm2835-vchiq.c
- create mode 100755 sound/arm/bcm2835.c
- create mode 100755 sound/arm/bcm2835.h
- create mode 100644 sound/arm/vc_vchi_audioserv_defs.h
-
---- a/arch/arm/configs/bcmrpi_cutdown_defconfig
-+++ b/arch/arm/configs/bcmrpi_cutdown_defconfig
-@@ -208,6 +208,26 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
- CONFIG_LOGO=y
- # CONFIG_LOGO_LINUX_MONO is not set
- # CONFIG_LOGO_LINUX_VGA16 is not set
-+CONFIG_SOUND=y
-+CONFIG_SND=m
-+CONFIG_SND_SEQUENCER=m
-+CONFIG_SND_SEQ_DUMMY=m
-+CONFIG_SND_MIXER_OSS=m
-+CONFIG_SND_PCM_OSS=m
-+CONFIG_SND_SEQUENCER_OSS=y
-+CONFIG_SND_HRTIMER=m
-+CONFIG_SND_DUMMY=m
-+CONFIG_SND_ALOOP=m
-+CONFIG_SND_VIRMIDI=m
-+CONFIG_SND_MTPAV=m
-+CONFIG_SND_SERIAL_U16550=m
-+CONFIG_SND_MPU401=m
-+CONFIG_SND_BCM2835=m
-+CONFIG_SND_USB_AUDIO=m
-+CONFIG_SND_USB_UA101=m
-+CONFIG_SND_USB_CAIAQ=m
-+CONFIG_SND_USB_6FIRE=m
-+CONFIG_SOUND_PRIME=m
- CONFIG_HID_PID=y
- CONFIG_USB_HIDDEV=y
- CONFIG_HID_A4TECH=m
---- a/arch/arm/configs/bcmrpi_defconfig
-+++ b/arch/arm/configs/bcmrpi_defconfig
-@@ -225,6 +225,26 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
- CONFIG_LOGO=y
- # CONFIG_LOGO_LINUX_MONO is not set
- # CONFIG_LOGO_LINUX_VGA16 is not set
-+CONFIG_SOUND=y
-+CONFIG_SND=m
-+CONFIG_SND_SEQUENCER=m
-+CONFIG_SND_SEQ_DUMMY=m
-+CONFIG_SND_MIXER_OSS=m
-+CONFIG_SND_PCM_OSS=m
-+CONFIG_SND_SEQUENCER_OSS=y
-+CONFIG_SND_HRTIMER=m
-+CONFIG_SND_DUMMY=m
-+CONFIG_SND_ALOOP=m
-+CONFIG_SND_VIRMIDI=m
-+CONFIG_SND_MTPAV=m
-+CONFIG_SND_SERIAL_U16550=m
-+CONFIG_SND_MPU401=m
-+CONFIG_SND_BCM2835=m
-+CONFIG_SND_USB_AUDIO=m
-+CONFIG_SND_USB_UA101=m
-+CONFIG_SND_USB_CAIAQ=m
-+CONFIG_SND_USB_6FIRE=m
-+CONFIG_SOUND_PRIME=m
- CONFIG_HID_PID=y
- CONFIG_USB_HIDDEV=y
- CONFIG_HID_A4TECH=m
---- a/arch/arm/mach-bcm2708/bcm2708.c
-+++ b/arch/arm/mach-bcm2708/bcm2708.c
-@@ -431,6 +431,58 @@ struct platform_device bcm2708_powerman_
-               .coherent_dma_mask = 0xffffffffUL},
- };
-+
-+static struct platform_device bcm2708_alsa_devices[] = {
-+      [0] = {
-+             .name = "bcm2835_AUD0",
-+             .id = 0,         /* first audio device */
-+             .resource = 0,
-+             .num_resources = 0,
-+             },
-+      [1] = {
-+             .name = "bcm2835_AUD1",
-+             .id = 1,         /* second audio device */
-+             .resource = 0,
-+             .num_resources = 0,
-+             },
-+      [2] = {
-+             .name = "bcm2835_AUD2",
-+             .id = 2,         /* third audio device */
-+             .resource = 0,
-+             .num_resources = 0,
-+             },
-+      [3] = {
-+             .name = "bcm2835_AUD3",
-+             .id = 3,         /* forth audio device */
-+             .resource = 0,
-+             .num_resources = 0,
-+             },
-+      [4] = {
-+             .name = "bcm2835_AUD4",
-+             .id = 4,         /* fifth audio device */
-+             .resource = 0,
-+             .num_resources = 0,
-+             },
-+      [5] = {
-+             .name = "bcm2835_AUD5",
-+             .id = 5,         /* sixth audio device */
-+             .resource = 0,
-+             .num_resources = 0,
-+             },
-+      [6] = {
-+             .name = "bcm2835_AUD6",
-+             .id = 6,         /* seventh audio device */
-+             .resource = 0,
-+             .num_resources = 0,
-+             },
-+      [7] = {
-+             .name = "bcm2835_AUD7",
-+             .id = 7,         /* eighth audio device */
-+             .resource = 0,
-+             .num_resources = 0,
-+             },
-+};
-+
- int __init bcm_register_device(struct platform_device *pdev)
- {
-       int ret;
-@@ -539,6 +591,8 @@ void __init bcm2708_init(void)
-       bcm_register_device(&bcm2708_emmc_device);
- #endif
-       bcm2708_init_led();
-+      for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
-+              bcm_register_device(&bcm2708_alsa_devices[i]);
-       for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
-               struct amba_device *d = amba_devs[i];
---- a/sound/arm/Kconfig
-+++ b/sound/arm/Kconfig
-@@ -39,5 +39,12 @@ config SND_PXA2XX_AC97
-         Say Y or M if you want to support any AC97 codec attached to
-         the PXA2xx AC97 interface.
-+config SND_BCM2835
-+      tristate "BCM2835 ALSA driver"
-+      depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND
-+      select SND_PCM
-+      help
-+        Say Y or M if you want to support BCM2835 Alsa pcm card driver
-+
- endif # SND_ARM
---- a/sound/arm/Makefile
-+++ b/sound/arm/Makefile
-@@ -14,3 +14,8 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_A
- obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
- snd-pxa2xx-ac97-objs          := pxa2xx-ac97.o
-+
-+obj-$(CONFIG_SND_BCM2835)     += snd-bcm2835.o
-+snd-bcm2835-objs              := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
-+
-+ccflags-y += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
---- /dev/null
-+++ b/sound/arm/bcm2835-ctl.c
-@@ -0,0 +1,200 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation.  All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/platform_device.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/jiffies.h>
-+#include <linux/slab.h>
-+#include <linux/time.h>
-+#include <linux/wait.h>
-+#include <linux/delay.h>
-+#include <linux/moduleparam.h>
-+#include <linux/sched.h>
-+
-+#include <sound/core.h>
-+#include <sound/control.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/rawmidi.h>
-+#include <sound/initval.h>
-+#include <sound/tlv.h>
-+
-+#include "bcm2835.h"
-+
-+/* volume maximum and minimum in terms of 0.01dB */
-+#define CTRL_VOL_MAX 400
-+#define CTRL_VOL_MIN -10239 /* originally -10240 */
-+
-+
-+static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
-+                              struct snd_ctl_elem_info *uinfo)
-+{
-+      audio_info(" ... IN\n");
-+      if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
-+              uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-+              uinfo->count = 1;
-+              uinfo->value.integer.min = CTRL_VOL_MIN;
-+              uinfo->value.integer.max = CTRL_VOL_MAX;      /* 2303 */
-+      } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
-+              uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-+              uinfo->count = 1;
-+              uinfo->value.integer.min = 0;
-+              uinfo->value.integer.max = 1;
-+      } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
-+              uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-+              uinfo->count = 1;
-+              uinfo->value.integer.min = 0;
-+              uinfo->value.integer.max = AUDIO_DEST_MAX-1;
-+      }
-+      audio_info(" ... OUT\n");
-+      return 0;
-+}
-+
-+/* toggles mute on or off depending on the value of nmute, and returns
-+ * 1 if the mute value was changed, otherwise 0
-+ */
-+static int toggle_mute(struct bcm2835_chip *chip, int nmute)
-+{
-+      /* if settings are ok, just return 0 */
-+      if(chip->mute == nmute)
-+              return 0;
-+
-+      /* if the sound is muted then we need to unmute */
-+      if(chip->mute == CTRL_VOL_MUTE)
-+      {
-+              chip->volume = chip->old_volume; /* copy the old volume back */
-+              audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
-+      }
-+      else /* otherwise we mute */
-+      {
-+              chip->old_volume = chip->volume;
-+              chip->volume = 26214; /* set volume to minimum level AKA mute */
-+              audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
-+      }
-+
-+      chip->mute = nmute;
-+      return 1;
-+}
-+
-+static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
-+                             struct snd_ctl_elem_value *ucontrol)
-+{
-+      struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-+
-+      BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
-+
-+      if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
-+              ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
-+      else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
-+              ucontrol->value.integer.value[0] = chip->mute;
-+      else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
-+              ucontrol->value.integer.value[0] = chip->dest;
-+
-+      return 0;
-+}
-+
-+static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
-+                             struct snd_ctl_elem_value *ucontrol)
-+{
-+      struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
-+      int changed = 0;
-+
-+      if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
-+              audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
-+              if (chip->mute == CTRL_VOL_MUTE) {
-+                      /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
-+                      return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
-+              }
-+              if (changed
-+                  || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
-+
-+                      chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
-+                      changed = 1;
-+              }
-+
-+      } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
-+              /* Now implemented */
-+              audio_info(" Mute attempted\n");
-+              changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
-+
-+      } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
-+              if (ucontrol->value.integer.value[0] != chip->dest) {
-+                      chip->dest = ucontrol->value.integer.value[0];
-+                      changed = 1;
-+              }
-+      }
-+
-+      if (changed) {
-+              if (bcm2835_audio_set_ctls(chip))
-+                      printk(KERN_ERR "Failed to set ALSA controls..\n");
-+      }
-+
-+      return changed;
-+}
-+
-+static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
-+
-+static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
-+      {
-+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+       .name = "PCM Playback Volume",
-+       .index = 0,
-+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+       .private_value = PCM_PLAYBACK_VOLUME,
-+       .info = snd_bcm2835_ctl_info,
-+       .get = snd_bcm2835_ctl_get,
-+       .put = snd_bcm2835_ctl_put,
-+       .count = 1,
-+       .tlv = {.p = snd_bcm2835_db_scale}
-+      },
-+      {
-+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+       .name = "PCM Playback Switch",
-+       .index = 0,
-+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+       .private_value = PCM_PLAYBACK_MUTE,
-+       .info = snd_bcm2835_ctl_info,
-+       .get = snd_bcm2835_ctl_get,
-+       .put = snd_bcm2835_ctl_put,
-+       .count = 1,
-+       },
-+      {
-+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+       .name = "PCM Playback Route",
-+       .index = 0,
-+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+       .private_value = PCM_PLAYBACK_DEVICE,
-+       .info = snd_bcm2835_ctl_info,
-+       .get = snd_bcm2835_ctl_get,
-+       .put = snd_bcm2835_ctl_put,
-+       .count = 1,
-+      },
-+};
-+
-+int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
-+{
-+      int err;
-+      unsigned int idx;
-+
-+      strcpy(chip->card->mixername, "Broadcom Mixer");
-+      for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
-+              err =
-+                  snd_ctl_add(chip->card,
-+                              snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
-+              if (err < 0)
-+                      return err;
-+      }
-+      return 0;
-+}
---- /dev/null
-+++ b/sound/arm/bcm2835-pcm.c
-@@ -0,0 +1,409 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation.  All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/interrupt.h>
-+#include <linux/slab.h>
-+
-+#include "bcm2835.h"
-+
-+/* hardware definition */
-+static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
-+      .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER),
-+      .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
-+      .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-+      .rate_min = 8000,
-+      .rate_max = 48000,
-+      .channels_min = 1,
-+      .channels_max = 2,
-+      .buffer_bytes_max = 128 * 1024,
-+      .period_bytes_min =   1 * 1024,
-+      .period_bytes_max = 128 * 1024,
-+      .periods_min = 1,
-+      .periods_max = 128,
-+};
-+
-+static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
-+{
-+      audio_info("Freeing up alsa stream here ..\n");
-+      if (runtime->private_data)
-+              kfree(runtime->private_data);
-+      runtime->private_data = NULL;
-+}
-+
-+static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
-+{
-+      bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
-+      uint32_t consumed = 0;
-+      int new_period = 0;
-+
-+      audio_info(" .. IN\n");
-+
-+      audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
-+                 alsa_stream ? alsa_stream->substream : 0);
-+
-+      if (alsa_stream->open)
-+              consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
-+
-+      /* We get called only if playback was triggered, So, the number of buffers we retrieve in
-+       * each iteration are the buffers that have been played out already
-+       */
-+
-+      if (alsa_stream->period_size) {
-+              if ((alsa_stream->pos / alsa_stream->period_size) !=
-+                  ((alsa_stream->pos + consumed) / alsa_stream->period_size))
-+                      new_period = 1;
-+      }
-+      audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
-+                    alsa_stream->pos,
-+                    consumed,
-+                    alsa_stream->buffer_size,
-+                        (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods),
-+                        frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
-+                        new_period);
-+      if (alsa_stream->buffer_size) {
-+              alsa_stream->pos += consumed &~ (1<<30);
-+              alsa_stream->pos %= alsa_stream->buffer_size;
-+      }
-+
-+      if (alsa_stream->substream) {
-+              if (new_period)
-+                      snd_pcm_period_elapsed(alsa_stream->substream);
-+      } else {
-+              audio_warning(" unexpected NULL substream\n");
-+      }
-+      audio_info(" .. OUT\n");
-+
-+      return IRQ_HANDLED;
-+}
-+
-+/* open callback */
-+static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
-+{
-+      bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
-+      struct snd_pcm_runtime *runtime = substream->runtime;
-+      bcm2835_alsa_stream_t *alsa_stream;
-+      int idx;
-+      int err;
-+
-+      audio_info(" .. IN (%d)\n", substream->number);
-+
-+      audio_info("Alsa open (%d)\n", substream->number);
-+      idx = substream->number;
-+
-+      if (idx > MAX_SUBSTREAMS) {
-+              audio_error
-+                  ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
-+                   idx, MAX_SUBSTREAMS);
-+              err = -ENODEV;
-+              goto out;
-+      }
-+
-+      /* Check if we are ready */
-+      if (!(chip->avail_substreams & (1 << idx))) {
-+              /* We are not ready yet */
-+              audio_error("substream(%d) device is not ready yet\n", idx);
-+              err = -EAGAIN;
-+              goto out;
-+      }
-+
-+      alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
-+      if (alsa_stream == NULL) {
-+              return -ENOMEM;
-+      }
-+
-+      /* Initialise alsa_stream */
-+      alsa_stream->chip = chip;
-+      alsa_stream->substream = substream;
-+      alsa_stream->idx = idx;
-+
-+      sema_init(&alsa_stream->buffers_update_sem, 0);
-+      sema_init(&alsa_stream->control_sem, 0);
-+      spin_lock_init(&alsa_stream->lock);
-+
-+      /* Enabled in start trigger, called on each "fifo irq" after that */
-+      alsa_stream->enable_fifo_irq = 0;
-+      alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;
-+
-+      err = bcm2835_audio_open(alsa_stream);
-+      if (err != 0) {
-+              kfree(alsa_stream);
-+              return err;
-+      }
-+      runtime->private_data = alsa_stream;
-+      runtime->private_free = snd_bcm2835_playback_free;
-+      runtime->hw = snd_bcm2835_playback_hw;
-+      /* minimum 16 bytes alignment (for vchiq bulk transfers) */
-+      snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-+                                 16);
-+
-+      chip->alsa_stream[idx] = alsa_stream;
-+
-+      alsa_stream->open = 1;
-+      alsa_stream->draining = 1;
-+
-+out:
-+      audio_info(" .. OUT =%d\n", err);
-+
-+      return err;
-+}
-+
-+/* close callback */
-+static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
-+{
-+      /* the hardware-specific codes will be here */
-+
-+      struct snd_pcm_runtime *runtime = substream->runtime;
-+      bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+
-+      audio_info(" .. IN\n");
-+      audio_info("Alsa close\n");
-+
-+      /*
-+       * Call stop if it's still running. This happens when app
-+       * is force killed and we don't get a stop trigger.
-+       */
-+      if (alsa_stream->running) {
-+              int err;
-+              err = bcm2835_audio_stop(alsa_stream);
-+              alsa_stream->running = 0;
-+              if (err != 0)
-+                      audio_error(" Failed to STOP alsa device\n");
-+      }
-+
-+      alsa_stream->period_size = 0;
-+      alsa_stream->buffer_size = 0;
-+
-+      if (alsa_stream->open) {
-+              alsa_stream->open = 0;
-+              bcm2835_audio_close(alsa_stream);
-+      }
-+      if (alsa_stream->chip)
-+              alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
-+      /*
-+       * Do not free up alsa_stream here, it will be freed up by
-+       * runtime->private_free callback we registered in *_open above
-+       */
-+
-+      audio_info(" .. OUT\n");
-+
-+      return 0;
-+}
-+
-+/* hw_params callback */
-+static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
-+                                   struct snd_pcm_hw_params *params)
-+{
-+      int err;
-+      struct snd_pcm_runtime *runtime = substream->runtime;
-+      bcm2835_alsa_stream_t *alsa_stream =
-+          (bcm2835_alsa_stream_t *) runtime->private_data;
-+
-+      audio_info(" .. IN\n");
-+
-+      err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-+      if (err < 0) {
-+              audio_error
-+                  (" pcm_lib_malloc failed to allocated pages for buffers\n");
-+              return err;
-+      }
-+
-+      err = bcm2835_audio_set_params(alsa_stream, params_channels(params),
-+                                     params_rate(params),
-+                                     snd_pcm_format_width(params_format
-+                                                          (params)));
-+      if (err < 0) {
-+              audio_error(" error setting hw params\n");
-+      }
-+
-+      bcm2835_audio_setup(alsa_stream);
-+
-+      /* in preparation of the stream, set the controls (volume level) of the stream */
-+      bcm2835_audio_set_ctls(alsa_stream->chip);
-+
-+      audio_info(" .. OUT\n");
-+
-+      return err;
-+}
-+
-+/* hw_free callback */
-+static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
-+{
-+      audio_info(" .. IN\n");
-+      return snd_pcm_lib_free_pages(substream);
-+}
-+
-+/* prepare callback */
-+static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
-+{
-+      struct snd_pcm_runtime *runtime = substream->runtime;
-+      bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+
-+      audio_info(" .. IN\n");
-+
-+      alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
-+      alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
-+      alsa_stream->pos = 0;
-+
-+      audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
-+                    alsa_stream->buffer_size, alsa_stream->period_size,
-+                    alsa_stream->pos, runtime->frame_bits);
-+
-+      audio_info(" .. OUT\n");
-+      return 0;
-+}
-+
-+/* trigger callback */
-+static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-+{
-+      struct snd_pcm_runtime *runtime = substream->runtime;
-+      bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+      int err = 0;
-+
-+      audio_info(" .. IN\n");
-+
-+      switch (cmd) {
-+      case SNDRV_PCM_TRIGGER_START:
-+              audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
-+                            alsa_stream->running);
-+              if (!alsa_stream->running) {
-+                      err = bcm2835_audio_start(alsa_stream);
-+                      if (err == 0) {
-+                              alsa_stream->running = 1;
-+                              alsa_stream->draining = 1;
-+                      } else {
-+                              audio_error(" Failed to START alsa device (%d)\n", err);
-+                      }
-+              }
-+              break;
-+      case SNDRV_PCM_TRIGGER_STOP:
-+              audio_debug
-+                  ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
-+                           alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
-+              if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
-+                      audio_info("DRAINING\n");
-+                      alsa_stream->draining = 1;
-+              } else {
-+                      audio_info("DROPPING\n");
-+                      alsa_stream->draining = 0;
-+              }
-+              if (alsa_stream->running) {
-+                      err = bcm2835_audio_stop(alsa_stream);
-+                      if (err != 0)
-+                              audio_error(" Failed to STOP alsa device (%d)\n", err);
-+                      alsa_stream->running = 0;
-+              }
-+              break;
-+      default:
-+              err = -EINVAL;
-+      }
-+
-+      audio_info(" .. OUT\n");
-+      return err;
-+}
-+
-+/* pointer callback */
-+static snd_pcm_uframes_t
-+snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
-+{
-+      struct snd_pcm_runtime *runtime = substream->runtime;
-+      bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+
-+      audio_info(" .. IN\n");
-+
-+      audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
-+                    frames_to_bytes(runtime, runtime->status->hw_ptr),
-+                    frames_to_bytes(runtime, runtime->control->appl_ptr),
-+                    alsa_stream->pos);
-+
-+      audio_info(" .. OUT\n");
-+      return bytes_to_frames(runtime, alsa_stream->pos);
-+}
-+
-+static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream,
-+                              int channel, snd_pcm_uframes_t pos, void *src,
-+                              snd_pcm_uframes_t count)
-+{
-+      int ret;
-+      struct snd_pcm_runtime *runtime = substream->runtime;
-+      bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-+
-+      audio_info(" .. IN\n");
-+      audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n",
-+                    frames_to_bytes(runtime, count), frames_to_bytes(runtime,
-+                                                                     runtime->
-+                                                                     status->
-+                                                                     hw_ptr),
-+                    frames_to_bytes(runtime, runtime->control->appl_ptr),
-+                    alsa_stream->pos);
-+      ret =
-+          bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count),
-+                              src);
-+      audio_info(" .. OUT\n");
-+      return ret;
-+}
-+
-+static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
-+                                   unsigned int cmd, void *arg)
-+{
-+      int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
-+      audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
-+                  cmd, arg, arg ? *(unsigned *)arg : 0, ret);
-+      return ret;
-+}
-+
-+/* operators */
-+static struct snd_pcm_ops snd_bcm2835_playback_ops = {
-+      .open = snd_bcm2835_playback_open,
-+      .close = snd_bcm2835_playback_close,
-+      .ioctl = snd_bcm2835_pcm_lib_ioctl,
-+      .hw_params = snd_bcm2835_pcm_hw_params,
-+      .hw_free = snd_bcm2835_pcm_hw_free,
-+      .prepare = snd_bcm2835_pcm_prepare,
-+      .trigger = snd_bcm2835_pcm_trigger,
-+      .pointer = snd_bcm2835_pcm_pointer,
-+      .copy = snd_bcm2835_pcm_copy,
-+};
-+
-+/* create a pcm device */
-+int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
-+{
-+      struct snd_pcm *pcm;
-+      int err;
-+
-+      audio_info(" .. IN\n");
-+      err =
-+          snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
-+      if (err < 0)
-+              return err;
-+      pcm->private_data = chip;
-+      strcpy(pcm->name, "bcm2835 ALSA");
-+      chip->pcm = pcm;
-+      chip->dest = AUDIO_DEST_AUTO;
-+      chip->volume = alsa2chip(0);
-+      chip->mute = CTRL_VOL_UNMUTE;   /*disable mute on startup */
-+      /* set operators */
-+      snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-+                      &snd_bcm2835_playback_ops);
-+
-+      /* pre-allocation of buffers */
-+      /* NOTE: this may fail */
-+      snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-+                                            snd_dma_continuous_data
-+                                            (GFP_KERNEL), 64 * 1024,
-+                                            64 * 1024);
-+
-+      audio_info(" .. OUT\n");
-+
-+      return 0;
-+}
---- /dev/null
-+++ b/sound/arm/bcm2835-vchiq.c
-@@ -0,0 +1,844 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation.  All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/device.h>
-+#include <sound/core.h>
-+#include <sound/initval.h>
-+#include <sound/pcm.h>
-+#include <linux/io.h>
-+#include <linux/interrupt.h>
-+#include <linux/fs.h>
-+#include <linux/file.h>
-+#include <linux/mm.h>
-+#include <linux/syscalls.h>
-+#include <asm/uaccess.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/atomic.h>
-+#include <linux/module.h>
-+
-+#include "bcm2835.h"
-+
-+/* ---- Include Files -------------------------------------------------------- */
-+
-+#include "interface/vchi/vchi.h"
-+#include "vc_vchi_audioserv_defs.h"
-+
-+/* ---- Private Constants and Types ------------------------------------------ */
-+
-+/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
-+#ifdef AUDIO_DEBUG_ENABLE
-+      #define LOG_ERR( fmt, arg... )   pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+      #define LOG_WARN( fmt, arg... )  pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+      #define LOG_INFO( fmt, arg... )  pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+      #define LOG_DBG( fmt, arg... )   pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+#else
-+      #define LOG_ERR( fmt, arg... )   pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
-+      #define LOG_WARN( fmt, arg... )
-+      #define LOG_INFO( fmt, arg... )
-+      #define LOG_DBG( fmt, arg... )
-+#endif
-+
-+typedef struct opaque_AUDIO_INSTANCE_T {
-+      uint32_t num_connections;
-+      VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
-+      struct semaphore msg_avail_event;
-+      struct mutex vchi_mutex;
-+      bcm2835_alsa_stream_t *alsa_stream;
-+      int32_t result;
-+      short peer_version;
-+} AUDIO_INSTANCE_T;
-+
-+bool force_bulk = false;
-+
-+/* ---- Private Variables ---------------------------------------------------- */
-+
-+/* ---- Private Function Prototypes ------------------------------------------ */
-+
-+/* ---- Private Functions ---------------------------------------------------- */
-+
-+static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
-+static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
-+
-+typedef struct {
-+      struct work_struct my_work;
-+      bcm2835_alsa_stream_t *alsa_stream;
-+      int x;
-+} my_work_t;
-+
-+static void my_wq_function(struct work_struct *work)
-+{
-+      my_work_t *w = (my_work_t *) work;
-+      int ret = -9;
-+      LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->x);
-+      switch (w->x) {
-+      case 1:
-+              ret = bcm2835_audio_start_worker(w->alsa_stream);
-+              break;
-+      case 2:
-+              ret = bcm2835_audio_stop_worker(w->alsa_stream);
-+              break;
-+      default:
-+              LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->x);
-+              break;
-+      }
-+      kfree((void *)work);
-+      LOG_DBG(" .. OUT %d\n", ret);
-+}
-+
-+int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      int ret = -1;
-+      LOG_DBG(" .. IN\n");
-+      if (alsa_stream->my_wq) {
-+              my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
-+              /*--- Queue some work (item 1) ---*/
-+              if (work) {
-+                      INIT_WORK((struct work_struct *)work, my_wq_function);
-+                      work->alsa_stream = alsa_stream;
-+                      work->x = 1;
-+                      if (queue_work
-+                          (alsa_stream->my_wq, (struct work_struct *)work))
-+                              ret = 0;
-+              } else
-+                      LOG_ERR(" .. Error: NULL work kmalloc\n");
-+      }
-+      LOG_DBG(" .. OUT %d\n", ret);
-+      return ret;
-+}
-+
-+int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      int ret = -1;
-+      LOG_DBG(" .. IN\n");
-+      if (alsa_stream->my_wq) {
-+              my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
-+               /*--- Queue some work (item 1) ---*/
-+              if (work) {
-+                      INIT_WORK((struct work_struct *)work, my_wq_function);
-+                      work->alsa_stream = alsa_stream;
-+                      work->x = 2;
-+                      if (queue_work
-+                          (alsa_stream->my_wq, (struct work_struct *)work))
-+                              ret = 0;
-+              } else
-+                      LOG_ERR(" .. Error: NULL work kmalloc\n");
-+      }
-+      LOG_DBG(" .. OUT %d\n", ret);
-+      return ret;
-+}
-+
-+void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
-+      return;
-+}
-+
-+void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      if (alsa_stream->my_wq) {
-+              flush_workqueue(alsa_stream->my_wq);
-+              destroy_workqueue(alsa_stream->my_wq);
-+              alsa_stream->my_wq = NULL;
-+      }
-+      return;
-+}
-+
-+static void audio_vchi_callback(void *param,
-+                              const VCHI_CALLBACK_REASON_T reason,
-+                              void *msg_handle)
-+{
-+      AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
-+      int32_t status;
-+      int32_t msg_len;
-+      VC_AUDIO_MSG_T m;
-+      bcm2835_alsa_stream_t *alsa_stream = 0;
-+      LOG_DBG(" .. IN instance=%p, param=%p, reason=%d, handle=%p\n",
-+              instance, param, reason, msg_handle);
-+
-+      if (!instance || reason != VCHI_CALLBACK_MSG_AVAILABLE) {
-+              return;
-+      }
-+      alsa_stream = instance->alsa_stream;
-+      status = vchi_msg_dequeue(instance->vchi_handle[0],
-+                                &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
-+      if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
-+              LOG_DBG
-+                  (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
-+                   instance, m.u.result.success);
-+              instance->result = m.u.result.success;
-+              up(&instance->msg_avail_event);
-+      } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
-+              irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
-+              LOG_DBG
-+                  (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
-+                   instance, m.u.complete.count);
-+              if (alsa_stream && callback) {
-+                      atomic_add(m.u.complete.count, &alsa_stream->retrieved);
-+                      callback(0, alsa_stream);
-+              } else {
-+                      LOG_DBG(" .. unexpected alsa_stream=%p, callback=%p\n",
-+                              alsa_stream, callback);
-+              }
-+      } else {
-+              LOG_DBG(" .. unexpected m.type=%d\n", m.type);
-+      }
-+      LOG_DBG(" .. OUT\n");
-+}
-+
-+static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
-+                                          VCHI_CONNECTION_T **
-+                                          vchi_connections,
-+                                          uint32_t num_connections)
-+{
-+      uint32_t i;
-+      AUDIO_INSTANCE_T *instance;
-+      int status;
-+
-+      LOG_DBG("%s: start", __func__);
-+
-+      if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
-+              LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
-+                      __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
-+
-+              return NULL;
-+      }
-+      /* Allocate memory for this instance */
-+      instance = kmalloc(sizeof(*instance), GFP_KERNEL);
-+
-+      memset(instance, 0, sizeof(*instance));
-+      instance->num_connections = num_connections;
-+
-+      /* Create a lock for exclusive, serialized VCHI connection access */
-+      mutex_init(&instance->vchi_mutex);
-+      /* Open the VCHI service connections */
-+      for (i = 0; i < num_connections; i++) {
-+              SERVICE_CREATION_T params = {
-+                      VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
-+                      VC_AUDIO_SERVER_NAME,   // 4cc service code
-+                      vchi_connections[i],    // passed in fn pointers
-+                      0,      // rx fifo size (unused)
-+                      0,      // tx fifo size (unused)
-+                      audio_vchi_callback,    // service callback
-+                      instance,       // service callback parameter
-+                      1,      //TODO: remove VCOS_FALSE,   // unaligned bulk recieves
-+                      1,      //TODO: remove VCOS_FALSE,   // unaligned bulk transmits
-+                      0       // want crc check on bulk transfers
-+              };
-+
-+              status = vchi_service_open(vchi_instance, &params,
-+                                         &instance->vchi_handle[i]);
-+              if (status) {
-+                      LOG_ERR
-+                          ("%s: failed to open VCHI service connection (status=%d)\n",
-+                           __func__, status);
-+
-+                      goto err_close_services;
-+              }
-+              /* Finished with the service for now */
-+              vchi_service_release(instance->vchi_handle[i]);
-+      }
-+
-+      return instance;
-+
-+err_close_services:
-+      for (i = 0; i < instance->num_connections; i++) {
-+              vchi_service_close(instance->vchi_handle[i]);
-+      }
-+
-+      kfree(instance);
-+
-+      return NULL;
-+}
-+
-+static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
-+{
-+      uint32_t i;
-+
-+      LOG_DBG(" .. IN\n");
-+
-+      if (instance == NULL) {
-+              LOG_ERR("%s: invalid handle %p\n", __func__, instance);
-+
-+              return -1;
-+      }
-+
-+      LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
-+      if(mutex_lock_interruptible(&instance->vchi_mutex))
-+      {
-+              LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+              return -EINTR;
-+      }
-+
-+      /* Close all VCHI service connections */
-+      for (i = 0; i < instance->num_connections; i++) {
-+              int32_t success;
-+              LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
-+              vchi_service_use(instance->vchi_handle[i]);
-+
-+              success = vchi_service_close(instance->vchi_handle[i]);
-+              if (success != 0) {
-+                      LOG_ERR
-+                          ("%s: failed to close VCHI service connection (status=%d)\n",
-+                           __func__, success);
-+              }
-+      }
-+
-+      mutex_unlock(&instance->vchi_mutex);
-+
-+      kfree(instance);
-+
-+      LOG_DBG(" .. OUT\n");
-+
-+      return 0;
-+}
-+
-+static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      static VCHI_INSTANCE_T vchi_instance;
-+      static VCHI_CONNECTION_T *vchi_connection;
-+      AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+      int ret;
-+      LOG_DBG(" .. IN\n");
-+
-+      LOG_INFO("%s: start", __func__);
-+      //BUG_ON(instance);
-+      if (instance) {
-+              LOG_ERR("%s: VCHI instance already open (%p)\n",
-+                      __func__, instance);
-+              instance->alsa_stream = alsa_stream;
-+              alsa_stream->instance = instance;
-+              ret = 0;        // xxx todo -1;
-+              goto err_free_mem;
-+      }
-+
-+      /* Initialize and create a VCHI connection */
-+      ret = vchi_initialise(&vchi_instance);
-+      if (ret != 0) {
-+              LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
-+                      __func__, ret);
-+
-+              ret = -EIO;
-+              goto err_free_mem;
-+      }
-+      ret = vchi_connect(NULL, 0, vchi_instance);
-+      if (ret != 0) {
-+              LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
-+                      __func__, ret);
-+
-+              ret = -EIO;
-+              goto err_free_mem;
-+      }
-+
-+      /* Initialize an instance of the audio service */
-+      instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
-+
-+      if (instance == NULL /*|| audio_handle != instance */ ) {
-+              LOG_ERR("%s: failed to initialize audio service\n", __func__);
-+
-+              ret = -EPERM;
-+              goto err_free_mem;
-+      }
-+
-+      instance->alsa_stream = alsa_stream;
-+      alsa_stream->instance = instance;
-+
-+      LOG_DBG(" success !\n");
-+err_free_mem:
-+      LOG_DBG(" .. OUT\n");
-+
-+      return ret;
-+}
-+
-+int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      AUDIO_INSTANCE_T *instance;
-+      VC_AUDIO_MSG_T m;
-+      int32_t success;
-+      int ret;
-+      LOG_DBG(" .. IN\n");
-+
-+      my_workqueue_init(alsa_stream);
-+
-+      ret = bcm2835_audio_open_connection(alsa_stream);
-+      if (ret != 0) {
-+              ret = -1;
-+              goto exit;
-+      }
-+      instance = alsa_stream->instance;
-+
-+      if(mutex_lock_interruptible(&instance->vchi_mutex))
-+      {
-+              LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+              return -EINTR;
-+      }
-+      vchi_service_use(instance->vchi_handle[0]);
-+
-+      m.type = VC_AUDIO_MSG_TYPE_OPEN;
-+
-+      /* Send the message to the videocore */
-+      success = vchi_msg_queue(instance->vchi_handle[0],
-+                               &m, sizeof m,
-+                               VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+      if (success != 0) {
-+              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+                      __func__, success);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+
-+      ret = 0;
-+
-+unlock:
-+      vchi_service_release(instance->vchi_handle[0]);
-+      mutex_unlock(&instance->vchi_mutex);
-+exit:
-+      LOG_DBG(" .. OUT\n");
-+      return ret;
-+}
-+
-+static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
-+                                     bcm2835_chip_t * chip)
-+{
-+      VC_AUDIO_MSG_T m;
-+      AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+      int32_t success;
-+      int ret;
-+      LOG_DBG(" .. IN\n");
-+
-+      LOG_INFO
-+          (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
-+
-+      if(mutex_lock_interruptible(&instance->vchi_mutex))
-+      {
-+              LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+              return -EINTR;
-+      }
-+      vchi_service_use(instance->vchi_handle[0]);
-+
-+      instance->result = -1;
-+
-+      m.type = VC_AUDIO_MSG_TYPE_CONTROL;
-+      m.u.control.dest = chip->dest;
-+      m.u.control.volume = chip->volume;
-+
-+      /* Create the message available event */
-+      sema_init(&instance->msg_avail_event, 0);
-+
-+      /* Send the message to the videocore */
-+      success = vchi_msg_queue(instance->vchi_handle[0],
-+                               &m, sizeof m,
-+                               VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+      if (success != 0) {
-+              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+                      __func__, success);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+
-+      /* We are expecting a reply from the videocore */
-+      if (down_interruptible(&instance->msg_avail_event)) {
-+              LOG_ERR("%s: failed on waiting for event (status=%d)\n",
-+                      __func__, success);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+
-+      if (instance->result != 0) {
-+              LOG_ERR("%s: result=%d\n", __func__, instance->result);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+
-+      ret = 0;
-+
-+unlock:
-+      vchi_service_release(instance->vchi_handle[0]);
-+      mutex_unlock(&instance->vchi_mutex);
-+
-+      LOG_DBG(" .. OUT\n");
-+      return ret;
-+}
-+
-+int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
-+{
-+      int i;
-+      int ret = 0;
-+      LOG_DBG(" .. IN\n");
-+
-+      /* change ctls for all substreams */
-+      for (i = 0; i < MAX_SUBSTREAMS; i++) {
-+              if (chip->avail_substreams & (1 << i)) {
-+                      if (!chip->alsa_stream[i])
-+                      {
-+                              LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
-+                              ret = 0;
-+                      }
-+                      else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
-+                               (chip->alsa_stream[i], chip) != 0)
-+                               {
-+                                      LOG_DBG("Couldn't set the controls for stream %d\n", i);
-+                                      ret = -1;
-+                               }
-+                      else LOG_DBG(" Controls set for stream %d\n", i);
-+              }
-+      }
-+      LOG_DBG(" .. OUT ret=%d\n", ret);
-+      return ret;
-+}
-+
-+int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
-+                           uint32_t channels, uint32_t samplerate,
-+                           uint32_t bps)
-+{
-+      VC_AUDIO_MSG_T m;
-+      AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+      int32_t success;
-+      int ret;
-+      LOG_DBG(" .. IN\n");
-+
-+      LOG_INFO
-+          (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
-+           channels, samplerate, bps);
-+
-+      /* resend ctls - alsa_stream may not have been open when first send */
-+      ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
-+      if (ret != 0) {
-+              LOG_ERR(" Alsa controls not supported\n");
-+              return -EINVAL;
-+      }
-+
-+      if(mutex_lock_interruptible(&instance->vchi_mutex))
-+      {
-+              LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+              return -EINTR;
-+      }
-+      vchi_service_use(instance->vchi_handle[0]);
-+
-+      instance->result = -1;
-+
-+      m.type = VC_AUDIO_MSG_TYPE_CONFIG;
-+      m.u.config.channels = channels;
-+      m.u.config.samplerate = samplerate;
-+      m.u.config.bps = bps;
-+
-+      /* Create the message available event */
-+      sema_init(&instance->msg_avail_event, 0);
-+
-+      /* Send the message to the videocore */
-+      success = vchi_msg_queue(instance->vchi_handle[0],
-+                               &m, sizeof m,
-+                               VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+      if (success != 0) {
-+              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
-+                      __func__, success);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+
-+      /* We are expecting a reply from the videocore */
-+      if (down_interruptible(&instance->msg_avail_event)) {
-+              LOG_ERR("%s: failed on waiting for event (status=%d)\n",
-+                      __func__, success);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+
-+      if (instance->result != 0) {
-+              LOG_ERR("%s: result=%d", __func__, instance->result);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+
-+      ret = 0;
-+
-+unlock:
-+      vchi_service_release(instance->vchi_handle[0]);
-+      mutex_unlock(&instance->vchi_mutex);
-+
-+      LOG_DBG(" .. OUT\n");
-+      return ret;
-+}
-+
-+int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      LOG_DBG(" .. IN\n");
-+
-+      LOG_DBG(" .. OUT\n");
-+
-+      return 0;
-+}
-+
-+static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      VC_AUDIO_MSG_T m;
-+      AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+      int32_t success;
-+      int ret;
-+      LOG_DBG(" .. IN\n");
-+
-+      if(mutex_lock_interruptible(&instance->vchi_mutex))
-+      {
-+              LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+              return -EINTR;
-+      }
-+      vchi_service_use(instance->vchi_handle[0]);
-+
-+      m.type = VC_AUDIO_MSG_TYPE_START;
-+
-+      /* Send the message to the videocore */
-+      success = vchi_msg_queue(instance->vchi_handle[0],
-+                               &m, sizeof m,
-+                               VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+      if (success != 0) {
-+              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
-+                      __func__, success);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+
-+      ret = 0;
-+
-+unlock:
-+      vchi_service_release(instance->vchi_handle[0]);
-+      mutex_unlock(&instance->vchi_mutex);
-+      LOG_DBG(" .. OUT\n");
-+      return ret;
-+}
-+
-+static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      VC_AUDIO_MSG_T m;
-+      AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+      int32_t success;
-+      int ret;
-+      LOG_DBG(" .. IN\n");
-+
-+      if(mutex_lock_interruptible(&instance->vchi_mutex))
-+      {
-+              LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+              return -EINTR;
-+      }
-+      vchi_service_use(instance->vchi_handle[0]);
-+
-+      m.type = VC_AUDIO_MSG_TYPE_STOP;
-+      m.u.stop.draining = alsa_stream->draining;
-+
-+      /* Send the message to the videocore */
-+      success = vchi_msg_queue(instance->vchi_handle[0],
-+                               &m, sizeof m,
-+                               VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+      if (success != 0) {
-+              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
-+                      __func__, success);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+
-+      ret = 0;
-+
-+unlock:
-+      vchi_service_release(instance->vchi_handle[0]);
-+      mutex_unlock(&instance->vchi_mutex);
-+      LOG_DBG(" .. OUT\n");
-+      return ret;
-+}
-+
-+int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      VC_AUDIO_MSG_T m;
-+      AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+      int32_t success;
-+      int ret;
-+      LOG_DBG(" .. IN\n");
-+
-+      my_workqueue_quit(alsa_stream);
-+
-+      if(mutex_lock_interruptible(&instance->vchi_mutex))
-+      {
-+              LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+              return -EINTR;
-+      }
-+      vchi_service_use(instance->vchi_handle[0]);
-+
-+      m.type = VC_AUDIO_MSG_TYPE_CLOSE;
-+
-+      /* Create the message available event */
-+      sema_init(&instance->msg_avail_event, 0);
-+
-+      /* Send the message to the videocore */
-+      success = vchi_msg_queue(instance->vchi_handle[0],
-+                               &m, sizeof m,
-+                               VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+      if (success != 0) {
-+              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
-+                      __func__, success);
-+              ret = -1;
-+              goto unlock;
-+      }
-+      if (down_interruptible(&instance->msg_avail_event)) {
-+              LOG_ERR("%s: failed on waiting for event (status=%d)",
-+                      __func__, success);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+      if (instance->result != 0) {
-+              LOG_ERR("%s: failed result (status=%d)",
-+                      __func__, instance->result);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+
-+      ret = 0;
-+
-+unlock:
-+      vchi_service_release(instance->vchi_handle[0]);
-+      mutex_unlock(&instance->vchi_mutex);
-+
-+      /* Stop the audio service */
-+      if (instance) {
-+              vc_vchi_audio_deinit(instance);
-+              alsa_stream->instance = NULL;
-+      }
-+      LOG_DBG(" .. OUT\n");
-+      return ret;
-+}
-+
-+int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
-+                      void *src)
-+{
-+      VC_AUDIO_MSG_T m;
-+      AUDIO_INSTANCE_T *instance = alsa_stream->instance;
-+      int32_t success;
-+      int ret;
-+
-+      LOG_DBG(" .. IN\n");
-+
-+      LOG_INFO(" Writing %d bytes from %p\n", count, src);
-+
-+      if(mutex_lock_interruptible(&instance->vchi_mutex))
-+      {
-+              LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
-+              return -EINTR;
-+      }
-+      vchi_service_use(instance->vchi_handle[0]);
-+
-+      if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) {
-+              LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
-+      }
-+      m.type = VC_AUDIO_MSG_TYPE_WRITE;
-+      m.u.write.count = count;
-+      // old version uses bulk, new version uses control
-+      m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000;
-+      m.u.write.callback = alsa_stream->fifo_irq_handler;
-+      m.u.write.cookie = alsa_stream;
-+      m.u.write.silence = src == NULL;
-+
-+      /* Send the message to the videocore */
-+      success = vchi_msg_queue(instance->vchi_handle[0],
-+                               &m, sizeof m,
-+                               VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+
-+      if (success != 0) {
-+              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
-+                      __func__, success);
-+
-+              ret = -1;
-+              goto unlock;
-+      }
-+      if (!m.u.write.silence) {
-+              if (m.u.write.max_packet == 0) {
-+                      /* Send the message to the videocore */
-+                      success = vchi_bulk_queue_transmit(instance->vchi_handle[0],
-+                                                         src, count,
-+                                                         0 *
-+                                                         VCHI_FLAGS_BLOCK_UNTIL_QUEUED
-+                                                         +
-+                                                         1 *
-+                                                         VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
-+                                                         NULL);
-+              } else {
-+                      while (count > 0) {
-+                              int bytes = min((int)m.u.write.max_packet, (int)count);
-+                              success = vchi_msg_queue(instance->vchi_handle[0],
-+                                                       src, bytes,
-+                                                       VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
-+                              src = (char *)src + bytes;
-+                              count -= bytes;
-+                      }
-+              }
-+              if (success != 0) {
-+                      LOG_ERR
-+                          ("%s: failed on vchi_bulk_queue_transmit (status=%d)",
-+                           __func__, success);
-+
-+                      ret = -1;
-+                      goto unlock;
-+              }
-+      }
-+      ret = 0;
-+
-+unlock:
-+      vchi_service_release(instance->vchi_handle[0]);
-+      mutex_unlock(&instance->vchi_mutex);
-+      LOG_DBG(" .. OUT\n");
-+      return ret;
-+}
-+
-+/**
-+  * Returns all buffers from arm->vc
-+  */
-+void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      LOG_DBG(" .. IN\n");
-+      LOG_DBG(" .. OUT\n");
-+      return;
-+}
-+
-+/**
-+  * Forces VC to flush(drop) its filled playback buffers and
-+  * return them the us. (VC->ARM)
-+  */
-+void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      LOG_DBG(" .. IN\n");
-+      LOG_DBG(" .. OUT\n");
-+}
-+
-+uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
-+{
-+      uint32_t count = atomic_read(&alsa_stream->retrieved);
-+      atomic_sub(count, &alsa_stream->retrieved);
-+      return count;
-+}
-+
-+module_param(force_bulk, bool, 0444);
-+MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
---- /dev/null
-+++ b/sound/arm/bcm2835.c
-@@ -0,0 +1,413 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation.  All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#include <linux/platform_device.h>
-+
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+
-+#include "bcm2835.h"
-+
-+/* module parameters (see "Module Parameters") */
-+/* SNDRV_CARDS: maximum number of cards supported by this module */
-+static int index[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = -1 };
-+static char *id[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = NULL };
-+static int enable[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = 1 };
-+
-+/* HACKY global pointers needed for successive probes to work : ssp
-+ * But compared against the changes we will have to do in VC audio_ipc code
-+ * to export 8 audio_ipc devices as a single IPC device and then monitor all
-+ * four devices in a thread, this gets things done quickly and should be easier
-+ * to debug if we run into issues
-+ */
-+
-+static struct snd_card *g_card = NULL;
-+static bcm2835_chip_t *g_chip = NULL;
-+
-+static int snd_bcm2835_free(bcm2835_chip_t * chip)
-+{
-+      kfree(chip);
-+      return 0;
-+}
-+
-+/* component-destructor
-+ * (see "Management of Cards and Components")
-+ */
-+static int snd_bcm2835_dev_free(struct snd_device *device)
-+{
-+      return snd_bcm2835_free(device->device_data);
-+}
-+
-+/* chip-specific constructor
-+ * (see "Management of Cards and Components")
-+ */
-+static int snd_bcm2835_create(struct snd_card *card,
-+                                      struct platform_device *pdev,
-+                                      bcm2835_chip_t ** rchip)
-+{
-+      bcm2835_chip_t *chip;
-+      int err;
-+      static struct snd_device_ops ops = {
-+              .dev_free = snd_bcm2835_dev_free,
-+      };
-+
-+      *rchip = NULL;
-+
-+      chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-+      if (chip == NULL)
-+              return -ENOMEM;
-+
-+      chip->card = card;
-+
-+      err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
-+      if (err < 0) {
-+              snd_bcm2835_free(chip);
-+              return err;
-+      }
-+
-+      *rchip = chip;
-+      return 0;
-+}
-+
-+static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
-+{
-+      static int dev;
-+      bcm2835_chip_t *chip;
-+      struct snd_card *card;
-+      int err;
-+
-+      if (dev >= MAX_SUBSTREAMS)
-+              return -ENODEV;
-+
-+      if (!enable[dev]) {
-+              dev++;
-+              return -ENOENT;
-+      }
-+
-+      if (dev > 0)
-+              goto add_register_map;
-+
-+      err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &g_card);
-+      if (err < 0)
-+              goto out;
-+
-+      snd_card_set_dev(g_card, &pdev->dev);
-+      strcpy(g_card->driver, "BRCM bcm2835 ALSA Driver");
-+      strcpy(g_card->shortname, "bcm2835 ALSA");
-+      sprintf(g_card->longname, "%s", g_card->shortname);
-+
-+      err = snd_bcm2835_create(g_card, pdev, &chip);
-+      if (err < 0) {
-+              printk(KERN_ERR "Failed to create bcm2835 chip\n");
-+              goto out_bcm2835_create;
-+      }
-+
-+      g_chip = chip;
-+      err = snd_bcm2835_new_pcm(chip);
-+      if (err < 0) {
-+              printk(KERN_ERR "Failed to create new BCM2835 pcm device\n");
-+              goto out_bcm2835_new_pcm;
-+      }
-+
-+      err = snd_bcm2835_new_ctl(chip);
-+      if (err < 0) {
-+              printk(KERN_ERR "Failed to create new BCM2835 ctl\n");
-+              goto out_bcm2835_new_ctl;
-+      }
-+
-+add_register_map:
-+      card = g_card;
-+      chip = g_chip;
-+
-+      BUG_ON(!(card && chip));
-+
-+      chip->avail_substreams |= (1 << dev);
-+      chip->pdev[dev] = pdev;
-+
-+      if (dev == 0) {
-+              err = snd_card_register(card);
-+              if (err < 0) {
-+                      printk(KERN_ERR
-+                             "Failed to register bcm2835 ALSA card \n");
-+                      goto out_card_register;
-+              }
-+              platform_set_drvdata(pdev, card);
-+              printk(KERN_INFO "bcm2835 ALSA card created!\n");
-+      } else {
-+              printk(KERN_INFO "bcm2835 ALSA chip created!\n");
-+              platform_set_drvdata(pdev, (void *)dev);
-+      }
-+
-+      dev++;
-+
-+      return 0;
-+
-+out_card_register:
-+out_bcm2835_new_ctl:
-+out_bcm2835_new_pcm:
-+out_bcm2835_create:
-+      BUG_ON(!g_card);
-+      if (snd_card_free(g_card))
-+              printk(KERN_ERR "Failed to free Registered alsa card\n");
-+      g_card = NULL;
-+out:
-+      dev = SNDRV_CARDS;      /* stop more avail_substreams from being probed */
-+      printk(KERN_ERR "BCM2835 ALSA Probe failed !!\n");
-+      return err;
-+}
-+
-+static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
-+{
-+      uint32_t idx;
-+      void *drv_data;
-+
-+      drv_data = platform_get_drvdata(pdev);
-+
-+      if (drv_data == (void *)g_card) {
-+              /* This is the card device */
-+              snd_card_free((struct snd_card *)drv_data);
-+              g_card = NULL;
-+              g_chip = NULL;
-+      } else {
-+              idx = (uint32_t) drv_data;
-+              if (g_card != NULL) {
-+                      BUG_ON(!g_chip);
-+                      /* We pass chip device numbers in audio ipc devices
-+                       * other than the one we registered our card with
-+                       */
-+                      idx = (uint32_t) drv_data;
-+                      BUG_ON(!idx || idx > MAX_SUBSTREAMS);
-+                      g_chip->avail_substreams &= ~(1 << idx);
-+                      /* There should be atleast one substream registered
-+                       * after we are done here, as it wil be removed when
-+                       * the *remove* is called for the card device
-+                       */
-+                      BUG_ON(!g_chip->avail_substreams);
-+              }
-+      }
-+
-+      platform_set_drvdata(pdev, NULL);
-+
-+      return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
-+                                  pm_message_t state)
-+{
-+      return 0;
-+}
-+
-+static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
-+{
-+      return 0;
-+}
-+
-+#endif
-+
-+static struct platform_driver bcm2835_alsa0_driver = {
-+      .probe = snd_bcm2835_alsa_probe,
-+      .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+      .suspend = snd_bcm2835_alsa_suspend,
-+      .resume = snd_bcm2835_alsa_resume,
-+#endif
-+      .driver = {
-+                 .name = "bcm2835_AUD0",
-+                 .owner = THIS_MODULE,
-+                 },
-+};
-+
-+static struct platform_driver bcm2835_alsa1_driver = {
-+      .probe = snd_bcm2835_alsa_probe,
-+      .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+      .suspend = snd_bcm2835_alsa_suspend,
-+      .resume = snd_bcm2835_alsa_resume,
-+#endif
-+      .driver = {
-+                 .name = "bcm2835_AUD1",
-+                 .owner = THIS_MODULE,
-+                 },
-+};
-+
-+static struct platform_driver bcm2835_alsa2_driver = {
-+      .probe = snd_bcm2835_alsa_probe,
-+      .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+      .suspend = snd_bcm2835_alsa_suspend,
-+      .resume = snd_bcm2835_alsa_resume,
-+#endif
-+      .driver = {
-+                 .name = "bcm2835_AUD2",
-+                 .owner = THIS_MODULE,
-+                 },
-+};
-+
-+static struct platform_driver bcm2835_alsa3_driver = {
-+      .probe = snd_bcm2835_alsa_probe,
-+      .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+      .suspend = snd_bcm2835_alsa_suspend,
-+      .resume = snd_bcm2835_alsa_resume,
-+#endif
-+      .driver = {
-+                 .name = "bcm2835_AUD3",
-+                 .owner = THIS_MODULE,
-+                 },
-+};
-+
-+static struct platform_driver bcm2835_alsa4_driver = {
-+      .probe = snd_bcm2835_alsa_probe,
-+      .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+      .suspend = snd_bcm2835_alsa_suspend,
-+      .resume = snd_bcm2835_alsa_resume,
-+#endif
-+      .driver = {
-+                 .name = "bcm2835_AUD4",
-+                 .owner = THIS_MODULE,
-+                 },
-+};
-+
-+static struct platform_driver bcm2835_alsa5_driver = {
-+      .probe = snd_bcm2835_alsa_probe,
-+      .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+      .suspend = snd_bcm2835_alsa_suspend,
-+      .resume = snd_bcm2835_alsa_resume,
-+#endif
-+      .driver = {
-+                 .name = "bcm2835_AUD5",
-+                 .owner = THIS_MODULE,
-+                 },
-+};
-+
-+static struct platform_driver bcm2835_alsa6_driver = {
-+      .probe = snd_bcm2835_alsa_probe,
-+      .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+      .suspend = snd_bcm2835_alsa_suspend,
-+      .resume = snd_bcm2835_alsa_resume,
-+#endif
-+      .driver = {
-+                 .name = "bcm2835_AUD6",
-+                 .owner = THIS_MODULE,
-+                 },
-+};
-+
-+static struct platform_driver bcm2835_alsa7_driver = {
-+      .probe = snd_bcm2835_alsa_probe,
-+      .remove = snd_bcm2835_alsa_remove,
-+#ifdef CONFIG_PM
-+      .suspend = snd_bcm2835_alsa_suspend,
-+      .resume = snd_bcm2835_alsa_resume,
-+#endif
-+      .driver = {
-+                 .name = "bcm2835_AUD7",
-+                 .owner = THIS_MODULE,
-+                 },
-+};
-+
-+static int bcm2835_alsa_device_init(void)
-+{
-+      int err;
-+      err = platform_driver_register(&bcm2835_alsa0_driver);
-+      if (err) {
-+              printk("Error registering bcm2835_alsa0_driver %d .\n", err);
-+              goto out;
-+      }
-+
-+      err = platform_driver_register(&bcm2835_alsa1_driver);
-+      if (err) {
-+              printk("Error registering bcm2835_alsa1_driver %d .\n", err);
-+              goto unregister_0;
-+      }
-+
-+      err = platform_driver_register(&bcm2835_alsa2_driver);
-+      if (err) {
-+              printk("Error registering bcm2835_alsa2_driver %d .\n", err);
-+              goto unregister_1;
-+      }
-+
-+      err = platform_driver_register(&bcm2835_alsa3_driver);
-+      if (err) {
-+              printk("Error registering bcm2835_alsa3_driver %d .\n", err);
-+              goto unregister_2;
-+      }
-+
-+      err = platform_driver_register(&bcm2835_alsa4_driver);
-+      if (err) {
-+              printk("Error registering bcm2835_alsa4_driver %d .\n", err);
-+              goto unregister_3;
-+      }
-+
-+      err = platform_driver_register(&bcm2835_alsa5_driver);
-+      if (err) {
-+              printk("Error registering bcm2835_alsa5_driver %d .\n", err);
-+              goto unregister_4;
-+      }
-+
-+      err = platform_driver_register(&bcm2835_alsa6_driver);
-+      if (err) {
-+              printk("Error registering bcm2835_alsa6_driver %d .\n", err);
-+              goto unregister_5;
-+      }
-+
-+      err = platform_driver_register(&bcm2835_alsa7_driver);
-+      if (err) {
-+              printk("Error registering bcm2835_alsa7_driver %d .\n", err);
-+              goto unregister_6;
-+      }
-+
-+      return 0;
-+
-+unregister_6:
-+      platform_driver_unregister(&bcm2835_alsa6_driver);
-+unregister_5:
-+      platform_driver_unregister(&bcm2835_alsa5_driver);
-+unregister_4:
-+      platform_driver_unregister(&bcm2835_alsa4_driver);
-+unregister_3:
-+      platform_driver_unregister(&bcm2835_alsa3_driver);
-+unregister_2:
-+      platform_driver_unregister(&bcm2835_alsa2_driver);
-+unregister_1:
-+      platform_driver_unregister(&bcm2835_alsa1_driver);
-+unregister_0:
-+      platform_driver_unregister(&bcm2835_alsa0_driver);
-+out:
-+      return err;
-+}
-+
-+static void bcm2835_alsa_device_exit(void)
-+{
-+      platform_driver_unregister(&bcm2835_alsa0_driver);
-+      platform_driver_unregister(&bcm2835_alsa1_driver);
-+      platform_driver_unregister(&bcm2835_alsa2_driver);
-+      platform_driver_unregister(&bcm2835_alsa3_driver);
-+      platform_driver_unregister(&bcm2835_alsa4_driver);
-+      platform_driver_unregister(&bcm2835_alsa5_driver);
-+      platform_driver_unregister(&bcm2835_alsa6_driver);
-+      platform_driver_unregister(&bcm2835_alsa7_driver);
-+}
-+
-+late_initcall(bcm2835_alsa_device_init);
-+module_exit(bcm2835_alsa_device_exit);
-+
-+MODULE_AUTHOR("Dom Cobley");
-+MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:bcm2835_alsa");
---- /dev/null
-+++ b/sound/arm/bcm2835.h
-@@ -0,0 +1,155 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation.  All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#ifndef __SOUND_ARM_BCM2835_H
-+#define __SOUND_ARM_BCM2835_H
-+
-+#include <linux/device.h>
-+#include <linux/list.h>
-+#include <linux/interrupt.h>
-+#include <linux/wait.h>
-+#include <sound/core.h>
-+#include <sound/initval.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <linux/workqueue.h>
-+
-+/*
-+#define AUDIO_DEBUG_ENABLE
-+#define AUDIO_VERBOSE_DEBUG_ENABLE
-+*/
-+
-+/* Debug macros */
-+
-+#ifdef AUDIO_DEBUG_ENABLE
-+#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
-+
-+#define audio_debug(fmt, arg...)      \
-+      printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define audio_info(fmt, arg...)       \
-+      printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#else
-+
-+#define audio_debug(fmt, arg...)
-+
-+#define audio_info(fmt, arg...)
-+
-+#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
-+
-+#else
-+
-+#define audio_debug(fmt, arg...)
-+
-+#define audio_info(fmt, arg...)
-+
-+#endif /* AUDIO_DEBUG_ENABLE */
-+
-+#define audio_error(fmt, arg...)      \
-+      printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define audio_warning(fmt, arg...)    \
-+      printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define audio_alert(fmt, arg...)      \
-+      printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
-+
-+#define MAX_SUBSTREAMS                        (8)
-+#define AVAIL_SUBSTREAMS_MASK         (0xff)
-+enum {
-+      CTRL_VOL_MUTE,
-+      CTRL_VOL_UNMUTE
-+};
-+
-+/* macros for alsa2chip and chip2alsa, instead of functions */
-+
-+#define alsa2chip(vol) (uint)(-((vol << 8) / 100))    /* convert alsa to chip volume (defined as macro rather than function call) */
-+#define chip2alsa(vol) -((vol * 100) >> 8)                    /* convert chip to alsa volume */
-+
-+/* Some constants for values .. */
-+typedef enum {
-+      AUDIO_DEST_AUTO = 0,
-+      AUDIO_DEST_HEADPHONES = 1,
-+      AUDIO_DEST_HDMI = 2,
-+      AUDIO_DEST_MAX,
-+} SND_BCM2835_ROUTE_T;
-+
-+typedef enum {
-+      PCM_PLAYBACK_VOLUME,
-+      PCM_PLAYBACK_MUTE,
-+      PCM_PLAYBACK_DEVICE,
-+} SND_BCM2835_CTRL_T;
-+
-+/* definition of the chip-specific record */
-+typedef struct bcm2835_chip {
-+      struct snd_card *card;
-+      struct snd_pcm *pcm;
-+      /* Bitmat for valid reg_base and irq numbers */
-+      uint32_t avail_substreams;
-+      struct platform_device *pdev[MAX_SUBSTREAMS];
-+      struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
-+
-+      int volume;
-+      int old_volume; /* stores the volume value whist muted */
-+      int dest;
-+      int mute;
-+} bcm2835_chip_t;
-+
-+typedef struct bcm2835_alsa_stream {
-+      bcm2835_chip_t *chip;
-+      struct snd_pcm_substream *substream;
-+
-+      struct semaphore buffers_update_sem;
-+      struct semaphore control_sem;
-+      spinlock_t lock;
-+      volatile uint32_t control;
-+      volatile uint32_t status;
-+
-+      int open;
-+      int running;
-+      int draining;
-+
-+      unsigned int pos;
-+      unsigned int buffer_size;
-+      unsigned int period_size;
-+
-+      uint32_t enable_fifo_irq;
-+      irq_handler_t fifo_irq_handler;
-+
-+      atomic_t retrieved;
-+      struct opaque_AUDIO_INSTANCE_T *instance;
-+      struct workqueue_struct *my_wq;
-+      int idx;
-+} bcm2835_alsa_stream_t;
-+
-+int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
-+int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
-+
-+int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
-+                           uint32_t channels, uint32_t samplerate,
-+                           uint32_t bps);
-+int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream);
-+int bcm2835_audio_set_ctls(bcm2835_chip_t * chip);
-+int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
-+                      void *src);
-+uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream);
-+void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream);
-+void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream);
-+
-+#endif /* __SOUND_ARM_BCM2835_H */
---- /dev/null
-+++ b/sound/arm/vc_vchi_audioserv_defs.h
-@@ -0,0 +1,116 @@
-+/*****************************************************************************
-+* Copyright 2011 Broadcom Corporation.  All rights reserved.
-+*
-+* Unless you and Broadcom execute a separate written software license
-+* agreement governing use of this software, this software is licensed to you
-+* under the terms of the GNU General Public License version 2, available at
-+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-+*
-+* Notwithstanding the above, under no circumstances may you combine this
-+* software in any way with any other Broadcom software provided under a
-+* license other than the GPL, without Broadcom's express prior written
-+* consent.
-+*****************************************************************************/
-+
-+#ifndef _VC_AUDIO_DEFS_H_
-+#define _VC_AUDIO_DEFS_H_
-+
-+#define VC_AUDIOSERV_MIN_VER 1
-+#define VC_AUDIOSERV_VER 2
-+
-+// FourCC code used for VCHI connection
-+#define VC_AUDIO_SERVER_NAME  MAKE_FOURCC("AUDS")
-+
-+// Maximum message length
-+#define VC_AUDIO_MAX_MSG_LEN  (sizeof( VC_AUDIO_MSG_T ))
-+
-+// List of screens that are currently supported
-+// All message types supported for HOST->VC direction
-+typedef enum {
-+      VC_AUDIO_MSG_TYPE_RESULT,       // Generic result
-+      VC_AUDIO_MSG_TYPE_COMPLETE,     // Generic result
-+      VC_AUDIO_MSG_TYPE_CONFIG,       // Configure audio
-+      VC_AUDIO_MSG_TYPE_CONTROL,      // Configure audio
-+      VC_AUDIO_MSG_TYPE_OPEN, // Configure audio
-+      VC_AUDIO_MSG_TYPE_CLOSE,        // Configure audio
-+      VC_AUDIO_MSG_TYPE_START,        // Configure audio
-+      VC_AUDIO_MSG_TYPE_STOP, // Configure audio
-+      VC_AUDIO_MSG_TYPE_WRITE,        // Configure audio
-+      VC_AUDIO_MSG_TYPE_MAX
-+} VC_AUDIO_MSG_TYPE;
-+
-+// configure the audio
-+typedef struct {
-+      uint32_t channels;
-+      uint32_t samplerate;
-+      uint32_t bps;
-+
-+} VC_AUDIO_CONFIG_T;
-+
-+typedef struct {
-+      uint32_t volume;
-+      uint32_t dest;
-+
-+} VC_AUDIO_CONTROL_T;
-+
-+// audio
-+typedef struct {
-+      uint32_t dummy;
-+
-+} VC_AUDIO_OPEN_T;
-+
-+// audio
-+typedef struct {
-+      uint32_t dummy;
-+
-+} VC_AUDIO_CLOSE_T;
-+// audio
-+typedef struct {
-+      uint32_t dummy;
-+
-+} VC_AUDIO_START_T;
-+// audio
-+typedef struct {
-+      uint32_t draining;
-+
-+} VC_AUDIO_STOP_T;
-+
-+// configure the write audio samples
-+typedef struct {
-+      uint32_t count;         // in bytes
-+      void *callback;
-+      void *cookie;
-+      uint16_t silence;
-+      uint16_t max_packet;
-+} VC_AUDIO_WRITE_T;
-+
-+// Generic result for a request (VC->HOST)
-+typedef struct {
-+      int32_t success;        // Success value
-+
-+} VC_AUDIO_RESULT_T;
-+
-+// Generic result for a request (VC->HOST)
-+typedef struct {
-+      int32_t count;          // Success value
-+      void *callback;
-+      void *cookie;
-+} VC_AUDIO_COMPLETE_T;
-+
-+// Message header for all messages in HOST->VC direction
-+typedef struct {
-+      int32_t type;           // Message type (VC_AUDIO_MSG_TYPE)
-+      union {
-+              VC_AUDIO_CONFIG_T config;
-+              VC_AUDIO_CONTROL_T control;
-+              VC_AUDIO_OPEN_T open;
-+              VC_AUDIO_CLOSE_T close;
-+              VC_AUDIO_START_T start;
-+              VC_AUDIO_STOP_T stop;
-+              VC_AUDIO_WRITE_T write;
-+              VC_AUDIO_RESULT_T result;
-+              VC_AUDIO_COMPLETE_T complete;
-+      } u;
-+} VC_AUDIO_MSG_T;
-+
-+#endif // _VC_AUDIO_DEFS_H_