aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-3.14/0010-alsa-add-mmap-support-and-some-cleanups-to-bcm2835-A.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-3.14/0010-alsa-add-mmap-support-and-some-cleanups-to-bcm2835-A.patch')
-rw-r--r--target/linux/brcm2708/patches-3.14/0010-alsa-add-mmap-support-and-some-cleanups-to-bcm2835-A.patch482
1 files changed, 482 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-3.14/0010-alsa-add-mmap-support-and-some-cleanups-to-bcm2835-A.patch b/target/linux/brcm2708/patches-3.14/0010-alsa-add-mmap-support-and-some-cleanups-to-bcm2835-A.patch
new file mode 100644
index 0000000000..509816e3aa
--- /dev/null
+++ b/target/linux/brcm2708/patches-3.14/0010-alsa-add-mmap-support-and-some-cleanups-to-bcm2835-A.patch
@@ -0,0 +1,482 @@
+From 00d2b7bf3cd58d9735f103ff4cc6982b7dc927fe Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Fri, 26 Apr 2013 10:08:31 -0700
+Subject: [PATCH 10/54] alsa: add mmap support and some cleanups to bcm2835
+ ALSA driver
+
+---
+ sound/arm/bcm2835-pcm.c | 69 ++++++++++++++++++++++--------------
+ sound/arm/bcm2835-vchiq.c | 89 +++++++++++++++++++++++++++++++++--------------
+ sound/arm/bcm2835.c | 34 +++++++++---------
+ sound/arm/bcm2835.h | 2 ++
+ 4 files changed, 124 insertions(+), 70 deletions(-)
+
+diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c
+index 2e7d405..b4084bb 100755
+--- a/sound/arm/bcm2835-pcm.c
++++ b/sound/arm/bcm2835-pcm.c
+@@ -19,7 +19,8 @@
+
+ /* hardware definition */
+ static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
+- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER),
++ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+@@ -251,6 +252,12 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
+
+ audio_info(" .. IN\n");
+
++ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
++
++ alsa_stream->pcm_indirect.hw_buffer_size =
++ alsa_stream->pcm_indirect.sw_buffer_size =
++ snd_pcm_lib_buffer_bytes(substream);
++
+ alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
+ alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
+ alsa_stream->pos = 0;
+@@ -263,6 +270,32 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
+ return 0;
+ }
+
++static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
++ struct snd_pcm_indirect *rec, size_t bytes)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
++ void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
++ int err;
++
++ err = bcm2835_audio_write(alsa_stream, bytes, src);
++ if (err)
++ audio_error(" Failed to transfer to alsa device (%d)\n", err);
++
++}
++
++static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
++ struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
++
++ pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
++ snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
++ snd_bcm2835_pcm_transfer);
++ return 0;
++}
++
+ /* trigger callback */
+ static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+ {
+@@ -279,6 +312,11 @@ static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+ if (!alsa_stream->running) {
+ err = bcm2835_audio_start(alsa_stream);
+ if (err == 0) {
++ alsa_stream->pcm_indirect.hw_io =
++ alsa_stream->pcm_indirect.hw_data =
++ bytes_to_frames(runtime,
++ alsa_stream->pos);
++ substream->ops->ack(substream);
+ alsa_stream->running = 1;
+ alsa_stream->draining = 1;
+ } else {
+@@ -327,30 +365,9 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
+ 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;
++ return snd_pcm_indirect_playback_pointer(substream,
++ &alsa_stream->pcm_indirect,
++ alsa_stream->pos);
+ }
+
+ static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
+@@ -372,7 +389,7 @@ static struct snd_pcm_ops snd_bcm2835_playback_ops = {
+ .prepare = snd_bcm2835_pcm_prepare,
+ .trigger = snd_bcm2835_pcm_trigger,
+ .pointer = snd_bcm2835_pcm_pointer,
+- .copy = snd_bcm2835_pcm_copy,
++ .ack = snd_bcm2835_pcm_ack,
+ };
+
+ /* create a pcm device */
+diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c
+index b9b4fe8..ee09b13 100755
+--- a/sound/arm/bcm2835-vchiq.c
++++ b/sound/arm/bcm2835-vchiq.c
+@@ -27,6 +27,7 @@
+ #include <linux/delay.h>
+ #include <linux/atomic.h>
+ #include <linux/module.h>
++#include <linux/completion.h>
+
+ #include "bcm2835.h"
+
+@@ -37,6 +38,10 @@
+
+ /* ---- 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)
+@@ -53,7 +58,7 @@
+ 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 completion msg_avail_comp;
+ struct mutex vchi_mutex;
+ bcm2835_alsa_stream_t *alsa_stream;
+ int32_t result;
+@@ -70,27 +75,35 @@ bool force_bulk = false;
+
+ static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
+ static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
++static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
++ uint32_t count, void *src);
+
+ typedef struct {
+ struct work_struct my_work;
+ bcm2835_alsa_stream_t *alsa_stream;
+- int x;
++ int cmd;
++ void *src;
++ uint32_t count;
+ } 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:
++ LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
++ switch (w->cmd) {
++ case BCM2835_AUDIO_START:
+ ret = bcm2835_audio_start_worker(w->alsa_stream);
+ break;
+- case 2:
++ 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->x);
++ LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
+ break;
+ }
+ kfree((void *)work);
+@@ -107,7 +120,7 @@ int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
+ if (work) {
+ INIT_WORK((struct work_struct *)work, my_wq_function);
+ work->alsa_stream = alsa_stream;
+- work->x = 1;
++ work->cmd = BCM2835_AUDIO_START;
+ if (queue_work
+ (alsa_stream->my_wq, (struct work_struct *)work))
+ ret = 0;
+@@ -128,7 +141,31 @@ int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
+ if (work) {
+ INIT_WORK((struct work_struct *)work, my_wq_function);
+ work->alsa_stream = alsa_stream;
+- work->x = 2;
++ work->cmd = BCM2835_AUDIO_STOP;
++ 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_write(bcm2835_alsa_stream_t *alsa_stream,
++ uint32_t count, void *src)
++{
++ 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->cmd = BCM2835_AUDIO_WRITE;
++ work->src = src;
++ work->count = count;
+ if (queue_work
+ (alsa_stream->my_wq, (struct work_struct *)work))
+ ret = 0;
+@@ -178,7 +215,7 @@ static void audio_vchi_callback(void *param,
+ (" .. 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);
++ complete(&instance->msg_avail_comp);
+ } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
+ irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
+ LOG_DBG
+@@ -435,8 +472,8 @@ static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
+ m.u.control.dest = chip->dest;
+ m.u.control.volume = chip->volume;
+
+- /* Create the message available event */
+- sema_init(&instance->msg_avail_event, 0);
++ /* Create the message available completion */
++ init_completion(&instance->msg_avail_comp);
+
+ /* Send the message to the videocore */
+ success = vchi_msg_queue(instance->vchi_handle[0],
+@@ -452,11 +489,10 @@ static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
+ }
+
+ /* We are expecting a reply from the videocore */
+- if (down_interruptible(&instance->msg_avail_event)) {
++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
++ if (ret) {
+ LOG_ERR("%s: failed on waiting for event (status=%d)\n",
+ __func__, success);
+-
+- ret = -1;
+ goto unlock;
+ }
+
+@@ -539,8 +575,8 @@ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
+ m.u.config.samplerate = samplerate;
+ m.u.config.bps = bps;
+
+- /* Create the message available event */
+- sema_init(&instance->msg_avail_event, 0);
++ /* Create the message available completion */
++ init_completion(&instance->msg_avail_comp);
+
+ /* Send the message to the videocore */
+ success = vchi_msg_queue(instance->vchi_handle[0],
+@@ -556,11 +592,10 @@ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
+ }
+
+ /* We are expecting a reply from the videocore */
+- if (down_interruptible(&instance->msg_avail_event)) {
++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
++ if (ret) {
+ LOG_ERR("%s: failed on waiting for event (status=%d)\n",
+ __func__, success);
+-
+- ret = -1;
+ goto unlock;
+ }
+
+@@ -688,8 +723,8 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
+
+ m.type = VC_AUDIO_MSG_TYPE_CLOSE;
+
+- /* Create the message available event */
+- sema_init(&instance->msg_avail_event, 0);
++ /* Create the message available completion */
++ init_completion(&instance->msg_avail_comp);
+
+ /* Send the message to the videocore */
+ success = vchi_msg_queue(instance->vchi_handle[0],
+@@ -702,11 +737,11 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
+ ret = -1;
+ goto unlock;
+ }
+- if (down_interruptible(&instance->msg_avail_event)) {
++
++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
++ if (ret) {
+ LOG_ERR("%s: failed on waiting for event (status=%d)",
+ __func__, success);
+-
+- ret = -1;
+ goto unlock;
+ }
+ if (instance->result != 0) {
+@@ -732,8 +767,8 @@ unlock:
+ return ret;
+ }
+
+-int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
+- void *src)
++int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
++ uint32_t count, void *src)
+ {
+ VC_AUDIO_MSG_T m;
+ AUDIO_INSTANCE_T *instance = alsa_stream->instance;
+diff --git a/sound/arm/bcm2835.c b/sound/arm/bcm2835.c
+index 317e7d9..e2047a7 100755
+--- a/sound/arm/bcm2835.c
++++ b/sound/arm/bcm2835.c
+@@ -110,20 +110,20 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
+
+ err = snd_bcm2835_create(g_card, pdev, &chip);
+ if (err < 0) {
+- printk(KERN_ERR "Failed to create bcm2835 chip\n");
++ dev_err(&pdev->dev, "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");
++ dev_err(&pdev->dev, "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");
++ dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
+ goto out_bcm2835_new_ctl;
+ }
+
+@@ -139,14 +139,14 @@ add_register_map:
+ if (dev == 0) {
+ err = snd_card_register(card);
+ if (err < 0) {
+- printk(KERN_ERR
+- "Failed to register bcm2835 ALSA card \n");
++ dev_err(&pdev->dev,
++ "Failed to register bcm2835 ALSA card \n");
+ goto out_card_register;
+ }
+ platform_set_drvdata(pdev, card);
+- printk(KERN_INFO "bcm2835 ALSA card created!\n");
++ audio_info("bcm2835 ALSA card created!\n");
+ } else {
+- printk(KERN_INFO "bcm2835 ALSA chip created!\n");
++ audio_info("bcm2835 ALSA chip created!\n");
+ platform_set_drvdata(pdev, (void *)dev);
+ }
+
+@@ -160,11 +160,11 @@ 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");
++ dev_err(&pdev->dev, "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");
++ dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
+ return err;
+ }
+
+@@ -326,49 +326,49 @@ 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);
++ pr_err("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);
++ pr_err("Error registering bcm2835_alsa0_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);
++ pr_err("Error registering bcm2835_alsa0_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);
++ pr_err("Error registering bcm2835_alsa0_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);
++ pr_err("Error registering bcm2835_alsa0_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);
++ pr_err("Error registering bcm2835_alsa0_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);
++ pr_err("Error registering bcm2835_alsa0_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);
++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
+ goto unregister_6;
+ }
+
+diff --git a/sound/arm/bcm2835.h b/sound/arm/bcm2835.h
+index 080bd5c..36afee3 100755
+--- a/sound/arm/bcm2835.h
++++ b/sound/arm/bcm2835.h
+@@ -23,6 +23,7 @@
+ #include <sound/initval.h>
+ #include <sound/pcm.h>
+ #include <sound/pcm_params.h>
++#include <sound/pcm-indirect.h>
+ #include <linux/workqueue.h>
+
+ /*
+@@ -110,6 +111,7 @@ typedef struct bcm2835_chip {
+ typedef struct bcm2835_alsa_stream {
+ bcm2835_chip_t *chip;
+ struct snd_pcm_substream *substream;
++ struct snd_pcm_indirect pcm_indirect;
+
+ struct semaphore buffers_update_sem;
+ struct semaphore control_sem;
+--
+1.9.1
+