kernel: refresh patches
[openwrt/svn-archive/archive.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 --- a/sound/arm/bcm2835-pcm.c
15 +++ b/sound/arm/bcm2835-pcm.c
16 @@ -19,7 +19,8 @@
17
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,
25 .rate_min = 8000,
26 @@ -251,6 +252,12 @@ static int snd_bcm2835_pcm_prepare(struc
27
28 audio_info(" .. IN\n");
29
30 + memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
31 +
32 + alsa_stream->pcm_indirect.hw_buffer_size =
33 + alsa_stream->pcm_indirect.sw_buffer_size =
34 + snd_pcm_lib_buffer_bytes(substream);
35 +
36 alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
37 alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
38 alsa_stream->pos = 0;
39 @@ -263,6 +270,32 @@ static int snd_bcm2835_pcm_prepare(struc
40 return 0;
41 }
42
43 +static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
44 + struct snd_pcm_indirect *rec, size_t bytes)
45 +{
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);
49 + int err;
50 +
51 + err = bcm2835_audio_write(alsa_stream, bytes, src);
52 + if (err)
53 + audio_error(" Failed to transfer to alsa device (%d)\n", err);
54 +
55 +}
56 +
57 +static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
58 +{
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;
62 +
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);
66 + return 0;
67 +}
68 +
69 /* trigger callback */
70 static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
71 {
72 @@ -279,6 +312,11 @@ static int snd_bcm2835_pcm_trigger(struc
73 if (!alsa_stream->running) {
74 err = bcm2835_audio_start(alsa_stream);
75 if (err == 0) {
76 + alsa_stream->pcm_indirect.hw_io =
77 + alsa_stream->pcm_indirect.hw_data =
78 + bytes_to_frames(runtime,
79 + alsa_stream->pos);
80 + substream->ops->ack(substream);
81 alsa_stream->running = 1;
82 alsa_stream->draining = 1;
83 } else {
84 @@ -327,30 +365,9 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_s
85 alsa_stream->pos);
86
87 audio_info(" .. OUT\n");
88 - return bytes_to_frames(runtime, alsa_stream->pos);
89 -}
90 -
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)
94 -{
95 - int ret;
96 - struct snd_pcm_runtime *runtime = substream->runtime;
97 - bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
98 -
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,
102 - runtime->
103 - status->
104 - hw_ptr),
105 - frames_to_bytes(runtime, runtime->control->appl_ptr),
106 - alsa_stream->pos);
107 - ret =
108 - bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count),
109 - src);
110 - audio_info(" .. OUT\n");
111 - return ret;
112 + return snd_pcm_indirect_playback_pointer(substream,
113 + &alsa_stream->pcm_indirect,
114 + alsa_stream->pos);
115 }
116
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,
124 };
125
126 /* create a pcm device */
127 --- a/sound/arm/bcm2835-vchiq.c
128 +++ b/sound/arm/bcm2835-vchiq.c
129 @@ -27,6 +27,7 @@
130 #include <linux/delay.h>
131 #include <linux/atomic.h>
132 #include <linux/module.h>
133 +#include <linux/completion.h>
134
135 #include "bcm2835.h"
136
137 @@ -37,6 +38,10 @@
138
139 /* ---- Private Constants and Types ------------------------------------------ */
140
141 +#define BCM2835_AUDIO_STOP 0
142 +#define BCM2835_AUDIO_START 1
143 +#define BCM2835_AUDIO_WRITE 2
144 +
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)
148 @@ -53,7 +58,7 @@
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;
156 int32_t result;
157 @@ -70,27 +75,35 @@ bool force_bulk = false;
158
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);
163
164 typedef struct {
165 struct work_struct my_work;
166 bcm2835_alsa_stream_t *alsa_stream;
167 - int x;
168 + int cmd;
169 + void *src;
170 + uint32_t count;
171 } my_work_t;
172
173 static void my_wq_function(struct work_struct *work)
174 {
175 my_work_t *w = (my_work_t *) work;
176 int ret = -9;
177 - LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->x);
178 - switch (w->x) {
179 - case 1:
180 + LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
181 + switch (w->cmd) {
182 + case BCM2835_AUDIO_START:
183 ret = bcm2835_audio_start_worker(w->alsa_stream);
184 break;
185 - case 2:
186 + case BCM2835_AUDIO_STOP:
187 ret = bcm2835_audio_stop_worker(w->alsa_stream);
188 break;
189 + case BCM2835_AUDIO_WRITE:
190 + ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
191 + w->src);
192 + break;
193 default:
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);
196 break;
197 }
198 kfree((void *)work);
199 @@ -107,7 +120,7 @@ int bcm2835_audio_start(bcm2835_alsa_str
200 if (work) {
201 INIT_WORK((struct work_struct *)work, my_wq_function);
202 work->alsa_stream = alsa_stream;
203 - work->x = 1;
204 + work->cmd = BCM2835_AUDIO_START;
205 if (queue_work
206 (alsa_stream->my_wq, (struct work_struct *)work))
207 ret = 0;
208 @@ -128,7 +141,31 @@ int bcm2835_audio_stop(bcm2835_alsa_stre
209 if (work) {
210 INIT_WORK((struct work_struct *)work, my_wq_function);
211 work->alsa_stream = alsa_stream;
212 - work->x = 2;
213 + work->cmd = BCM2835_AUDIO_STOP;
214 + if (queue_work
215 + (alsa_stream->my_wq, (struct work_struct *)work))
216 + ret = 0;
217 + } else
218 + LOG_ERR(" .. Error: NULL work kmalloc\n");
219 + }
220 + LOG_DBG(" .. OUT %d\n", ret);
221 + return ret;
222 +}
223 +
224 +int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
225 + uint32_t count, void *src)
226 +{
227 + int ret = -1;
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) ---*/
232 + if (work) {
233 + INIT_WORK((struct work_struct *)work, my_wq_function);
234 + work->alsa_stream = alsa_stream;
235 + work->cmd = BCM2835_AUDIO_WRITE;
236 + work->src = src;
237 + work->count = count;
238 if (queue_work
239 (alsa_stream->my_wq, (struct work_struct *)work))
240 ret = 0;
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;
249 LOG_DBG
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;
253
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);
258
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
262 }
263
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);
267 + if (ret) {
268 LOG_ERR("%s: failed on waiting for event (status=%d)\n",
269 __func__, success);
270 -
271 - ret = -1;
272 goto unlock;
273 }
274
275 @@ -539,8 +575,8 @@ int bcm2835_audio_set_params(bcm2835_als
276 m.u.config.samplerate = samplerate;
277 m.u.config.bps = bps;
278
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);
283
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
287 }
288
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);
292 + if (ret) {
293 LOG_ERR("%s: failed on waiting for event (status=%d)\n",
294 __func__, success);
295 -
296 - ret = -1;
297 goto unlock;
298 }
299
300 @@ -688,8 +723,8 @@ int bcm2835_audio_close(bcm2835_alsa_str
301
302 m.type = VC_AUDIO_MSG_TYPE_CLOSE;
303
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);
308
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
312 ret = -1;
313 goto unlock;
314 }
315 - if (down_interruptible(&instance->msg_avail_event)) {
316 +
317 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
318 + if (ret) {
319 LOG_ERR("%s: failed on waiting for event (status=%d)",
320 __func__, success);
321 -
322 - ret = -1;
323 goto unlock;
324 }
325 if (instance->result != 0) {
326 @@ -732,8 +767,8 @@ unlock:
327 return ret;
328 }
329
330 -int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
331 - void *src)
332 +int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
333 + uint32_t count, void *src)
334 {
335 VC_AUDIO_MSG_T m;
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
340
341 err = snd_bcm2835_create(g_card, pdev, &chip);
342 if (err < 0) {
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;
346 }
347
348 g_chip = chip;
349 err = snd_bcm2835_new_pcm(chip);
350 if (err < 0) {
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;
354 }
355
356 err = snd_bcm2835_new_ctl(chip);
357 if (err < 0) {
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;
361 }
362
363 @@ -139,14 +139,14 @@ add_register_map:
364 if (dev == 0) {
365 err = snd_card_register(card);
366 if (err < 0) {
367 - printk(KERN_ERR
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;
372 }
373 platform_set_drvdata(pdev, card);
374 - printk(KERN_INFO "bcm2835 ALSA card created!\n");
375 + audio_info("bcm2835 ALSA card created!\n");
376 } else {
377 - printk(KERN_INFO "bcm2835 ALSA chip created!\n");
378 + audio_info("bcm2835 ALSA chip created!\n");
379 platform_set_drvdata(pdev, (void *)dev);
380 }
381
382 @@ -160,11 +160,11 @@ out_bcm2835_new_pcm:
383 out_bcm2835_create:
384 BUG_ON(!g_card);
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");
388 g_card = NULL;
389 out:
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");
393 return err;
394 }
395
396 @@ -326,49 +326,49 @@ static int bcm2835_alsa_device_init(void
397 int err;
398 err = platform_driver_register(&bcm2835_alsa0_driver);
399 if (err) {
400 - printk("Error registering bcm2835_alsa0_driver %d .\n", err);
401 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
402 goto out;
403 }
404
405 err = platform_driver_register(&bcm2835_alsa1_driver);
406 if (err) {
407 - printk("Error registering bcm2835_alsa1_driver %d .\n", err);
408 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
409 goto unregister_0;
410 }
411
412 err = platform_driver_register(&bcm2835_alsa2_driver);
413 if (err) {
414 - printk("Error registering bcm2835_alsa2_driver %d .\n", err);
415 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
416 goto unregister_1;
417 }
418
419 err = platform_driver_register(&bcm2835_alsa3_driver);
420 if (err) {
421 - printk("Error registering bcm2835_alsa3_driver %d .\n", err);
422 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
423 goto unregister_2;
424 }
425
426 err = platform_driver_register(&bcm2835_alsa4_driver);
427 if (err) {
428 - printk("Error registering bcm2835_alsa4_driver %d .\n", err);
429 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
430 goto unregister_3;
431 }
432
433 err = platform_driver_register(&bcm2835_alsa5_driver);
434 if (err) {
435 - printk("Error registering bcm2835_alsa5_driver %d .\n", err);
436 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
437 goto unregister_4;
438 }
439
440 err = platform_driver_register(&bcm2835_alsa6_driver);
441 if (err) {
442 - printk("Error registering bcm2835_alsa6_driver %d .\n", err);
443 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
444 goto unregister_5;
445 }
446
447 err = platform_driver_register(&bcm2835_alsa7_driver);
448 if (err) {
449 - printk("Error registering bcm2835_alsa7_driver %d .\n", err);
450 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
451 goto unregister_6;
452 }
453
454 --- a/sound/arm/bcm2835.h
455 +++ b/sound/arm/bcm2835.h
456 @@ -23,6 +23,7 @@
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>
462
463 /*
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;
469
470 struct semaphore buffers_update_sem;
471 struct semaphore control_sem;