diff options
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.patch | 482 |
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 + |