509816e3aa9f39c3b4d2b23203b7252bb8ae0cd2
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-3.14 / 0010-alsa-add-mmap-support-and-some-cleanups-to-bcm2835-A.patch
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
5 ALSA driver
6
7 ---
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(-)
13
14 diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c
15 index 2e7d405..b4084bb 100755
16 --- a/sound/arm/bcm2835-pcm.c
17 +++ b/sound/arm/bcm2835-pcm.c
18 @@ -19,7 +19,8 @@
19
20 /* hardware definition */
21 static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
22 - .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER),
23 + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
24 + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
25 .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
26 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
27 .rate_min = 8000,
28 @@ -251,6 +252,12 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
29
30 audio_info(" .. IN\n");
31
32 + memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
33 +
34 + alsa_stream->pcm_indirect.hw_buffer_size =
35 + alsa_stream->pcm_indirect.sw_buffer_size =
36 + snd_pcm_lib_buffer_bytes(substream);
37 +
38 alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
39 alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
40 alsa_stream->pos = 0;
41 @@ -263,6 +270,32 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
42 return 0;
43 }
44
45 +static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
46 + struct snd_pcm_indirect *rec, size_t bytes)
47 +{
48 + struct snd_pcm_runtime *runtime = substream->runtime;
49 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
50 + void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
51 + int err;
52 +
53 + err = bcm2835_audio_write(alsa_stream, bytes, src);
54 + if (err)
55 + audio_error(" Failed to transfer to alsa device (%d)\n", err);
56 +
57 +}
58 +
59 +static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
60 +{
61 + struct snd_pcm_runtime *runtime = substream->runtime;
62 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
63 + struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
64 +
65 + pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
66 + snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
67 + snd_bcm2835_pcm_transfer);
68 + return 0;
69 +}
70 +
71 /* trigger callback */
72 static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
73 {
74 @@ -279,6 +312,11 @@ static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
75 if (!alsa_stream->running) {
76 err = bcm2835_audio_start(alsa_stream);
77 if (err == 0) {
78 + alsa_stream->pcm_indirect.hw_io =
79 + alsa_stream->pcm_indirect.hw_data =
80 + bytes_to_frames(runtime,
81 + alsa_stream->pos);
82 + substream->ops->ack(substream);
83 alsa_stream->running = 1;
84 alsa_stream->draining = 1;
85 } else {
86 @@ -327,30 +365,9 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
87 alsa_stream->pos);
88
89 audio_info(" .. OUT\n");
90 - return bytes_to_frames(runtime, alsa_stream->pos);
91 -}
92 -
93 -static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream,
94 - int channel, snd_pcm_uframes_t pos, void *src,
95 - snd_pcm_uframes_t count)
96 -{
97 - int ret;
98 - struct snd_pcm_runtime *runtime = substream->runtime;
99 - bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
100 -
101 - audio_info(" .. IN\n");
102 - audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n",
103 - frames_to_bytes(runtime, count), frames_to_bytes(runtime,
104 - runtime->
105 - status->
106 - hw_ptr),
107 - frames_to_bytes(runtime, runtime->control->appl_ptr),
108 - alsa_stream->pos);
109 - ret =
110 - bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count),
111 - src);
112 - audio_info(" .. OUT\n");
113 - return ret;
114 + return snd_pcm_indirect_playback_pointer(substream,
115 + &alsa_stream->pcm_indirect,
116 + alsa_stream->pos);
117 }
118
119 static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
120 @@ -372,7 +389,7 @@ static struct snd_pcm_ops snd_bcm2835_playback_ops = {
121 .prepare = snd_bcm2835_pcm_prepare,
122 .trigger = snd_bcm2835_pcm_trigger,
123 .pointer = snd_bcm2835_pcm_pointer,
124 - .copy = snd_bcm2835_pcm_copy,
125 + .ack = snd_bcm2835_pcm_ack,
126 };
127
128 /* create a pcm device */
129 diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c
130 index b9b4fe8..ee09b13 100755
131 --- a/sound/arm/bcm2835-vchiq.c
132 +++ b/sound/arm/bcm2835-vchiq.c
133 @@ -27,6 +27,7 @@
134 #include <linux/delay.h>
135 #include <linux/atomic.h>
136 #include <linux/module.h>
137 +#include <linux/completion.h>
138
139 #include "bcm2835.h"
140
141 @@ -37,6 +38,10 @@
142
143 /* ---- Private Constants and Types ------------------------------------------ */
144
145 +#define BCM2835_AUDIO_STOP 0
146 +#define BCM2835_AUDIO_START 1
147 +#define BCM2835_AUDIO_WRITE 2
148 +
149 /* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
150 #ifdef AUDIO_DEBUG_ENABLE
151 #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
152 @@ -53,7 +58,7 @@
153 typedef struct opaque_AUDIO_INSTANCE_T {
154 uint32_t num_connections;
155 VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
156 - struct semaphore msg_avail_event;
157 + struct completion msg_avail_comp;
158 struct mutex vchi_mutex;
159 bcm2835_alsa_stream_t *alsa_stream;
160 int32_t result;
161 @@ -70,27 +75,35 @@ bool force_bulk = false;
162
163 static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
164 static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
165 +static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
166 + uint32_t count, void *src);
167
168 typedef struct {
169 struct work_struct my_work;
170 bcm2835_alsa_stream_t *alsa_stream;
171 - int x;
172 + int cmd;
173 + void *src;
174 + uint32_t count;
175 } my_work_t;
176
177 static void my_wq_function(struct work_struct *work)
178 {
179 my_work_t *w = (my_work_t *) work;
180 int ret = -9;
181 - LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->x);
182 - switch (w->x) {
183 - case 1:
184 + LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
185 + switch (w->cmd) {
186 + case BCM2835_AUDIO_START:
187 ret = bcm2835_audio_start_worker(w->alsa_stream);
188 break;
189 - case 2:
190 + case BCM2835_AUDIO_STOP:
191 ret = bcm2835_audio_stop_worker(w->alsa_stream);
192 break;
193 + case BCM2835_AUDIO_WRITE:
194 + ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
195 + w->src);
196 + break;
197 default:
198 - LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->x);
199 + LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
200 break;
201 }
202 kfree((void *)work);
203 @@ -107,7 +120,7 @@ int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
204 if (work) {
205 INIT_WORK((struct work_struct *)work, my_wq_function);
206 work->alsa_stream = alsa_stream;
207 - work->x = 1;
208 + work->cmd = BCM2835_AUDIO_START;
209 if (queue_work
210 (alsa_stream->my_wq, (struct work_struct *)work))
211 ret = 0;
212 @@ -128,7 +141,31 @@ int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
213 if (work) {
214 INIT_WORK((struct work_struct *)work, my_wq_function);
215 work->alsa_stream = alsa_stream;
216 - work->x = 2;
217 + work->cmd = BCM2835_AUDIO_STOP;
218 + if (queue_work
219 + (alsa_stream->my_wq, (struct work_struct *)work))
220 + ret = 0;
221 + } else
222 + LOG_ERR(" .. Error: NULL work kmalloc\n");
223 + }
224 + LOG_DBG(" .. OUT %d\n", ret);
225 + return ret;
226 +}
227 +
228 +int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
229 + uint32_t count, void *src)
230 +{
231 + int ret = -1;
232 + LOG_DBG(" .. IN\n");
233 + if (alsa_stream->my_wq) {
234 + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
235 + /*--- Queue some work (item 1) ---*/
236 + if (work) {
237 + INIT_WORK((struct work_struct *)work, my_wq_function);
238 + work->alsa_stream = alsa_stream;
239 + work->cmd = BCM2835_AUDIO_WRITE;
240 + work->src = src;
241 + work->count = count;
242 if (queue_work
243 (alsa_stream->my_wq, (struct work_struct *)work))
244 ret = 0;
245 @@ -178,7 +215,7 @@ static void audio_vchi_callback(void *param,
246 (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
247 instance, m.u.result.success);
248 instance->result = m.u.result.success;
249 - up(&instance->msg_avail_event);
250 + complete(&instance->msg_avail_comp);
251 } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
252 irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
253 LOG_DBG
254 @@ -435,8 +472,8 @@ static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
255 m.u.control.dest = chip->dest;
256 m.u.control.volume = chip->volume;
257
258 - /* Create the message available event */
259 - sema_init(&instance->msg_avail_event, 0);
260 + /* Create the message available completion */
261 + init_completion(&instance->msg_avail_comp);
262
263 /* Send the message to the videocore */
264 success = vchi_msg_queue(instance->vchi_handle[0],
265 @@ -452,11 +489,10 @@ static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
266 }
267
268 /* We are expecting a reply from the videocore */
269 - if (down_interruptible(&instance->msg_avail_event)) {
270 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
271 + if (ret) {
272 LOG_ERR("%s: failed on waiting for event (status=%d)\n",
273 __func__, success);
274 -
275 - ret = -1;
276 goto unlock;
277 }
278
279 @@ -539,8 +575,8 @@ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
280 m.u.config.samplerate = samplerate;
281 m.u.config.bps = bps;
282
283 - /* Create the message available event */
284 - sema_init(&instance->msg_avail_event, 0);
285 + /* Create the message available completion */
286 + init_completion(&instance->msg_avail_comp);
287
288 /* Send the message to the videocore */
289 success = vchi_msg_queue(instance->vchi_handle[0],
290 @@ -556,11 +592,10 @@ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
291 }
292
293 /* We are expecting a reply from the videocore */
294 - if (down_interruptible(&instance->msg_avail_event)) {
295 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
296 + if (ret) {
297 LOG_ERR("%s: failed on waiting for event (status=%d)\n",
298 __func__, success);
299 -
300 - ret = -1;
301 goto unlock;
302 }
303
304 @@ -688,8 +723,8 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
305
306 m.type = VC_AUDIO_MSG_TYPE_CLOSE;
307
308 - /* Create the message available event */
309 - sema_init(&instance->msg_avail_event, 0);
310 + /* Create the message available completion */
311 + init_completion(&instance->msg_avail_comp);
312
313 /* Send the message to the videocore */
314 success = vchi_msg_queue(instance->vchi_handle[0],
315 @@ -702,11 +737,11 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
316 ret = -1;
317 goto unlock;
318 }
319 - if (down_interruptible(&instance->msg_avail_event)) {
320 +
321 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
322 + if (ret) {
323 LOG_ERR("%s: failed on waiting for event (status=%d)",
324 __func__, success);
325 -
326 - ret = -1;
327 goto unlock;
328 }
329 if (instance->result != 0) {
330 @@ -732,8 +767,8 @@ unlock:
331 return ret;
332 }
333
334 -int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
335 - void *src)
336 +int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
337 + uint32_t count, void *src)
338 {
339 VC_AUDIO_MSG_T m;
340 AUDIO_INSTANCE_T *instance = alsa_stream->instance;
341 diff --git a/sound/arm/bcm2835.c b/sound/arm/bcm2835.c
342 index 317e7d9..e2047a7 100755
343 --- a/sound/arm/bcm2835.c
344 +++ b/sound/arm/bcm2835.c
345 @@ -110,20 +110,20 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
346
347 err = snd_bcm2835_create(g_card, pdev, &chip);
348 if (err < 0) {
349 - printk(KERN_ERR "Failed to create bcm2835 chip\n");
350 + dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
351 goto out_bcm2835_create;
352 }
353
354 g_chip = chip;
355 err = snd_bcm2835_new_pcm(chip);
356 if (err < 0) {
357 - printk(KERN_ERR "Failed to create new BCM2835 pcm device\n");
358 + dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
359 goto out_bcm2835_new_pcm;
360 }
361
362 err = snd_bcm2835_new_ctl(chip);
363 if (err < 0) {
364 - printk(KERN_ERR "Failed to create new BCM2835 ctl\n");
365 + dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
366 goto out_bcm2835_new_ctl;
367 }
368
369 @@ -139,14 +139,14 @@ add_register_map:
370 if (dev == 0) {
371 err = snd_card_register(card);
372 if (err < 0) {
373 - printk(KERN_ERR
374 - "Failed to register bcm2835 ALSA card \n");
375 + dev_err(&pdev->dev,
376 + "Failed to register bcm2835 ALSA card \n");
377 goto out_card_register;
378 }
379 platform_set_drvdata(pdev, card);
380 - printk(KERN_INFO "bcm2835 ALSA card created!\n");
381 + audio_info("bcm2835 ALSA card created!\n");
382 } else {
383 - printk(KERN_INFO "bcm2835 ALSA chip created!\n");
384 + audio_info("bcm2835 ALSA chip created!\n");
385 platform_set_drvdata(pdev, (void *)dev);
386 }
387
388 @@ -160,11 +160,11 @@ out_bcm2835_new_pcm:
389 out_bcm2835_create:
390 BUG_ON(!g_card);
391 if (snd_card_free(g_card))
392 - printk(KERN_ERR "Failed to free Registered alsa card\n");
393 + dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
394 g_card = NULL;
395 out:
396 dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
397 - printk(KERN_ERR "BCM2835 ALSA Probe failed !!\n");
398 + dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
399 return err;
400 }
401
402 @@ -326,49 +326,49 @@ static int bcm2835_alsa_device_init(void)
403 int err;
404 err = platform_driver_register(&bcm2835_alsa0_driver);
405 if (err) {
406 - printk("Error registering bcm2835_alsa0_driver %d .\n", err);
407 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
408 goto out;
409 }
410
411 err = platform_driver_register(&bcm2835_alsa1_driver);
412 if (err) {
413 - printk("Error registering bcm2835_alsa1_driver %d .\n", err);
414 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
415 goto unregister_0;
416 }
417
418 err = platform_driver_register(&bcm2835_alsa2_driver);
419 if (err) {
420 - printk("Error registering bcm2835_alsa2_driver %d .\n", err);
421 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
422 goto unregister_1;
423 }
424
425 err = platform_driver_register(&bcm2835_alsa3_driver);
426 if (err) {
427 - printk("Error registering bcm2835_alsa3_driver %d .\n", err);
428 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
429 goto unregister_2;
430 }
431
432 err = platform_driver_register(&bcm2835_alsa4_driver);
433 if (err) {
434 - printk("Error registering bcm2835_alsa4_driver %d .\n", err);
435 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
436 goto unregister_3;
437 }
438
439 err = platform_driver_register(&bcm2835_alsa5_driver);
440 if (err) {
441 - printk("Error registering bcm2835_alsa5_driver %d .\n", err);
442 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
443 goto unregister_4;
444 }
445
446 err = platform_driver_register(&bcm2835_alsa6_driver);
447 if (err) {
448 - printk("Error registering bcm2835_alsa6_driver %d .\n", err);
449 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
450 goto unregister_5;
451 }
452
453 err = platform_driver_register(&bcm2835_alsa7_driver);
454 if (err) {
455 - printk("Error registering bcm2835_alsa7_driver %d .\n", err);
456 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
457 goto unregister_6;
458 }
459
460 diff --git a/sound/arm/bcm2835.h b/sound/arm/bcm2835.h
461 index 080bd5c..36afee3 100755
462 --- a/sound/arm/bcm2835.h
463 +++ b/sound/arm/bcm2835.h
464 @@ -23,6 +23,7 @@
465 #include <sound/initval.h>
466 #include <sound/pcm.h>
467 #include <sound/pcm_params.h>
468 +#include <sound/pcm-indirect.h>
469 #include <linux/workqueue.h>
470
471 /*
472 @@ -110,6 +111,7 @@ typedef struct bcm2835_chip {
473 typedef struct bcm2835_alsa_stream {
474 bcm2835_chip_t *chip;
475 struct snd_pcm_substream *substream;
476 + struct snd_pcm_indirect pcm_indirect;
477
478 struct semaphore buffers_update_sem;
479 struct semaphore control_sem;
480 --
481 1.9.1
482