1 From 40fe0b17b886f30b316614830eedf0cfc755bbbd Mon Sep 17 00:00:00 2001
2 From: popcornmix <popcornmix@gmail.com>
3 Date: Mon, 26 Mar 2012 22:15:50 +0100
4 Subject: [PATCH 013/114] bcm2708: alsa sound driver
6 Signed-off-by: popcornmix <popcornmix@gmail.com>
8 alsa: add mmap support and some cleanups to bcm2835 ALSA driver
10 snd-bcm2835: Add support for spdif/hdmi passthrough
12 This adds a dedicated subdevice which can be used for passthrough of non-audio
13 formats (ie encoded a52) through the hdmi audio link. In addition to this
14 driver extension an appropriate card config is required to make alsa-lib
15 support the AES parameters for this device.
17 snd-bcm2708: Add mutex, improve logging
19 Fix for ALSA driver crash
21 Avoids an issue when closing and opening vchiq where a message can arrive before service handle has been written
23 alsa: reduce severity of expected warning message
25 snd-bcm2708: Fix dmesg spam for non-error case
27 arch/arm/configs/bcmrpi_defconfig | 20 +
28 arch/arm/mach-bcm2708/bcm2708.c | 54 ++
29 .../interface/vchiq_arm/vchiq_kern_lib.c | 7 +-
30 .../vc04_services/interface/vchiq_arm/vchiq_shim.c | 12 +-
31 sound/arm/Kconfig | 7 +
32 sound/arm/Makefile | 5 +
33 sound/arm/bcm2835-ctl.c | 323 ++++++++
34 sound/arm/bcm2835-pcm.c | 552 +++++++++++++
35 sound/arm/bcm2835-vchiq.c | 902 +++++++++++++++++++++
36 sound/arm/bcm2835.c | 420 ++++++++++
37 sound/arm/bcm2835.h | 167 ++++
38 sound/arm/vc_vchi_audioserv_defs.h | 116 +++
39 12 files changed, 2578 insertions(+), 7 deletions(-)
40 create mode 100755 sound/arm/bcm2835-ctl.c
41 create mode 100755 sound/arm/bcm2835-pcm.c
42 create mode 100755 sound/arm/bcm2835-vchiq.c
43 create mode 100755 sound/arm/bcm2835.c
44 create mode 100755 sound/arm/bcm2835.h
45 create mode 100644 sound/arm/vc_vchi_audioserv_defs.h
47 diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig
48 index 8950e53..63cb6a4 100644
49 --- a/arch/arm/configs/bcmrpi_defconfig
50 +++ b/arch/arm/configs/bcmrpi_defconfig
51 @@ -202,6 +202,26 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
53 # CONFIG_LOGO_LINUX_MONO is not set
54 # CONFIG_LOGO_LINUX_VGA16 is not set
57 +CONFIG_SND_SEQUENCER=m
58 +CONFIG_SND_SEQ_DUMMY=m
59 +CONFIG_SND_MIXER_OSS=m
61 +CONFIG_SND_SEQUENCER_OSS=y
67 +CONFIG_SND_SERIAL_U16550=m
70 +CONFIG_SND_USB_AUDIO=m
71 +CONFIG_SND_USB_UA101=m
72 +CONFIG_SND_USB_CAIAQ=m
73 +CONFIG_SND_USB_6FIRE=m
78 diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c
79 index 7503649..f3dccae 100644
80 --- a/arch/arm/mach-bcm2708/bcm2708.c
81 +++ b/arch/arm/mach-bcm2708/bcm2708.c
82 @@ -403,6 +403,58 @@ struct platform_device bcm2708_powerman_device = {
83 .coherent_dma_mask = 0xffffffffUL},
87 +static struct platform_device bcm2708_alsa_devices[] = {
89 + .name = "bcm2835_AUD0",
90 + .id = 0, /* first audio device */
95 + .name = "bcm2835_AUD1",
96 + .id = 1, /* second audio device */
101 + .name = "bcm2835_AUD2",
102 + .id = 2, /* third audio device */
104 + .num_resources = 0,
107 + .name = "bcm2835_AUD3",
108 + .id = 3, /* forth audio device */
110 + .num_resources = 0,
113 + .name = "bcm2835_AUD4",
114 + .id = 4, /* fifth audio device */
116 + .num_resources = 0,
119 + .name = "bcm2835_AUD5",
120 + .id = 5, /* sixth audio device */
122 + .num_resources = 0,
125 + .name = "bcm2835_AUD6",
126 + .id = 6, /* seventh audio device */
128 + .num_resources = 0,
131 + .name = "bcm2835_AUD7",
132 + .id = 7, /* eighth audio device */
134 + .num_resources = 0,
138 int __init bcm_register_device(struct platform_device *pdev)
141 @@ -508,6 +560,8 @@ void __init bcm2708_init(void)
142 bcm_register_device(&bcm2708_powerman_device);
145 + for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
146 + bcm_register_device(&bcm2708_alsa_devices[i]);
148 for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
149 struct amba_device *d = amba_devs[i];
150 diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
151 index 5a4182e..25e7011 100644
152 --- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
153 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
154 @@ -288,11 +288,12 @@ VCHIQ_STATUS_T vchiq_open_service(
158 + *phandle = service->handle;
159 status = vchiq_open_service_internal(service, current->pid);
160 - if (status == VCHIQ_SUCCESS)
161 - *phandle = service->handle;
163 + if (status != VCHIQ_SUCCESS) {
164 vchiq_remove_service(service->handle);
165 + *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
170 diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
171 index 72eacdaf..c26eff7 100644
172 --- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
173 +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
174 @@ -634,6 +634,9 @@ int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
176 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
177 SHIM_SERVICE_T *service = service_alloc(instance, setup);
179 + *handle = (VCHI_SERVICE_HANDLE_T)service;
182 VCHIQ_SERVICE_PARAMS_T params;
183 VCHIQ_STATUS_T status;
184 @@ -650,11 +653,10 @@ int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle,
185 if (status != VCHIQ_SUCCESS) {
186 service_free(service);
192 - *handle = (VCHI_SERVICE_HANDLE_T)service;
194 return (service != NULL) ? 0 : -1;
196 EXPORT_SYMBOL(vchi_service_open);
197 @@ -665,6 +667,9 @@ int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
199 VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
200 SHIM_SERVICE_T *service = service_alloc(instance, setup);
202 + *handle = (VCHI_SERVICE_HANDLE_T)service;
205 VCHIQ_SERVICE_PARAMS_T params;
206 VCHIQ_STATUS_T status;
207 @@ -680,11 +685,10 @@ int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
208 if (status != VCHIQ_SUCCESS) {
209 service_free(service);
215 - *handle = (VCHI_SERVICE_HANDLE_T)service;
217 return (service != NULL) ? 0 : -1;
219 EXPORT_SYMBOL(vchi_service_create);
220 diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
221 index 885683a..f7ceafd 100644
222 --- a/sound/arm/Kconfig
223 +++ b/sound/arm/Kconfig
224 @@ -39,5 +39,12 @@ config SND_PXA2XX_AC97
225 Say Y or M if you want to support any AC97 codec attached to
226 the PXA2xx AC97 interface.
229 + tristate "BCM2835 ALSA driver"
230 + depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND
233 + Say Y or M if you want to support BCM2835 Alsa pcm card driver
237 diff --git a/sound/arm/Makefile b/sound/arm/Makefile
238 index 8c0c851..6796d7f 100644
239 --- a/sound/arm/Makefile
240 +++ b/sound/arm/Makefile
241 @@ -14,3 +14,8 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o
243 obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
244 snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
246 +obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o
247 +snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
249 +ccflags-y += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000
250 diff --git a/sound/arm/bcm2835-ctl.c b/sound/arm/bcm2835-ctl.c
252 index 0000000..aad905f
254 +++ b/sound/arm/bcm2835-ctl.c
256 +/*****************************************************************************
257 +* Copyright 2011 Broadcom Corporation. All rights reserved.
259 +* Unless you and Broadcom execute a separate written software license
260 +* agreement governing use of this software, this software is licensed to you
261 +* under the terms of the GNU General Public License version 2, available at
262 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
264 +* Notwithstanding the above, under no circumstances may you combine this
265 +* software in any way with any other Broadcom software provided under a
266 +* license other than the GPL, without Broadcom's express prior written
268 +*****************************************************************************/
270 +#include <linux/platform_device.h>
271 +#include <linux/init.h>
272 +#include <linux/io.h>
273 +#include <linux/jiffies.h>
274 +#include <linux/slab.h>
275 +#include <linux/time.h>
276 +#include <linux/wait.h>
277 +#include <linux/delay.h>
278 +#include <linux/moduleparam.h>
279 +#include <linux/sched.h>
281 +#include <sound/core.h>
282 +#include <sound/control.h>
283 +#include <sound/pcm.h>
284 +#include <sound/pcm_params.h>
285 +#include <sound/rawmidi.h>
286 +#include <sound/initval.h>
287 +#include <sound/tlv.h>
288 +#include <sound/asoundef.h>
290 +#include "bcm2835.h"
292 +/* volume maximum and minimum in terms of 0.01dB */
293 +#define CTRL_VOL_MAX 400
294 +#define CTRL_VOL_MIN -10239 /* originally -10240 */
297 +static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
298 + struct snd_ctl_elem_info *uinfo)
300 + audio_info(" ... IN\n");
301 + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
302 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
304 + uinfo->value.integer.min = CTRL_VOL_MIN;
305 + uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
306 + } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
307 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
309 + uinfo->value.integer.min = 0;
310 + uinfo->value.integer.max = 1;
311 + } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
312 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
314 + uinfo->value.integer.min = 0;
315 + uinfo->value.integer.max = AUDIO_DEST_MAX-1;
317 + audio_info(" ... OUT\n");
321 +/* toggles mute on or off depending on the value of nmute, and returns
322 + * 1 if the mute value was changed, otherwise 0
324 +static int toggle_mute(struct bcm2835_chip *chip, int nmute)
326 + /* if settings are ok, just return 0 */
327 + if(chip->mute == nmute)
330 + /* if the sound is muted then we need to unmute */
331 + if(chip->mute == CTRL_VOL_MUTE)
333 + chip->volume = chip->old_volume; /* copy the old volume back */
334 + audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
336 + else /* otherwise we mute */
338 + chip->old_volume = chip->volume;
339 + chip->volume = 26214; /* set volume to minimum level AKA mute */
340 + audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
343 + chip->mute = nmute;
347 +static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
348 + struct snd_ctl_elem_value *ucontrol)
350 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
352 + BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
354 + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
355 + ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
356 + else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
357 + ucontrol->value.integer.value[0] = chip->mute;
358 + else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
359 + ucontrol->value.integer.value[0] = chip->dest;
364 +static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
365 + struct snd_ctl_elem_value *ucontrol)
367 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
370 + if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
371 + audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]);
372 + if (chip->mute == CTRL_VOL_MUTE) {
373 + /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
374 + return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
377 + || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
379 + chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
383 + } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
384 + /* Now implemented */
385 + audio_info(" Mute attempted\n");
386 + changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
388 + } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
389 + if (ucontrol->value.integer.value[0] != chip->dest) {
390 + chip->dest = ucontrol->value.integer.value[0];
396 + if (bcm2835_audio_set_ctls(chip))
397 + printk(KERN_ERR "Failed to set ALSA controls..\n");
403 +static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
405 +static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
407 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
408 + .name = "PCM Playback Volume",
410 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
411 + .private_value = PCM_PLAYBACK_VOLUME,
412 + .info = snd_bcm2835_ctl_info,
413 + .get = snd_bcm2835_ctl_get,
414 + .put = snd_bcm2835_ctl_put,
416 + .tlv = {.p = snd_bcm2835_db_scale}
419 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
420 + .name = "PCM Playback Switch",
422 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
423 + .private_value = PCM_PLAYBACK_MUTE,
424 + .info = snd_bcm2835_ctl_info,
425 + .get = snd_bcm2835_ctl_get,
426 + .put = snd_bcm2835_ctl_put,
430 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
431 + .name = "PCM Playback Route",
433 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
434 + .private_value = PCM_PLAYBACK_DEVICE,
435 + .info = snd_bcm2835_ctl_info,
436 + .get = snd_bcm2835_ctl_get,
437 + .put = snd_bcm2835_ctl_put,
442 +static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
443 + struct snd_ctl_elem_info *uinfo)
445 + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
450 +static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
451 + struct snd_ctl_elem_value *ucontrol)
453 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
456 + for (i = 0; i < 4; i++)
457 + ucontrol->value.iec958.status[i] =
458 + (chip->spdif_status >> (i * 8)) && 0xff;
463 +static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
464 + struct snd_ctl_elem_value *ucontrol)
466 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
467 + unsigned int val = 0;
470 + for (i = 0; i < 4; i++)
471 + val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
473 + change = val != chip->spdif_status;
474 + chip->spdif_status = val;
479 +static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
480 + struct snd_ctl_elem_info *uinfo)
482 + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
487 +static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
488 + struct snd_ctl_elem_value *ucontrol)
490 + /* bcm2835 supports only consumer mode and sets all other format flags
491 + * automatically. So the only thing left is signalling non-audio
493 + ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
497 +static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
498 + struct snd_ctl_elem_info *uinfo)
500 + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
505 +static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
506 + struct snd_ctl_elem_value *ucontrol)
508 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
511 + for (i = 0; i < 4; i++)
512 + ucontrol->value.iec958.status[i] =
513 + (chip->spdif_status >> (i * 8)) & 0xff;
517 +static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
518 + struct snd_ctl_elem_value *ucontrol)
520 + struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
521 + unsigned int val = 0;
524 + for (i = 0; i < 4; i++)
525 + val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
526 + change = val != chip->spdif_status;
527 + chip->spdif_status = val;
532 +static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
534 + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
535 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
536 + .info = snd_bcm2835_spdif_default_info,
537 + .get = snd_bcm2835_spdif_default_get,
538 + .put = snd_bcm2835_spdif_default_put
541 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
542 + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
543 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
544 + .info = snd_bcm2835_spdif_mask_info,
545 + .get = snd_bcm2835_spdif_mask_get,
548 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
549 + SNDRV_CTL_ELEM_ACCESS_INACTIVE,
550 + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
551 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
552 + .info = snd_bcm2835_spdif_stream_info,
553 + .get = snd_bcm2835_spdif_stream_get,
554 + .put = snd_bcm2835_spdif_stream_put,
558 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
563 + strcpy(chip->card->mixername, "Broadcom Mixer");
564 + for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
566 + snd_ctl_add(chip->card,
567 + snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
571 + for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
572 + err = snd_ctl_add(chip->card,
573 + snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
579 diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c
581 index 0000000..3a20b34
583 +++ b/sound/arm/bcm2835-pcm.c
585 +/*****************************************************************************
586 +* Copyright 2011 Broadcom Corporation. All rights reserved.
588 +* Unless you and Broadcom execute a separate written software license
589 +* agreement governing use of this software, this software is licensed to you
590 +* under the terms of the GNU General Public License version 2, available at
591 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
593 +* Notwithstanding the above, under no circumstances may you combine this
594 +* software in any way with any other Broadcom software provided under a
595 +* license other than the GPL, without Broadcom's express prior written
597 +*****************************************************************************/
599 +#include <linux/interrupt.h>
600 +#include <linux/slab.h>
602 +#include <sound/asoundef.h>
604 +#include "bcm2835.h"
606 +/* hardware definition */
607 +static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
608 + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
609 + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
610 + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
611 + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
616 + .buffer_bytes_max = 128 * 1024,
617 + .period_bytes_min = 1 * 1024,
618 + .period_bytes_max = 128 * 1024,
620 + .periods_max = 128,
623 +static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
624 + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
625 + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
626 + .formats = SNDRV_PCM_FMTBIT_S16_LE,
627 + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
628 + SNDRV_PCM_RATE_48000,
633 + .buffer_bytes_max = 128 * 1024,
634 + .period_bytes_min = 1 * 1024,
635 + .period_bytes_max = 128 * 1024,
637 + .periods_max = 128,
640 +static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
642 + audio_info("Freeing up alsa stream here ..\n");
643 + if (runtime->private_data)
644 + kfree(runtime->private_data);
645 + runtime->private_data = NULL;
648 +static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
650 + bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
651 + uint32_t consumed = 0;
652 + int new_period = 0;
654 + audio_info(" .. IN\n");
656 + audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
657 + alsa_stream ? alsa_stream->substream : 0);
659 + if (alsa_stream->open)
660 + consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
662 + /* We get called only if playback was triggered, So, the number of buffers we retrieve in
663 + * each iteration are the buffers that have been played out already
666 + if (alsa_stream->period_size) {
667 + if ((alsa_stream->pos / alsa_stream->period_size) !=
668 + ((alsa_stream->pos + consumed) / alsa_stream->period_size))
671 + audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
674 + alsa_stream->buffer_size,
675 + (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods),
676 + frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
678 + if (alsa_stream->buffer_size) {
679 + alsa_stream->pos += consumed &~ (1<<30);
680 + alsa_stream->pos %= alsa_stream->buffer_size;
683 + if (alsa_stream->substream) {
685 + snd_pcm_period_elapsed(alsa_stream->substream);
687 + audio_warning(" unexpected NULL substream\n");
689 + audio_info(" .. OUT\n");
691 + return IRQ_HANDLED;
695 +static int snd_bcm2835_playback_open_generic(
696 + struct snd_pcm_substream *substream, int spdif)
698 + bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
699 + struct snd_pcm_runtime *runtime = substream->runtime;
700 + bcm2835_alsa_stream_t *alsa_stream;
704 + audio_info(" .. IN (%d)\n", substream->number);
706 + if(mutex_lock_interruptible(&chip->audio_mutex))
708 + audio_error("Interrupted whilst waiting for lock\n");
711 + audio_info("Alsa open (%d)\n", substream->number);
712 + idx = substream->number;
714 + if (spdif && chip->opened != 0)
716 + else if (!spdif && (chip->opened & (1 << idx)))
719 + if (idx > MAX_SUBSTREAMS) {
721 + ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
722 + idx, MAX_SUBSTREAMS);
727 + /* Check if we are ready */
728 + if (!(chip->avail_substreams & (1 << idx))) {
729 + /* We are not ready yet */
730 + audio_error("substream(%d) device is not ready yet\n", idx);
735 + alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
736 + if (alsa_stream == NULL) {
741 + /* Initialise alsa_stream */
742 + alsa_stream->chip = chip;
743 + alsa_stream->substream = substream;
744 + alsa_stream->idx = idx;
746 + sema_init(&alsa_stream->buffers_update_sem, 0);
747 + sema_init(&alsa_stream->control_sem, 0);
748 + spin_lock_init(&alsa_stream->lock);
750 + /* Enabled in start trigger, called on each "fifo irq" after that */
751 + alsa_stream->enable_fifo_irq = 0;
752 + alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;
754 + err = bcm2835_audio_open(alsa_stream);
756 + kfree(alsa_stream);
759 + runtime->private_data = alsa_stream;
760 + runtime->private_free = snd_bcm2835_playback_free;
762 + runtime->hw = snd_bcm2835_playback_spdif_hw;
764 + /* clear spdif status, as we are not in spdif mode */
765 + chip->spdif_status = 0;
766 + runtime->hw = snd_bcm2835_playback_hw;
768 + /* minimum 16 bytes alignment (for vchiq bulk transfers) */
769 + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
772 + chip->alsa_stream[idx] = alsa_stream;
774 + chip->opened |= (1 << idx);
775 + alsa_stream->open = 1;
776 + alsa_stream->draining = 1;
779 + mutex_unlock(&chip->audio_mutex);
781 + audio_info(" .. OUT =%d\n", err);
786 +static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
788 + return snd_bcm2835_playback_open_generic(substream, 0);
791 +static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
793 + return snd_bcm2835_playback_open_generic(substream, 1);
796 +/* close callback */
797 +static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
799 + /* the hardware-specific codes will be here */
801 + bcm2835_chip_t *chip;
802 + struct snd_pcm_runtime *runtime;
803 + bcm2835_alsa_stream_t *alsa_stream;
805 + audio_info(" .. IN\n");
807 + chip = snd_pcm_substream_chip(substream);
808 + if(mutex_lock_interruptible(&chip->audio_mutex))
810 + audio_error("Interrupted whilst waiting for lock\n");
813 + runtime = substream->runtime;
814 + alsa_stream = runtime->private_data;
816 + audio_info("Alsa close\n");
819 + * Call stop if it's still running. This happens when app
820 + * is force killed and we don't get a stop trigger.
822 + if (alsa_stream->running) {
824 + err = bcm2835_audio_stop(alsa_stream);
825 + alsa_stream->running = 0;
827 + audio_error(" Failed to STOP alsa device\n");
830 + alsa_stream->period_size = 0;
831 + alsa_stream->buffer_size = 0;
833 + if (alsa_stream->open) {
834 + alsa_stream->open = 0;
835 + bcm2835_audio_close(alsa_stream);
837 + if (alsa_stream->chip)
838 + alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
840 + * Do not free up alsa_stream here, it will be freed up by
841 + * runtime->private_free callback we registered in *_open above
844 + chip->opened &= ~(1 << substream->number);
846 + mutex_unlock(&chip->audio_mutex);
847 + audio_info(" .. OUT\n");
852 +/* hw_params callback */
853 +static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
854 + struct snd_pcm_hw_params *params)
856 + struct snd_pcm_runtime *runtime = substream->runtime;
857 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
860 + audio_info(" .. IN\n");
862 + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
865 + (" pcm_lib_malloc failed to allocated pages for buffers\n");
869 + alsa_stream->channels = params_channels(params);
870 + alsa_stream->params_rate = params_rate(params);
871 + alsa_stream->pcm_format_width = snd_pcm_format_width(params_format (params));
872 + audio_info(" .. OUT\n");
877 +/* hw_free callback */
878 +static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
880 + audio_info(" .. IN\n");
881 + return snd_pcm_lib_free_pages(substream);
884 +/* prepare callback */
885 +static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
887 + bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
888 + struct snd_pcm_runtime *runtime = substream->runtime;
889 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
893 + audio_info(" .. IN\n");
895 + /* notify the vchiq that it should enter spdif passthrough mode by
896 + * setting channels=0 (see
897 + * https://github.com/raspberrypi/linux/issues/528) */
898 + if (chip->spdif_status & IEC958_AES0_NONAUDIO)
901 + channels = alsa_stream->channels;
903 + err = bcm2835_audio_set_params(alsa_stream, channels,
904 + alsa_stream->params_rate,
905 + alsa_stream->pcm_format_width);
907 + audio_error(" error setting hw params\n");
910 + bcm2835_audio_setup(alsa_stream);
912 + /* in preparation of the stream, set the controls (volume level) of the stream */
913 + bcm2835_audio_set_ctls(alsa_stream->chip);
916 + memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
918 + alsa_stream->pcm_indirect.hw_buffer_size =
919 + alsa_stream->pcm_indirect.sw_buffer_size =
920 + snd_pcm_lib_buffer_bytes(substream);
922 + alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
923 + alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
924 + alsa_stream->pos = 0;
926 + audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
927 + alsa_stream->buffer_size, alsa_stream->period_size,
928 + alsa_stream->pos, runtime->frame_bits);
930 + audio_info(" .. OUT\n");
934 +static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
935 + struct snd_pcm_indirect *rec, size_t bytes)
937 + struct snd_pcm_runtime *runtime = substream->runtime;
938 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
939 + void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
942 + err = bcm2835_audio_write(alsa_stream, bytes, src);
944 + audio_error(" Failed to transfer to alsa device (%d)\n", err);
948 +static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
950 + struct snd_pcm_runtime *runtime = substream->runtime;
951 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
952 + struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
954 + pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
955 + snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
956 + snd_bcm2835_pcm_transfer);
960 +/* trigger callback */
961 +static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
963 + struct snd_pcm_runtime *runtime = substream->runtime;
964 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
967 + audio_info(" .. IN\n");
970 + case SNDRV_PCM_TRIGGER_START:
971 + audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
972 + alsa_stream->running);
973 + if (!alsa_stream->running) {
974 + err = bcm2835_audio_start(alsa_stream);
976 + alsa_stream->pcm_indirect.hw_io =
977 + alsa_stream->pcm_indirect.hw_data =
978 + bytes_to_frames(runtime,
980 + substream->ops->ack(substream);
981 + alsa_stream->running = 1;
982 + alsa_stream->draining = 1;
984 + audio_error(" Failed to START alsa device (%d)\n", err);
988 + case SNDRV_PCM_TRIGGER_STOP:
990 + ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
991 + alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
992 + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
993 + audio_info("DRAINING\n");
994 + alsa_stream->draining = 1;
996 + audio_info("DROPPING\n");
997 + alsa_stream->draining = 0;
999 + if (alsa_stream->running) {
1000 + err = bcm2835_audio_stop(alsa_stream);
1002 + audio_error(" Failed to STOP alsa device (%d)\n", err);
1003 + alsa_stream->running = 0;
1010 + audio_info(" .. OUT\n");
1014 +/* pointer callback */
1015 +static snd_pcm_uframes_t
1016 +snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
1018 + struct snd_pcm_runtime *runtime = substream->runtime;
1019 + bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
1021 + audio_info(" .. IN\n");
1023 + audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
1024 + frames_to_bytes(runtime, runtime->status->hw_ptr),
1025 + frames_to_bytes(runtime, runtime->control->appl_ptr),
1026 + alsa_stream->pos);
1028 + audio_info(" .. OUT\n");
1029 + return snd_pcm_indirect_playback_pointer(substream,
1030 + &alsa_stream->pcm_indirect,
1031 + alsa_stream->pos);
1034 +static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
1035 + unsigned int cmd, void *arg)
1037 + int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
1038 + audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
1039 + cmd, arg, arg ? *(unsigned *)arg : 0, ret);
1044 +static struct snd_pcm_ops snd_bcm2835_playback_ops = {
1045 + .open = snd_bcm2835_playback_open,
1046 + .close = snd_bcm2835_playback_close,
1047 + .ioctl = snd_bcm2835_pcm_lib_ioctl,
1048 + .hw_params = snd_bcm2835_pcm_hw_params,
1049 + .hw_free = snd_bcm2835_pcm_hw_free,
1050 + .prepare = snd_bcm2835_pcm_prepare,
1051 + .trigger = snd_bcm2835_pcm_trigger,
1052 + .pointer = snd_bcm2835_pcm_pointer,
1053 + .ack = snd_bcm2835_pcm_ack,
1056 +static struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
1057 + .open = snd_bcm2835_playback_spdif_open,
1058 + .close = snd_bcm2835_playback_close,
1059 + .ioctl = snd_bcm2835_pcm_lib_ioctl,
1060 + .hw_params = snd_bcm2835_pcm_hw_params,
1061 + .hw_free = snd_bcm2835_pcm_hw_free,
1062 + .prepare = snd_bcm2835_pcm_prepare,
1063 + .trigger = snd_bcm2835_pcm_trigger,
1064 + .pointer = snd_bcm2835_pcm_pointer,
1065 + .ack = snd_bcm2835_pcm_ack,
1068 +/* create a pcm device */
1069 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
1071 + struct snd_pcm *pcm;
1074 + audio_info(" .. IN\n");
1075 + mutex_init(&chip->audio_mutex);
1076 + if(mutex_lock_interruptible(&chip->audio_mutex))
1078 + audio_error("Interrupted whilst waiting for lock\n");
1082 + snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
1085 + pcm->private_data = chip;
1086 + strcpy(pcm->name, "bcm2835 ALSA");
1088 + chip->dest = AUDIO_DEST_AUTO;
1089 + chip->volume = alsa2chip(0);
1090 + chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
1091 + /* set operators */
1092 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1093 + &snd_bcm2835_playback_ops);
1095 + /* pre-allocation of buffers */
1096 + /* NOTE: this may fail */
1097 + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
1098 + snd_dma_continuous_data
1099 + (GFP_KERNEL), 64 * 1024,
1102 + mutex_unlock(&chip->audio_mutex);
1103 + audio_info(" .. OUT\n");
1108 +int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip)
1110 + struct snd_pcm *pcm;
1113 + audio_info(" .. IN\n");
1114 + if(mutex_lock_interruptible(&chip->audio_mutex))
1116 + audio_error("Interrupted whilst waiting for lock\n");
1119 + err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
1123 + pcm->private_data = chip;
1124 + strcpy(pcm->name, "bcm2835 IEC958/HDMI");
1125 + chip->pcm_spdif = pcm;
1126 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1127 + &snd_bcm2835_playback_spdif_ops);
1129 + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
1130 + snd_dma_continuous_data (GFP_KERNEL),
1131 + 64 * 1024, 64 * 1024);
1132 + mutex_unlock(&chip->audio_mutex);
1133 + audio_info(" .. OUT\n");
1137 diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c
1138 new file mode 100755
1139 index 0000000..3c95381
1141 +++ b/sound/arm/bcm2835-vchiq.c
1143 +/*****************************************************************************
1144 +* Copyright 2011 Broadcom Corporation. All rights reserved.
1146 +* Unless you and Broadcom execute a separate written software license
1147 +* agreement governing use of this software, this software is licensed to you
1148 +* under the terms of the GNU General Public License version 2, available at
1149 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
1151 +* Notwithstanding the above, under no circumstances may you combine this
1152 +* software in any way with any other Broadcom software provided under a
1153 +* license other than the GPL, without Broadcom's express prior written
1155 +*****************************************************************************/
1157 +#include <linux/device.h>
1158 +#include <sound/core.h>
1159 +#include <sound/initval.h>
1160 +#include <sound/pcm.h>
1161 +#include <linux/io.h>
1162 +#include <linux/interrupt.h>
1163 +#include <linux/fs.h>
1164 +#include <linux/file.h>
1165 +#include <linux/mm.h>
1166 +#include <linux/syscalls.h>
1167 +#include <asm/uaccess.h>
1168 +#include <linux/slab.h>
1169 +#include <linux/delay.h>
1170 +#include <linux/atomic.h>
1171 +#include <linux/module.h>
1172 +#include <linux/completion.h>
1174 +#include "bcm2835.h"
1176 +/* ---- Include Files -------------------------------------------------------- */
1178 +#include "interface/vchi/vchi.h"
1179 +#include "vc_vchi_audioserv_defs.h"
1181 +/* ---- Private Constants and Types ------------------------------------------ */
1183 +#define BCM2835_AUDIO_STOP 0
1184 +#define BCM2835_AUDIO_START 1
1185 +#define BCM2835_AUDIO_WRITE 2
1187 +/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
1188 +#ifdef AUDIO_DEBUG_ENABLE
1189 + #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
1190 + #define LOG_WARN( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
1191 + #define LOG_INFO( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
1192 + #define LOG_DBG( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg)
1194 + #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
1195 + #define LOG_WARN( fmt, arg... )
1196 + #define LOG_INFO( fmt, arg... )
1197 + #define LOG_DBG( fmt, arg... )
1200 +typedef struct opaque_AUDIO_INSTANCE_T {
1201 + uint32_t num_connections;
1202 + VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
1203 + struct completion msg_avail_comp;
1204 + struct mutex vchi_mutex;
1205 + bcm2835_alsa_stream_t *alsa_stream;
1207 + short peer_version;
1208 +} AUDIO_INSTANCE_T;
1210 +bool force_bulk = false;
1212 +/* ---- Private Variables ---------------------------------------------------- */
1214 +/* ---- Private Function Prototypes ------------------------------------------ */
1216 +/* ---- Private Functions ---------------------------------------------------- */
1218 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
1219 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
1220 +static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
1221 + uint32_t count, void *src);
1224 + struct work_struct my_work;
1225 + bcm2835_alsa_stream_t *alsa_stream;
1231 +static void my_wq_function(struct work_struct *work)
1233 + my_work_t *w = (my_work_t *) work;
1235 + LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
1237 + case BCM2835_AUDIO_START:
1238 + ret = bcm2835_audio_start_worker(w->alsa_stream);
1240 + case BCM2835_AUDIO_STOP:
1241 + ret = bcm2835_audio_stop_worker(w->alsa_stream);
1243 + case BCM2835_AUDIO_WRITE:
1244 + ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
1248 + LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
1251 + kfree((void *)work);
1252 + LOG_DBG(" .. OUT %d\n", ret);
1255 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
1258 + LOG_DBG(" .. IN\n");
1259 + if (alsa_stream->my_wq) {
1260 + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
1261 + /*--- Queue some work (item 1) ---*/
1263 + INIT_WORK((struct work_struct *)work, my_wq_function);
1264 + work->alsa_stream = alsa_stream;
1265 + work->cmd = BCM2835_AUDIO_START;
1267 + (alsa_stream->my_wq, (struct work_struct *)work))
1270 + LOG_ERR(" .. Error: NULL work kmalloc\n");
1272 + LOG_DBG(" .. OUT %d\n", ret);
1276 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
1279 + LOG_DBG(" .. IN\n");
1280 + if (alsa_stream->my_wq) {
1281 + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
1282 + /*--- Queue some work (item 1) ---*/
1284 + INIT_WORK((struct work_struct *)work, my_wq_function);
1285 + work->alsa_stream = alsa_stream;
1286 + work->cmd = BCM2835_AUDIO_STOP;
1288 + (alsa_stream->my_wq, (struct work_struct *)work))
1291 + LOG_ERR(" .. Error: NULL work kmalloc\n");
1293 + LOG_DBG(" .. OUT %d\n", ret);
1297 +int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
1298 + uint32_t count, void *src)
1301 + LOG_DBG(" .. IN\n");
1302 + if (alsa_stream->my_wq) {
1303 + my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
1304 + /*--- Queue some work (item 1) ---*/
1306 + INIT_WORK((struct work_struct *)work, my_wq_function);
1307 + work->alsa_stream = alsa_stream;
1308 + work->cmd = BCM2835_AUDIO_WRITE;
1310 + work->count = count;
1312 + (alsa_stream->my_wq, (struct work_struct *)work))
1315 + LOG_ERR(" .. Error: NULL work kmalloc\n");
1317 + LOG_DBG(" .. OUT %d\n", ret);
1321 +void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
1323 + alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
1327 +void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
1329 + if (alsa_stream->my_wq) {
1330 + flush_workqueue(alsa_stream->my_wq);
1331 + destroy_workqueue(alsa_stream->my_wq);
1332 + alsa_stream->my_wq = NULL;
1337 +static void audio_vchi_callback(void *param,
1338 + const VCHI_CALLBACK_REASON_T reason,
1341 + AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
1345 + LOG_DBG(" .. IN instance=%p, handle=%p, alsa=%p, reason=%d, handle=%p\n",
1346 + instance, instance ? instance->vchi_handle[0] : NULL, instance ? instance->alsa_stream : NULL, reason, msg_handle);
1348 + if (reason != VCHI_CALLBACK_MSG_AVAILABLE) {
1352 + LOG_ERR(" .. instance is null\n");
1356 + if (!instance->vchi_handle[0]) {
1357 + LOG_ERR(" .. instance->vchi_handle[0] is null\n");
1361 + status = vchi_msg_dequeue(instance->vchi_handle[0],
1362 + &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
1363 + if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
1365 + (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
1366 + instance, m.u.result.success);
1367 + instance->result = m.u.result.success;
1368 + complete(&instance->msg_avail_comp);
1369 + } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
1370 + bcm2835_alsa_stream_t *alsa_stream = instance->alsa_stream;
1371 + irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
1373 + (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
1374 + instance, m.u.complete.count);
1375 + if (alsa_stream && callback) {
1376 + atomic_add(m.u.complete.count, &alsa_stream->retrieved);
1377 + callback(0, alsa_stream);
1379 + LOG_ERR(" .. unexpected alsa_stream=%p, callback=%p\n",
1380 + alsa_stream, callback);
1383 + LOG_ERR(" .. unexpected m.type=%d\n", m.type);
1385 + LOG_DBG(" .. OUT\n");
1388 +static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
1389 + VCHI_CONNECTION_T **
1391 + uint32_t num_connections)
1394 + AUDIO_INSTANCE_T *instance;
1397 + LOG_DBG("%s: start", __func__);
1399 + if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
1400 + LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
1401 + __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
1405 + /* Allocate memory for this instance */
1406 + instance = kmalloc(sizeof(*instance), GFP_KERNEL);
1410 + memset(instance, 0, sizeof(*instance));
1411 + instance->num_connections = num_connections;
1413 + /* Create a lock for exclusive, serialized VCHI connection access */
1414 + mutex_init(&instance->vchi_mutex);
1415 + /* Open the VCHI service connections */
1416 + for (i = 0; i < num_connections; i++) {
1417 + SERVICE_CREATION_T params = {
1418 + VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
1419 + VC_AUDIO_SERVER_NAME, // 4cc service code
1420 + vchi_connections[i], // passed in fn pointers
1421 + 0, // rx fifo size (unused)
1422 + 0, // tx fifo size (unused)
1423 + audio_vchi_callback, // service callback
1424 + instance, // service callback parameter
1425 + 1, //TODO: remove VCOS_FALSE, // unaligned bulk recieves
1426 + 1, //TODO: remove VCOS_FALSE, // unaligned bulk transmits
1427 + 0 // want crc check on bulk transfers
1430 + LOG_DBG("%s: about to open %i\n", __func__, i);
1431 + status = vchi_service_open(vchi_instance, ¶ms,
1432 + &instance->vchi_handle[i]);
1433 + LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
1436 + ("%s: failed to open VCHI service connection (status=%d)\n",
1437 + __func__, status);
1439 + goto err_close_services;
1441 + /* Finished with the service for now */
1442 + vchi_service_release(instance->vchi_handle[i]);
1445 + LOG_DBG("%s: okay\n", __func__);
1448 +err_close_services:
1449 + for (i = 0; i < instance->num_connections; i++) {
1450 + LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
1451 + if (instance->vchi_handle[i])
1452 + vchi_service_close(instance->vchi_handle[i]);
1456 + LOG_ERR("%s: error\n", __func__);
1461 +static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
1465 + LOG_DBG(" .. IN\n");
1467 + if (instance == NULL) {
1468 + LOG_ERR("%s: invalid handle %p\n", __func__, instance);
1473 + LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
1474 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1476 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1480 + /* Close all VCHI service connections */
1481 + for (i = 0; i < instance->num_connections; i++) {
1483 + LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
1484 + vchi_service_use(instance->vchi_handle[i]);
1486 + success = vchi_service_close(instance->vchi_handle[i]);
1487 + if (success != 0) {
1489 + ("%s: failed to close VCHI service connection (status=%d)\n",
1490 + __func__, success);
1494 + mutex_unlock(&instance->vchi_mutex);
1498 + LOG_DBG(" .. OUT\n");
1503 +static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
1505 + static VCHI_INSTANCE_T vchi_instance;
1506 + static VCHI_CONNECTION_T *vchi_connection;
1507 + static int initted;
1508 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1510 + LOG_DBG(" .. IN\n");
1512 + LOG_INFO("%s: start\n", __func__);
1515 + LOG_ERR("%s: VCHI instance already open (%p)\n",
1516 + __func__, instance);
1517 + instance->alsa_stream = alsa_stream;
1518 + alsa_stream->instance = instance;
1519 + ret = 0; // xxx todo -1;
1520 + goto err_free_mem;
1523 + /* Initialize and create a VCHI connection */
1525 + ret = vchi_initialise(&vchi_instance);
1527 + LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
1531 + goto err_free_mem;
1533 + ret = vchi_connect(NULL, 0, vchi_instance);
1535 + LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
1539 + goto err_free_mem;
1544 + /* Initialize an instance of the audio service */
1545 + instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
1547 + if (instance == NULL) {
1548 + LOG_ERR("%s: failed to initialize audio service\n", __func__);
1551 + goto err_free_mem;
1554 + instance->alsa_stream = alsa_stream;
1555 + alsa_stream->instance = instance;
1557 + LOG_DBG(" success !\n");
1559 + LOG_DBG(" .. OUT\n");
1564 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
1566 + AUDIO_INSTANCE_T *instance;
1570 + LOG_DBG(" .. IN\n");
1572 + my_workqueue_init(alsa_stream);
1574 + ret = bcm2835_audio_open_connection(alsa_stream);
1579 + instance = alsa_stream->instance;
1580 + LOG_DBG(" instance (%p)\n", instance);
1582 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1584 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1587 + vchi_service_use(instance->vchi_handle[0]);
1589 + m.type = VC_AUDIO_MSG_TYPE_OPEN;
1591 + /* Send the message to the videocore */
1592 + success = vchi_msg_queue(instance->vchi_handle[0],
1594 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1596 + if (success != 0) {
1597 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1598 + __func__, success);
1607 + vchi_service_release(instance->vchi_handle[0]);
1608 + mutex_unlock(&instance->vchi_mutex);
1610 + LOG_DBG(" .. OUT\n");
1614 +static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
1615 + bcm2835_chip_t * chip)
1618 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1621 + LOG_DBG(" .. IN\n");
1624 + (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
1626 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1628 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1631 + vchi_service_use(instance->vchi_handle[0]);
1633 + instance->result = -1;
1635 + m.type = VC_AUDIO_MSG_TYPE_CONTROL;
1636 + m.u.control.dest = chip->dest;
1637 + m.u.control.volume = chip->volume;
1639 + /* Create the message available completion */
1640 + init_completion(&instance->msg_avail_comp);
1642 + /* Send the message to the videocore */
1643 + success = vchi_msg_queue(instance->vchi_handle[0],
1645 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1647 + if (success != 0) {
1648 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1649 + __func__, success);
1655 + /* We are expecting a reply from the videocore */
1656 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1658 + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1659 + __func__, success);
1663 + if (instance->result != 0) {
1664 + LOG_ERR("%s: result=%d\n", __func__, instance->result);
1673 + vchi_service_release(instance->vchi_handle[0]);
1674 + mutex_unlock(&instance->vchi_mutex);
1676 + LOG_DBG(" .. OUT\n");
1680 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
1684 + LOG_DBG(" .. IN\n");
1685 + LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
1687 + /* change ctls for all substreams */
1688 + for (i = 0; i < MAX_SUBSTREAMS; i++) {
1689 + if (chip->avail_substreams & (1 << i)) {
1690 + if (!chip->alsa_stream[i])
1692 + LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
1695 + else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
1696 + (chip->alsa_stream[i], chip) != 0)
1698 + LOG_ERR("Couldn't set the controls for stream %d\n", i);
1701 + else LOG_DBG(" Controls set for stream %d\n", i);
1704 + LOG_DBG(" .. OUT ret=%d\n", ret);
1708 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
1709 + uint32_t channels, uint32_t samplerate,
1713 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1716 + LOG_DBG(" .. IN\n");
1719 + (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
1720 + channels, samplerate, bps);
1722 + /* resend ctls - alsa_stream may not have been open when first send */
1723 + ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
1725 + LOG_ERR(" Alsa controls not supported\n");
1729 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1731 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1734 + vchi_service_use(instance->vchi_handle[0]);
1736 + instance->result = -1;
1738 + m.type = VC_AUDIO_MSG_TYPE_CONFIG;
1739 + m.u.config.channels = channels;
1740 + m.u.config.samplerate = samplerate;
1741 + m.u.config.bps = bps;
1743 + /* Create the message available completion */
1744 + init_completion(&instance->msg_avail_comp);
1746 + /* Send the message to the videocore */
1747 + success = vchi_msg_queue(instance->vchi_handle[0],
1749 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1751 + if (success != 0) {
1752 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1753 + __func__, success);
1759 + /* We are expecting a reply from the videocore */
1760 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1762 + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1763 + __func__, success);
1767 + if (instance->result != 0) {
1768 + LOG_ERR("%s: result=%d", __func__, instance->result);
1777 + vchi_service_release(instance->vchi_handle[0]);
1778 + mutex_unlock(&instance->vchi_mutex);
1780 + LOG_DBG(" .. OUT\n");
1784 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
1786 + LOG_DBG(" .. IN\n");
1788 + LOG_DBG(" .. OUT\n");
1793 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
1796 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1799 + LOG_DBG(" .. IN\n");
1801 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1803 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1806 + vchi_service_use(instance->vchi_handle[0]);
1808 + m.type = VC_AUDIO_MSG_TYPE_START;
1810 + /* Send the message to the videocore */
1811 + success = vchi_msg_queue(instance->vchi_handle[0],
1813 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1815 + if (success != 0) {
1816 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1817 + __func__, success);
1826 + vchi_service_release(instance->vchi_handle[0]);
1827 + mutex_unlock(&instance->vchi_mutex);
1828 + LOG_DBG(" .. OUT\n");
1832 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
1835 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1838 + LOG_DBG(" .. IN\n");
1840 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1842 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1845 + vchi_service_use(instance->vchi_handle[0]);
1847 + m.type = VC_AUDIO_MSG_TYPE_STOP;
1848 + m.u.stop.draining = alsa_stream->draining;
1850 + /* Send the message to the videocore */
1851 + success = vchi_msg_queue(instance->vchi_handle[0],
1853 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1855 + if (success != 0) {
1856 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1857 + __func__, success);
1866 + vchi_service_release(instance->vchi_handle[0]);
1867 + mutex_unlock(&instance->vchi_mutex);
1868 + LOG_DBG(" .. OUT\n");
1872 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
1875 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1878 + LOG_DBG(" .. IN\n");
1880 + my_workqueue_quit(alsa_stream);
1882 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1884 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1887 + vchi_service_use(instance->vchi_handle[0]);
1889 + m.type = VC_AUDIO_MSG_TYPE_CLOSE;
1891 + /* Create the message available completion */
1892 + init_completion(&instance->msg_avail_comp);
1894 + /* Send the message to the videocore */
1895 + success = vchi_msg_queue(instance->vchi_handle[0],
1897 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1899 + if (success != 0) {
1900 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1901 + __func__, success);
1906 + ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1908 + LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1909 + __func__, success);
1912 + if (instance->result != 0) {
1913 + LOG_ERR("%s: failed result (status=%d)\n",
1914 + __func__, instance->result);
1923 + vchi_service_release(instance->vchi_handle[0]);
1924 + mutex_unlock(&instance->vchi_mutex);
1926 + /* Stop the audio service */
1928 + vc_vchi_audio_deinit(instance);
1929 + alsa_stream->instance = NULL;
1931 + LOG_DBG(" .. OUT\n");
1935 +int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
1936 + uint32_t count, void *src)
1939 + AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1943 + LOG_DBG(" .. IN\n");
1945 + LOG_INFO(" Writing %d bytes from %p\n", count, src);
1947 + if(mutex_lock_interruptible(&instance->vchi_mutex))
1949 + LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1952 + vchi_service_use(instance->vchi_handle[0]);
1954 + if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) {
1955 + LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
1957 + m.type = VC_AUDIO_MSG_TYPE_WRITE;
1958 + m.u.write.count = count;
1959 + // old version uses bulk, new version uses control
1960 + m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000;
1961 + m.u.write.callback = alsa_stream->fifo_irq_handler;
1962 + m.u.write.cookie = alsa_stream;
1963 + m.u.write.silence = src == NULL;
1965 + /* Send the message to the videocore */
1966 + success = vchi_msg_queue(instance->vchi_handle[0],
1968 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1970 + if (success != 0) {
1971 + LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1972 + __func__, success);
1977 + if (!m.u.write.silence) {
1978 + if (m.u.write.max_packet == 0) {
1979 + /* Send the message to the videocore */
1980 + success = vchi_bulk_queue_transmit(instance->vchi_handle[0],
1983 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED
1986 + VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
1989 + while (count > 0) {
1990 + int bytes = min((int)m.u.write.max_packet, (int)count);
1991 + success = vchi_msg_queue(instance->vchi_handle[0],
1993 + VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1994 + src = (char *)src + bytes;
1998 + if (success != 0) {
2000 + ("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
2001 + __func__, success);
2010 + vchi_service_release(instance->vchi_handle[0]);
2011 + mutex_unlock(&instance->vchi_mutex);
2012 + LOG_DBG(" .. OUT\n");
2017 + * Returns all buffers from arm->vc
2019 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
2021 + LOG_DBG(" .. IN\n");
2022 + LOG_DBG(" .. OUT\n");
2027 + * Forces VC to flush(drop) its filled playback buffers and
2028 + * return them the us. (VC->ARM)
2030 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
2032 + LOG_DBG(" .. IN\n");
2033 + LOG_DBG(" .. OUT\n");
2036 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
2038 + uint32_t count = atomic_read(&alsa_stream->retrieved);
2039 + atomic_sub(count, &alsa_stream->retrieved);
2043 +module_param(force_bulk, bool, 0444);
2044 +MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
2045 diff --git a/sound/arm/bcm2835.c b/sound/arm/bcm2835.c
2046 new file mode 100755
2047 index 0000000..7ed5079
2049 +++ b/sound/arm/bcm2835.c
2051 +/*****************************************************************************
2052 +* Copyright 2011 Broadcom Corporation. All rights reserved.
2054 +* Unless you and Broadcom execute a separate written software license
2055 +* agreement governing use of this software, this software is licensed to you
2056 +* under the terms of the GNU General Public License version 2, available at
2057 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2059 +* Notwithstanding the above, under no circumstances may you combine this
2060 +* software in any way with any other Broadcom software provided under a
2061 +* license other than the GPL, without Broadcom's express prior written
2063 +*****************************************************************************/
2065 +#include <linux/platform_device.h>
2067 +#include <linux/init.h>
2068 +#include <linux/slab.h>
2069 +#include <linux/module.h>
2071 +#include "bcm2835.h"
2073 +/* module parameters (see "Module Parameters") */
2074 +/* SNDRV_CARDS: maximum number of cards supported by this module */
2075 +static int index[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = -1 };
2076 +static char *id[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = NULL };
2077 +static int enable[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = 1 };
2079 +/* HACKY global pointers needed for successive probes to work : ssp
2080 + * But compared against the changes we will have to do in VC audio_ipc code
2081 + * to export 8 audio_ipc devices as a single IPC device and then monitor all
2082 + * four devices in a thread, this gets things done quickly and should be easier
2083 + * to debug if we run into issues
2086 +static struct snd_card *g_card = NULL;
2087 +static bcm2835_chip_t *g_chip = NULL;
2089 +static int snd_bcm2835_free(bcm2835_chip_t * chip)
2095 +/* component-destructor
2096 + * (see "Management of Cards and Components")
2098 +static int snd_bcm2835_dev_free(struct snd_device *device)
2100 + return snd_bcm2835_free(device->device_data);
2103 +/* chip-specific constructor
2104 + * (see "Management of Cards and Components")
2106 +static int snd_bcm2835_create(struct snd_card *card,
2107 + struct platform_device *pdev,
2108 + bcm2835_chip_t ** rchip)
2110 + bcm2835_chip_t *chip;
2112 + static struct snd_device_ops ops = {
2113 + .dev_free = snd_bcm2835_dev_free,
2118 + chip = kzalloc(sizeof(*chip), GFP_KERNEL);
2122 + chip->card = card;
2124 + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
2126 + snd_bcm2835_free(chip);
2134 +static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
2137 + bcm2835_chip_t *chip;
2138 + struct snd_card *card;
2141 + if (dev >= MAX_SUBSTREAMS)
2144 + if (!enable[dev]) {
2150 + goto add_register_map;
2152 + err = snd_card_new(NULL, index[dev], id[dev], THIS_MODULE, 0, &g_card);
2156 + snd_card_set_dev(g_card, &pdev->dev);
2157 + strcpy(g_card->driver, "bcm2835");
2158 + strcpy(g_card->shortname, "bcm2835 ALSA");
2159 + sprintf(g_card->longname, "%s", g_card->shortname);
2161 + err = snd_bcm2835_create(g_card, pdev, &chip);
2163 + dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
2164 + goto out_bcm2835_create;
2168 + err = snd_bcm2835_new_pcm(chip);
2170 + dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
2171 + goto out_bcm2835_new_pcm;
2174 + err = snd_bcm2835_new_spdif_pcm(chip);
2176 + dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n");
2177 + goto out_bcm2835_new_spdif;
2180 + err = snd_bcm2835_new_ctl(chip);
2182 + dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
2183 + goto out_bcm2835_new_ctl;
2190 + BUG_ON(!(card && chip));
2192 + chip->avail_substreams |= (1 << dev);
2193 + chip->pdev[dev] = pdev;
2196 + err = snd_card_register(card);
2198 + dev_err(&pdev->dev,
2199 + "Failed to register bcm2835 ALSA card \n");
2200 + goto out_card_register;
2202 + platform_set_drvdata(pdev, card);
2203 + audio_info("bcm2835 ALSA card created!\n");
2205 + audio_info("bcm2835 ALSA chip created!\n");
2206 + platform_set_drvdata(pdev, (void *)dev);
2214 +out_bcm2835_new_ctl:
2215 +out_bcm2835_new_spdif:
2216 +out_bcm2835_new_pcm:
2217 +out_bcm2835_create:
2219 + if (snd_card_free(g_card))
2220 + dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
2223 + dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
2224 + dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
2228 +static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
2233 + drv_data = platform_get_drvdata(pdev);
2235 + if (drv_data == (void *)g_card) {
2236 + /* This is the card device */
2237 + snd_card_free((struct snd_card *)drv_data);
2241 + idx = (uint32_t) drv_data;
2242 + if (g_card != NULL) {
2244 + /* We pass chip device numbers in audio ipc devices
2245 + * other than the one we registered our card with
2247 + idx = (uint32_t) drv_data;
2248 + BUG_ON(!idx || idx > MAX_SUBSTREAMS);
2249 + g_chip->avail_substreams &= ~(1 << idx);
2250 + /* There should be atleast one substream registered
2251 + * after we are done here, as it wil be removed when
2252 + * the *remove* is called for the card device
2254 + BUG_ON(!g_chip->avail_substreams);
2258 + platform_set_drvdata(pdev, NULL);
2264 +static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
2265 + pm_message_t state)
2270 +static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
2277 +static struct platform_driver bcm2835_alsa0_driver = {
2278 + .probe = snd_bcm2835_alsa_probe,
2279 + .remove = snd_bcm2835_alsa_remove,
2281 + .suspend = snd_bcm2835_alsa_suspend,
2282 + .resume = snd_bcm2835_alsa_resume,
2285 + .name = "bcm2835_AUD0",
2286 + .owner = THIS_MODULE,
2290 +static struct platform_driver bcm2835_alsa1_driver = {
2291 + .probe = snd_bcm2835_alsa_probe,
2292 + .remove = snd_bcm2835_alsa_remove,
2294 + .suspend = snd_bcm2835_alsa_suspend,
2295 + .resume = snd_bcm2835_alsa_resume,
2298 + .name = "bcm2835_AUD1",
2299 + .owner = THIS_MODULE,
2303 +static struct platform_driver bcm2835_alsa2_driver = {
2304 + .probe = snd_bcm2835_alsa_probe,
2305 + .remove = snd_bcm2835_alsa_remove,
2307 + .suspend = snd_bcm2835_alsa_suspend,
2308 + .resume = snd_bcm2835_alsa_resume,
2311 + .name = "bcm2835_AUD2",
2312 + .owner = THIS_MODULE,
2316 +static struct platform_driver bcm2835_alsa3_driver = {
2317 + .probe = snd_bcm2835_alsa_probe,
2318 + .remove = snd_bcm2835_alsa_remove,
2320 + .suspend = snd_bcm2835_alsa_suspend,
2321 + .resume = snd_bcm2835_alsa_resume,
2324 + .name = "bcm2835_AUD3",
2325 + .owner = THIS_MODULE,
2329 +static struct platform_driver bcm2835_alsa4_driver = {
2330 + .probe = snd_bcm2835_alsa_probe,
2331 + .remove = snd_bcm2835_alsa_remove,
2333 + .suspend = snd_bcm2835_alsa_suspend,
2334 + .resume = snd_bcm2835_alsa_resume,
2337 + .name = "bcm2835_AUD4",
2338 + .owner = THIS_MODULE,
2342 +static struct platform_driver bcm2835_alsa5_driver = {
2343 + .probe = snd_bcm2835_alsa_probe,
2344 + .remove = snd_bcm2835_alsa_remove,
2346 + .suspend = snd_bcm2835_alsa_suspend,
2347 + .resume = snd_bcm2835_alsa_resume,
2350 + .name = "bcm2835_AUD5",
2351 + .owner = THIS_MODULE,
2355 +static struct platform_driver bcm2835_alsa6_driver = {
2356 + .probe = snd_bcm2835_alsa_probe,
2357 + .remove = snd_bcm2835_alsa_remove,
2359 + .suspend = snd_bcm2835_alsa_suspend,
2360 + .resume = snd_bcm2835_alsa_resume,
2363 + .name = "bcm2835_AUD6",
2364 + .owner = THIS_MODULE,
2368 +static struct platform_driver bcm2835_alsa7_driver = {
2369 + .probe = snd_bcm2835_alsa_probe,
2370 + .remove = snd_bcm2835_alsa_remove,
2372 + .suspend = snd_bcm2835_alsa_suspend,
2373 + .resume = snd_bcm2835_alsa_resume,
2376 + .name = "bcm2835_AUD7",
2377 + .owner = THIS_MODULE,
2381 +static int bcm2835_alsa_device_init(void)
2384 + err = platform_driver_register(&bcm2835_alsa0_driver);
2386 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2390 + err = platform_driver_register(&bcm2835_alsa1_driver);
2392 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2393 + goto unregister_0;
2396 + err = platform_driver_register(&bcm2835_alsa2_driver);
2398 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2399 + goto unregister_1;
2402 + err = platform_driver_register(&bcm2835_alsa3_driver);
2404 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2405 + goto unregister_2;
2408 + err = platform_driver_register(&bcm2835_alsa4_driver);
2410 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2411 + goto unregister_3;
2414 + err = platform_driver_register(&bcm2835_alsa5_driver);
2416 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2417 + goto unregister_4;
2420 + err = platform_driver_register(&bcm2835_alsa6_driver);
2422 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2423 + goto unregister_5;
2426 + err = platform_driver_register(&bcm2835_alsa7_driver);
2428 + pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2429 + goto unregister_6;
2435 + platform_driver_unregister(&bcm2835_alsa6_driver);
2437 + platform_driver_unregister(&bcm2835_alsa5_driver);
2439 + platform_driver_unregister(&bcm2835_alsa4_driver);
2441 + platform_driver_unregister(&bcm2835_alsa3_driver);
2443 + platform_driver_unregister(&bcm2835_alsa2_driver);
2445 + platform_driver_unregister(&bcm2835_alsa1_driver);
2447 + platform_driver_unregister(&bcm2835_alsa0_driver);
2452 +static void bcm2835_alsa_device_exit(void)
2454 + platform_driver_unregister(&bcm2835_alsa0_driver);
2455 + platform_driver_unregister(&bcm2835_alsa1_driver);
2456 + platform_driver_unregister(&bcm2835_alsa2_driver);
2457 + platform_driver_unregister(&bcm2835_alsa3_driver);
2458 + platform_driver_unregister(&bcm2835_alsa4_driver);
2459 + platform_driver_unregister(&bcm2835_alsa5_driver);
2460 + platform_driver_unregister(&bcm2835_alsa6_driver);
2461 + platform_driver_unregister(&bcm2835_alsa7_driver);
2464 +late_initcall(bcm2835_alsa_device_init);
2465 +module_exit(bcm2835_alsa_device_exit);
2467 +MODULE_AUTHOR("Dom Cobley");
2468 +MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
2469 +MODULE_LICENSE("GPL");
2470 +MODULE_ALIAS("platform:bcm2835_alsa");
2471 diff --git a/sound/arm/bcm2835.h b/sound/arm/bcm2835.h
2472 new file mode 100755
2473 index 0000000..0f71c5d
2475 +++ b/sound/arm/bcm2835.h
2477 +/*****************************************************************************
2478 +* Copyright 2011 Broadcom Corporation. All rights reserved.
2480 +* Unless you and Broadcom execute a separate written software license
2481 +* agreement governing use of this software, this software is licensed to you
2482 +* under the terms of the GNU General Public License version 2, available at
2483 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2485 +* Notwithstanding the above, under no circumstances may you combine this
2486 +* software in any way with any other Broadcom software provided under a
2487 +* license other than the GPL, without Broadcom's express prior written
2489 +*****************************************************************************/
2491 +#ifndef __SOUND_ARM_BCM2835_H
2492 +#define __SOUND_ARM_BCM2835_H
2494 +#include <linux/device.h>
2495 +#include <linux/list.h>
2496 +#include <linux/interrupt.h>
2497 +#include <linux/wait.h>
2498 +#include <sound/core.h>
2499 +#include <sound/initval.h>
2500 +#include <sound/pcm.h>
2501 +#include <sound/pcm_params.h>
2502 +#include <sound/pcm-indirect.h>
2503 +#include <linux/workqueue.h>
2506 +#define AUDIO_DEBUG_ENABLE
2507 +#define AUDIO_VERBOSE_DEBUG_ENABLE
2512 +#ifdef AUDIO_DEBUG_ENABLE
2513 +#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
2515 +#define audio_debug(fmt, arg...) \
2516 + printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
2518 +#define audio_info(fmt, arg...) \
2519 + printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
2523 +#define audio_debug(fmt, arg...)
2525 +#define audio_info(fmt, arg...)
2527 +#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
2531 +#define audio_debug(fmt, arg...)
2533 +#define audio_info(fmt, arg...)
2535 +#endif /* AUDIO_DEBUG_ENABLE */
2537 +#define audio_error(fmt, arg...) \
2538 + printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
2540 +#define audio_warning(fmt, arg...) \
2541 + printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
2543 +#define audio_alert(fmt, arg...) \
2544 + printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
2546 +#define MAX_SUBSTREAMS (8)
2547 +#define AVAIL_SUBSTREAMS_MASK (0xff)
2553 +/* macros for alsa2chip and chip2alsa, instead of functions */
2555 +#define alsa2chip(vol) (uint)(-((vol << 8) / 100)) /* convert alsa to chip volume (defined as macro rather than function call) */
2556 +#define chip2alsa(vol) -((vol * 100) >> 8) /* convert chip to alsa volume */
2558 +/* Some constants for values .. */
2560 + AUDIO_DEST_AUTO = 0,
2561 + AUDIO_DEST_HEADPHONES = 1,
2562 + AUDIO_DEST_HDMI = 2,
2564 +} SND_BCM2835_ROUTE_T;
2567 + PCM_PLAYBACK_VOLUME,
2568 + PCM_PLAYBACK_MUTE,
2569 + PCM_PLAYBACK_DEVICE,
2570 +} SND_BCM2835_CTRL_T;
2572 +/* definition of the chip-specific record */
2573 +typedef struct bcm2835_chip {
2574 + struct snd_card *card;
2575 + struct snd_pcm *pcm;
2576 + struct snd_pcm *pcm_spdif;
2577 + /* Bitmat for valid reg_base and irq numbers */
2578 + uint32_t avail_substreams;
2579 + struct platform_device *pdev[MAX_SUBSTREAMS];
2580 + struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
2583 + int old_volume; /* stores the volume value whist muted */
2587 + unsigned int opened;
2588 + unsigned int spdif_status;
2589 + struct mutex audio_mutex;
2592 +typedef struct bcm2835_alsa_stream {
2593 + bcm2835_chip_t *chip;
2594 + struct snd_pcm_substream *substream;
2595 + struct snd_pcm_indirect pcm_indirect;
2597 + struct semaphore buffers_update_sem;
2598 + struct semaphore control_sem;
2600 + volatile uint32_t control;
2601 + volatile uint32_t status;
2609 + int pcm_format_width;
2612 + unsigned int buffer_size;
2613 + unsigned int period_size;
2615 + uint32_t enable_fifo_irq;
2616 + irq_handler_t fifo_irq_handler;
2618 + atomic_t retrieved;
2619 + struct opaque_AUDIO_INSTANCE_T *instance;
2620 + struct workqueue_struct *my_wq;
2622 +} bcm2835_alsa_stream_t;
2624 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
2625 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
2626 +int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip);
2628 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
2629 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
2630 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
2631 + uint32_t channels, uint32_t samplerate,
2633 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream);
2634 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream);
2635 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream);
2636 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip);
2637 +int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
2639 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream);
2640 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream);
2641 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream);
2643 +#endif /* __SOUND_ARM_BCM2835_H */
2644 diff --git a/sound/arm/vc_vchi_audioserv_defs.h b/sound/arm/vc_vchi_audioserv_defs.h
2645 new file mode 100644
2646 index 0000000..af3e6eb
2648 +++ b/sound/arm/vc_vchi_audioserv_defs.h
2650 +/*****************************************************************************
2651 +* Copyright 2011 Broadcom Corporation. All rights reserved.
2653 +* Unless you and Broadcom execute a separate written software license
2654 +* agreement governing use of this software, this software is licensed to you
2655 +* under the terms of the GNU General Public License version 2, available at
2656 +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
2658 +* Notwithstanding the above, under no circumstances may you combine this
2659 +* software in any way with any other Broadcom software provided under a
2660 +* license other than the GPL, without Broadcom's express prior written
2662 +*****************************************************************************/
2664 +#ifndef _VC_AUDIO_DEFS_H_
2665 +#define _VC_AUDIO_DEFS_H_
2667 +#define VC_AUDIOSERV_MIN_VER 1
2668 +#define VC_AUDIOSERV_VER 2
2670 +// FourCC code used for VCHI connection
2671 +#define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
2673 +// Maximum message length
2674 +#define VC_AUDIO_MAX_MSG_LEN (sizeof( VC_AUDIO_MSG_T ))
2676 +// List of screens that are currently supported
2677 +// All message types supported for HOST->VC direction
2679 + VC_AUDIO_MSG_TYPE_RESULT, // Generic result
2680 + VC_AUDIO_MSG_TYPE_COMPLETE, // Generic result
2681 + VC_AUDIO_MSG_TYPE_CONFIG, // Configure audio
2682 + VC_AUDIO_MSG_TYPE_CONTROL, // Configure audio
2683 + VC_AUDIO_MSG_TYPE_OPEN, // Configure audio
2684 + VC_AUDIO_MSG_TYPE_CLOSE, // Configure audio
2685 + VC_AUDIO_MSG_TYPE_START, // Configure audio
2686 + VC_AUDIO_MSG_TYPE_STOP, // Configure audio
2687 + VC_AUDIO_MSG_TYPE_WRITE, // Configure audio
2688 + VC_AUDIO_MSG_TYPE_MAX
2689 +} VC_AUDIO_MSG_TYPE;
2691 +// configure the audio
2693 + uint32_t channels;
2694 + uint32_t samplerate;
2697 +} VC_AUDIO_CONFIG_T;
2703 +} VC_AUDIO_CONTROL_T;
2715 +} VC_AUDIO_CLOSE_T;
2720 +} VC_AUDIO_START_T;
2723 + uint32_t draining;
2727 +// configure the write audio samples
2729 + uint32_t count; // in bytes
2733 + uint16_t max_packet;
2734 +} VC_AUDIO_WRITE_T;
2736 +// Generic result for a request (VC->HOST)
2738 + int32_t success; // Success value
2740 +} VC_AUDIO_RESULT_T;
2742 +// Generic result for a request (VC->HOST)
2744 + int32_t count; // Success value
2747 +} VC_AUDIO_COMPLETE_T;
2749 +// Message header for all messages in HOST->VC direction
2751 + int32_t type; // Message type (VC_AUDIO_MSG_TYPE)
2753 + VC_AUDIO_CONFIG_T config;
2754 + VC_AUDIO_CONTROL_T control;
2755 + VC_AUDIO_OPEN_T open;
2756 + VC_AUDIO_CLOSE_T close;
2757 + VC_AUDIO_START_T start;
2758 + VC_AUDIO_STOP_T stop;
2759 + VC_AUDIO_WRITE_T write;
2760 + VC_AUDIO_RESULT_T result;
2761 + VC_AUDIO_COMPLETE_T complete;
2765 +#endif // _VC_AUDIO_DEFS_H_