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