1 From 00d2b7bf3cd58d9735f103ff4cc6982b7dc927fe Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Fri, 26 Apr 2013 10:08:31 -0700
4 Subject: [PATCH 10/54] alsa: add mmap support and some cleanups to bcm2835
8 sound/arm/bcm2835-pcm.c | 69 ++++++++++++++++++++++--------------
9 sound/arm/bcm2835-vchiq.c | 89 +++++++++++++++++++++++++++++++++--------------
10 sound/arm/bcm2835.c | 34 +++++++++---------
11 sound/arm/bcm2835.h | 2 ++
12 4 files changed, 124 insertions(+), 70 deletions(-)
14 --- a/sound/arm/bcm2835-pcm.c
15 +++ b/sound/arm/bcm2835-pcm.c
18 /* hardware definition */
19 static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
20 - .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER),
21 + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
22 + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
23 .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
24 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
26 @@ -251,6 +252,12 @@ static int snd_bcm2835_pcm_prepare(struc
28 audio_info(" .. IN\n");
30 + memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
32 + alsa_stream->pcm_indirect.hw_buffer_size =
33 + alsa_stream->pcm_indirect.sw_buffer_size =
34 + snd_pcm_lib_buffer_bytes(substream);
36 alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
37 alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
39 @@ -263,6 +270,32 @@ static int snd_bcm2835_pcm_prepare(struc
43 +static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
44 + struct snd_pcm_indirect *rec, size_t bytes)
46 + struct snd_pcm_runtime *runtime = substream->runtime;
47 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
48 + void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
51 + err = bcm2835_audio_write(alsa_stream, bytes, src);
53 + audio_error(" Failed to transfer to alsa device (%d)\n", err);
57 +static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
59 + struct snd_pcm_runtime *runtime = substream->runtime;
60 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
61 + struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
63 + pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
64 + snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
65 + snd_bcm2835_pcm_transfer);
69 /* trigger callback */
70 static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
72 @@ -279,6 +312,11 @@ static int snd_bcm2835_pcm_trigger(struc
73 if (!alsa_stream->running) {
74 err = bcm2835_audio_start(alsa_stream);
76 + alsa_stream->pcm_indirect.hw_io =
77 + alsa_stream->pcm_indirect.hw_data =
78 + bytes_to_frames(runtime,
80 + substream->ops->ack(substream);
81 alsa_stream->running = 1;
82 alsa_stream->draining = 1;
84 @@ -327,30 +365,9 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
87 audio_info(" .. OUT\n");
88 - return bytes_to_frames(runtime, alsa_stream->pos);
91 -static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream,
92 - int channel, snd_pcm_uframes_t pos, void *src,
93 - snd_pcm_uframes_t count)
96 - struct snd_pcm_runtime *runtime = substream->runtime;
97 - bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
99 - audio_info(" .. IN\n");
100 - audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n",
101 - frames_to_bytes(runtime, count), frames_to_bytes(runtime,
105 - frames_to_bytes(runtime, runtime->control->appl_ptr),
108 - bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count),
110 - audio_info(" .. OUT\n");
112 + return snd_pcm_indirect_playback_pointer(substream,
113 + &alsa_stream->pcm_indirect,
117 static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
118 @@ -372,7 +389,7 @@ static struct snd_pcm_ops snd_bcm2835_pl
119 .prepare = snd_bcm2835_pcm_prepare,
120 .trigger = snd_bcm2835_pcm_trigger,
121 .pointer = snd_bcm2835_pcm_pointer,
122 - .copy = snd_bcm2835_pcm_copy,
123 + .ack = snd_bcm2835_pcm_ack,
126 /* create a pcm device */
127 --- a/sound/arm/bcm2835-vchiq.c
128 +++ b/sound/arm/bcm2835-vchiq.c
130 #include <linux/delay.h>
131 #include <linux/atomic.h>
132 #include <linux/module.h>
133 +#include <linux/completion.h>
139 /* ---- Private Constants and Types ------------------------------------------ */
141 +#define BCM2835_AUDIO_STOP 0
142 +#define BCM2835_AUDIO_START 1
143 +#define BCM2835_AUDIO_WRITE 2
145 /* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
146 #ifdef AUDIO_DEBUG_ENABLE
147 #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
149 typedef struct opaque_AUDIO_INSTANCE_T {
150 uint32_t num_connections;
151 VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
152 - struct semaphore msg_avail_event;
153 + struct completion msg_avail_comp;
154 struct mutex vchi_mutex;
155 bcm2835_alsa_stream_t *alsa_stream;
157 @@ -70,27 +75,35 @@ bool force_bulk = false;
159 static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
160 static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
161 +static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
162 + uint32_t count, void *src);
165 struct work_struct my_work;
166 bcm2835_alsa_stream_t *alsa_stream;
173 static void my_wq_function(struct work_struct *work)
175 my_work_t *w = (my_work_t *) work;
177 - LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->x);
180 + LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
182 + case BCM2835_AUDIO_START:
183 ret = bcm2835_audio_start_worker(w->alsa_stream);
186 + case BCM2835_AUDIO_STOP:
187 ret = bcm2835_audio_stop_worker(w->alsa_stream);
189 + case BCM2835_AUDIO_WRITE:
190 + ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
194 - LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->x);
195 + LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
199 @@ -107,7 +120,7 @@ int bcm2835_audio_start(bcm2835_alsa_str
201 INIT_WORK((struct work_struct *)work, my_wq_function);
202 work->alsa_stream = alsa_stream;
204 + work->cmd = BCM2835_AUDIO_START;
206 (alsa_stream->my_wq, (struct work_struct *)work))
208 @@ -128,7 +141,31 @@ int bcm2835_audio_stop(bcm2835_alsa_stre
210 INIT_WORK((struct work_struct *)work, my_wq_function);
211 work->alsa_stream = alsa_stream;
213 + work->cmd = BCM2835_AUDIO_STOP;
215 + (alsa_stream->my_wq, (struct work_struct *)work))
218 + LOG_ERR(" .. Error: NULL work kmalloc\n");
220 + LOG_DBG(" .. OUT %d\n", ret);
224 +int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
225 + uint32_t count, void *src)
228 + LOG_DBG(" .. IN\n");
229 + if (alsa_stream->my_wq) {
230 + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
231 + /*--- Queue some work (item 1) ---*/
233 + INIT_WORK((struct work_struct *)work, my_wq_function);
234 + work->alsa_stream = alsa_stream;
235 + work->cmd = BCM2835_AUDIO_WRITE;
237 + work->count = count;
239 (alsa_stream->my_wq, (struct work_struct *)work))
241 @@ -178,7 +215,7 @@ static void audio_vchi_callback(void *pa
242 (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
243 instance, m.u.result.success);
244 instance->result = m.u.result.success;
245 - up(&instance->msg_avail_event);
246 + complete(&instance->msg_avail_comp);
247 } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
248 irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
250 @@ -435,8 +472,8 @@ static int bcm2835_audio_set_ctls_chan(b
251 m.u.control.dest = chip->dest;
252 m.u.control.volume = chip->volume;
254 - /* Create the message available event */
255 - sema_init(&instance->msg_avail_event, 0);
256 + /* Create the message available completion */
257 + init_completion(&instance->msg_avail_comp);
259 /* Send the message to the videocore */
260 success = vchi_msg_queue(instance->vchi_handle[0],
261 @@ -452,11 +489,10 @@ static int bcm2835_audio_set_ctls_chan(b
264 /* We are expecting a reply from the videocore */
265 - if (down_interruptible(&instance->msg_avail_event)) {
266 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
268 LOG_ERR("%s: failed on waiting for event (status=%d)\n",
275 @@ -539,8 +575,8 @@ int bcm2835_audio_set_params(bcm2835_als
276 m.u.config.samplerate = samplerate;
277 m.u.config.bps = bps;
279 - /* Create the message available event */
280 - sema_init(&instance->msg_avail_event, 0);
281 + /* Create the message available completion */
282 + init_completion(&instance->msg_avail_comp);
284 /* Send the message to the videocore */
285 success = vchi_msg_queue(instance->vchi_handle[0],
286 @@ -556,11 +592,10 @@ int bcm2835_audio_set_params(bcm2835_als
289 /* We are expecting a reply from the videocore */
290 - if (down_interruptible(&instance->msg_avail_event)) {
291 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
293 LOG_ERR("%s: failed on waiting for event (status=%d)\n",
300 @@ -688,8 +723,8 @@ int bcm2835_audio_close(bcm2835_alsa_str
302 m.type = VC_AUDIO_MSG_TYPE_CLOSE;
304 - /* Create the message available event */
305 - sema_init(&instance->msg_avail_event, 0);
306 + /* Create the message available completion */
307 + init_completion(&instance->msg_avail_comp);
309 /* Send the message to the videocore */
310 success = vchi_msg_queue(instance->vchi_handle[0],
311 @@ -702,11 +737,11 @@ int bcm2835_audio_close(bcm2835_alsa_str
315 - if (down_interruptible(&instance->msg_avail_event)) {
317 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
319 LOG_ERR("%s: failed on waiting for event (status=%d)",
325 if (instance->result != 0) {
326 @@ -732,8 +767,8 @@ unlock:
330 -int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
332 +int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
333 + uint32_t count, void *src)
336 AUDIO_INSTANCE_T *instance = alsa_stream->instance;
337 --- a/sound/arm/bcm2835.c
338 +++ b/sound/arm/bcm2835.c
339 @@ -110,20 +110,20 @@ static int snd_bcm2835_alsa_probe(struct
341 err = snd_bcm2835_create(g_card, pdev, &chip);
343 - printk(KERN_ERR "Failed to create bcm2835 chip\n");
344 + dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
345 goto out_bcm2835_create;
349 err = snd_bcm2835_new_pcm(chip);
351 - printk(KERN_ERR "Failed to create new BCM2835 pcm device\n");
352 + dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
353 goto out_bcm2835_new_pcm;
356 err = snd_bcm2835_new_ctl(chip);
358 - printk(KERN_ERR "Failed to create new BCM2835 ctl\n");
359 + dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
360 goto out_bcm2835_new_ctl;
363 @@ -139,14 +139,14 @@ add_register_map:
365 err = snd_card_register(card);
368 - "Failed to register bcm2835 ALSA card \n");
369 + dev_err(&pdev->dev,
370 + "Failed to register bcm2835 ALSA card \n");
371 goto out_card_register;
373 platform_set_drvdata(pdev, card);
374 - printk(KERN_INFO "bcm2835 ALSA card created!\n");
375 + audio_info("bcm2835 ALSA card created!\n");
377 - printk(KERN_INFO "bcm2835 ALSA chip created!\n");
378 + audio_info("bcm2835 ALSA chip created!\n");
379 platform_set_drvdata(pdev, (void *)dev);
382 @@ -160,11 +160,11 @@ out_bcm2835_new_pcm:
385 if (snd_card_free(g_card))
386 - printk(KERN_ERR "Failed to free Registered alsa card\n");
387 + dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
390 dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
391 - printk(KERN_ERR "BCM2835 ALSA Probe failed !!\n");
392 + dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
396 @@ -326,49 +326,49 @@ static int bcm2835_alsa_device_init(void
398 err = platform_driver_register(&bcm2835_alsa0_driver);
400 - printk("Error registering bcm2835_alsa0_driver %d .\n", err);
401 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
405 err = platform_driver_register(&bcm2835_alsa1_driver);
407 - printk("Error registering bcm2835_alsa1_driver %d .\n", err);
408 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
412 err = platform_driver_register(&bcm2835_alsa2_driver);
414 - printk("Error registering bcm2835_alsa2_driver %d .\n", err);
415 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
419 err = platform_driver_register(&bcm2835_alsa3_driver);
421 - printk("Error registering bcm2835_alsa3_driver %d .\n", err);
422 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
426 err = platform_driver_register(&bcm2835_alsa4_driver);
428 - printk("Error registering bcm2835_alsa4_driver %d .\n", err);
429 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
433 err = platform_driver_register(&bcm2835_alsa5_driver);
435 - printk("Error registering bcm2835_alsa5_driver %d .\n", err);
436 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
440 err = platform_driver_register(&bcm2835_alsa6_driver);
442 - printk("Error registering bcm2835_alsa6_driver %d .\n", err);
443 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
447 err = platform_driver_register(&bcm2835_alsa7_driver);
449 - printk("Error registering bcm2835_alsa7_driver %d .\n", err);
450 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
454 --- a/sound/arm/bcm2835.h
455 +++ b/sound/arm/bcm2835.h
457 #include <sound/initval.h>
458 #include <sound/pcm.h>
459 #include <sound/pcm_params.h>
460 +#include <sound/pcm-indirect.h>
461 #include <linux/workqueue.h>
464 @@ -110,6 +111,7 @@ typedef struct bcm2835_chip {
465 typedef struct bcm2835_alsa_stream {
466 bcm2835_chip_t *chip;
467 struct snd_pcm_substream *substream;
468 + struct snd_pcm_indirect pcm_indirect;
470 struct semaphore buffers_update_sem;
471 struct semaphore control_sem;