d1f2eb4f0648d5525a9d05082d275ed045d1a907
[openwrt.git] / target / linux / brcm2708 / patches-3.10 / 012-bcm2708-sound-driver.patch
1 diff -urN linux-3.10/sound/arm/bcm2835.c linux-rpi-3.10.y/sound/arm/bcm2835.c
2 --- linux-3.10/sound/arm/bcm2835.c      1970-01-01 01:00:00.000000000 +0100
3 +++ linux-rpi-3.10.y/sound/arm/bcm2835.c        2013-07-06 15:25:50.000000000 +0100
4 @@ -0,0 +1,413 @@
5 +/*****************************************************************************
6 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
7 +*
8 +* Unless you and Broadcom execute a separate written software license
9 +* agreement governing use of this software, this software is licensed to you
10 +* under the terms of the GNU General Public License version 2, available at
11 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
12 +*      
13 +* Notwithstanding the above, under no circumstances may you combine this
14 +* software in any way with any other Broadcom software provided under a
15 +* license other than the GPL, without Broadcom's express prior written
16 +* consent.
17 +*****************************************************************************/
18 +
19 +#include <linux/platform_device.h>
20 +
21 +#include <linux/init.h>
22 +#include <linux/slab.h>
23 +#include <linux/module.h>
24 +
25 +#include "bcm2835.h"
26 +
27 +/* module parameters (see "Module Parameters") */
28 +/* SNDRV_CARDS: maximum number of cards supported by this module */
29 +static int index[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = -1 };
30 +static char *id[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = NULL };
31 +static int enable[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = 1 };
32 +
33 +/* HACKY global pointers needed for successive probes to work : ssp
34 + * But compared against the changes we will have to do in VC audio_ipc code
35 + * to export 8 audio_ipc devices as a single IPC device and then monitor all
36 + * four devices in a thread, this gets things done quickly and should be easier
37 + * to debug if we run into issues
38 + */
39 +
40 +static struct snd_card *g_card = NULL;
41 +static bcm2835_chip_t *g_chip = NULL;
42 +
43 +static int snd_bcm2835_free(bcm2835_chip_t * chip)
44 +{
45 +       kfree(chip);
46 +       return 0;
47 +}
48 +
49 +/* component-destructor
50 + * (see "Management of Cards and Components")
51 + */
52 +static int snd_bcm2835_dev_free(struct snd_device *device)
53 +{
54 +       return snd_bcm2835_free(device->device_data);
55 +}
56 +
57 +/* chip-specific constructor
58 + * (see "Management of Cards and Components")
59 + */
60 +static int snd_bcm2835_create(struct snd_card *card,
61 +                                       struct platform_device *pdev,
62 +                                       bcm2835_chip_t ** rchip)
63 +{
64 +       bcm2835_chip_t *chip;
65 +       int err;
66 +       static struct snd_device_ops ops = {
67 +               .dev_free = snd_bcm2835_dev_free,
68 +       };
69 +
70 +       *rchip = NULL;
71 +
72 +       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
73 +       if (chip == NULL)
74 +               return -ENOMEM;
75 +
76 +       chip->card = card;
77 +
78 +       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
79 +       if (err < 0) {
80 +               snd_bcm2835_free(chip);
81 +               return err;
82 +       }
83 +
84 +       *rchip = chip;
85 +       return 0;
86 +}
87 +
88 +static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
89 +{
90 +       static int dev;
91 +       bcm2835_chip_t *chip;
92 +       struct snd_card *card;
93 +       int err;
94 +
95 +       if (dev >= MAX_SUBSTREAMS)
96 +               return -ENODEV;
97 +
98 +       if (!enable[dev]) {
99 +               dev++;
100 +               return -ENOENT;
101 +       }
102 +
103 +       if (dev > 0)
104 +               goto add_register_map;
105 +
106 +       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &g_card);
107 +       if (err < 0)
108 +               goto out;
109 +
110 +       snd_card_set_dev(g_card, &pdev->dev);
111 +       strcpy(g_card->driver, "BRCM bcm2835 ALSA Driver");
112 +       strcpy(g_card->shortname, "bcm2835 ALSA");
113 +       sprintf(g_card->longname, "%s", g_card->shortname);
114 +
115 +       err = snd_bcm2835_create(g_card, pdev, &chip);
116 +       if (err < 0) {
117 +               dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
118 +               goto out_bcm2835_create;
119 +       }
120 +
121 +       g_chip = chip;
122 +       err = snd_bcm2835_new_pcm(chip);
123 +       if (err < 0) {
124 +               dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
125 +               goto out_bcm2835_new_pcm;
126 +       }
127 +
128 +       err = snd_bcm2835_new_ctl(chip);
129 +       if (err < 0) {
130 +               dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
131 +               goto out_bcm2835_new_ctl;
132 +       }
133 +
134 +add_register_map:
135 +       card = g_card;
136 +       chip = g_chip;
137 +
138 +       BUG_ON(!(card && chip));
139 +
140 +       chip->avail_substreams |= (1 << dev);
141 +       chip->pdev[dev] = pdev;
142 +
143 +       if (dev == 0) {
144 +               err = snd_card_register(card);
145 +               if (err < 0) {
146 +                       dev_err(&pdev->dev,
147 +                               "Failed to register bcm2835 ALSA card \n");
148 +                       goto out_card_register;
149 +               }
150 +               platform_set_drvdata(pdev, card);
151 +               audio_info("bcm2835 ALSA card created!\n");
152 +       } else {
153 +               audio_info("bcm2835 ALSA chip created!\n");
154 +               platform_set_drvdata(pdev, (void *)dev);
155 +       }
156 +
157 +       dev++;
158 +
159 +       return 0;
160 +
161 +out_card_register:
162 +out_bcm2835_new_ctl:
163 +out_bcm2835_new_pcm:
164 +out_bcm2835_create:
165 +       BUG_ON(!g_card);
166 +       if (snd_card_free(g_card))
167 +               dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
168 +       g_card = NULL;
169 +out:
170 +       dev = SNDRV_CARDS;      /* stop more avail_substreams from being probed */
171 +       dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
172 +       return err;
173 +}
174 +
175 +static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
176 +{
177 +       uint32_t idx;
178 +       void *drv_data;
179 +
180 +       drv_data = platform_get_drvdata(pdev);
181 +
182 +       if (drv_data == (void *)g_card) {
183 +               /* This is the card device */
184 +               snd_card_free((struct snd_card *)drv_data);
185 +               g_card = NULL;
186 +               g_chip = NULL;
187 +       } else {
188 +               idx = (uint32_t) drv_data;
189 +               if (g_card != NULL) {
190 +                       BUG_ON(!g_chip);
191 +                       /* We pass chip device numbers in audio ipc devices
192 +                        * other than the one we registered our card with
193 +                        */
194 +                       idx = (uint32_t) drv_data;
195 +                       BUG_ON(!idx || idx > MAX_SUBSTREAMS);
196 +                       g_chip->avail_substreams &= ~(1 << idx);
197 +                       /* There should be atleast one substream registered
198 +                        * after we are done here, as it wil be removed when
199 +                        * the *remove* is called for the card device
200 +                        */
201 +                       BUG_ON(!g_chip->avail_substreams);
202 +               }
203 +       }
204 +
205 +       platform_set_drvdata(pdev, NULL);
206 +
207 +       return 0;
208 +}
209 +
210 +#ifdef CONFIG_PM
211 +static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
212 +                                   pm_message_t state)
213 +{
214 +       return 0;
215 +}
216 +
217 +static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
218 +{
219 +       return 0;
220 +}
221 +
222 +#endif
223 +
224 +static struct platform_driver bcm2835_alsa0_driver = {
225 +       .probe = snd_bcm2835_alsa_probe,
226 +       .remove = snd_bcm2835_alsa_remove,
227 +#ifdef CONFIG_PM
228 +       .suspend = snd_bcm2835_alsa_suspend,
229 +       .resume = snd_bcm2835_alsa_resume,
230 +#endif
231 +       .driver = {
232 +                  .name = "bcm2835_AUD0",
233 +                  .owner = THIS_MODULE,
234 +                  },
235 +};
236 +
237 +static struct platform_driver bcm2835_alsa1_driver = {
238 +       .probe = snd_bcm2835_alsa_probe,
239 +       .remove = snd_bcm2835_alsa_remove,
240 +#ifdef CONFIG_PM
241 +       .suspend = snd_bcm2835_alsa_suspend,
242 +       .resume = snd_bcm2835_alsa_resume,
243 +#endif
244 +       .driver = {
245 +                  .name = "bcm2835_AUD1",
246 +                  .owner = THIS_MODULE,
247 +                  },
248 +};
249 +
250 +static struct platform_driver bcm2835_alsa2_driver = {
251 +       .probe = snd_bcm2835_alsa_probe,
252 +       .remove = snd_bcm2835_alsa_remove,
253 +#ifdef CONFIG_PM
254 +       .suspend = snd_bcm2835_alsa_suspend,
255 +       .resume = snd_bcm2835_alsa_resume,
256 +#endif
257 +       .driver = {
258 +                  .name = "bcm2835_AUD2",
259 +                  .owner = THIS_MODULE,
260 +                  },
261 +};
262 +
263 +static struct platform_driver bcm2835_alsa3_driver = {
264 +       .probe = snd_bcm2835_alsa_probe,
265 +       .remove = snd_bcm2835_alsa_remove,
266 +#ifdef CONFIG_PM
267 +       .suspend = snd_bcm2835_alsa_suspend,
268 +       .resume = snd_bcm2835_alsa_resume,
269 +#endif
270 +       .driver = {
271 +                  .name = "bcm2835_AUD3",
272 +                  .owner = THIS_MODULE,
273 +                  },
274 +};
275 +
276 +static struct platform_driver bcm2835_alsa4_driver = {
277 +       .probe = snd_bcm2835_alsa_probe,
278 +       .remove = snd_bcm2835_alsa_remove,
279 +#ifdef CONFIG_PM
280 +       .suspend = snd_bcm2835_alsa_suspend,
281 +       .resume = snd_bcm2835_alsa_resume,
282 +#endif
283 +       .driver = {
284 +                  .name = "bcm2835_AUD4",
285 +                  .owner = THIS_MODULE,
286 +                  },
287 +};
288 +
289 +static struct platform_driver bcm2835_alsa5_driver = {
290 +       .probe = snd_bcm2835_alsa_probe,
291 +       .remove = snd_bcm2835_alsa_remove,
292 +#ifdef CONFIG_PM
293 +       .suspend = snd_bcm2835_alsa_suspend,
294 +       .resume = snd_bcm2835_alsa_resume,
295 +#endif
296 +       .driver = {
297 +                  .name = "bcm2835_AUD5",
298 +                  .owner = THIS_MODULE,
299 +                  },
300 +};
301 +
302 +static struct platform_driver bcm2835_alsa6_driver = {
303 +       .probe = snd_bcm2835_alsa_probe,
304 +       .remove = snd_bcm2835_alsa_remove,
305 +#ifdef CONFIG_PM
306 +       .suspend = snd_bcm2835_alsa_suspend,
307 +       .resume = snd_bcm2835_alsa_resume,
308 +#endif
309 +       .driver = {
310 +                  .name = "bcm2835_AUD6",
311 +                  .owner = THIS_MODULE,
312 +                  },
313 +};
314 +
315 +static struct platform_driver bcm2835_alsa7_driver = {
316 +       .probe = snd_bcm2835_alsa_probe,
317 +       .remove = snd_bcm2835_alsa_remove,
318 +#ifdef CONFIG_PM
319 +       .suspend = snd_bcm2835_alsa_suspend,
320 +       .resume = snd_bcm2835_alsa_resume,
321 +#endif
322 +       .driver = {
323 +                  .name = "bcm2835_AUD7",
324 +                  .owner = THIS_MODULE,
325 +                  },
326 +};
327 +
328 +static int bcm2835_alsa_device_init(void)
329 +{
330 +       int err;
331 +       err = platform_driver_register(&bcm2835_alsa0_driver);
332 +       if (err) {
333 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
334 +               goto out;
335 +       }
336 +
337 +       err = platform_driver_register(&bcm2835_alsa1_driver);
338 +       if (err) {
339 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
340 +               goto unregister_0;
341 +       }
342 +
343 +       err = platform_driver_register(&bcm2835_alsa2_driver);
344 +       if (err) {
345 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
346 +               goto unregister_1;
347 +       }
348 +
349 +       err = platform_driver_register(&bcm2835_alsa3_driver);
350 +       if (err) {
351 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
352 +               goto unregister_2;
353 +       }
354 +
355 +       err = platform_driver_register(&bcm2835_alsa4_driver);
356 +       if (err) {
357 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
358 +               goto unregister_3;
359 +       }
360 +
361 +       err = platform_driver_register(&bcm2835_alsa5_driver);
362 +       if (err) {
363 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
364 +               goto unregister_4;
365 +       }
366 +
367 +       err = platform_driver_register(&bcm2835_alsa6_driver);
368 +       if (err) {
369 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
370 +               goto unregister_5;
371 +       }
372 +
373 +       err = platform_driver_register(&bcm2835_alsa7_driver);
374 +       if (err) {
375 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
376 +               goto unregister_6;
377 +       }
378 +
379 +       return 0;
380 +
381 +unregister_6:
382 +       platform_driver_unregister(&bcm2835_alsa6_driver);
383 +unregister_5:
384 +       platform_driver_unregister(&bcm2835_alsa5_driver);
385 +unregister_4:
386 +       platform_driver_unregister(&bcm2835_alsa4_driver);
387 +unregister_3:
388 +       platform_driver_unregister(&bcm2835_alsa3_driver);
389 +unregister_2:
390 +       platform_driver_unregister(&bcm2835_alsa2_driver);
391 +unregister_1:
392 +       platform_driver_unregister(&bcm2835_alsa1_driver);
393 +unregister_0:
394 +       platform_driver_unregister(&bcm2835_alsa0_driver);
395 +out:
396 +       return err;
397 +}
398 +
399 +static void bcm2835_alsa_device_exit(void)
400 +{
401 +       platform_driver_unregister(&bcm2835_alsa0_driver);
402 +       platform_driver_unregister(&bcm2835_alsa1_driver);
403 +       platform_driver_unregister(&bcm2835_alsa2_driver);
404 +       platform_driver_unregister(&bcm2835_alsa3_driver);
405 +       platform_driver_unregister(&bcm2835_alsa4_driver);
406 +       platform_driver_unregister(&bcm2835_alsa5_driver);
407 +       platform_driver_unregister(&bcm2835_alsa6_driver);
408 +       platform_driver_unregister(&bcm2835_alsa7_driver);
409 +}
410 +
411 +late_initcall(bcm2835_alsa_device_init);
412 +module_exit(bcm2835_alsa_device_exit);
413 +
414 +MODULE_AUTHOR("Dom Cobley");
415 +MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
416 +MODULE_LICENSE("GPL");
417 +MODULE_ALIAS("platform:bcm2835_alsa");
418 diff -urN linux-3.10/sound/arm/bcm2835-ctl.c linux-rpi-3.10.y/sound/arm/bcm2835-ctl.c
419 --- linux-3.10/sound/arm/bcm2835-ctl.c  1970-01-01 01:00:00.000000000 +0100
420 +++ linux-rpi-3.10.y/sound/arm/bcm2835-ctl.c    2013-07-06 15:25:50.000000000 +0100
421 @@ -0,0 +1,200 @@
422 +/*****************************************************************************
423 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
424 +*
425 +* Unless you and Broadcom execute a separate written software license
426 +* agreement governing use of this software, this software is licensed to you
427 +* under the terms of the GNU General Public License version 2, available at
428 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
429 +*      
430 +* Notwithstanding the above, under no circumstances may you combine this
431 +* software in any way with any other Broadcom software provided under a
432 +* license other than the GPL, without Broadcom's express prior written
433 +* consent.
434 +*****************************************************************************/
435 +
436 +#include <linux/platform_device.h>
437 +#include <linux/init.h>
438 +#include <linux/io.h>
439 +#include <linux/jiffies.h>
440 +#include <linux/slab.h>
441 +#include <linux/time.h>
442 +#include <linux/wait.h>
443 +#include <linux/delay.h>
444 +#include <linux/moduleparam.h>
445 +#include <linux/sched.h>
446 +
447 +#include <sound/core.h>
448 +#include <sound/control.h>
449 +#include <sound/pcm.h>
450 +#include <sound/pcm_params.h>
451 +#include <sound/rawmidi.h>
452 +#include <sound/initval.h>
453 +#include <sound/tlv.h>
454 +
455 +#include "bcm2835.h"
456 +
457 +/* volume maximum and minimum in terms of 0.01dB */
458 +#define CTRL_VOL_MAX 400
459 +#define CTRL_VOL_MIN -10239 /* originally -10240 */
460 +
461 +
462 +static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
463 +                               struct snd_ctl_elem_info *uinfo)
464 +{
465 +       audio_info(" ... IN\n");
466 +       if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
467 +               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
468 +               uinfo->count = 1;
469 +               uinfo->value.integer.min = CTRL_VOL_MIN;
470 +               uinfo->value.integer.max = CTRL_VOL_MAX;      /* 2303 */
471 +       } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
472 +               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
473 +               uinfo->count = 1;
474 +               uinfo->value.integer.min = 0;
475 +               uinfo->value.integer.max = 1;
476 +       } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
477 +               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
478 +               uinfo->count = 1;
479 +               uinfo->value.integer.min = 0;
480 +               uinfo->value.integer.max = AUDIO_DEST_MAX-1;
481 +       }
482 +       audio_info(" ... OUT\n");
483 +       return 0;
484 +}
485 +
486 +/* toggles mute on or off depending on the value of nmute, and returns
487 + * 1 if the mute value was changed, otherwise 0
488 + */
489 +static int toggle_mute(struct bcm2835_chip *chip, int nmute)
490 +{
491 +       /* if settings are ok, just return 0 */
492 +       if(chip->mute == nmute)
493 +               return 0;
494 +
495 +       /* if the sound is muted then we need to unmute */
496 +       if(chip->mute == CTRL_VOL_MUTE)
497 +       {
498 +               chip->volume = chip->old_volume; /* copy the old volume back */
499 +               audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
500 +       }
501 +       else /* otherwise we mute */
502 +       {
503 +               chip->old_volume = chip->volume;
504 +               chip->volume = 26214; /* set volume to minimum level AKA mute */
505 +               audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
506 +       }
507 +
508 +       chip->mute = nmute;
509 +       return 1;
510 +}
511 +
512 +static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
513 +                              struct snd_ctl_elem_value *ucontrol)
514 +{
515 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
516 +
517 +       BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
518 +
519 +       if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
520 +               ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
521 +       else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
522 +               ucontrol->value.integer.value[0] = chip->mute;
523 +       else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
524 +               ucontrol->value.integer.value[0] = chip->dest;
525 +
526 +       return 0;
527 +}
528 +
529 +static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
530 +                              struct snd_ctl_elem_value *ucontrol)
531 +{
532 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
533 +       int changed = 0;
534 +
535 +       if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
536 +               audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
537 +               if (chip->mute == CTRL_VOL_MUTE) {
538 +                       /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
539 +                       return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
540 +               }
541 +               if (changed
542 +                   || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
543 +
544 +                       chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
545 +                       changed = 1;
546 +               }
547 +
548 +       } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
549 +               /* Now implemented */
550 +               audio_info(" Mute attempted\n");
551 +               changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
552 +
553 +       } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
554 +               if (ucontrol->value.integer.value[0] != chip->dest) {
555 +                       chip->dest = ucontrol->value.integer.value[0];
556 +                       changed = 1;
557 +               }
558 +       }
559 +
560 +       if (changed) {
561 +               if (bcm2835_audio_set_ctls(chip))
562 +                       printk(KERN_ERR "Failed to set ALSA controls..\n");
563 +       }
564 +
565 +       return changed;
566 +}
567 +
568 +static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
569 +
570 +static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
571 +       {
572 +        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
573 +        .name = "PCM Playback Volume",
574 +        .index = 0,
575 +        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
576 +        .private_value = PCM_PLAYBACK_VOLUME,
577 +        .info = snd_bcm2835_ctl_info,
578 +        .get = snd_bcm2835_ctl_get,
579 +        .put = snd_bcm2835_ctl_put,
580 +        .count = 1,
581 +        .tlv = {.p = snd_bcm2835_db_scale}
582 +       },
583 +       {
584 +        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
585 +        .name = "PCM Playback Switch",
586 +        .index = 0,
587 +        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
588 +        .private_value = PCM_PLAYBACK_MUTE,
589 +        .info = snd_bcm2835_ctl_info,
590 +        .get = snd_bcm2835_ctl_get,
591 +        .put = snd_bcm2835_ctl_put,
592 +        .count = 1,
593 +        },
594 +       {
595 +        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
596 +        .name = "PCM Playback Route",
597 +        .index = 0,
598 +        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
599 +        .private_value = PCM_PLAYBACK_DEVICE,
600 +        .info = snd_bcm2835_ctl_info,
601 +        .get = snd_bcm2835_ctl_get,
602 +        .put = snd_bcm2835_ctl_put,
603 +        .count = 1,
604 +       },
605 +};
606 +
607 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
608 +{
609 +       int err;
610 +       unsigned int idx;
611 +
612 +       strcpy(chip->card->mixername, "Broadcom Mixer");
613 +       for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
614 +               err =
615 +                   snd_ctl_add(chip->card,
616 +                               snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
617 +               if (err < 0)
618 +                       return err;
619 +       }
620 +       return 0;
621 +}
622 diff -urN linux-3.10/sound/arm/bcm2835.h linux-rpi-3.10.y/sound/arm/bcm2835.h
623 --- linux-3.10/sound/arm/bcm2835.h      1970-01-01 01:00:00.000000000 +0100
624 +++ linux-rpi-3.10.y/sound/arm/bcm2835.h        2013-07-06 15:25:50.000000000 +0100
625 @@ -0,0 +1,157 @@
626 +/*****************************************************************************
627 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
628 +*
629 +* Unless you and Broadcom execute a separate written software license
630 +* agreement governing use of this software, this software is licensed to you
631 +* under the terms of the GNU General Public License version 2, available at
632 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
633 +*      
634 +* Notwithstanding the above, under no circumstances may you combine this
635 +* software in any way with any other Broadcom software provided under a
636 +* license other than the GPL, without Broadcom's express prior written
637 +* consent.
638 +*****************************************************************************/
639 +
640 +#ifndef __SOUND_ARM_BCM2835_H
641 +#define __SOUND_ARM_BCM2835_H
642 +
643 +#include <linux/device.h>
644 +#include <linux/list.h>
645 +#include <linux/interrupt.h>
646 +#include <linux/wait.h>
647 +#include <sound/core.h>
648 +#include <sound/initval.h>
649 +#include <sound/pcm.h>
650 +#include <sound/pcm_params.h>
651 +#include <sound/pcm-indirect.h>
652 +#include <linux/workqueue.h>
653 +
654 +/*
655 +#define AUDIO_DEBUG_ENABLE
656 +#define AUDIO_VERBOSE_DEBUG_ENABLE
657 +*/
658 +
659 +/* Debug macros */
660 +
661 +#ifdef AUDIO_DEBUG_ENABLE
662 +#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
663 +
664 +#define audio_debug(fmt, arg...)       \
665 +       printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
666 +
667 +#define audio_info(fmt, arg...)        \
668 +       printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
669 +
670 +#else
671 +
672 +#define audio_debug(fmt, arg...)
673 +
674 +#define audio_info(fmt, arg...)
675 +
676 +#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
677 +
678 +#else
679 +
680 +#define audio_debug(fmt, arg...)
681 +
682 +#define audio_info(fmt, arg...)
683 +
684 +#endif /* AUDIO_DEBUG_ENABLE */
685 +
686 +#define audio_error(fmt, arg...)       \
687 +       printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
688 +
689 +#define audio_warning(fmt, arg...)     \
690 +       printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
691 +
692 +#define audio_alert(fmt, arg...)       \
693 +       printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
694 +
695 +#define MAX_SUBSTREAMS                 (8)
696 +#define AVAIL_SUBSTREAMS_MASK          (0xff)
697 +enum {
698 +       CTRL_VOL_MUTE,
699 +       CTRL_VOL_UNMUTE
700 +};
701 +
702 +/* macros for alsa2chip and chip2alsa, instead of functions */
703 +
704 +#define alsa2chip(vol) (uint)(-((vol << 8) / 100))     /* convert alsa to chip volume (defined as macro rather than function call) */
705 +#define chip2alsa(vol) -((vol * 100) >> 8)                     /* convert chip to alsa volume */
706 +
707 +/* Some constants for values .. */
708 +typedef enum {
709 +       AUDIO_DEST_AUTO = 0,
710 +       AUDIO_DEST_HEADPHONES = 1,
711 +       AUDIO_DEST_HDMI = 2,
712 +       AUDIO_DEST_MAX,
713 +} SND_BCM2835_ROUTE_T;
714 +
715 +typedef enum {
716 +       PCM_PLAYBACK_VOLUME,
717 +       PCM_PLAYBACK_MUTE,
718 +       PCM_PLAYBACK_DEVICE,
719 +} SND_BCM2835_CTRL_T;
720 +
721 +/* definition of the chip-specific record */
722 +typedef struct bcm2835_chip {
723 +       struct snd_card *card;
724 +       struct snd_pcm *pcm;
725 +       /* Bitmat for valid reg_base and irq numbers */
726 +       uint32_t avail_substreams;
727 +       struct platform_device *pdev[MAX_SUBSTREAMS];
728 +       struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
729 +
730 +       int volume;
731 +       int old_volume; /* stores the volume value whist muted */
732 +       int dest;
733 +       int mute;
734 +} bcm2835_chip_t;
735 +
736 +typedef struct bcm2835_alsa_stream {
737 +       bcm2835_chip_t *chip;
738 +       struct snd_pcm_substream *substream;
739 +       struct snd_pcm_indirect pcm_indirect;
740 +
741 +       struct semaphore buffers_update_sem;
742 +       struct semaphore control_sem;
743 +       spinlock_t lock;
744 +       volatile uint32_t control;
745 +       volatile uint32_t status;
746 +
747 +       int open;
748 +       int running;
749 +       int draining;
750 +
751 +       unsigned int pos;
752 +       unsigned int buffer_size;
753 +       unsigned int period_size;
754 +
755 +       uint32_t enable_fifo_irq;
756 +       irq_handler_t fifo_irq_handler;
757 +
758 +       atomic_t retrieved;
759 +       struct opaque_AUDIO_INSTANCE_T *instance;
760 +       struct workqueue_struct *my_wq;
761 +       int idx;
762 +} bcm2835_alsa_stream_t;
763 +
764 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
765 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
766 +
767 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
768 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
769 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
770 +                            uint32_t channels, uint32_t samplerate,
771 +                            uint32_t bps);
772 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream);
773 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream);
774 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream);
775 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip);
776 +int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
777 +                       void *src);
778 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream);
779 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream);
780 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream);
781 +
782 +#endif /* __SOUND_ARM_BCM2835_H */
783 diff -urN linux-3.10/sound/arm/bcm2835-pcm.c linux-rpi-3.10.y/sound/arm/bcm2835-pcm.c
784 --- linux-3.10/sound/arm/bcm2835-pcm.c  1970-01-01 01:00:00.000000000 +0100
785 +++ linux-rpi-3.10.y/sound/arm/bcm2835-pcm.c    2013-07-06 15:25:50.000000000 +0100
786 @@ -0,0 +1,426 @@
787 +/*****************************************************************************
788 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
789 +*
790 +* Unless you and Broadcom execute a separate written software license
791 +* agreement governing use of this software, this software is licensed to you
792 +* under the terms of the GNU General Public License version 2, available at
793 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
794 +*      
795 +* Notwithstanding the above, under no circumstances may you combine this
796 +* software in any way with any other Broadcom software provided under a
797 +* license other than the GPL, without Broadcom's express prior written
798 +* consent.
799 +*****************************************************************************/
800 +
801 +#include <linux/interrupt.h>
802 +#include <linux/slab.h>
803 +
804 +#include "bcm2835.h"
805 +
806 +/* hardware definition */
807 +static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
808 +       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
809 +                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
810 +       .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
811 +       .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
812 +       .rate_min = 8000,
813 +       .rate_max = 48000,
814 +       .channels_min = 1,
815 +       .channels_max = 2,
816 +       .buffer_bytes_max = 128 * 1024,
817 +       .period_bytes_min =   1 * 1024,
818 +       .period_bytes_max = 128 * 1024,
819 +       .periods_min = 1,
820 +       .periods_max = 128,
821 +};
822 +
823 +static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
824 +{
825 +       audio_info("Freeing up alsa stream here ..\n");
826 +       if (runtime->private_data)
827 +               kfree(runtime->private_data);
828 +       runtime->private_data = NULL;
829 +}
830 +
831 +static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
832 +{
833 +       bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
834 +       uint32_t consumed = 0;
835 +       int new_period = 0;
836 +
837 +       audio_info(" .. IN\n");
838 +
839 +       audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
840 +                  alsa_stream ? alsa_stream->substream : 0);
841 +
842 +       if (alsa_stream->open)
843 +               consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
844 +
845 +       /* We get called only if playback was triggered, So, the number of buffers we retrieve in
846 +        * each iteration are the buffers that have been played out already
847 +        */
848 +
849 +       if (alsa_stream->period_size) {
850 +               if ((alsa_stream->pos / alsa_stream->period_size) !=
851 +                   ((alsa_stream->pos + consumed) / alsa_stream->period_size))
852 +                       new_period = 1;
853 +       }
854 +       audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
855 +                     alsa_stream->pos,
856 +                     consumed,
857 +                     alsa_stream->buffer_size,
858 +                         (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods),
859 +                         frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
860 +                         new_period);
861 +       if (alsa_stream->buffer_size) {
862 +               alsa_stream->pos += consumed &~ (1<<30);
863 +               alsa_stream->pos %= alsa_stream->buffer_size;
864 +       }
865 +
866 +       if (alsa_stream->substream) {
867 +               if (new_period)
868 +                       snd_pcm_period_elapsed(alsa_stream->substream);
869 +       } else {
870 +               audio_warning(" unexpected NULL substream\n");
871 +       }
872 +       audio_info(" .. OUT\n");
873 +
874 +       return IRQ_HANDLED;
875 +}
876 +
877 +/* open callback */
878 +static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
879 +{
880 +       bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
881 +       struct snd_pcm_runtime *runtime = substream->runtime;
882 +       bcm2835_alsa_stream_t *alsa_stream;
883 +       int idx;
884 +       int err;
885 +
886 +       audio_info(" .. IN (%d)\n", substream->number);
887 +
888 +       audio_info("Alsa open (%d)\n", substream->number);
889 +       idx = substream->number;
890 +
891 +       if (idx > MAX_SUBSTREAMS) {
892 +               audio_error
893 +                   ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
894 +                    idx, MAX_SUBSTREAMS);
895 +               err = -ENODEV;
896 +               goto out;
897 +       }
898 +
899 +       /* Check if we are ready */
900 +       if (!(chip->avail_substreams & (1 << idx))) {
901 +               /* We are not ready yet */
902 +               audio_error("substream(%d) device is not ready yet\n", idx);
903 +               err = -EAGAIN;
904 +               goto out;
905 +       }
906 +
907 +       alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
908 +       if (alsa_stream == NULL) {
909 +               return -ENOMEM;
910 +       }
911 +
912 +       /* Initialise alsa_stream */
913 +       alsa_stream->chip = chip;
914 +       alsa_stream->substream = substream;
915 +       alsa_stream->idx = idx;
916 +       chip->alsa_stream[idx] = alsa_stream;
917 +
918 +       sema_init(&alsa_stream->buffers_update_sem, 0);
919 +       sema_init(&alsa_stream->control_sem, 0);
920 +       spin_lock_init(&alsa_stream->lock);
921 +
922 +       /* Enabled in start trigger, called on each "fifo irq" after that */
923 +       alsa_stream->enable_fifo_irq = 0;
924 +       alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;
925 +
926 +       runtime->private_data = alsa_stream;
927 +       runtime->private_free = snd_bcm2835_playback_free;
928 +       runtime->hw = snd_bcm2835_playback_hw;
929 +       /* minimum 16 bytes alignment (for vchiq bulk transfers) */
930 +       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
931 +                                  16);
932 +
933 +       err = bcm2835_audio_open(alsa_stream);
934 +       if (err != 0) {
935 +               kfree(alsa_stream);
936 +               return err;
937 +       }
938 +
939 +       alsa_stream->open = 1;
940 +       alsa_stream->draining = 1;
941 +
942 +out:
943 +       audio_info(" .. OUT =%d\n", err);
944 +
945 +       return err;
946 +}
947 +
948 +/* close callback */
949 +static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
950 +{
951 +       /* the hardware-specific codes will be here */
952 +
953 +       struct snd_pcm_runtime *runtime = substream->runtime;
954 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
955 +
956 +       audio_info(" .. IN\n");
957 +       audio_info("Alsa close\n");
958 +
959 +       /*
960 +        * Call stop if it's still running. This happens when app
961 +        * is force killed and we don't get a stop trigger.
962 +        */
963 +       if (alsa_stream->running) {
964 +               int err;
965 +               err = bcm2835_audio_stop(alsa_stream);
966 +               alsa_stream->running = 0;
967 +               if (err != 0)
968 +                       audio_error(" Failed to STOP alsa device\n");
969 +       }
970 +
971 +       alsa_stream->period_size = 0;
972 +       alsa_stream->buffer_size = 0;
973 +
974 +       if (alsa_stream->open) {
975 +               alsa_stream->open = 0;
976 +               bcm2835_audio_close(alsa_stream);
977 +       }
978 +       if (alsa_stream->chip)
979 +               alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
980 +       /*
981 +        * Do not free up alsa_stream here, it will be freed up by
982 +        * runtime->private_free callback we registered in *_open above
983 +        */
984 +
985 +       audio_info(" .. OUT\n");
986 +
987 +       return 0;
988 +}
989 +
990 +/* hw_params callback */
991 +static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
992 +                                    struct snd_pcm_hw_params *params)
993 +{
994 +       int err;
995 +       struct snd_pcm_runtime *runtime = substream->runtime;
996 +       bcm2835_alsa_stream_t *alsa_stream =
997 +           (bcm2835_alsa_stream_t *) runtime->private_data;
998 +
999 +       audio_info(" .. IN\n");
1000 +
1001 +       err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
1002 +       if (err < 0) {
1003 +               audio_error
1004 +                   (" pcm_lib_malloc failed to allocated pages for buffers\n");
1005 +               return err;
1006 +       }
1007 +
1008 +       err = bcm2835_audio_set_params(alsa_stream, params_channels(params),
1009 +                                      params_rate(params),
1010 +                                      snd_pcm_format_width(params_format
1011 +                                                           (params)));
1012 +       if (err < 0) {
1013 +               audio_error(" error setting hw params\n");
1014 +       }
1015 +
1016 +       bcm2835_audio_setup(alsa_stream);
1017 +
1018 +       /* in preparation of the stream, set the controls (volume level) of the stream */
1019 +       bcm2835_audio_set_ctls(alsa_stream->chip);
1020 +
1021 +       audio_info(" .. OUT\n");
1022 +
1023 +       return err;
1024 +}
1025 +
1026 +/* hw_free callback */
1027 +static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
1028 +{
1029 +       audio_info(" .. IN\n");
1030 +       return snd_pcm_lib_free_pages(substream);
1031 +}
1032 +
1033 +/* prepare callback */
1034 +static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
1035 +{
1036 +       struct snd_pcm_runtime *runtime = substream->runtime;
1037 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
1038 +
1039 +       audio_info(" .. IN\n");
1040 +
1041 +       memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
1042 +
1043 +       alsa_stream->pcm_indirect.hw_buffer_size =
1044 +       alsa_stream->pcm_indirect.sw_buffer_size =
1045 +               snd_pcm_lib_buffer_bytes(substream);
1046 +
1047 +       alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
1048 +       alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
1049 +       alsa_stream->pos = 0;
1050 +
1051 +       audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
1052 +                     alsa_stream->buffer_size, alsa_stream->period_size,
1053 +                     alsa_stream->pos, runtime->frame_bits);
1054 +
1055 +       audio_info(" .. OUT\n");
1056 +       return 0;
1057 +}
1058 +
1059 +static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
1060 +                                   struct snd_pcm_indirect *rec, size_t bytes)
1061 +{
1062 +       struct snd_pcm_runtime *runtime = substream->runtime;
1063 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
1064 +       void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
1065 +       int err;
1066 +
1067 +       err = bcm2835_audio_write(alsa_stream, bytes, src);
1068 +       if (err)
1069 +               audio_error(" Failed to transfer to alsa device (%d)\n", err);
1070 +
1071 +}
1072 +
1073 +static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
1074 +{
1075 +       struct snd_pcm_runtime *runtime = substream->runtime;
1076 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
1077 +       struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
1078 +
1079 +       pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
1080 +       snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
1081 +                                          snd_bcm2835_pcm_transfer);
1082 +       return 0;
1083 +}
1084 +
1085 +/* trigger callback */
1086 +static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1087 +{
1088 +       struct snd_pcm_runtime *runtime = substream->runtime;
1089 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
1090 +       int err = 0;
1091 +
1092 +       audio_info(" .. IN\n");
1093 +
1094 +       switch (cmd) {
1095 +       case SNDRV_PCM_TRIGGER_START:
1096 +               audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
1097 +                             alsa_stream->running);
1098 +               if (!alsa_stream->running) {
1099 +                       err = bcm2835_audio_start(alsa_stream);
1100 +                       if (err == 0) {
1101 +                               alsa_stream->pcm_indirect.hw_io =
1102 +                               alsa_stream->pcm_indirect.hw_data =
1103 +                                       bytes_to_frames(runtime,
1104 +                                                       alsa_stream->pos);
1105 +                               substream->ops->ack(substream);
1106 +                               alsa_stream->running = 1;
1107 +                               alsa_stream->draining = 1;
1108 +                       } else {
1109 +                               audio_error(" Failed to START alsa device (%d)\n", err);
1110 +                       }
1111 +               }
1112 +               break;
1113 +       case SNDRV_PCM_TRIGGER_STOP:
1114 +               audio_debug
1115 +                   ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
1116 +                            alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
1117 +               if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
1118 +                       audio_info("DRAINING\n");
1119 +                       alsa_stream->draining = 1;
1120 +               } else {
1121 +                       audio_info("DROPPING\n");
1122 +                       alsa_stream->draining = 0;
1123 +               }
1124 +               if (alsa_stream->running) {
1125 +                       err = bcm2835_audio_stop(alsa_stream);
1126 +                       if (err != 0)
1127 +                               audio_error(" Failed to STOP alsa device (%d)\n", err);
1128 +                       alsa_stream->running = 0;
1129 +               }
1130 +               break;
1131 +       default:
1132 +               err = -EINVAL;
1133 +       }
1134 +
1135 +       audio_info(" .. OUT\n");
1136 +       return err;
1137 +}
1138 +
1139 +/* pointer callback */
1140 +static snd_pcm_uframes_t
1141 +snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
1142 +{
1143 +       struct snd_pcm_runtime *runtime = substream->runtime;
1144 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
1145 +
1146 +       audio_info(" .. IN\n");
1147 +
1148 +       audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
1149 +                     frames_to_bytes(runtime, runtime->status->hw_ptr),
1150 +                     frames_to_bytes(runtime, runtime->control->appl_ptr),
1151 +                     alsa_stream->pos);
1152 +
1153 +       audio_info(" .. OUT\n");
1154 +       return snd_pcm_indirect_playback_pointer(substream,
1155 +                                                &alsa_stream->pcm_indirect,
1156 +                                                alsa_stream->pos);
1157 +}
1158 +
1159 +static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
1160 +                                    unsigned int cmd, void *arg)
1161 +{
1162 +       int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
1163 +       audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
1164 +                   cmd, arg, arg ? *(unsigned *)arg : 0, ret);
1165 +       return ret;
1166 +}
1167 +
1168 +/* operators */
1169 +static struct snd_pcm_ops snd_bcm2835_playback_ops = {
1170 +       .open = snd_bcm2835_playback_open,
1171 +       .close = snd_bcm2835_playback_close,
1172 +       .ioctl = snd_bcm2835_pcm_lib_ioctl,
1173 +       .hw_params = snd_bcm2835_pcm_hw_params,
1174 +       .hw_free = snd_bcm2835_pcm_hw_free,
1175 +       .prepare = snd_bcm2835_pcm_prepare,
1176 +       .trigger = snd_bcm2835_pcm_trigger,
1177 +       .pointer = snd_bcm2835_pcm_pointer,
1178 +       .ack = snd_bcm2835_pcm_ack,
1179 +};
1180 +
1181 +/* create a pcm device */
1182 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
1183 +{
1184 +       struct snd_pcm *pcm;
1185 +       int err;
1186 +
1187 +       audio_info(" .. IN\n");
1188 +       err =
1189 +           snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
1190 +       if (err < 0)
1191 +               return err;
1192 +       pcm->private_data = chip;
1193 +       strcpy(pcm->name, "bcm2835 ALSA");
1194 +       chip->pcm = pcm;
1195 +       chip->dest = AUDIO_DEST_AUTO;
1196 +       chip->volume = alsa2chip(0);
1197 +       chip->mute = CTRL_VOL_UNMUTE;   /*disable mute on startup */
1198 +       /* set operators */
1199 +       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1200 +                       &snd_bcm2835_playback_ops);
1201 +
1202 +       /* pre-allocation of buffers */
1203 +       /* NOTE: this may fail */
1204 +       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
1205 +                                             snd_dma_continuous_data
1206 +                                             (GFP_KERNEL), 64 * 1024,
1207 +                                             64 * 1024);
1208 +
1209 +       audio_info(" .. OUT\n");
1210 +
1211 +       return 0;
1212 +}
1213 diff -urN linux-3.10/sound/arm/bcm2835-vchiq.c linux-rpi-3.10.y/sound/arm/bcm2835-vchiq.c
1214 --- linux-3.10/sound/arm/bcm2835-vchiq.c        1970-01-01 01:00:00.000000000 +0100
1215 +++ linux-rpi-3.10.y/sound/arm/bcm2835-vchiq.c  2013-07-06 15:25:50.000000000 +0100
1216 @@ -0,0 +1,879 @@
1217 +/*****************************************************************************
1218 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
1219 +*
1220 +* Unless you and Broadcom execute a separate written software license
1221 +* agreement governing use of this software, this software is licensed to you
1222 +* under the terms of the GNU General Public License version 2, available at
1223 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
1224 +*      
1225 +* Notwithstanding the above, under no circumstances may you combine this
1226 +* software in any way with any other Broadcom software provided under a
1227 +* license other than the GPL, without Broadcom's express prior written
1228 +* consent.
1229 +*****************************************************************************/
1230 +
1231 +#include <linux/device.h>
1232 +#include <sound/core.h>
1233 +#include <sound/initval.h>
1234 +#include <sound/pcm.h>
1235 +#include <linux/io.h>
1236 +#include <linux/interrupt.h>
1237 +#include <linux/fs.h>
1238 +#include <linux/file.h>
1239 +#include <linux/mm.h>
1240 +#include <linux/syscalls.h>
1241 +#include <asm/uaccess.h>
1242 +#include <linux/slab.h>
1243 +#include <linux/delay.h>
1244 +#include <linux/atomic.h>
1245 +#include <linux/module.h>
1246 +#include <linux/completion.h>
1247 +
1248 +#include "bcm2835.h"
1249 +
1250 +/* ---- Include Files -------------------------------------------------------- */
1251 +
1252 +#include "interface/vchi/vchi.h"
1253 +#include "vc_vchi_audioserv_defs.h"
1254 +
1255 +/* ---- Private Constants and Types ------------------------------------------ */
1256 +
1257 +#define BCM2835_AUDIO_STOP           0
1258 +#define BCM2835_AUDIO_START          1
1259 +#define BCM2835_AUDIO_WRITE          2
1260 +
1261 +/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
1262 +#ifdef AUDIO_DEBUG_ENABLE
1263 +       #define LOG_ERR( fmt, arg... )   pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
1264 +       #define LOG_WARN( fmt, arg... )  pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
1265 +       #define LOG_INFO( fmt, arg... )  pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
1266 +       #define LOG_DBG( fmt, arg... )   pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
1267 +#else
1268 +       #define LOG_ERR( fmt, arg... )   pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
1269 +       #define LOG_WARN( fmt, arg... )
1270 +       #define LOG_INFO( fmt, arg... )
1271 +       #define LOG_DBG( fmt, arg... )
1272 +#endif
1273 +
1274 +typedef struct opaque_AUDIO_INSTANCE_T {
1275 +       uint32_t num_connections;
1276 +       VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
1277 +       struct completion msg_avail_comp;
1278 +       struct mutex vchi_mutex;
1279 +       bcm2835_alsa_stream_t *alsa_stream;
1280 +       int32_t result;
1281 +       short peer_version;
1282 +} AUDIO_INSTANCE_T;
1283 +
1284 +bool force_bulk = false;
1285 +
1286 +/* ---- Private Variables ---------------------------------------------------- */
1287 +
1288 +/* ---- Private Function Prototypes ------------------------------------------ */
1289 +
1290 +/* ---- Private Functions ---------------------------------------------------- */
1291 +
1292 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
1293 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
1294 +static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
1295 +                                     uint32_t count, void *src);
1296 +
1297 +typedef struct {
1298 +       struct work_struct my_work;
1299 +       bcm2835_alsa_stream_t *alsa_stream;
1300 +       int cmd;
1301 +       void *src;
1302 +       uint32_t count;
1303 +} my_work_t;
1304 +
1305 +static void my_wq_function(struct work_struct *work)
1306 +{
1307 +       my_work_t *w = (my_work_t *) work;
1308 +       int ret = -9;
1309 +       LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
1310 +       switch (w->cmd) {
1311 +       case BCM2835_AUDIO_START:
1312 +               ret = bcm2835_audio_start_worker(w->alsa_stream);
1313 +               break;
1314 +       case BCM2835_AUDIO_STOP:
1315 +               ret = bcm2835_audio_stop_worker(w->alsa_stream);
1316 +               break;
1317 +       case BCM2835_AUDIO_WRITE:
1318 +               ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
1319 +                                                w->src);
1320 +               break;
1321 +       default:
1322 +               LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
1323 +               break;
1324 +       }
1325 +       kfree((void *)work);
1326 +       LOG_DBG(" .. OUT %d\n", ret);
1327 +}
1328 +
1329 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
1330 +{
1331 +       int ret = -1;
1332 +       LOG_DBG(" .. IN\n");
1333 +       if (alsa_stream->my_wq) {
1334 +               my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
1335 +               /*--- Queue some work (item 1) ---*/
1336 +               if (work) {
1337 +                       INIT_WORK((struct work_struct *)work, my_wq_function);
1338 +                       work->alsa_stream = alsa_stream;
1339 +                       work->cmd = BCM2835_AUDIO_START;
1340 +                       if (queue_work
1341 +                           (alsa_stream->my_wq, (struct work_struct *)work))
1342 +                               ret = 0;
1343 +               } else
1344 +                       LOG_ERR(" .. Error: NULL work kmalloc\n");
1345 +       }
1346 +       LOG_DBG(" .. OUT %d\n", ret);
1347 +       return ret;
1348 +}
1349 +
1350 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
1351 +{
1352 +       int ret = -1;
1353 +       LOG_DBG(" .. IN\n");
1354 +       if (alsa_stream->my_wq) {
1355 +               my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
1356 +                /*--- Queue some work (item 1) ---*/
1357 +               if (work) {
1358 +                       INIT_WORK((struct work_struct *)work, my_wq_function);
1359 +                       work->alsa_stream = alsa_stream;
1360 +                       work->cmd = BCM2835_AUDIO_STOP;
1361 +                       if (queue_work
1362 +                           (alsa_stream->my_wq, (struct work_struct *)work))
1363 +                               ret = 0;
1364 +               } else
1365 +                       LOG_ERR(" .. Error: NULL work kmalloc\n");
1366 +       }
1367 +       LOG_DBG(" .. OUT %d\n", ret);
1368 +       return ret;
1369 +}
1370 +
1371 +int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
1372 +                       uint32_t count, void *src)
1373 +{
1374 +       int ret = -1;
1375 +       LOG_DBG(" .. IN\n");
1376 +       if (alsa_stream->my_wq) {
1377 +               my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
1378 +                /*--- Queue some work (item 1) ---*/
1379 +               if (work) {
1380 +                       INIT_WORK((struct work_struct *)work, my_wq_function);
1381 +                       work->alsa_stream = alsa_stream;
1382 +                       work->cmd = BCM2835_AUDIO_WRITE;
1383 +                       work->src = src;
1384 +                       work->count = count;
1385 +                       if (queue_work
1386 +                           (alsa_stream->my_wq, (struct work_struct *)work))
1387 +                               ret = 0;
1388 +               } else
1389 +                       LOG_ERR(" .. Error: NULL work kmalloc\n");
1390 +       }
1391 +       LOG_DBG(" .. OUT %d\n", ret);
1392 +       return ret;
1393 +}
1394 +
1395 +void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
1396 +{
1397 +       alsa_stream->my_wq = create_workqueue("my_queue");
1398 +       return;
1399 +}
1400 +
1401 +void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
1402 +{
1403 +       if (alsa_stream->my_wq) {
1404 +               flush_workqueue(alsa_stream->my_wq);
1405 +               destroy_workqueue(alsa_stream->my_wq);
1406 +               alsa_stream->my_wq = NULL;
1407 +       }
1408 +       return;
1409 +}
1410 +
1411 +static void audio_vchi_callback(void *param,
1412 +                               const VCHI_CALLBACK_REASON_T reason,
1413 +                               void *msg_handle)
1414 +{
1415 +       AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
1416 +       int32_t status;
1417 +       int32_t msg_len;
1418 +       VC_AUDIO_MSG_T m;
1419 +       bcm2835_alsa_stream_t *alsa_stream = 0;
1420 +       LOG_DBG(" .. IN instance=%p, param=%p, reason=%d, handle=%p\n",
1421 +               instance, param, reason, msg_handle);
1422 +
1423 +       if (!instance || reason != VCHI_CALLBACK_MSG_AVAILABLE) {
1424 +               return;
1425 +       }
1426 +       alsa_stream = instance->alsa_stream;
1427 +       status = vchi_msg_dequeue(instance->vchi_handle[0],
1428 +                                 &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
1429 +       if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
1430 +               LOG_DBG
1431 +                   (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
1432 +                    instance, m.u.result.success);
1433 +               instance->result = m.u.result.success;
1434 +               complete(&instance->msg_avail_comp);
1435 +       } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
1436 +               irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
1437 +               LOG_DBG
1438 +                   (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
1439 +                    instance, m.u.complete.count);
1440 +               if (alsa_stream && callback) {
1441 +                       atomic_add(m.u.complete.count, &alsa_stream->retrieved);
1442 +                       callback(0, alsa_stream);
1443 +               } else {
1444 +                       LOG_DBG(" .. unexpected alsa_stream=%p, callback=%p\n",
1445 +                               alsa_stream, callback);
1446 +               }
1447 +       } else {
1448 +               LOG_DBG(" .. unexpected m.type=%d\n", m.type);
1449 +       }
1450 +       LOG_DBG(" .. OUT\n");
1451 +}
1452 +
1453 +static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
1454 +                                           VCHI_CONNECTION_T **
1455 +                                           vchi_connections,
1456 +                                           uint32_t num_connections)
1457 +{
1458 +       uint32_t i;
1459 +       AUDIO_INSTANCE_T *instance;
1460 +       int status;
1461 +
1462 +       LOG_DBG("%s: start", __func__);
1463 +
1464 +       if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
1465 +               LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
1466 +                       __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
1467 +
1468 +               return NULL;
1469 +       }
1470 +       /* Allocate memory for this instance */
1471 +       instance = kmalloc(sizeof(*instance), GFP_KERNEL);
1472 +
1473 +       memset(instance, 0, sizeof(*instance));
1474 +       instance->num_connections = num_connections;
1475 +
1476 +       /* Create a lock for exclusive, serialized VCHI connection access */
1477 +       mutex_init(&instance->vchi_mutex);
1478 +       /* Open the VCHI service connections */
1479 +       for (i = 0; i < num_connections; i++) {
1480 +               SERVICE_CREATION_T params = {
1481 +                       VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
1482 +                       VC_AUDIO_SERVER_NAME,   // 4cc service code
1483 +                       vchi_connections[i],    // passed in fn pointers
1484 +                       0,      // rx fifo size (unused)
1485 +                       0,      // tx fifo size (unused)
1486 +                       audio_vchi_callback,    // service callback
1487 +                       instance,       // service callback parameter
1488 +                       1,      //TODO: remove VCOS_FALSE,   // unaligned bulk recieves
1489 +                       1,      //TODO: remove VCOS_FALSE,   // unaligned bulk transmits
1490 +                       0       // want crc check on bulk transfers
1491 +               };
1492 +
1493 +               status = vchi_service_open(vchi_instance, &params,
1494 +                                          &instance->vchi_handle[i]);
1495 +               if (status) {
1496 +                       LOG_ERR
1497 +                           ("%s: failed to open VCHI service connection (status=%d)\n",
1498 +                            __func__, status);
1499 +
1500 +                       goto err_close_services;
1501 +               }
1502 +               /* Finished with the service for now */
1503 +               vchi_service_release(instance->vchi_handle[i]);
1504 +       }
1505 +
1506 +       return instance;
1507 +
1508 +err_close_services:
1509 +       for (i = 0; i < instance->num_connections; i++) {
1510 +               vchi_service_close(instance->vchi_handle[i]);
1511 +       }
1512 +
1513 +       kfree(instance);
1514 +
1515 +       return NULL;
1516 +}
1517 +
1518 +static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
1519 +{
1520 +       uint32_t i;
1521 +
1522 +       LOG_DBG(" .. IN\n");
1523 +
1524 +       if (instance == NULL) {
1525 +               LOG_ERR("%s: invalid handle %p\n", __func__, instance);
1526 +
1527 +               return -1;
1528 +       }
1529 +
1530 +       LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
1531 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1532 +       {
1533 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1534 +               return -EINTR;
1535 +       }
1536 +
1537 +       /* Close all VCHI service connections */
1538 +       for (i = 0; i < instance->num_connections; i++) {
1539 +               int32_t success;
1540 +               LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
1541 +               vchi_service_use(instance->vchi_handle[i]);
1542 +
1543 +               success = vchi_service_close(instance->vchi_handle[i]);
1544 +               if (success != 0) {
1545 +                       LOG_ERR
1546 +                           ("%s: failed to close VCHI service connection (status=%d)\n",
1547 +                            __func__, success);
1548 +               }
1549 +       }
1550 +
1551 +       mutex_unlock(&instance->vchi_mutex);
1552 +
1553 +       kfree(instance);
1554 +
1555 +       LOG_DBG(" .. OUT\n");
1556 +
1557 +       return 0;
1558 +}
1559 +
1560 +static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
1561 +{
1562 +       static VCHI_INSTANCE_T vchi_instance;
1563 +       static VCHI_CONNECTION_T *vchi_connection;
1564 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1565 +       int ret;
1566 +       LOG_DBG(" .. IN\n");
1567 +
1568 +       LOG_INFO("%s: start", __func__);
1569 +       //BUG_ON(instance);
1570 +       if (instance) {
1571 +               LOG_ERR("%s: VCHI instance already open (%p)\n",
1572 +                       __func__, instance);
1573 +               instance->alsa_stream = alsa_stream;
1574 +               alsa_stream->instance = instance;
1575 +               ret = 0;        // xxx todo -1;
1576 +               goto err_free_mem;
1577 +       }
1578 +
1579 +       /* Initialize and create a VCHI connection */
1580 +       ret = vchi_initialise(&vchi_instance);
1581 +       if (ret != 0) {
1582 +               LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
1583 +                       __func__, ret);
1584 +
1585 +               ret = -EIO;
1586 +               goto err_free_mem;
1587 +       }
1588 +       ret = vchi_connect(NULL, 0, vchi_instance);
1589 +       if (ret != 0) {
1590 +               LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
1591 +                       __func__, ret);
1592 +
1593 +               ret = -EIO;
1594 +               goto err_free_mem;
1595 +       }
1596 +
1597 +       /* Initialize an instance of the audio service */
1598 +       instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
1599 +
1600 +       if (instance == NULL /*|| audio_handle != instance */ ) {
1601 +               LOG_ERR("%s: failed to initialize audio service\n", __func__);
1602 +
1603 +               ret = -EPERM;
1604 +               goto err_free_mem;
1605 +       }
1606 +
1607 +       instance->alsa_stream = alsa_stream;
1608 +       alsa_stream->instance = instance;
1609 +
1610 +       LOG_DBG(" success !\n");
1611 +err_free_mem:
1612 +       LOG_DBG(" .. OUT\n");
1613 +
1614 +       return ret;
1615 +}
1616 +
1617 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
1618 +{
1619 +       AUDIO_INSTANCE_T *instance;
1620 +       VC_AUDIO_MSG_T m;
1621 +       int32_t success;
1622 +       int ret;
1623 +       LOG_DBG(" .. IN\n");
1624 +
1625 +       my_workqueue_init(alsa_stream);
1626 +
1627 +       ret = bcm2835_audio_open_connection(alsa_stream);
1628 +       if (ret != 0) {
1629 +               ret = -1;
1630 +               goto exit;
1631 +       }
1632 +       instance = alsa_stream->instance;
1633 +
1634 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1635 +       {
1636 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1637 +               return -EINTR;
1638 +       }
1639 +       vchi_service_use(instance->vchi_handle[0]);
1640 +
1641 +       m.type = VC_AUDIO_MSG_TYPE_OPEN;
1642 +
1643 +       /* Send the message to the videocore */
1644 +       success = vchi_msg_queue(instance->vchi_handle[0],
1645 +                                &m, sizeof m,
1646 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1647 +
1648 +       if (success != 0) {
1649 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1650 +                       __func__, success);
1651 +
1652 +               ret = -1;
1653 +               goto unlock;
1654 +       }
1655 +
1656 +       ret = 0;
1657 +
1658 +unlock:
1659 +       vchi_service_release(instance->vchi_handle[0]);
1660 +       mutex_unlock(&instance->vchi_mutex);
1661 +exit:
1662 +       LOG_DBG(" .. OUT\n");
1663 +       return ret;
1664 +}
1665 +
1666 +static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
1667 +                                      bcm2835_chip_t * chip)
1668 +{
1669 +       VC_AUDIO_MSG_T m;
1670 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1671 +       int32_t success;
1672 +       int ret;
1673 +       LOG_DBG(" .. IN\n");
1674 +
1675 +       LOG_INFO
1676 +           (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
1677 +
1678 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1679 +       {
1680 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1681 +               return -EINTR;
1682 +       }
1683 +       vchi_service_use(instance->vchi_handle[0]);
1684 +
1685 +       instance->result = -1;
1686 +
1687 +       m.type = VC_AUDIO_MSG_TYPE_CONTROL;
1688 +       m.u.control.dest = chip->dest;
1689 +       m.u.control.volume = chip->volume;
1690 +
1691 +       /* Create the message available completion */
1692 +       init_completion(&instance->msg_avail_comp);
1693 +
1694 +       /* Send the message to the videocore */
1695 +       success = vchi_msg_queue(instance->vchi_handle[0],
1696 +                                &m, sizeof m,
1697 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1698 +
1699 +       if (success != 0) {
1700 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1701 +                       __func__, success);
1702 +
1703 +               ret = -1;
1704 +               goto unlock;
1705 +       }
1706 +
1707 +       /* We are expecting a reply from the videocore */
1708 +       ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1709 +       if (ret) {
1710 +               LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1711 +                       __func__, success);
1712 +               goto unlock;
1713 +       }
1714 +
1715 +       if (instance->result != 0) {
1716 +               LOG_ERR("%s: result=%d\n", __func__, instance->result);
1717 +
1718 +               ret = -1;
1719 +               goto unlock;
1720 +       }
1721 +
1722 +       ret = 0;
1723 +
1724 +unlock:
1725 +       vchi_service_release(instance->vchi_handle[0]);
1726 +       mutex_unlock(&instance->vchi_mutex);
1727 +
1728 +       LOG_DBG(" .. OUT\n");
1729 +       return ret;
1730 +}
1731 +
1732 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
1733 +{
1734 +       int i;
1735 +       int ret = 0;
1736 +       LOG_DBG(" .. IN\n");
1737 +
1738 +       /* change ctls for all substreams */
1739 +       for (i = 0; i < MAX_SUBSTREAMS; i++) {
1740 +               if (chip->avail_substreams & (1 << i)) {
1741 +                       if (!chip->alsa_stream[i])
1742 +                       {
1743 +                               LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
1744 +                               ret = 0;
1745 +                       }
1746 +                       else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
1747 +                                (chip->alsa_stream[i], chip) != 0)
1748 +                                {
1749 +                                       LOG_DBG("Couldn't set the controls for stream %d\n", i);
1750 +                                       ret = -1;
1751 +                                }
1752 +                       else LOG_DBG(" Controls set for stream %d\n", i);
1753 +               }
1754 +       }
1755 +       LOG_DBG(" .. OUT ret=%d\n", ret);
1756 +       return ret;
1757 +}
1758 +
1759 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
1760 +                            uint32_t channels, uint32_t samplerate,
1761 +                            uint32_t bps)
1762 +{
1763 +       VC_AUDIO_MSG_T m;
1764 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1765 +       int32_t success;
1766 +       int ret;
1767 +       LOG_DBG(" .. IN\n");
1768 +
1769 +       LOG_INFO
1770 +           (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
1771 +            channels, samplerate, bps);
1772 +
1773 +       /* resend ctls - alsa_stream may not have been open when first send */
1774 +       ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
1775 +       if (ret != 0) {
1776 +               LOG_ERR(" Alsa controls not supported\n");
1777 +               return -EINVAL;
1778 +       }
1779 +
1780 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1781 +       {
1782 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1783 +               return -EINTR;
1784 +       }
1785 +       vchi_service_use(instance->vchi_handle[0]);
1786 +
1787 +       instance->result = -1;
1788 +
1789 +       m.type = VC_AUDIO_MSG_TYPE_CONFIG;
1790 +       m.u.config.channels = channels;
1791 +       m.u.config.samplerate = samplerate;
1792 +       m.u.config.bps = bps;
1793 +
1794 +       /* Create the message available completion */
1795 +       init_completion(&instance->msg_avail_comp);
1796 +
1797 +       /* Send the message to the videocore */
1798 +       success = vchi_msg_queue(instance->vchi_handle[0],
1799 +                                &m, sizeof m,
1800 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1801 +
1802 +       if (success != 0) {
1803 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1804 +                       __func__, success);
1805 +
1806 +               ret = -1;
1807 +               goto unlock;
1808 +       }
1809 +
1810 +       /* We are expecting a reply from the videocore */
1811 +       ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1812 +       if (ret) {
1813 +               LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1814 +                       __func__, success);
1815 +               goto unlock;
1816 +       }
1817 +
1818 +       if (instance->result != 0) {
1819 +               LOG_ERR("%s: result=%d", __func__, instance->result);
1820 +
1821 +               ret = -1;
1822 +               goto unlock;
1823 +       }
1824 +
1825 +       ret = 0;
1826 +
1827 +unlock:
1828 +       vchi_service_release(instance->vchi_handle[0]);
1829 +       mutex_unlock(&instance->vchi_mutex);
1830 +
1831 +       LOG_DBG(" .. OUT\n");
1832 +       return ret;
1833 +}
1834 +
1835 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
1836 +{
1837 +       LOG_DBG(" .. IN\n");
1838 +
1839 +       LOG_DBG(" .. OUT\n");
1840 +
1841 +       return 0;
1842 +}
1843 +
1844 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
1845 +{
1846 +       VC_AUDIO_MSG_T m;
1847 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1848 +       int32_t success;
1849 +       int ret;
1850 +       LOG_DBG(" .. IN\n");
1851 +
1852 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1853 +       {
1854 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1855 +               return -EINTR;
1856 +       }
1857 +       vchi_service_use(instance->vchi_handle[0]);
1858 +
1859 +       m.type = VC_AUDIO_MSG_TYPE_START;
1860 +
1861 +       /* Send the message to the videocore */
1862 +       success = vchi_msg_queue(instance->vchi_handle[0],
1863 +                                &m, sizeof m,
1864 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1865 +
1866 +       if (success != 0) {
1867 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1868 +                       __func__, success);
1869 +
1870 +               ret = -1;
1871 +               goto unlock;
1872 +       }
1873 +
1874 +       ret = 0;
1875 +
1876 +unlock:
1877 +       vchi_service_release(instance->vchi_handle[0]);
1878 +       mutex_unlock(&instance->vchi_mutex);
1879 +       LOG_DBG(" .. OUT\n");
1880 +       return ret;
1881 +}
1882 +
1883 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
1884 +{
1885 +       VC_AUDIO_MSG_T m;
1886 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1887 +       int32_t success;
1888 +       int ret;
1889 +       LOG_DBG(" .. IN\n");
1890 +
1891 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1892 +       {
1893 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1894 +               return -EINTR;
1895 +       }
1896 +       vchi_service_use(instance->vchi_handle[0]);
1897 +
1898 +       m.type = VC_AUDIO_MSG_TYPE_STOP;
1899 +       m.u.stop.draining = alsa_stream->draining;
1900 +
1901 +       /* Send the message to the videocore */
1902 +       success = vchi_msg_queue(instance->vchi_handle[0],
1903 +                                &m, sizeof m,
1904 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1905 +
1906 +       if (success != 0) {
1907 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1908 +                       __func__, success);
1909 +
1910 +               ret = -1;
1911 +               goto unlock;
1912 +       }
1913 +
1914 +       ret = 0;
1915 +
1916 +unlock:
1917 +       vchi_service_release(instance->vchi_handle[0]);
1918 +       mutex_unlock(&instance->vchi_mutex);
1919 +       LOG_DBG(" .. OUT\n");
1920 +       return ret;
1921 +}
1922 +
1923 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
1924 +{
1925 +       VC_AUDIO_MSG_T m;
1926 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1927 +       int32_t success;
1928 +       int ret;
1929 +       LOG_DBG(" .. IN\n");
1930 +
1931 +       my_workqueue_quit(alsa_stream);
1932 +
1933 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1934 +       {
1935 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1936 +               return -EINTR;
1937 +       }
1938 +       vchi_service_use(instance->vchi_handle[0]);
1939 +
1940 +       m.type = VC_AUDIO_MSG_TYPE_CLOSE;
1941 +
1942 +       /* Create the message available completion */
1943 +       init_completion(&instance->msg_avail_comp);
1944 +
1945 +       /* Send the message to the videocore */
1946 +       success = vchi_msg_queue(instance->vchi_handle[0],
1947 +                                &m, sizeof m,
1948 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1949 +
1950 +       if (success != 0) {
1951 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1952 +                       __func__, success);
1953 +               ret = -1;
1954 +               goto unlock;
1955 +       }
1956 +
1957 +       ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1958 +       if (ret) {
1959 +               LOG_ERR("%s: failed on waiting for event (status=%d)",
1960 +                       __func__, success);
1961 +               goto unlock;
1962 +       }
1963 +       if (instance->result != 0) {
1964 +               LOG_ERR("%s: failed result (status=%d)",
1965 +                       __func__, instance->result);
1966 +
1967 +               ret = -1;
1968 +               goto unlock;
1969 +       }
1970 +
1971 +       ret = 0;
1972 +
1973 +unlock:
1974 +       vchi_service_release(instance->vchi_handle[0]);
1975 +       mutex_unlock(&instance->vchi_mutex);
1976 +
1977 +       /* Stop the audio service */
1978 +       if (instance) {
1979 +               vc_vchi_audio_deinit(instance);
1980 +               alsa_stream->instance = NULL;
1981 +       }
1982 +       LOG_DBG(" .. OUT\n");
1983 +       return ret;
1984 +}
1985 +
1986 +int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
1987 +                              uint32_t count, void *src)
1988 +{
1989 +       VC_AUDIO_MSG_T m;
1990 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1991 +       int32_t success;
1992 +       int ret;
1993 +
1994 +       LOG_DBG(" .. IN\n");
1995 +
1996 +       LOG_INFO(" Writing %d bytes from %p\n", count, src);
1997 +
1998 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1999 +       {
2000 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
2001 +               return -EINTR;
2002 +       }
2003 +       vchi_service_use(instance->vchi_handle[0]);
2004 +
2005 +       if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) {
2006 +               LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
2007 +       }
2008 +       m.type = VC_AUDIO_MSG_TYPE_WRITE;
2009 +       m.u.write.count = count;
2010 +       // old version uses bulk, new version uses control
2011 +       m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000;
2012 +       m.u.write.callback = alsa_stream->fifo_irq_handler;
2013 +       m.u.write.cookie = alsa_stream;
2014 +       m.u.write.silence = src == NULL;
2015 +
2016 +       /* Send the message to the videocore */
2017 +       success = vchi_msg_queue(instance->vchi_handle[0],
2018 +                                &m, sizeof m,
2019 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
2020 +
2021 +       if (success != 0) {
2022 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
2023 +                       __func__, success);
2024 +
2025 +               ret = -1;
2026 +               goto unlock;
2027 +       }
2028 +       if (!m.u.write.silence) {
2029 +               if (m.u.write.max_packet == 0) {
2030 +                       /* Send the message to the videocore */
2031 +                       success = vchi_bulk_queue_transmit(instance->vchi_handle[0],
2032 +                                                          src, count,
2033 +                                                          0 *
2034 +                                                          VCHI_FLAGS_BLOCK_UNTIL_QUEUED
2035 +                                                          +
2036 +                                                          1 *
2037 +                                                          VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
2038 +                                                          NULL);
2039 +               } else {
2040 +                       while (count > 0) {
2041 +                               int bytes = min((int)m.u.write.max_packet, (int)count);
2042 +                               success = vchi_msg_queue(instance->vchi_handle[0],
2043 +                                                        src, bytes,
2044 +                                                        VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
2045 +                               src = (char *)src + bytes;
2046 +                               count -= bytes;
2047 +                       }
2048 +               }
2049 +               if (success != 0) {
2050 +                       LOG_ERR
2051 +                           ("%s: failed on vchi_bulk_queue_transmit (status=%d)",
2052 +                            __func__, success);
2053 +
2054 +                       ret = -1;
2055 +                       goto unlock;
2056 +               }
2057 +       }
2058 +       ret = 0;
2059 +
2060 +unlock:
2061 +       vchi_service_release(instance->vchi_handle[0]);
2062 +       mutex_unlock(&instance->vchi_mutex);
2063 +       LOG_DBG(" .. OUT\n");
2064 +       return ret;
2065 +}
2066 +
2067 +/**
2068 +  * Returns all buffers from arm->vc
2069 +  */
2070 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
2071 +{
2072 +       LOG_DBG(" .. IN\n");
2073 +       LOG_DBG(" .. OUT\n");
2074 +       return;
2075 +}
2076 +
2077 +/**
2078 +  * Forces VC to flush(drop) its filled playback buffers and 
2079 +  * return them the us. (VC->ARM)
2080 +  */
2081 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
2082 +{
2083 +       LOG_DBG(" .. IN\n");
2084 +       LOG_DBG(" .. OUT\n");
2085 +}
2086 +
2087 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
2088 +{
2089 +       uint32_t count = atomic_read(&alsa_stream->retrieved);
2090 +       atomic_sub(count, &alsa_stream->retrieved);
2091 +       return count;
2092 +}
2093 +
2094 +module_param(force_bulk, bool, 0444);
2095 +MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
2096 diff -urN linux-3.10/sound/arm/Kconfig linux-rpi-3.10.y/sound/arm/Kconfig
2097 --- linux-3.10/sound/arm/Kconfig        2013-06-30 23:13:29.000000000 +0100
2098 +++ linux-rpi-3.10.y/sound/arm/Kconfig  2013-07-06 15:25:50.000000000 +0100
2099 @@ -39,5 +39,12 @@
2100           Say Y or M if you want to support any AC97 codec attached to
2101           the PXA2xx AC97 interface.
2102  
2103 +config SND_BCM2835
2104 +       tristate "BCM2835 ALSA driver"
2105 +       depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND
2106 +       select SND_PCM
2107 +       help
2108 +         Say Y or M if you want to support BCM2835 Alsa pcm card driver
2109 +
2110  endif  # SND_ARM
2111  
2112 diff -urN linux-3.10/sound/arm/Makefile linux-rpi-3.10.y/sound/arm/Makefile
2113 --- linux-3.10/sound/arm/Makefile       2013-06-30 23:13:29.000000000 +0100
2114 +++ linux-rpi-3.10.y/sound/arm/Makefile 2013-07-06 15:25:50.000000000 +0100
2115 @@ -14,3 +14,9 @@
2116  
2117  obj-$(CONFIG_SND_PXA2XX_AC97)  += snd-pxa2xx-ac97.o
2118  snd-pxa2xx-ac97-objs           := pxa2xx-ac97.o
2119 +
2120 +obj-$(CONFIG_SND_BCM2835)      += snd-bcm2835.o
2121 +snd-bcm2835-objs               := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
2122 +
2123 +EXTRA_CFLAGS += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
2124 +
2125 diff -urN linux-3.10/sound/arm/vc_vchi_audioserv_defs.h linux-rpi-3.10.y/sound/arm/vc_vchi_audioserv_defs.h
2126 --- linux-3.10/sound/arm/vc_vchi_audioserv_defs.h       1970-01-01 01:00:00.000000000 +0100
2127 +++ linux-rpi-3.10.y/sound/arm/vc_vchi_audioserv_defs.h 2013-07-06 15:25:50.000000000 +0100
2128 @@ -0,0 +1,116 @@
2129 +/*****************************************************************************
2130 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
2131 +*
2132 +* Unless you and Broadcom execute a separate written software license
2133 +* agreement governing use of this software, this software is licensed to you
2134 +* under the terms of the GNU General Public License version 2, available at
2135 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2136 +*
2137 +* Notwithstanding the above, under no circumstances may you combine this
2138 +* software in any way with any other Broadcom software provided under a
2139 +* license other than the GPL, without Broadcom's express prior written
2140 +* consent.
2141 +*****************************************************************************/
2142 +
2143 +#ifndef _VC_AUDIO_DEFS_H_
2144 +#define _VC_AUDIO_DEFS_H_
2145 +
2146 +#define VC_AUDIOSERV_MIN_VER 1
2147 +#define VC_AUDIOSERV_VER 2
2148 +
2149 +// FourCC code used for VCHI connection
2150 +#define VC_AUDIO_SERVER_NAME  MAKE_FOURCC("AUDS")
2151 +
2152 +// Maximum message length
2153 +#define VC_AUDIO_MAX_MSG_LEN  (sizeof( VC_AUDIO_MSG_T ))
2154 +
2155 +// List of screens that are currently supported
2156 +// All message types supported for HOST->VC direction
2157 +typedef enum {
2158 +       VC_AUDIO_MSG_TYPE_RESULT,       // Generic result
2159 +       VC_AUDIO_MSG_TYPE_COMPLETE,     // Generic result
2160 +       VC_AUDIO_MSG_TYPE_CONFIG,       // Configure audio
2161 +       VC_AUDIO_MSG_TYPE_CONTROL,      // Configure audio
2162 +       VC_AUDIO_MSG_TYPE_OPEN, // Configure audio
2163 +       VC_AUDIO_MSG_TYPE_CLOSE,        // Configure audio
2164 +       VC_AUDIO_MSG_TYPE_START,        // Configure audio
2165 +       VC_AUDIO_MSG_TYPE_STOP, // Configure audio
2166 +       VC_AUDIO_MSG_TYPE_WRITE,        // Configure audio
2167 +       VC_AUDIO_MSG_TYPE_MAX
2168 +} VC_AUDIO_MSG_TYPE;
2169 +
2170 +// configure the audio
2171 +typedef struct {
2172 +       uint32_t channels;
2173 +       uint32_t samplerate;
2174 +       uint32_t bps;
2175 +
2176 +} VC_AUDIO_CONFIG_T;
2177 +
2178 +typedef struct {
2179 +       uint32_t volume;
2180 +       uint32_t dest;
2181 +
2182 +} VC_AUDIO_CONTROL_T;
2183 +
2184 +// audio
2185 +typedef struct {
2186 +       uint32_t dummy;
2187 +
2188 +} VC_AUDIO_OPEN_T;
2189 +
2190 +// audio
2191 +typedef struct {
2192 +       uint32_t dummy;
2193 +
2194 +} VC_AUDIO_CLOSE_T;
2195 +// audio
2196 +typedef struct {
2197 +       uint32_t dummy;
2198 +
2199 +} VC_AUDIO_START_T;
2200 +// audio
2201 +typedef struct {
2202 +       uint32_t draining;
2203 +
2204 +} VC_AUDIO_STOP_T;
2205 +
2206 +// configure the write audio samples
2207 +typedef struct {
2208 +       uint32_t count;         // in bytes
2209 +       void *callback;
2210 +       void *cookie;
2211 +       uint16_t silence;
2212 +       uint16_t max_packet;
2213 +} VC_AUDIO_WRITE_T;
2214 +
2215 +// Generic result for a request (VC->HOST)
2216 +typedef struct {
2217 +       int32_t success;        // Success value
2218 +
2219 +} VC_AUDIO_RESULT_T;
2220 +
2221 +// Generic result for a request (VC->HOST)
2222 +typedef struct {
2223 +       int32_t count;          // Success value
2224 +       void *callback;
2225 +       void *cookie;
2226 +} VC_AUDIO_COMPLETE_T;
2227 +
2228 +// Message header for all messages in HOST->VC direction
2229 +typedef struct {
2230 +       int32_t type;           // Message type (VC_AUDIO_MSG_TYPE)
2231 +       union {
2232 +               VC_AUDIO_CONFIG_T config;
2233 +               VC_AUDIO_CONTROL_T control;
2234 +               VC_AUDIO_OPEN_T open;
2235 +               VC_AUDIO_CLOSE_T close;
2236 +               VC_AUDIO_START_T start;
2237 +               VC_AUDIO_STOP_T stop;
2238 +               VC_AUDIO_WRITE_T write;
2239 +               VC_AUDIO_RESULT_T result;
2240 +               VC_AUDIO_COMPLETE_T complete;
2241 +       } u;
2242 +} VC_AUDIO_MSG_T;
2243 +
2244 +#endif // _VC_AUDIO_DEFS_H_