1 From 5d42dfcf42ba987a03d8b5f2dfa30e9cb2dc4721 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 061/174] Merge pull request #286 from
5 martinezjavier/rpi-3.6.y-dev
7 add mmap support and some cleanups to bcm2835 ALSA driver
9 sound/arm/bcm2835-pcm.c | 69 ++++++++++++++++++++++--------------
10 sound/arm/bcm2835-vchiq.c | 89 +++++++++++++++++++++++++++++++++--------------
11 sound/arm/bcm2835.c | 34 +++++++++---------
12 sound/arm/bcm2835.h | 2 ++
13 4 files changed, 124 insertions(+), 70 deletions(-)
15 --- a/sound/arm/bcm2835-pcm.c
16 +++ b/sound/arm/bcm2835-pcm.c
19 /* hardware definition */
20 static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
21 - .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER),
22 + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
23 + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
24 .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
25 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
27 @@ -251,6 +252,12 @@ static int snd_bcm2835_pcm_prepare(struc
29 audio_info(" .. IN\n");
31 + memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
33 + alsa_stream->pcm_indirect.hw_buffer_size =
34 + alsa_stream->pcm_indirect.sw_buffer_size =
35 + snd_pcm_lib_buffer_bytes(substream);
37 alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
38 alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
40 @@ -263,6 +270,32 @@ static int snd_bcm2835_pcm_prepare(struc
44 +static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
45 + struct snd_pcm_indirect *rec, size_t bytes)
47 + struct snd_pcm_runtime *runtime = substream->runtime;
48 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
49 + void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
52 + err = bcm2835_audio_write(alsa_stream, bytes, src);
54 + audio_error(" Failed to transfer to alsa device (%d)\n", err);
58 +static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
60 + struct snd_pcm_runtime *runtime = substream->runtime;
61 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
62 + struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
64 + pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
65 + snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
66 + snd_bcm2835_pcm_transfer);
70 /* trigger callback */
71 static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
73 @@ -279,6 +312,11 @@ static int snd_bcm2835_pcm_trigger(struc
74 if (!alsa_stream->running) {
75 err = bcm2835_audio_start(alsa_stream);
77 + alsa_stream->pcm_indirect.hw_io =
78 + alsa_stream->pcm_indirect.hw_data =
79 + bytes_to_frames(runtime,
81 + substream->ops->ack(substream);
82 alsa_stream->running = 1;
83 alsa_stream->draining = 1;
85 @@ -327,30 +365,9 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
88 audio_info(" .. OUT\n");
89 - return bytes_to_frames(runtime, alsa_stream->pos);
92 -static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream,
93 - int channel, snd_pcm_uframes_t pos, void *src,
94 - snd_pcm_uframes_t count)
97 - struct snd_pcm_runtime *runtime = substream->runtime;
98 - bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
100 - audio_info(" .. IN\n");
101 - audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n",
102 - frames_to_bytes(runtime, count), frames_to_bytes(runtime,
106 - frames_to_bytes(runtime, runtime->control->appl_ptr),
109 - bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count),
111 - audio_info(" .. OUT\n");
113 + return snd_pcm_indirect_playback_pointer(substream,
114 + &alsa_stream->pcm_indirect,
118 static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
119 @@ -372,7 +389,7 @@ static struct snd_pcm_ops snd_bcm2835_pl
120 .prepare = snd_bcm2835_pcm_prepare,
121 .trigger = snd_bcm2835_pcm_trigger,
122 .pointer = snd_bcm2835_pcm_pointer,
123 - .copy = snd_bcm2835_pcm_copy,
124 + .ack = snd_bcm2835_pcm_ack,
127 /* create a pcm device */
128 --- a/sound/arm/bcm2835-vchiq.c
129 +++ b/sound/arm/bcm2835-vchiq.c
131 #include <linux/delay.h>
132 #include <linux/atomic.h>
133 #include <linux/module.h>
134 +#include <linux/completion.h>
140 /* ---- Private Constants and Types ------------------------------------------ */
142 +#define BCM2835_AUDIO_STOP 0
143 +#define BCM2835_AUDIO_START 1
144 +#define BCM2835_AUDIO_WRITE 2
146 /* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
147 #ifdef AUDIO_DEBUG_ENABLE
148 #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
150 typedef struct opaque_AUDIO_INSTANCE_T {
151 uint32_t num_connections;
152 VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
153 - struct semaphore msg_avail_event;
154 + struct completion msg_avail_comp;
155 struct mutex vchi_mutex;
156 bcm2835_alsa_stream_t *alsa_stream;
158 @@ -70,27 +75,35 @@ bool force_bulk = false;
160 static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
161 static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
162 +static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
163 + uint32_t count, void *src);
166 struct work_struct my_work;
167 bcm2835_alsa_stream_t *alsa_stream;
174 static void my_wq_function(struct work_struct *work)
176 my_work_t *w = (my_work_t *) work;
178 - LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->x);
181 + LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
183 + case BCM2835_AUDIO_START:
184 ret = bcm2835_audio_start_worker(w->alsa_stream);
187 + case BCM2835_AUDIO_STOP:
188 ret = bcm2835_audio_stop_worker(w->alsa_stream);
190 + case BCM2835_AUDIO_WRITE:
191 + ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
195 - LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->x);
196 + LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
200 @@ -107,7 +120,7 @@ int bcm2835_audio_start(bcm2835_alsa_str
202 INIT_WORK((struct work_struct *)work, my_wq_function);
203 work->alsa_stream = alsa_stream;
205 + work->cmd = BCM2835_AUDIO_START;
207 (alsa_stream->my_wq, (struct work_struct *)work))
209 @@ -128,7 +141,31 @@ int bcm2835_audio_stop(bcm2835_alsa_stre
211 INIT_WORK((struct work_struct *)work, my_wq_function);
212 work->alsa_stream = alsa_stream;
214 + work->cmd = BCM2835_AUDIO_STOP;
216 + (alsa_stream->my_wq, (struct work_struct *)work))
219 + LOG_ERR(" .. Error: NULL work kmalloc\n");
221 + LOG_DBG(" .. OUT %d\n", ret);
225 +int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
226 + uint32_t count, void *src)
229 + LOG_DBG(" .. IN\n");
230 + if (alsa_stream->my_wq) {
231 + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
232 + /*--- Queue some work (item 1) ---*/
234 + INIT_WORK((struct work_struct *)work, my_wq_function);
235 + work->alsa_stream = alsa_stream;
236 + work->cmd = BCM2835_AUDIO_WRITE;
238 + work->count = count;
240 (alsa_stream->my_wq, (struct work_struct *)work))
242 @@ -178,7 +215,7 @@ static void audio_vchi_callback(void *pa
243 (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
244 instance, m.u.result.success);
245 instance->result = m.u.result.success;
246 - up(&instance->msg_avail_event);
247 + complete(&instance->msg_avail_comp);
248 } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
249 irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
251 @@ -435,8 +472,8 @@ static int bcm2835_audio_set_ctls_chan(b
252 m.u.control.dest = chip->dest;
253 m.u.control.volume = chip->volume;
255 - /* Create the message available event */
256 - sema_init(&instance->msg_avail_event, 0);
257 + /* Create the message available completion */
258 + init_completion(&instance->msg_avail_comp);
260 /* Send the message to the videocore */
261 success = vchi_msg_queue(instance->vchi_handle[0],
262 @@ -452,11 +489,10 @@ static int bcm2835_audio_set_ctls_chan(b
265 /* We are expecting a reply from the videocore */
266 - if (down_interruptible(&instance->msg_avail_event)) {
267 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
269 LOG_ERR("%s: failed on waiting for event (status=%d)\n",
276 @@ -539,8 +575,8 @@ int bcm2835_audio_set_params(bcm2835_als
277 m.u.config.samplerate = samplerate;
278 m.u.config.bps = bps;
280 - /* Create the message available event */
281 - sema_init(&instance->msg_avail_event, 0);
282 + /* Create the message available completion */
283 + init_completion(&instance->msg_avail_comp);
285 /* Send the message to the videocore */
286 success = vchi_msg_queue(instance->vchi_handle[0],
287 @@ -556,11 +592,10 @@ int bcm2835_audio_set_params(bcm2835_als
290 /* We are expecting a reply from the videocore */
291 - if (down_interruptible(&instance->msg_avail_event)) {
292 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
294 LOG_ERR("%s: failed on waiting for event (status=%d)\n",
301 @@ -688,8 +723,8 @@ int bcm2835_audio_close(bcm2835_alsa_str
303 m.type = VC_AUDIO_MSG_TYPE_CLOSE;
305 - /* Create the message available event */
306 - sema_init(&instance->msg_avail_event, 0);
307 + /* Create the message available completion */
308 + init_completion(&instance->msg_avail_comp);
310 /* Send the message to the videocore */
311 success = vchi_msg_queue(instance->vchi_handle[0],
312 @@ -702,11 +737,11 @@ int bcm2835_audio_close(bcm2835_alsa_str
316 - if (down_interruptible(&instance->msg_avail_event)) {
318 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
320 LOG_ERR("%s: failed on waiting for event (status=%d)",
326 if (instance->result != 0) {
327 @@ -732,8 +767,8 @@ unlock:
331 -int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
333 +int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
334 + uint32_t count, void *src)
337 AUDIO_INSTANCE_T *instance = alsa_stream->instance;
338 --- a/sound/arm/bcm2835.c
339 +++ b/sound/arm/bcm2835.c
340 @@ -110,20 +110,20 @@ static int snd_bcm2835_alsa_probe(struct
342 err = snd_bcm2835_create(g_card, pdev, &chip);
344 - printk(KERN_ERR "Failed to create bcm2835 chip\n");
345 + dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
346 goto out_bcm2835_create;
350 err = snd_bcm2835_new_pcm(chip);
352 - printk(KERN_ERR "Failed to create new BCM2835 pcm device\n");
353 + dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
354 goto out_bcm2835_new_pcm;
357 err = snd_bcm2835_new_ctl(chip);
359 - printk(KERN_ERR "Failed to create new BCM2835 ctl\n");
360 + dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
361 goto out_bcm2835_new_ctl;
364 @@ -139,14 +139,14 @@ add_register_map:
366 err = snd_card_register(card);
369 - "Failed to register bcm2835 ALSA card \n");
370 + dev_err(&pdev->dev,
371 + "Failed to register bcm2835 ALSA card \n");
372 goto out_card_register;
374 platform_set_drvdata(pdev, card);
375 - printk(KERN_INFO "bcm2835 ALSA card created!\n");
376 + audio_info("bcm2835 ALSA card created!\n");
378 - printk(KERN_INFO "bcm2835 ALSA chip created!\n");
379 + audio_info("bcm2835 ALSA chip created!\n");
380 platform_set_drvdata(pdev, (void *)dev);
383 @@ -160,11 +160,11 @@ out_bcm2835_new_pcm:
386 if (snd_card_free(g_card))
387 - printk(KERN_ERR "Failed to free Registered alsa card\n");
388 + dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
391 dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
392 - printk(KERN_ERR "BCM2835 ALSA Probe failed !!\n");
393 + dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
397 @@ -326,49 +326,49 @@ static int bcm2835_alsa_device_init(void
399 err = platform_driver_register(&bcm2835_alsa0_driver);
401 - printk("Error registering bcm2835_alsa0_driver %d .\n", err);
402 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
406 err = platform_driver_register(&bcm2835_alsa1_driver);
408 - printk("Error registering bcm2835_alsa1_driver %d .\n", err);
409 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
413 err = platform_driver_register(&bcm2835_alsa2_driver);
415 - printk("Error registering bcm2835_alsa2_driver %d .\n", err);
416 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
420 err = platform_driver_register(&bcm2835_alsa3_driver);
422 - printk("Error registering bcm2835_alsa3_driver %d .\n", err);
423 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
427 err = platform_driver_register(&bcm2835_alsa4_driver);
429 - printk("Error registering bcm2835_alsa4_driver %d .\n", err);
430 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
434 err = platform_driver_register(&bcm2835_alsa5_driver);
436 - printk("Error registering bcm2835_alsa5_driver %d .\n", err);
437 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
441 err = platform_driver_register(&bcm2835_alsa6_driver);
443 - printk("Error registering bcm2835_alsa6_driver %d .\n", err);
444 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
448 err = platform_driver_register(&bcm2835_alsa7_driver);
450 - printk("Error registering bcm2835_alsa7_driver %d .\n", err);
451 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
455 --- a/sound/arm/bcm2835.h
456 +++ b/sound/arm/bcm2835.h
458 #include <sound/initval.h>
459 #include <sound/pcm.h>
460 #include <sound/pcm_params.h>
461 +#include <sound/pcm-indirect.h>
462 #include <linux/workqueue.h>
465 @@ -110,6 +111,7 @@ typedef struct bcm2835_chip {
466 typedef struct bcm2835_alsa_stream {
467 bcm2835_chip_t *chip;
468 struct snd_pcm_substream *substream;
469 + struct snd_pcm_indirect pcm_indirect;
471 struct semaphore buffers_update_sem;
472 struct semaphore control_sem;