509816e3aa9f39c3b4d2b23203b7252bb8ae0cd2
[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