brcm2708: update to latest patches from RPi Foundation
[openwrt/staging/chunkeey.git] / target / linux / brcm2708 / patches-4.19 / 950-0410-staging-bcm2835-audio-Operate-non-atomic-PCM-ops.patch
diff --git a/target/linux/brcm2708/patches-4.19/950-0410-staging-bcm2835-audio-Operate-non-atomic-PCM-ops.patch b/target/linux/brcm2708/patches-4.19/950-0410-staging-bcm2835-audio-Operate-non-atomic-PCM-ops.patch
deleted file mode 100644 (file)
index 722804f..0000000
+++ /dev/null
@@ -1,593 +0,0 @@
-From 87ba8310e9f0882e85926ac1ef91333f8906b303 Mon Sep 17 00:00:00 2001
-From: Takashi Iwai <tiwai@suse.de>
-Date: Tue, 4 Sep 2018 17:58:49 +0200
-Subject: [PATCH] staging: bcm2835-audio: Operate non-atomic PCM ops
-
-commit 5c7883e5f27e829f3f3a2ba174d4a724bfd5f026 upstream.
-
-This is the most significant part in the patch series.
-
-The bcm2835-audio driver used to queue the commands to vc04 core via
-workqueue, but basically the whole accesses to vc04 core are done in
-the sleepable context, including the callback calls.  In such a case,
-rewriting the code using non-atomic PCM ops will simplify the logic a
-lot.
-
-This patch does it: all workqueue are gone and each former-work
-implementation is now directly called from PCM ops like trigger and
-write transfer.
-
-Along with it, the DMA position updater, bcm2835_playback_fifo(), was
-also rewritten to use a simpler logic.  Now it handles the XRUN and
-draining properly by calling snd_pcm_stop() conditionally.
-
-The current position is kept in atomic_t value so that it can be read
-concurrently from the pointer callback.
-
-Also, the bcm2835_audio_instance object is allocated at the beginning
-of bcm2835_audio_open().  This makes the resource management clearer.
-
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Tested-by: Stefan Wahren <stefan.wahren@i2se.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- .../vc04_services/bcm2835-audio/bcm2835-pcm.c |  74 +++---
- .../bcm2835-audio/bcm2835-vchiq.c             | 244 +++---------------
- .../vc04_services/bcm2835-audio/bcm2835.h     |   9 +-
- 3 files changed, 82 insertions(+), 245 deletions(-)
-
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
-@@ -11,7 +11,8 @@
- /* hardware definition */
- static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
-       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
--      SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
-+               SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-+               SNDRV_PCM_INFO_DRAIN_TRIGGER),
-       .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
-       .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-       .rate_min = 8000,
-@@ -27,7 +28,8 @@ static const struct snd_pcm_hardware snd
- static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
-       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
--      SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
-+               SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-+               SNDRV_PCM_INFO_DRAIN_TRIGGER),
-       .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
-       SNDRV_PCM_RATE_48000,
-@@ -47,42 +49,34 @@ static void snd_bcm2835_playback_free(st
-       kfree(runtime->private_data);
- }
--void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream)
-+void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream,
-+                         unsigned int bytes)
- {
--      unsigned int consumed = 0;
--      int new_period = 0;
-+      struct snd_pcm_substream *substream = alsa_stream->substream;
-+      unsigned int pos;
--      audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
--              alsa_stream ? alsa_stream->substream : 0);
-+      if (!alsa_stream->period_size)
-+              return;
--      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 (bytes >= alsa_stream->buffer_size) {
-+              snd_pcm_stream_lock(substream);
-+              snd_pcm_stop(substream,
-+                           alsa_stream->draining ?
-+                           SNDRV_PCM_STATE_SETUP :
-+                           SNDRV_PCM_STATE_XRUN);
-+              snd_pcm_stream_unlock(substream);
-+              return;
-       }
--      if (alsa_stream->substream) {
--              if (new_period)
--                      snd_pcm_period_elapsed(alsa_stream->substream);
--      } else {
--              audio_warning(" unexpected NULL substream\n");
-+      pos = atomic_read(&alsa_stream->pos);
-+      pos += bytes;
-+      pos %= alsa_stream->buffer_size;
-+      atomic_set(&alsa_stream->pos, pos);
-+
-+      alsa_stream->period_offset += bytes;
-+      if (alsa_stream->period_offset >= alsa_stream->period_size) {
-+              alsa_stream->period_offset %= alsa_stream->period_size;
-+              snd_pcm_period_elapsed(substream);
-       }
- }
-@@ -246,7 +240,8 @@ static int snd_bcm2835_pcm_prepare(struc
-       alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
-       alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
--      alsa_stream->pos = 0;
-+      atomic_set(&alsa_stream->pos, 0);
-+      alsa_stream->period_offset = 0;
-       alsa_stream->draining = false;
-       return 0;
-@@ -283,7 +278,7 @@ static int snd_bcm2835_pcm_trigger(struc
-               return bcm2835_audio_start(alsa_stream);
-       case SNDRV_PCM_TRIGGER_DRAIN:
-               alsa_stream->draining = true;
--              return 0;
-+              return bcm2835_audio_drain(alsa_stream);
-       case SNDRV_PCM_TRIGGER_STOP:
-               return bcm2835_audio_stop(alsa_stream);
-       default:
-@@ -300,7 +295,7 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
-       return snd_pcm_indirect_playback_pointer(substream,
-               &alsa_stream->pcm_indirect,
--              alsa_stream->pos);
-+              atomic_read(&alsa_stream->pos));
- }
- /* operators */
-@@ -338,6 +333,7 @@ int snd_bcm2835_new_pcm(struct bcm2835_c
-       if (err < 0)
-               return err;
-       pcm->private_data = chip;
-+      pcm->nonatomic = true;
-       strcpy(pcm->name, "bcm2835 ALSA");
-       chip->pcm = pcm;
-       chip->dest = AUDIO_DEST_AUTO;
-@@ -367,6 +363,7 @@ int snd_bcm2835_new_spdif_pcm(struct bcm
-               return err;
-       pcm->private_data = chip;
-+      pcm->nonatomic = true;
-       strcpy(pcm->name, "bcm2835 IEC958/HDMI");
-       chip->pcm_spdif = pcm;
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-@@ -395,6 +392,7 @@ int snd_bcm2835_new_simple_pcm(struct bc
-               return err;
-       pcm->private_data = chip;
-+      pcm->nonatomic = true;
-       strcpy(pcm->name, name);
-       chip->pcm = pcm;
-       chip->dest = route;
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
-@@ -26,10 +26,6 @@
- /* ---- Private Constants and Types ------------------------------------------ */
--#define BCM2835_AUDIO_STOP           0
--#define BCM2835_AUDIO_START          1
--#define BCM2835_AUDIO_WRITE          2
--
- /* 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)
-@@ -55,17 +51,6 @@ struct bcm2835_audio_instance {
- static bool force_bulk;
--/* ---- Private Variables ---------------------------------------------------- */
--
--/* ---- Private Function Prototypes ------------------------------------------ */
--
--/* ---- Private Functions ---------------------------------------------------- */
--
--static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream);
--static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream);
--static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
--                                    unsigned int count, void *src);
--
- static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
- {
-       mutex_lock(&instance->vchi_mutex);
-@@ -135,108 +120,6 @@ static const u32 BCM2835_AUDIO_WRITE_COO
- static const u32 BCM2835_AUDIO_WRITE_COOKIE2 = ('D' << 24 | 'A' << 16 |
-                                               'T' << 8  | 'A');
--struct bcm2835_audio_work {
--      struct work_struct my_work;
--      struct bcm2835_alsa_stream *alsa_stream;
--      int cmd;
--      void *src;
--      unsigned int count;
--};
--
--static void my_wq_function(struct work_struct *work)
--{
--      struct bcm2835_audio_work *w =
--              container_of(work, struct bcm2835_audio_work, my_work);
--      int ret = -9;
--
--      switch (w->cmd) {
--      case BCM2835_AUDIO_START:
--              ret = bcm2835_audio_start_worker(w->alsa_stream);
--              break;
--      case BCM2835_AUDIO_STOP:
--              ret = bcm2835_audio_stop_worker(w->alsa_stream);
--              break;
--      case BCM2835_AUDIO_WRITE:
--              ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
--                                               w->src);
--              break;
--      default:
--              LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
--              break;
--      }
--      kfree((void *)work);
--}
--
--int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
--{
--      struct bcm2835_audio_work *work;
--
--      work = kmalloc(sizeof(*work), GFP_ATOMIC);
--      /*--- Queue some work (item 1) ---*/
--      if (!work) {
--              LOG_ERR(" .. Error: NULL work kmalloc\n");
--              return -ENOMEM;
--      }
--      INIT_WORK(&work->my_work, my_wq_function);
--      work->alsa_stream = alsa_stream;
--      work->cmd = BCM2835_AUDIO_START;
--      if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
--              kfree(work);
--              return -EBUSY;
--      }
--      return 0;
--}
--
--int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
--{
--      struct bcm2835_audio_work *work;
--
--      work = kmalloc(sizeof(*work), GFP_ATOMIC);
--      /*--- Queue some work (item 1) ---*/
--      if (!work) {
--              LOG_ERR(" .. Error: NULL work kmalloc\n");
--              return -ENOMEM;
--      }
--      INIT_WORK(&work->my_work, my_wq_function);
--      work->alsa_stream = alsa_stream;
--      work->cmd = BCM2835_AUDIO_STOP;
--      if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
--              kfree(work);
--              return -EBUSY;
--      }
--      return 0;
--}
--
--int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
--                      unsigned int count, void *src)
--{
--      struct bcm2835_audio_work *work;
--
--      work = kmalloc(sizeof(*work), GFP_ATOMIC);
--      /*--- Queue some work (item 1) ---*/
--      if (!work) {
--              LOG_ERR(" .. Error: NULL work kmalloc\n");
--              return -ENOMEM;
--      }
--      INIT_WORK(&work->my_work, my_wq_function);
--      work->alsa_stream = alsa_stream;
--      work->cmd = BCM2835_AUDIO_WRITE;
--      work->src = src;
--      work->count = count;
--      if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
--              kfree(work);
--              return -EBUSY;
--      }
--      return 0;
--}
--
--static void my_workqueue_quit(struct bcm2835_alsa_stream *alsa_stream)
--{
--      flush_workqueue(alsa_stream->my_wq);
--      destroy_workqueue(alsa_stream->my_wq);
--      alsa_stream->my_wq = NULL;
--}
--
- static void audio_vchi_callback(void *param,
-                               const VCHI_CALLBACK_REASON_T reason,
-                               void *msg_handle)
-@@ -249,47 +132,27 @@ static void audio_vchi_callback(void *pa
-       if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
-               return;
--      if (!instance) {
--              LOG_ERR(" .. instance is null\n");
--              BUG();
--              return;
--      }
--      if (!instance->vchi_handle) {
--              LOG_ERR(" .. instance->vchi_handle is null\n");
--              BUG();
--              return;
--      }
-       status = vchi_msg_dequeue(instance->vchi_handle,
-                                 &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;
-               complete(&instance->msg_avail_comp);
-       } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
--              struct bcm2835_alsa_stream *alsa_stream = instance->alsa_stream;
--
--              LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
--                      instance, m.u.complete.count);
-               if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
-                   m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
--                      LOG_ERR(" .. response is corrupt\n");
--              else if (alsa_stream) {
--                      atomic_add(m.u.complete.count,
--                                 &alsa_stream->retrieved);
--                      bcm2835_playback_fifo(alsa_stream);
--              } else {
--                      LOG_ERR(" .. unexpected alsa_stream=%p\n",
--                              alsa_stream);
--              }
-+                      LOG_ERR("invalid cookie\n");
-+              else
-+                      bcm2835_playback_fifo(instance->alsa_stream,
-+                                            m.u.complete.count);
-       } else {
--              LOG_ERR(" .. unexpected m.type=%d\n", m.type);
-+              LOG_ERR("unexpected callback type=%d\n", m.type);
-       }
- }
--static struct bcm2835_audio_instance *
-+static int
- vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
--                 VCHI_CONNECTION_T *vchi_connection)
-+                 VCHI_CONNECTION_T *vchi_connection,
-+                 struct bcm2835_audio_instance *instance)
- {
-       SERVICE_CREATION_T params = {
-               .version                = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
-@@ -298,23 +161,14 @@ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_
-               .rx_fifo_size           = 0,
-               .tx_fifo_size           = 0,
-               .callback               = audio_vchi_callback,
-+              .callback_param         = instance,
-               .want_unaligned_bulk_rx = 1, //TODO: remove VCOS_FALSE
-               .want_unaligned_bulk_tx = 1, //TODO: remove VCOS_FALSE
-               .want_crc               = 0
-       };
--      struct bcm2835_audio_instance *instance;
-       int status;
--      /* Allocate memory for this instance */
--      instance = kzalloc(sizeof(*instance), GFP_KERNEL);
--      if (!instance)
--              return ERR_PTR(-ENOMEM);
--
--      /* Create a lock for exclusive, serialized VCHI connection access */
--      mutex_init(&instance->vchi_mutex);
-       /* Open the VCHI service connections */
--      params.callback_param = instance,
--
-       status = vchi_service_open(vchi_instance, &params,
-                                  &instance->vchi_handle);
-@@ -322,16 +176,16 @@ vc_vchi_audio_init(VCHI_INSTANCE_T vchi_
-               LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
-                       __func__, status);
-               kfree(instance);
--              return ERR_PTR(-EPERM);
-+              return -EPERM;
-       }
-       /* Finished with the service for now */
-       vchi_service_release(instance->vchi_handle);
--      return instance;
-+      return 0;
- }
--static int vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
-+static void vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
- {
-       int status;
-@@ -346,10 +200,6 @@ static int vc_vchi_audio_deinit(struct b
-       }
-       mutex_unlock(&instance->vchi_mutex);
--
--      kfree(instance);
--
--      return 0;
- }
- int bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
-@@ -387,39 +237,25 @@ void bcm2835_free_vchi_ctx(struct bcm283
-       vchi_ctx->vchi_instance = NULL;
- }
--static int bcm2835_audio_open_connection(struct bcm2835_alsa_stream *alsa_stream)
--{
--      struct bcm2835_audio_instance *instance =
--              (struct bcm2835_audio_instance *)alsa_stream->instance;
--      struct bcm2835_vchi_ctx *vhci_ctx = alsa_stream->chip->vchi_ctx;
--
--      /* Initialize an instance of the audio service */
--      instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
--                                    vhci_ctx->vchi_connection);
--
--      if (IS_ERR(instance))
--              return PTR_ERR(instance);
--
--      instance->alsa_stream = alsa_stream;
--      alsa_stream->instance = instance;
--
--      return 0;
--}
--
- int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
- {
-+      struct bcm2835_vchi_ctx *vchi_ctx = alsa_stream->chip->vchi_ctx;
-       struct bcm2835_audio_instance *instance;
-       int err;
--      alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
--      if (!alsa_stream->my_wq)
-+      /* Allocate memory for this instance */
-+      instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-+      if (!instance)
-               return -ENOMEM;
-+      mutex_init(&instance->vchi_mutex);
-+      instance->alsa_stream = alsa_stream;
-+      alsa_stream->instance = instance;
--      err = bcm2835_audio_open_connection(alsa_stream);
-+      err = vc_vchi_audio_init(vchi_ctx->vchi_instance,
-+                               vchi_ctx->vchi_connection,
-+                               instance);
-       if (err < 0)
--              goto free_wq;
--
--      instance = alsa_stream->instance;
-+              goto free_instance;
-       err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
-                                       false);
-@@ -438,8 +274,9 @@ int bcm2835_audio_open(struct bcm2835_al
-  deinit:
-       vc_vchi_audio_deinit(instance);
-- free_wq:
--      destroy_workqueue(alsa_stream->my_wq);
-+ free_instance:
-+      alsa_stream->instance = NULL;
-+      kfree(instance);
-       return err;
- }
-@@ -478,37 +315,46 @@ int bcm2835_audio_set_params(struct bcm2
-       return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
- }
--static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
-+int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
- {
-       return bcm2835_audio_send_simple(alsa_stream->instance,
-                                        VC_AUDIO_MSG_TYPE_START, false);
- }
--static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
-+int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
- {
-       return bcm2835_audio_send_simple(alsa_stream->instance,
-                                        VC_AUDIO_MSG_TYPE_STOP, false);
- }
-+int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream)
-+{
-+      struct vc_audio_msg m = {
-+              .type = VC_AUDIO_MSG_TYPE_STOP,
-+              .u.stop.draining = 1,
-+      };
-+
-+      return bcm2835_audio_send_msg(alsa_stream->instance, &m, false);
-+}
-+
- int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
- {
-       struct bcm2835_audio_instance *instance = alsa_stream->instance;
-       int err;
--      my_workqueue_quit(alsa_stream);
--
-       err = bcm2835_audio_send_simple(alsa_stream->instance,
-                                       VC_AUDIO_MSG_TYPE_CLOSE, true);
-       /* Stop the audio service */
-       vc_vchi_audio_deinit(instance);
-       alsa_stream->instance = NULL;
-+      kfree(instance);
-       return err;
- }
--static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
--                                    unsigned int size, void *src)
-+int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
-+                      unsigned int size, void *src)
- {
-       struct bcm2835_audio_instance *instance = alsa_stream->instance;
-       struct vc_audio_msg m = {
-@@ -558,13 +404,5 @@ static int bcm2835_audio_write_worker(st
-       return err;
- }
--unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
--{
--      unsigned int 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");
---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
-@@ -121,13 +121,12 @@ struct bcm2835_alsa_stream {
-       int draining;
--      unsigned int pos;
-+      atomic_t pos;
-+      unsigned int period_offset;
-       unsigned int buffer_size;
-       unsigned int period_size;
--      atomic_t retrieved;
-       struct bcm2835_audio_instance *instance;
--      struct workqueue_struct *my_wq;
-       int idx;
- };
-@@ -152,11 +151,13 @@ int bcm2835_audio_set_params(struct bcm2
-                            unsigned int bps);
- int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream);
-+int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream);
- int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
-                       unsigned int count,
-                       void *src);
--void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream);
-+void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream,
-+                         unsigned int size);
- unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream);
- #endif /* __SOUND_ARM_BCM2835_H */