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
5 +/*****************************************************************************
6 +* Copyright 2011 Broadcom Corporation. All rights reserved.
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").
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
17 +*****************************************************************************/
19 +#include <linux/platform_device.h>
21 +#include <linux/init.h>
22 +#include <linux/slab.h>
23 +#include <linux/module.h>
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 };
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
40 +static struct snd_card *g_card = NULL;
41 +static bcm2835_chip_t *g_chip = NULL;
43 +static int snd_bcm2835_free(bcm2835_chip_t * chip)
49 +/* component-destructor
50 + * (see "Management of Cards and Components")
52 +static int snd_bcm2835_dev_free(struct snd_device *device)
54 + return snd_bcm2835_free(device->device_data);
57 +/* chip-specific constructor
58 + * (see "Management of Cards and Components")
60 +static int snd_bcm2835_create(struct snd_card *card,
61 + struct platform_device *pdev,
62 + bcm2835_chip_t ** rchip)
64 + bcm2835_chip_t *chip;
66 + static struct snd_device_ops ops = {
67 + .dev_free = snd_bcm2835_dev_free,
72 + chip = kzalloc(sizeof(*chip), GFP_KERNEL);
78 + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
80 + snd_bcm2835_free(chip);
88 +static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
91 + bcm2835_chip_t *chip;
92 + struct snd_card *card;
95 + if (dev >= MAX_SUBSTREAMS)
104 + goto add_register_map;
106 + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &g_card);
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);
115 + err = snd_bcm2835_create(g_card, pdev, &chip);
117 + dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
118 + goto out_bcm2835_create;
122 + err = snd_bcm2835_new_pcm(chip);
124 + dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
125 + goto out_bcm2835_new_pcm;
128 + err = snd_bcm2835_new_ctl(chip);
130 + dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
131 + goto out_bcm2835_new_ctl;
138 + BUG_ON(!(card && chip));
140 + chip->avail_substreams |= (1 << dev);
141 + chip->pdev[dev] = pdev;
144 + err = snd_card_register(card);
146 + dev_err(&pdev->dev,
147 + "Failed to register bcm2835 ALSA card \n");
148 + goto out_card_register;
150 + platform_set_drvdata(pdev, card);
151 + audio_info("bcm2835 ALSA card created!\n");
153 + audio_info("bcm2835 ALSA chip created!\n");
154 + platform_set_drvdata(pdev, (void *)dev);
162 +out_bcm2835_new_ctl:
163 +out_bcm2835_new_pcm:
166 + if (snd_card_free(g_card))
167 + dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
170 + dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
171 + dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
175 +static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
180 + drv_data = platform_get_drvdata(pdev);
182 + if (drv_data == (void *)g_card) {
183 + /* This is the card device */
184 + snd_card_free((struct snd_card *)drv_data);
188 + idx = (uint32_t) drv_data;
189 + if (g_card != NULL) {
191 + /* We pass chip device numbers in audio ipc devices
192 + * other than the one we registered our card with
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
201 + BUG_ON(!g_chip->avail_substreams);
205 + platform_set_drvdata(pdev, NULL);
211 +static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
212 + pm_message_t state)
217 +static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
224 +static struct platform_driver bcm2835_alsa0_driver = {
225 + .probe = snd_bcm2835_alsa_probe,
226 + .remove = snd_bcm2835_alsa_remove,
228 + .suspend = snd_bcm2835_alsa_suspend,
229 + .resume = snd_bcm2835_alsa_resume,
232 + .name = "bcm2835_AUD0",
233 + .owner = THIS_MODULE,
237 +static struct platform_driver bcm2835_alsa1_driver = {
238 + .probe = snd_bcm2835_alsa_probe,
239 + .remove = snd_bcm2835_alsa_remove,
241 + .suspend = snd_bcm2835_alsa_suspend,
242 + .resume = snd_bcm2835_alsa_resume,
245 + .name = "bcm2835_AUD1",
246 + .owner = THIS_MODULE,
250 +static struct platform_driver bcm2835_alsa2_driver = {
251 + .probe = snd_bcm2835_alsa_probe,
252 + .remove = snd_bcm2835_alsa_remove,
254 + .suspend = snd_bcm2835_alsa_suspend,
255 + .resume = snd_bcm2835_alsa_resume,
258 + .name = "bcm2835_AUD2",
259 + .owner = THIS_MODULE,
263 +static struct platform_driver bcm2835_alsa3_driver = {
264 + .probe = snd_bcm2835_alsa_probe,
265 + .remove = snd_bcm2835_alsa_remove,
267 + .suspend = snd_bcm2835_alsa_suspend,
268 + .resume = snd_bcm2835_alsa_resume,
271 + .name = "bcm2835_AUD3",
272 + .owner = THIS_MODULE,
276 +static struct platform_driver bcm2835_alsa4_driver = {
277 + .probe = snd_bcm2835_alsa_probe,
278 + .remove = snd_bcm2835_alsa_remove,
280 + .suspend = snd_bcm2835_alsa_suspend,
281 + .resume = snd_bcm2835_alsa_resume,
284 + .name = "bcm2835_AUD4",
285 + .owner = THIS_MODULE,
289 +static struct platform_driver bcm2835_alsa5_driver = {
290 + .probe = snd_bcm2835_alsa_probe,
291 + .remove = snd_bcm2835_alsa_remove,
293 + .suspend = snd_bcm2835_alsa_suspend,
294 + .resume = snd_bcm2835_alsa_resume,
297 + .name = "bcm2835_AUD5",
298 + .owner = THIS_MODULE,
302 +static struct platform_driver bcm2835_alsa6_driver = {
303 + .probe = snd_bcm2835_alsa_probe,
304 + .remove = snd_bcm2835_alsa_remove,
306 + .suspend = snd_bcm2835_alsa_suspend,
307 + .resume = snd_bcm2835_alsa_resume,
310 + .name = "bcm2835_AUD6",
311 + .owner = THIS_MODULE,
315 +static struct platform_driver bcm2835_alsa7_driver = {
316 + .probe = snd_bcm2835_alsa_probe,
317 + .remove = snd_bcm2835_alsa_remove,
319 + .suspend = snd_bcm2835_alsa_suspend,
320 + .resume = snd_bcm2835_alsa_resume,
323 + .name = "bcm2835_AUD7",
324 + .owner = THIS_MODULE,
328 +static int bcm2835_alsa_device_init(void)
331 + err = platform_driver_register(&bcm2835_alsa0_driver);
333 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
337 + err = platform_driver_register(&bcm2835_alsa1_driver);
339 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
343 + err = platform_driver_register(&bcm2835_alsa2_driver);
345 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
349 + err = platform_driver_register(&bcm2835_alsa3_driver);
351 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
355 + err = platform_driver_register(&bcm2835_alsa4_driver);
357 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
361 + err = platform_driver_register(&bcm2835_alsa5_driver);
363 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
367 + err = platform_driver_register(&bcm2835_alsa6_driver);
369 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
373 + err = platform_driver_register(&bcm2835_alsa7_driver);
375 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
382 + platform_driver_unregister(&bcm2835_alsa6_driver);
384 + platform_driver_unregister(&bcm2835_alsa5_driver);
386 + platform_driver_unregister(&bcm2835_alsa4_driver);
388 + platform_driver_unregister(&bcm2835_alsa3_driver);
390 + platform_driver_unregister(&bcm2835_alsa2_driver);
392 + platform_driver_unregister(&bcm2835_alsa1_driver);
394 + platform_driver_unregister(&bcm2835_alsa0_driver);
399 +static void bcm2835_alsa_device_exit(void)
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);
411 +late_initcall(bcm2835_alsa_device_init);
412 +module_exit(bcm2835_alsa_device_exit);
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
422 +/*****************************************************************************
423 +* Copyright 2011 Broadcom Corporation. All rights reserved.
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").
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
434 +*****************************************************************************/
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>
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>
455 +#include "bcm2835.h"
457 +/* volume maximum and minimum in terms of 0.01dB */
458 +#define CTRL_VOL_MAX 400
459 +#define CTRL_VOL_MIN -10239 /* originally -10240 */
462 +static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
463 + struct snd_ctl_elem_info *uinfo)
465 + audio_info(" ... IN\n");
466 + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
467 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
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;
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;
479 + uinfo->value.integer.min = 0;
480 + uinfo->value.integer.max = AUDIO_DEST_MAX-1;
482 + audio_info(" ... OUT\n");
486 +/* toggles mute on or off depending on the value of nmute, and returns
487 + * 1 if the mute value was changed, otherwise 0
489 +static int toggle_mute(struct bcm2835_chip *chip, int nmute)
491 + /* if settings are ok, just return 0 */
492 + if(chip->mute == nmute)
495 + /* if the sound is muted then we need to unmute */
496 + if(chip->mute == CTRL_VOL_MUTE)
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);
501 + else /* otherwise we mute */
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);
508 + chip->mute = nmute;
512 +static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
513 + struct snd_ctl_elem_value *ucontrol)
515 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
517 + BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
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;
529 +static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
530 + struct snd_ctl_elem_value *ucontrol)
532 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
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) */
542 + || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
544 + chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
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]);
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];
561 + if (bcm2835_audio_set_ctls(chip))
562 + printk(KERN_ERR "Failed to set ALSA controls..\n");
568 +static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
570 +static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
572 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
573 + .name = "PCM Playback Volume",
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,
581 + .tlv = {.p = snd_bcm2835_db_scale}
584 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
585 + .name = "PCM Playback Switch",
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,
595 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
596 + .name = "PCM Playback Route",
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,
607 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
612 + strcpy(chip->card->mixername, "Broadcom Mixer");
613 + for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
615 + snd_ctl_add(chip->card,
616 + snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
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
626 +/*****************************************************************************
627 +* Copyright 2011 Broadcom Corporation. All rights reserved.
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").
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
638 +*****************************************************************************/
640 +#ifndef __SOUND_ARM_BCM2835_H
641 +#define __SOUND_ARM_BCM2835_H
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>
655 +#define AUDIO_DEBUG_ENABLE
656 +#define AUDIO_VERBOSE_DEBUG_ENABLE
661 +#ifdef AUDIO_DEBUG_ENABLE
662 +#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
664 +#define audio_debug(fmt, arg...) \
665 + printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
667 +#define audio_info(fmt, arg...) \
668 + printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
672 +#define audio_debug(fmt, arg...)
674 +#define audio_info(fmt, arg...)
676 +#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
680 +#define audio_debug(fmt, arg...)
682 +#define audio_info(fmt, arg...)
684 +#endif /* AUDIO_DEBUG_ENABLE */
686 +#define audio_error(fmt, arg...) \
687 + printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
689 +#define audio_warning(fmt, arg...) \
690 + printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
692 +#define audio_alert(fmt, arg...) \
693 + printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
695 +#define MAX_SUBSTREAMS (8)
696 +#define AVAIL_SUBSTREAMS_MASK (0xff)
702 +/* macros for alsa2chip and chip2alsa, instead of functions */
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 */
707 +/* Some constants for values .. */
709 + AUDIO_DEST_AUTO = 0,
710 + AUDIO_DEST_HEADPHONES = 1,
711 + AUDIO_DEST_HDMI = 2,
713 +} SND_BCM2835_ROUTE_T;
716 + PCM_PLAYBACK_VOLUME,
718 + PCM_PLAYBACK_DEVICE,
719 +} SND_BCM2835_CTRL_T;
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];
731 + int old_volume; /* stores the volume value whist muted */
736 +typedef struct bcm2835_alsa_stream {
737 + bcm2835_chip_t *chip;
738 + struct snd_pcm_substream *substream;
739 + struct snd_pcm_indirect pcm_indirect;
741 + struct semaphore buffers_update_sem;
742 + struct semaphore control_sem;
744 + volatile uint32_t control;
745 + volatile uint32_t status;
752 + unsigned int buffer_size;
753 + unsigned int period_size;
755 + uint32_t enable_fifo_irq;
756 + irq_handler_t fifo_irq_handler;
758 + atomic_t retrieved;
759 + struct opaque_AUDIO_INSTANCE_T *instance;
760 + struct workqueue_struct *my_wq;
762 +} bcm2835_alsa_stream_t;
764 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
765 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
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,
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,
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);
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
787 +/*****************************************************************************
788 +* Copyright 2011 Broadcom Corporation. All rights reserved.
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").
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
799 +*****************************************************************************/
801 +#include <linux/interrupt.h>
802 +#include <linux/slab.h>
804 +#include "bcm2835.h"
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,
816 + .buffer_bytes_max = 128 * 1024,
817 + .period_bytes_min = 1 * 1024,
818 + .period_bytes_max = 128 * 1024,
820 + .periods_max = 128,
823 +static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
825 + audio_info("Freeing up alsa stream here ..\n");
826 + if (runtime->private_data)
827 + kfree(runtime->private_data);
828 + runtime->private_data = NULL;
831 +static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
833 + bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
834 + uint32_t consumed = 0;
835 + int new_period = 0;
837 + audio_info(" .. IN\n");
839 + audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
840 + alsa_stream ? alsa_stream->substream : 0);
842 + if (alsa_stream->open)
843 + consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
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
849 + if (alsa_stream->period_size) {
850 + if ((alsa_stream->pos / alsa_stream->period_size) !=
851 + ((alsa_stream->pos + consumed) / alsa_stream->period_size))
854 + audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
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),
861 + if (alsa_stream->buffer_size) {
862 + alsa_stream->pos += consumed &~ (1<<30);
863 + alsa_stream->pos %= alsa_stream->buffer_size;
866 + if (alsa_stream->substream) {
868 + snd_pcm_period_elapsed(alsa_stream->substream);
870 + audio_warning(" unexpected NULL substream\n");
872 + audio_info(" .. OUT\n");
874 + return IRQ_HANDLED;
878 +static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
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;
886 + audio_info(" .. IN (%d)\n", substream->number);
888 + audio_info("Alsa open (%d)\n", substream->number);
889 + idx = substream->number;
891 + if (idx > MAX_SUBSTREAMS) {
893 + ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
894 + idx, MAX_SUBSTREAMS);
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);
907 + alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
908 + if (alsa_stream == NULL) {
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;
918 + sema_init(&alsa_stream->buffers_update_sem, 0);
919 + sema_init(&alsa_stream->control_sem, 0);
920 + spin_lock_init(&alsa_stream->lock);
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;
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,
933 + err = bcm2835_audio_open(alsa_stream);
935 + kfree(alsa_stream);
939 + alsa_stream->open = 1;
940 + alsa_stream->draining = 1;
943 + audio_info(" .. OUT =%d\n", err);
948 +/* close callback */
949 +static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
951 + /* the hardware-specific codes will be here */
953 + struct snd_pcm_runtime *runtime = substream->runtime;
954 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
956 + audio_info(" .. IN\n");
957 + audio_info("Alsa close\n");
960 + * Call stop if it's still running. This happens when app
961 + * is force killed and we don't get a stop trigger.
963 + if (alsa_stream->running) {
965 + err = bcm2835_audio_stop(alsa_stream);
966 + alsa_stream->running = 0;
968 + audio_error(" Failed to STOP alsa device\n");
971 + alsa_stream->period_size = 0;
972 + alsa_stream->buffer_size = 0;
974 + if (alsa_stream->open) {
975 + alsa_stream->open = 0;
976 + bcm2835_audio_close(alsa_stream);
978 + if (alsa_stream->chip)
979 + alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
981 + * Do not free up alsa_stream here, it will be freed up by
982 + * runtime->private_free callback we registered in *_open above
985 + audio_info(" .. OUT\n");
990 +/* hw_params callback */
991 +static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
992 + struct snd_pcm_hw_params *params)
995 + struct snd_pcm_runtime *runtime = substream->runtime;
996 + bcm2835_alsa_stream_t *alsa_stream =
997 + (bcm2835_alsa_stream_t *) runtime->private_data;
999 + audio_info(" .. IN\n");
1001 + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
1004 + (" pcm_lib_malloc failed to allocated pages for buffers\n");
1008 + err = bcm2835_audio_set_params(alsa_stream, params_channels(params),
1009 + params_rate(params),
1010 + snd_pcm_format_width(params_format
1013 + audio_error(" error setting hw params\n");
1016 + bcm2835_audio_setup(alsa_stream);
1018 + /* in preparation of the stream, set the controls (volume level) of the stream */
1019 + bcm2835_audio_set_ctls(alsa_stream->chip);
1021 + audio_info(" .. OUT\n");
1026 +/* hw_free callback */
1027 +static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
1029 + audio_info(" .. IN\n");
1030 + return snd_pcm_lib_free_pages(substream);
1033 +/* prepare callback */
1034 +static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
1036 + struct snd_pcm_runtime *runtime = substream->runtime;
1037 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
1039 + audio_info(" .. IN\n");
1041 + memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
1043 + alsa_stream->pcm_indirect.hw_buffer_size =
1044 + alsa_stream->pcm_indirect.sw_buffer_size =
1045 + snd_pcm_lib_buffer_bytes(substream);
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;
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);
1055 + audio_info(" .. OUT\n");
1059 +static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
1060 + struct snd_pcm_indirect *rec, size_t bytes)
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);
1067 + err = bcm2835_audio_write(alsa_stream, bytes, src);
1069 + audio_error(" Failed to transfer to alsa device (%d)\n", err);
1073 +static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
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;
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);
1085 +/* trigger callback */
1086 +static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
1088 + struct snd_pcm_runtime *runtime = substream->runtime;
1089 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
1092 + audio_info(" .. IN\n");
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);
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;
1109 + audio_error(" Failed to START alsa device (%d)\n", err);
1113 + case SNDRV_PCM_TRIGGER_STOP:
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;
1121 + audio_info("DROPPING\n");
1122 + alsa_stream->draining = 0;
1124 + if (alsa_stream->running) {
1125 + err = bcm2835_audio_stop(alsa_stream);
1127 + audio_error(" Failed to STOP alsa device (%d)\n", err);
1128 + alsa_stream->running = 0;
1135 + audio_info(" .. OUT\n");
1139 +/* pointer callback */
1140 +static snd_pcm_uframes_t
1141 +snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
1143 + struct snd_pcm_runtime *runtime = substream->runtime;
1144 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
1146 + audio_info(" .. IN\n");
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);
1153 + audio_info(" .. OUT\n");
1154 + return snd_pcm_indirect_playback_pointer(substream,
1155 + &alsa_stream->pcm_indirect,
1156 + alsa_stream->pos);
1159 +static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
1160 + unsigned int cmd, void *arg)
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);
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,
1181 +/* create a pcm device */
1182 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
1184 + struct snd_pcm *pcm;
1187 + audio_info(" .. IN\n");
1189 + snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
1192 + pcm->private_data = chip;
1193 + strcpy(pcm->name, "bcm2835 ALSA");
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);
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,
1209 + audio_info(" .. OUT\n");
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
1217 +/*****************************************************************************
1218 +* Copyright 2011 Broadcom Corporation. All rights reserved.
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").
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
1229 +*****************************************************************************/
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>
1248 +#include "bcm2835.h"
1250 +/* ---- Include Files -------------------------------------------------------- */
1252 +#include "interface/vchi/vchi.h"
1253 +#include "vc_vchi_audioserv_defs.h"
1255 +/* ---- Private Constants and Types ------------------------------------------ */
1257 +#define BCM2835_AUDIO_STOP 0
1258 +#define BCM2835_AUDIO_START 1
1259 +#define BCM2835_AUDIO_WRITE 2
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)
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... )
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;
1281 + short peer_version;
1282 +} AUDIO_INSTANCE_T;
1284 +bool force_bulk = false;
1286 +/* ---- Private Variables ---------------------------------------------------- */
1288 +/* ---- Private Function Prototypes ------------------------------------------ */
1290 +/* ---- Private Functions ---------------------------------------------------- */
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);
1298 + struct work_struct my_work;
1299 + bcm2835_alsa_stream_t *alsa_stream;
1305 +static void my_wq_function(struct work_struct *work)
1307 + my_work_t *w = (my_work_t *) work;
1309 + LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
1311 + case BCM2835_AUDIO_START:
1312 + ret = bcm2835_audio_start_worker(w->alsa_stream);
1314 + case BCM2835_AUDIO_STOP:
1315 + ret = bcm2835_audio_stop_worker(w->alsa_stream);
1317 + case BCM2835_AUDIO_WRITE:
1318 + ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
1322 + LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
1325 + kfree((void *)work);
1326 + LOG_DBG(" .. OUT %d\n", ret);
1329 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
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) ---*/
1337 + INIT_WORK((struct work_struct *)work, my_wq_function);
1338 + work->alsa_stream = alsa_stream;
1339 + work->cmd = BCM2835_AUDIO_START;
1341 + (alsa_stream->my_wq, (struct work_struct *)work))
1344 + LOG_ERR(" .. Error: NULL work kmalloc\n");
1346 + LOG_DBG(" .. OUT %d\n", ret);
1350 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
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) ---*/
1358 + INIT_WORK((struct work_struct *)work, my_wq_function);
1359 + work->alsa_stream = alsa_stream;
1360 + work->cmd = BCM2835_AUDIO_STOP;
1362 + (alsa_stream->my_wq, (struct work_struct *)work))
1365 + LOG_ERR(" .. Error: NULL work kmalloc\n");
1367 + LOG_DBG(" .. OUT %d\n", ret);
1371 +int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
1372 + uint32_t count, void *src)
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) ---*/
1380 + INIT_WORK((struct work_struct *)work, my_wq_function);
1381 + work->alsa_stream = alsa_stream;
1382 + work->cmd = BCM2835_AUDIO_WRITE;
1384 + work->count = count;
1386 + (alsa_stream->my_wq, (struct work_struct *)work))
1389 + LOG_ERR(" .. Error: NULL work kmalloc\n");
1391 + LOG_DBG(" .. OUT %d\n", ret);
1395 +void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
1397 + alsa_stream->my_wq = create_workqueue("my_queue");
1401 +void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
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;
1411 +static void audio_vchi_callback(void *param,
1412 + const VCHI_CALLBACK_REASON_T reason,
1415 + AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
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);
1423 + if (!instance || reason != VCHI_CALLBACK_MSG_AVAILABLE) {
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) {
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;
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);
1444 + LOG_DBG(" .. unexpected alsa_stream=%p, callback=%p\n",
1445 + alsa_stream, callback);
1448 + LOG_DBG(" .. unexpected m.type=%d\n", m.type);
1450 + LOG_DBG(" .. OUT\n");
1453 +static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
1454 + VCHI_CONNECTION_T **
1456 + uint32_t num_connections)
1459 + AUDIO_INSTANCE_T *instance;
1462 + LOG_DBG("%s: start", __func__);
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);
1470 + /* Allocate memory for this instance */
1471 + instance = kmalloc(sizeof(*instance), GFP_KERNEL);
1473 + memset(instance, 0, sizeof(*instance));
1474 + instance->num_connections = num_connections;
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
1493 + status = vchi_service_open(vchi_instance, ¶ms,
1494 + &instance->vchi_handle[i]);
1497 + ("%s: failed to open VCHI service connection (status=%d)\n",
1498 + __func__, status);
1500 + goto err_close_services;
1502 + /* Finished with the service for now */
1503 + vchi_service_release(instance->vchi_handle[i]);
1508 +err_close_services:
1509 + for (i = 0; i < instance->num_connections; i++) {
1510 + vchi_service_close(instance->vchi_handle[i]);
1518 +static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
1522 + LOG_DBG(" .. IN\n");
1524 + if (instance == NULL) {
1525 + LOG_ERR("%s: invalid handle %p\n", __func__, instance);
1530 + LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
1531 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1533 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1537 + /* Close all VCHI service connections */
1538 + for (i = 0; i < instance->num_connections; i++) {
1540 + LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
1541 + vchi_service_use(instance->vchi_handle[i]);
1543 + success = vchi_service_close(instance->vchi_handle[i]);
1544 + if (success != 0) {
1546 + ("%s: failed to close VCHI service connection (status=%d)\n",
1547 + __func__, success);
1551 + mutex_unlock(&instance->vchi_mutex);
1555 + LOG_DBG(" .. OUT\n");
1560 +static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
1562 + static VCHI_INSTANCE_T vchi_instance;
1563 + static VCHI_CONNECTION_T *vchi_connection;
1564 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1566 + LOG_DBG(" .. IN\n");
1568 + LOG_INFO("%s: start", __func__);
1569 + //BUG_ON(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;
1579 + /* Initialize and create a VCHI connection */
1580 + ret = vchi_initialise(&vchi_instance);
1582 + LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
1586 + goto err_free_mem;
1588 + ret = vchi_connect(NULL, 0, vchi_instance);
1590 + LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
1594 + goto err_free_mem;
1597 + /* Initialize an instance of the audio service */
1598 + instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
1600 + if (instance == NULL /*|| audio_handle != instance */ ) {
1601 + LOG_ERR("%s: failed to initialize audio service\n", __func__);
1604 + goto err_free_mem;
1607 + instance->alsa_stream = alsa_stream;
1608 + alsa_stream->instance = instance;
1610 + LOG_DBG(" success !\n");
1612 + LOG_DBG(" .. OUT\n");
1617 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
1619 + AUDIO_INSTANCE_T *instance;
1623 + LOG_DBG(" .. IN\n");
1625 + my_workqueue_init(alsa_stream);
1627 + ret = bcm2835_audio_open_connection(alsa_stream);
1632 + instance = alsa_stream->instance;
1634 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1636 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1639 + vchi_service_use(instance->vchi_handle[0]);
1641 + m.type = VC_AUDIO_MSG_TYPE_OPEN;
1643 + /* Send the message to the videocore */
1644 + success = vchi_msg_queue(instance->vchi_handle[0],
1646 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1648 + if (success != 0) {
1649 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1650 + __func__, success);
1659 + vchi_service_release(instance->vchi_handle[0]);
1660 + mutex_unlock(&instance->vchi_mutex);
1662 + LOG_DBG(" .. OUT\n");
1666 +static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
1667 + bcm2835_chip_t * chip)
1670 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1673 + LOG_DBG(" .. IN\n");
1676 + (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
1678 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1680 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1683 + vchi_service_use(instance->vchi_handle[0]);
1685 + instance->result = -1;
1687 + m.type = VC_AUDIO_MSG_TYPE_CONTROL;
1688 + m.u.control.dest = chip->dest;
1689 + m.u.control.volume = chip->volume;
1691 + /* Create the message available completion */
1692 + init_completion(&instance->msg_avail_comp);
1694 + /* Send the message to the videocore */
1695 + success = vchi_msg_queue(instance->vchi_handle[0],
1697 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1699 + if (success != 0) {
1700 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1701 + __func__, success);
1707 + /* We are expecting a reply from the videocore */
1708 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1710 + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1711 + __func__, success);
1715 + if (instance->result != 0) {
1716 + LOG_ERR("%s: result=%d\n", __func__, instance->result);
1725 + vchi_service_release(instance->vchi_handle[0]);
1726 + mutex_unlock(&instance->vchi_mutex);
1728 + LOG_DBG(" .. OUT\n");
1732 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
1736 + LOG_DBG(" .. IN\n");
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])
1743 + LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
1746 + else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
1747 + (chip->alsa_stream[i], chip) != 0)
1749 + LOG_DBG("Couldn't set the controls for stream %d\n", i);
1752 + else LOG_DBG(" Controls set for stream %d\n", i);
1755 + LOG_DBG(" .. OUT ret=%d\n", ret);
1759 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
1760 + uint32_t channels, uint32_t samplerate,
1764 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1767 + LOG_DBG(" .. IN\n");
1770 + (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
1771 + channels, samplerate, bps);
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);
1776 + LOG_ERR(" Alsa controls not supported\n");
1780 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1782 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1785 + vchi_service_use(instance->vchi_handle[0]);
1787 + instance->result = -1;
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;
1794 + /* Create the message available completion */
1795 + init_completion(&instance->msg_avail_comp);
1797 + /* Send the message to the videocore */
1798 + success = vchi_msg_queue(instance->vchi_handle[0],
1800 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1802 + if (success != 0) {
1803 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1804 + __func__, success);
1810 + /* We are expecting a reply from the videocore */
1811 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1813 + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1814 + __func__, success);
1818 + if (instance->result != 0) {
1819 + LOG_ERR("%s: result=%d", __func__, instance->result);
1828 + vchi_service_release(instance->vchi_handle[0]);
1829 + mutex_unlock(&instance->vchi_mutex);
1831 + LOG_DBG(" .. OUT\n");
1835 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
1837 + LOG_DBG(" .. IN\n");
1839 + LOG_DBG(" .. OUT\n");
1844 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
1847 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1850 + LOG_DBG(" .. IN\n");
1852 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1854 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1857 + vchi_service_use(instance->vchi_handle[0]);
1859 + m.type = VC_AUDIO_MSG_TYPE_START;
1861 + /* Send the message to the videocore */
1862 + success = vchi_msg_queue(instance->vchi_handle[0],
1864 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1866 + if (success != 0) {
1867 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1868 + __func__, success);
1877 + vchi_service_release(instance->vchi_handle[0]);
1878 + mutex_unlock(&instance->vchi_mutex);
1879 + LOG_DBG(" .. OUT\n");
1883 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
1886 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1889 + LOG_DBG(" .. IN\n");
1891 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1893 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1896 + vchi_service_use(instance->vchi_handle[0]);
1898 + m.type = VC_AUDIO_MSG_TYPE_STOP;
1899 + m.u.stop.draining = alsa_stream->draining;
1901 + /* Send the message to the videocore */
1902 + success = vchi_msg_queue(instance->vchi_handle[0],
1904 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1906 + if (success != 0) {
1907 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1908 + __func__, success);
1917 + vchi_service_release(instance->vchi_handle[0]);
1918 + mutex_unlock(&instance->vchi_mutex);
1919 + LOG_DBG(" .. OUT\n");
1923 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
1926 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1929 + LOG_DBG(" .. IN\n");
1931 + my_workqueue_quit(alsa_stream);
1933 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1935 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1938 + vchi_service_use(instance->vchi_handle[0]);
1940 + m.type = VC_AUDIO_MSG_TYPE_CLOSE;
1942 + /* Create the message available completion */
1943 + init_completion(&instance->msg_avail_comp);
1945 + /* Send the message to the videocore */
1946 + success = vchi_msg_queue(instance->vchi_handle[0],
1948 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1950 + if (success != 0) {
1951 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
1952 + __func__, success);
1957 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1959 + LOG_ERR("%s: failed on waiting for event (status=%d)",
1960 + __func__, success);
1963 + if (instance->result != 0) {
1964 + LOG_ERR("%s: failed result (status=%d)",
1965 + __func__, instance->result);
1974 + vchi_service_release(instance->vchi_handle[0]);
1975 + mutex_unlock(&instance->vchi_mutex);
1977 + /* Stop the audio service */
1979 + vc_vchi_audio_deinit(instance);
1980 + alsa_stream->instance = NULL;
1982 + LOG_DBG(" .. OUT\n");
1986 +int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
1987 + uint32_t count, void *src)
1990 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1994 + LOG_DBG(" .. IN\n");
1996 + LOG_INFO(" Writing %d bytes from %p\n", count, src);
1998 + if(mutex_lock_interruptible(&instance->vchi_mutex))
2000 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
2003 + vchi_service_use(instance->vchi_handle[0]);
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);
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;
2016 + /* Send the message to the videocore */
2017 + success = vchi_msg_queue(instance->vchi_handle[0],
2019 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
2021 + if (success != 0) {
2022 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)",
2023 + __func__, success);
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],
2034 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED
2037 + VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
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],
2044 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
2045 + src = (char *)src + bytes;
2049 + if (success != 0) {
2051 + ("%s: failed on vchi_bulk_queue_transmit (status=%d)",
2052 + __func__, success);
2061 + vchi_service_release(instance->vchi_handle[0]);
2062 + mutex_unlock(&instance->vchi_mutex);
2063 + LOG_DBG(" .. OUT\n");
2068 + * Returns all buffers from arm->vc
2070 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
2072 + LOG_DBG(" .. IN\n");
2073 + LOG_DBG(" .. OUT\n");
2078 + * Forces VC to flush(drop) its filled playback buffers and
2079 + * return them the us. (VC->ARM)
2081 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
2083 + LOG_DBG(" .. IN\n");
2084 + LOG_DBG(" .. OUT\n");
2087 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
2089 + uint32_t count = atomic_read(&alsa_stream->retrieved);
2090 + atomic_sub(count, &alsa_stream->retrieved);
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
2100 Say Y or M if you want to support any AC97 codec attached to
2101 the PXA2xx AC97 interface.
2104 + tristate "BCM2835 ALSA driver"
2105 + depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND
2108 + Say Y or M if you want to support BCM2835 Alsa pcm card driver
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
2117 obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
2118 snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
2120 +obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o
2121 +snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
2123 +EXTRA_CFLAGS += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
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
2129 +/*****************************************************************************
2130 +* Copyright 2011 Broadcom Corporation. All rights reserved.
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").
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
2141 +*****************************************************************************/
2143 +#ifndef _VC_AUDIO_DEFS_H_
2144 +#define _VC_AUDIO_DEFS_H_
2146 +#define VC_AUDIOSERV_MIN_VER 1
2147 +#define VC_AUDIOSERV_VER 2
2149 +// FourCC code used for VCHI connection
2150 +#define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
2152 +// Maximum message length
2153 +#define VC_AUDIO_MAX_MSG_LEN (sizeof( VC_AUDIO_MSG_T ))
2155 +// List of screens that are currently supported
2156 +// All message types supported for HOST->VC direction
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;
2170 +// configure the audio
2172 + uint32_t channels;
2173 + uint32_t samplerate;
2176 +} VC_AUDIO_CONFIG_T;
2182 +} VC_AUDIO_CONTROL_T;
2194 +} VC_AUDIO_CLOSE_T;
2199 +} VC_AUDIO_START_T;
2202 + uint32_t draining;
2206 +// configure the write audio samples
2208 + uint32_t count; // in bytes
2212 + uint16_t max_packet;
2213 +} VC_AUDIO_WRITE_T;
2215 +// Generic result for a request (VC->HOST)
2217 + int32_t success; // Success value
2219 +} VC_AUDIO_RESULT_T;
2221 +// Generic result for a request (VC->HOST)
2223 + int32_t count; // Success value
2226 +} VC_AUDIO_COMPLETE_T;
2228 +// Message header for all messages in HOST->VC direction
2230 + int32_t type; // Message type (VC_AUDIO_MSG_TYPE)
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;
2244 +#endif // _VC_AUDIO_DEFS_H_