brcm2708: update to v3.18
[15.05/openwrt.git] / target / linux / brcm2708 / patches-3.18 / 0013-bcm2708-alsa-sound-driver.patch
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
5
6     Signed-off-by: popcornmix <popcornmix@gmail.com>
7
8 alsa: add mmap support and some cleanups to bcm2835 ALSA driver
9
10 snd-bcm2835: Add support for spdif/hdmi passthrough
11
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.
16
17 snd-bcm2708: Add mutex, improve logging
18
19 Fix for ALSA driver crash
20
21 Avoids an issue when closing and opening vchiq where a message can arrive before service handle has been written
22
23 alsa: reduce severity of expected warning message
24
25 snd-bcm2708: Fix dmesg spam for non-error case
26 ---
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
46
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
52  CONFIG_LOGO=y
53  # CONFIG_LOGO_LINUX_MONO is not set
54  # CONFIG_LOGO_LINUX_VGA16 is not set
55 +CONFIG_SOUND=y
56 +CONFIG_SND=m
57 +CONFIG_SND_SEQUENCER=m
58 +CONFIG_SND_SEQ_DUMMY=m
59 +CONFIG_SND_MIXER_OSS=m
60 +CONFIG_SND_PCM_OSS=m
61 +CONFIG_SND_SEQUENCER_OSS=y
62 +CONFIG_SND_HRTIMER=m
63 +CONFIG_SND_DUMMY=m
64 +CONFIG_SND_ALOOP=m
65 +CONFIG_SND_VIRMIDI=m
66 +CONFIG_SND_MTPAV=m
67 +CONFIG_SND_SERIAL_U16550=m
68 +CONFIG_SND_MPU401=m
69 +CONFIG_SND_BCM2835=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
74 +CONFIG_SOUND_PRIME=m
75  CONFIG_HID_A4TECH=m
76  CONFIG_HID_ACRUX=m
77  CONFIG_HID_APPLE=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},
84  };
85  
86 +
87 +static struct platform_device bcm2708_alsa_devices[] = {
88 +       [0] = {
89 +              .name = "bcm2835_AUD0",
90 +              .id = 0,         /* first audio device */
91 +              .resource = 0,
92 +              .num_resources = 0,
93 +              },
94 +       [1] = {
95 +              .name = "bcm2835_AUD1",
96 +              .id = 1,         /* second audio device */
97 +              .resource = 0,
98 +              .num_resources = 0,
99 +              },
100 +       [2] = {
101 +              .name = "bcm2835_AUD2",
102 +              .id = 2,         /* third audio device */
103 +              .resource = 0,
104 +              .num_resources = 0,
105 +              },
106 +       [3] = {
107 +              .name = "bcm2835_AUD3",
108 +              .id = 3,         /* forth audio device */
109 +              .resource = 0,
110 +              .num_resources = 0,
111 +              },
112 +       [4] = {
113 +              .name = "bcm2835_AUD4",
114 +              .id = 4,         /* fifth audio device */
115 +              .resource = 0,
116 +              .num_resources = 0,
117 +              },
118 +       [5] = {
119 +              .name = "bcm2835_AUD5",
120 +              .id = 5,         /* sixth audio device */
121 +              .resource = 0,
122 +              .num_resources = 0,
123 +              },
124 +       [6] = {
125 +              .name = "bcm2835_AUD6",
126 +              .id = 6,         /* seventh audio device */
127 +              .resource = 0,
128 +              .num_resources = 0,
129 +              },
130 +       [7] = {
131 +              .name = "bcm2835_AUD7",
132 +              .id = 7,         /* eighth audio device */
133 +              .resource = 0,
134 +              .num_resources = 0,
135 +              },
136 +};
137 +
138  int __init bcm_register_device(struct platform_device *pdev)
139  {
140         int ret;
141 @@ -508,6 +560,8 @@ void __init bcm2708_init(void)
142         bcm_register_device(&bcm2708_powerman_device);
143  
144         bcm2708_init_led();
145 +       for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
146 +               bcm_register_device(&bcm2708_alsa_devices[i]);
147  
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(
155                 NULL);
156  
157         if (service) {
158 +               *phandle = service->handle;
159                 status = vchiq_open_service_internal(service, current->pid);
160 -               if (status == VCHIQ_SUCCESS)
161 -                       *phandle = service->handle;
162 -               else
163 +               if (status != VCHIQ_SUCCESS) {
164                         vchiq_remove_service(service->handle);
165 +                       *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
166 +               }
167         }
168  
169  failed:
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,
175  {
176         VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
177         SHIM_SERVICE_T *service = service_alloc(instance, setup);
178 +
179 +       *handle = (VCHI_SERVICE_HANDLE_T)service;
180 +
181         if (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);
187                         service = NULL;
188 +                       *handle = NULL;
189                 }
190         }
191  
192 -       *handle = (VCHI_SERVICE_HANDLE_T)service;
193 -
194         return (service != NULL) ? 0 : -1;
195  }
196  EXPORT_SYMBOL(vchi_service_open);
197 @@ -665,6 +667,9 @@ int32_t vchi_service_create(VCHI_INSTANCE_T instance_handle,
198  {
199         VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle;
200         SHIM_SERVICE_T *service = service_alloc(instance, setup);
201 +
202 +       *handle = (VCHI_SERVICE_HANDLE_T)service;
203 +
204         if (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);
210                         service = NULL;
211 +                       *handle = NULL;
212                 }
213         }
214  
215 -       *handle = (VCHI_SERVICE_HANDLE_T)service;
216 -
217         return (service != NULL) ? 0 : -1;
218  }
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.
227  
228 +config SND_BCM2835
229 +       tristate "BCM2835 ALSA driver"
230 +       depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND
231 +       select SND_PCM
232 +       help
233 +         Say Y or M if you want to support BCM2835 Alsa pcm card driver
234 +
235  endif  # SND_ARM
236  
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
242  
243  obj-$(CONFIG_SND_PXA2XX_AC97)  += snd-pxa2xx-ac97.o
244  snd-pxa2xx-ac97-objs           := pxa2xx-ac97.o
245 +
246 +obj-$(CONFIG_SND_BCM2835)      += snd-bcm2835.o
247 +snd-bcm2835-objs               := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
248 +
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
251 new file mode 100755
252 index 0000000..aad905f
253 --- /dev/null
254 +++ b/sound/arm/bcm2835-ctl.c
255 @@ -0,0 +1,323 @@
256 +/*****************************************************************************
257 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
258 +*
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").
263 +*
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
267 +* consent.
268 +*****************************************************************************/
269 +
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>
280 +
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>
289 +
290 +#include "bcm2835.h"
291 +
292 +/* volume maximum and minimum in terms of 0.01dB */
293 +#define CTRL_VOL_MAX 400
294 +#define CTRL_VOL_MIN -10239 /* originally -10240 */
295 +
296 +
297 +static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
298 +                               struct snd_ctl_elem_info *uinfo)
299 +{
300 +       audio_info(" ... IN\n");
301 +       if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
302 +               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
303 +               uinfo->count = 1;
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;
308 +               uinfo->count = 1;
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;
313 +               uinfo->count = 1;
314 +               uinfo->value.integer.min = 0;
315 +               uinfo->value.integer.max = AUDIO_DEST_MAX-1;
316 +       }
317 +       audio_info(" ... OUT\n");
318 +       return 0;
319 +}
320 +
321 +/* toggles mute on or off depending on the value of nmute, and returns
322 + * 1 if the mute value was changed, otherwise 0
323 + */
324 +static int toggle_mute(struct bcm2835_chip *chip, int nmute)
325 +{
326 +       /* if settings are ok, just return 0 */
327 +       if(chip->mute == nmute)
328 +               return 0;
329 +
330 +       /* if the sound is muted then we need to unmute */
331 +       if(chip->mute == CTRL_VOL_MUTE)
332 +       {
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);
335 +       }
336 +       else /* otherwise we mute */
337 +       {
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);
341 +       }
342 +
343 +       chip->mute = nmute;
344 +       return 1;
345 +}
346 +
347 +static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
348 +                              struct snd_ctl_elem_value *ucontrol)
349 +{
350 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
351 +
352 +       BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
353 +
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;
360 +
361 +       return 0;
362 +}
363 +
364 +static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
365 +                              struct snd_ctl_elem_value *ucontrol)
366 +{
367 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
368 +       int changed = 0;
369 +
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) */
375 +               }
376 +               if (changed
377 +                   || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
378 +
379 +                       chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
380 +                       changed = 1;
381 +               }
382 +
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]);
387 +
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];
391 +                       changed = 1;
392 +               }
393 +       }
394 +
395 +       if (changed) {
396 +               if (bcm2835_audio_set_ctls(chip))
397 +                       printk(KERN_ERR "Failed to set ALSA controls..\n");
398 +       }
399 +
400 +       return changed;
401 +}
402 +
403 +static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
404 +
405 +static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
406 +       {
407 +        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
408 +        .name = "PCM Playback Volume",
409 +        .index = 0,
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,
415 +        .count = 1,
416 +        .tlv = {.p = snd_bcm2835_db_scale}
417 +       },
418 +       {
419 +        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
420 +        .name = "PCM Playback Switch",
421 +        .index = 0,
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,
427 +        .count = 1,
428 +        },
429 +       {
430 +        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
431 +        .name = "PCM Playback Route",
432 +        .index = 0,
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,
438 +        .count = 1,
439 +       },
440 +};
441 +
442 +static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
443 +                                         struct snd_ctl_elem_info *uinfo)
444 +{
445 +       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
446 +       uinfo->count = 1;
447 +       return 0;
448 +}
449 +
450 +static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
451 +                                        struct snd_ctl_elem_value *ucontrol)
452 +{
453 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
454 +       int i;
455 +
456 +       for (i = 0; i < 4; i++)
457 +               ucontrol->value.iec958.status[i] =
458 +                       (chip->spdif_status >> (i * 8)) && 0xff;
459 +
460 +       return 0;
461 +}
462 +
463 +static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
464 +                                        struct snd_ctl_elem_value *ucontrol)
465 +{
466 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
467 +       unsigned int val = 0;
468 +       int i, change;
469 +
470 +       for (i = 0; i < 4; i++)
471 +               val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
472 +
473 +       change = val != chip->spdif_status;
474 +       chip->spdif_status = val;
475 +
476 +       return change;
477 +}
478 +
479 +static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
480 +                                      struct snd_ctl_elem_info *uinfo)
481 +{
482 +       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
483 +       uinfo->count = 1;
484 +       return 0;
485 +}
486 +
487 +static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
488 +                                     struct snd_ctl_elem_value *ucontrol)
489 +{
490 +       /* bcm2835 supports only consumer mode and sets all other format flags
491 +        * automatically. So the only thing left is signalling non-audio
492 +        * content */
493 +       ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
494 +       return 0;
495 +}
496 +
497 +static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
498 +                                        struct snd_ctl_elem_info *uinfo)
499 +{
500 +       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
501 +       uinfo->count = 1;
502 +       return 0;
503 +}
504 +
505 +static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
506 +                                       struct snd_ctl_elem_value *ucontrol)
507 +{
508 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
509 +       int i;
510 +
511 +       for (i = 0; i < 4; i++)
512 +               ucontrol->value.iec958.status[i] =
513 +                       (chip->spdif_status >> (i * 8)) & 0xff;
514 +       return 0;
515 +}
516 +
517 +static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
518 +                                       struct snd_ctl_elem_value *ucontrol)
519 +{
520 +       struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
521 +       unsigned int val = 0;
522 +       int i, change;
523 +
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;
528 +
529 +       return change;
530 +}
531 +
532 +static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
533 +       {
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
539 +       },
540 +       {
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,
546 +       },
547 +       {
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,
555 +       },
556 +};
557 +
558 +int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
559 +{
560 +       int err;
561 +       unsigned int idx;
562 +
563 +       strcpy(chip->card->mixername, "Broadcom Mixer");
564 +       for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
565 +               err =
566 +                   snd_ctl_add(chip->card,
567 +                               snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
568 +               if (err < 0)
569 +                       return err;
570 +       }
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));
574 +               if (err < 0)
575 +                       return err;
576 +       }
577 +       return 0;
578 +}
579 diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c
580 new file mode 100755
581 index 0000000..3a20b34
582 --- /dev/null
583 +++ b/sound/arm/bcm2835-pcm.c
584 @@ -0,0 +1,552 @@
585 +/*****************************************************************************
586 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
587 +*
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").
592 +*
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
596 +* consent.
597 +*****************************************************************************/
598 +
599 +#include <linux/interrupt.h>
600 +#include <linux/slab.h>
601 +
602 +#include <sound/asoundef.h>
603 +
604 +#include "bcm2835.h"
605 +
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,
612 +       .rate_min = 8000,
613 +       .rate_max = 48000,
614 +       .channels_min = 1,
615 +       .channels_max = 2,
616 +       .buffer_bytes_max = 128 * 1024,
617 +       .period_bytes_min =   1 * 1024,
618 +       .period_bytes_max = 128 * 1024,
619 +       .periods_min = 1,
620 +       .periods_max = 128,
621 +};
622 +
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,
629 +       .rate_min = 44100,
630 +       .rate_max = 48000,
631 +       .channels_min = 2,
632 +       .channels_max = 2,
633 +       .buffer_bytes_max = 128 * 1024,
634 +       .period_bytes_min =   1 * 1024,
635 +       .period_bytes_max = 128 * 1024,
636 +       .periods_min = 1,
637 +       .periods_max = 128,
638 +};
639 +
640 +static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
641 +{
642 +       audio_info("Freeing up alsa stream here ..\n");
643 +       if (runtime->private_data)
644 +               kfree(runtime->private_data);
645 +       runtime->private_data = NULL;
646 +}
647 +
648 +static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
649 +{
650 +       bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id;
651 +       uint32_t consumed = 0;
652 +       int new_period = 0;
653 +
654 +       audio_info(" .. IN\n");
655 +
656 +       audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
657 +                  alsa_stream ? alsa_stream->substream : 0);
658 +
659 +       if (alsa_stream->open)
660 +               consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
661 +
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
664 +        */
665 +
666 +       if (alsa_stream->period_size) {
667 +               if ((alsa_stream->pos / alsa_stream->period_size) !=
668 +                   ((alsa_stream->pos + consumed) / alsa_stream->period_size))
669 +                       new_period = 1;
670 +       }
671 +       audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
672 +                     alsa_stream->pos,
673 +                     consumed,
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),
677 +                         new_period);
678 +       if (alsa_stream->buffer_size) {
679 +               alsa_stream->pos += consumed &~ (1<<30);
680 +               alsa_stream->pos %= alsa_stream->buffer_size;
681 +       }
682 +
683 +       if (alsa_stream->substream) {
684 +               if (new_period)
685 +                       snd_pcm_period_elapsed(alsa_stream->substream);
686 +       } else {
687 +               audio_warning(" unexpected NULL substream\n");
688 +       }
689 +       audio_info(" .. OUT\n");
690 +
691 +       return IRQ_HANDLED;
692 +}
693 +
694 +/* open callback */
695 +static int snd_bcm2835_playback_open_generic(
696 +               struct snd_pcm_substream *substream, int spdif)
697 +{
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;
701 +       int idx;
702 +       int err;
703 +
704 +       audio_info(" .. IN (%d)\n", substream->number);
705 +
706 +       if(mutex_lock_interruptible(&chip->audio_mutex))
707 +       {
708 +               audio_error("Interrupted whilst waiting for lock\n");
709 +               return -EINTR;
710 +       }
711 +       audio_info("Alsa open (%d)\n", substream->number);
712 +       idx = substream->number;
713 +
714 +       if (spdif && chip->opened != 0)
715 +               return -EBUSY;
716 +       else if (!spdif && (chip->opened & (1 << idx)))
717 +               return -EBUSY;
718 +
719 +       if (idx > MAX_SUBSTREAMS) {
720 +               audio_error
721 +                   ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
722 +                    idx, MAX_SUBSTREAMS);
723 +               err = -ENODEV;
724 +               goto out;
725 +       }
726 +
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);
731 +               err = -EAGAIN;
732 +               goto out;
733 +       }
734 +
735 +       alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL);
736 +       if (alsa_stream == NULL) {
737 +               err = -ENOMEM;
738 +               goto out;
739 +       }
740 +
741 +       /* Initialise alsa_stream */
742 +       alsa_stream->chip = chip;
743 +       alsa_stream->substream = substream;
744 +       alsa_stream->idx = idx;
745 +
746 +       sema_init(&alsa_stream->buffers_update_sem, 0);
747 +       sema_init(&alsa_stream->control_sem, 0);
748 +       spin_lock_init(&alsa_stream->lock);
749 +
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;
753 +
754 +       err = bcm2835_audio_open(alsa_stream);
755 +       if (err != 0) {
756 +               kfree(alsa_stream);
757 +               return err;
758 +       }
759 +       runtime->private_data = alsa_stream;
760 +       runtime->private_free = snd_bcm2835_playback_free;
761 +       if (spdif) {
762 +               runtime->hw = snd_bcm2835_playback_spdif_hw;
763 +       } else {
764 +               /* clear spdif status, as we are not in spdif mode */
765 +               chip->spdif_status = 0;
766 +               runtime->hw = snd_bcm2835_playback_hw;
767 +       }
768 +       /* minimum 16 bytes alignment (for vchiq bulk transfers) */
769 +       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
770 +                                  16);
771 +
772 +       chip->alsa_stream[idx] = alsa_stream;
773 +
774 +       chip->opened |= (1 << idx);
775 +       alsa_stream->open = 1;
776 +       alsa_stream->draining = 1;
777 +
778 +out:
779 +       mutex_unlock(&chip->audio_mutex);
780 +
781 +       audio_info(" .. OUT =%d\n", err);
782 +
783 +       return err;
784 +}
785 +
786 +static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
787 +{
788 +       return snd_bcm2835_playback_open_generic(substream, 0);
789 +}
790 +
791 +static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
792 +{
793 +       return snd_bcm2835_playback_open_generic(substream, 1);
794 +}
795 +
796 +/* close callback */
797 +static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
798 +{
799 +       /* the hardware-specific codes will be here */
800 +
801 +       bcm2835_chip_t *chip;
802 +       struct snd_pcm_runtime *runtime;
803 +       bcm2835_alsa_stream_t *alsa_stream;
804 +
805 +       audio_info(" .. IN\n");
806 +
807 +       chip = snd_pcm_substream_chip(substream);
808 +       if(mutex_lock_interruptible(&chip->audio_mutex))
809 +       {
810 +               audio_error("Interrupted whilst waiting for lock\n");
811 +               return -EINTR;
812 +       }
813 +       runtime = substream->runtime;
814 +       alsa_stream = runtime->private_data;
815 +
816 +       audio_info("Alsa close\n");
817 +
818 +       /*
819 +        * Call stop if it's still running. This happens when app
820 +        * is force killed and we don't get a stop trigger.
821 +        */
822 +       if (alsa_stream->running) {
823 +               int err;
824 +               err = bcm2835_audio_stop(alsa_stream);
825 +               alsa_stream->running = 0;
826 +               if (err != 0)
827 +                       audio_error(" Failed to STOP alsa device\n");
828 +       }
829 +
830 +       alsa_stream->period_size = 0;
831 +       alsa_stream->buffer_size = 0;
832 +
833 +       if (alsa_stream->open) {
834 +               alsa_stream->open = 0;
835 +               bcm2835_audio_close(alsa_stream);
836 +       }
837 +       if (alsa_stream->chip)
838 +               alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
839 +       /*
840 +        * Do not free up alsa_stream here, it will be freed up by
841 +        * runtime->private_free callback we registered in *_open above
842 +        */
843 +
844 +       chip->opened &= ~(1 << substream->number);
845 +
846 +       mutex_unlock(&chip->audio_mutex);
847 +       audio_info(" .. OUT\n");
848 +
849 +       return 0;
850 +}
851 +
852 +/* hw_params callback */
853 +static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
854 +                                    struct snd_pcm_hw_params *params)
855 +{
856 +       struct snd_pcm_runtime *runtime = substream->runtime;
857 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
858 +       int err;
859 +
860 +       audio_info(" .. IN\n");
861 +
862 +       err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
863 +       if (err < 0) {
864 +               audio_error
865 +                   (" pcm_lib_malloc failed to allocated pages for buffers\n");
866 +               return err;
867 +       }
868 +
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");
873 +
874 +       return err;
875 +}
876 +
877 +/* hw_free callback */
878 +static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
879 +{
880 +       audio_info(" .. IN\n");
881 +       return snd_pcm_lib_free_pages(substream);
882 +}
883 +
884 +/* prepare callback */
885 +static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
886 +{
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;
890 +       int channels;
891 +       int err;
892 +
893 +       audio_info(" .. IN\n");
894 +
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)
899 +               channels = 0;
900 +       else
901 +               channels = alsa_stream->channels;
902 +
903 +       err = bcm2835_audio_set_params(alsa_stream, channels,
904 +                                      alsa_stream->params_rate,
905 +                                      alsa_stream->pcm_format_width);
906 +       if (err < 0) {
907 +               audio_error(" error setting hw params\n");
908 +       }
909 +
910 +       bcm2835_audio_setup(alsa_stream);
911 +
912 +       /* in preparation of the stream, set the controls (volume level) of the stream */
913 +       bcm2835_audio_set_ctls(alsa_stream->chip);
914 +
915 +
916 +       memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
917 +
918 +       alsa_stream->pcm_indirect.hw_buffer_size =
919 +       alsa_stream->pcm_indirect.sw_buffer_size =
920 +               snd_pcm_lib_buffer_bytes(substream);
921 +
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;
925 +
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);
929 +
930 +       audio_info(" .. OUT\n");
931 +       return 0;
932 +}
933 +
934 +static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
935 +                                   struct snd_pcm_indirect *rec, size_t bytes)
936 +{
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);
940 +       int err;
941 +
942 +       err = bcm2835_audio_write(alsa_stream, bytes, src);
943 +       if (err)
944 +               audio_error(" Failed to transfer to alsa device (%d)\n", err);
945 +
946 +}
947 +
948 +static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
949 +{
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;
953 +
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);
957 +       return 0;
958 +}
959 +
960 +/* trigger callback */
961 +static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
962 +{
963 +       struct snd_pcm_runtime *runtime = substream->runtime;
964 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
965 +       int err = 0;
966 +
967 +       audio_info(" .. IN\n");
968 +
969 +       switch (cmd) {
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);
975 +                       if (err == 0) {
976 +                               alsa_stream->pcm_indirect.hw_io =
977 +                               alsa_stream->pcm_indirect.hw_data =
978 +                                       bytes_to_frames(runtime,
979 +                                                       alsa_stream->pos);
980 +                               substream->ops->ack(substream);
981 +                               alsa_stream->running = 1;
982 +                               alsa_stream->draining = 1;
983 +                       } else {
984 +                               audio_error(" Failed to START alsa device (%d)\n", err);
985 +                       }
986 +               }
987 +               break;
988 +       case SNDRV_PCM_TRIGGER_STOP:
989 +               audio_debug
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;
995 +               } else {
996 +                       audio_info("DROPPING\n");
997 +                       alsa_stream->draining = 0;
998 +               }
999 +               if (alsa_stream->running) {
1000 +                       err = bcm2835_audio_stop(alsa_stream);
1001 +                       if (err != 0)
1002 +                               audio_error(" Failed to STOP alsa device (%d)\n", err);
1003 +                       alsa_stream->running = 0;
1004 +               }
1005 +               break;
1006 +       default:
1007 +               err = -EINVAL;
1008 +       }
1009 +
1010 +       audio_info(" .. OUT\n");
1011 +       return err;
1012 +}
1013 +
1014 +/* pointer callback */
1015 +static snd_pcm_uframes_t
1016 +snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
1017 +{
1018 +       struct snd_pcm_runtime *runtime = substream->runtime;
1019 +       bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
1020 +
1021 +       audio_info(" .. IN\n");
1022 +
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);
1027 +
1028 +       audio_info(" .. OUT\n");
1029 +       return snd_pcm_indirect_playback_pointer(substream,
1030 +                                                &alsa_stream->pcm_indirect,
1031 +                                                alsa_stream->pos);
1032 +}
1033 +
1034 +static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
1035 +                                    unsigned int cmd, void *arg)
1036 +{
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);
1040 +       return ret;
1041 +}
1042 +
1043 +/* operators */
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,
1054 +};
1055 +
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,
1066 +};
1067 +
1068 +/* create a pcm device */
1069 +int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
1070 +{
1071 +       struct snd_pcm *pcm;
1072 +       int err;
1073 +
1074 +       audio_info(" .. IN\n");
1075 +       mutex_init(&chip->audio_mutex);
1076 +       if(mutex_lock_interruptible(&chip->audio_mutex))
1077 +       {
1078 +               audio_error("Interrupted whilst waiting for lock\n");
1079 +               return -EINTR;
1080 +       }
1081 +       err =
1082 +           snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
1083 +       if (err < 0)
1084 +               return err;
1085 +       pcm->private_data = chip;
1086 +       strcpy(pcm->name, "bcm2835 ALSA");
1087 +       chip->pcm = pcm;
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);
1094 +
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,
1100 +                                             64 * 1024);
1101 +
1102 +       mutex_unlock(&chip->audio_mutex);
1103 +       audio_info(" .. OUT\n");
1104 +
1105 +       return 0;
1106 +}
1107 +
1108 +int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip)
1109 +{
1110 +       struct snd_pcm *pcm;
1111 +       int err;
1112 +
1113 +       audio_info(" .. IN\n");
1114 +       if(mutex_lock_interruptible(&chip->audio_mutex))
1115 +       {
1116 +               audio_error("Interrupted whilst waiting for lock\n");
1117 +               return -EINTR;
1118 +       }
1119 +       err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
1120 +       if (err < 0)
1121 +               return err;
1122 +
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);
1128 +
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");
1134 +
1135 +       return 0;
1136 +}
1137 diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c
1138 new file mode 100755
1139 index 0000000..3c95381
1140 --- /dev/null
1141 +++ b/sound/arm/bcm2835-vchiq.c
1142 @@ -0,0 +1,902 @@
1143 +/*****************************************************************************
1144 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
1145 +*
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").
1150 +*
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
1154 +* consent.
1155 +*****************************************************************************/
1156 +
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>
1173 +
1174 +#include "bcm2835.h"
1175 +
1176 +/* ---- Include Files -------------------------------------------------------- */
1177 +
1178 +#include "interface/vchi/vchi.h"
1179 +#include "vc_vchi_audioserv_defs.h"
1180 +
1181 +/* ---- Private Constants and Types ------------------------------------------ */
1182 +
1183 +#define BCM2835_AUDIO_STOP           0
1184 +#define BCM2835_AUDIO_START          1
1185 +#define BCM2835_AUDIO_WRITE          2
1186 +
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)
1193 +#else
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... )
1198 +#endif
1199 +
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;
1206 +       int32_t result;
1207 +       short peer_version;
1208 +} AUDIO_INSTANCE_T;
1209 +
1210 +bool force_bulk = false;
1211 +
1212 +/* ---- Private Variables ---------------------------------------------------- */
1213 +
1214 +/* ---- Private Function Prototypes ------------------------------------------ */
1215 +
1216 +/* ---- Private Functions ---------------------------------------------------- */
1217 +
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);
1222 +
1223 +typedef struct {
1224 +       struct work_struct my_work;
1225 +       bcm2835_alsa_stream_t *alsa_stream;
1226 +       int cmd;
1227 +       void *src;
1228 +       uint32_t count;
1229 +} my_work_t;
1230 +
1231 +static void my_wq_function(struct work_struct *work)
1232 +{
1233 +       my_work_t *w = (my_work_t *) work;
1234 +       int ret = -9;
1235 +       LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
1236 +       switch (w->cmd) {
1237 +       case BCM2835_AUDIO_START:
1238 +               ret = bcm2835_audio_start_worker(w->alsa_stream);
1239 +               break;
1240 +       case BCM2835_AUDIO_STOP:
1241 +               ret = bcm2835_audio_stop_worker(w->alsa_stream);
1242 +               break;
1243 +       case BCM2835_AUDIO_WRITE:
1244 +               ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
1245 +                                                w->src);
1246 +               break;
1247 +       default:
1248 +               LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
1249 +               break;
1250 +       }
1251 +       kfree((void *)work);
1252 +       LOG_DBG(" .. OUT %d\n", ret);
1253 +}
1254 +
1255 +int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
1256 +{
1257 +       int ret = -1;
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) ---*/
1262 +               if (work) {
1263 +                       INIT_WORK((struct work_struct *)work, my_wq_function);
1264 +                       work->alsa_stream = alsa_stream;
1265 +                       work->cmd = BCM2835_AUDIO_START;
1266 +                       if (queue_work
1267 +                           (alsa_stream->my_wq, (struct work_struct *)work))
1268 +                               ret = 0;
1269 +               } else
1270 +                       LOG_ERR(" .. Error: NULL work kmalloc\n");
1271 +       }
1272 +       LOG_DBG(" .. OUT %d\n", ret);
1273 +       return ret;
1274 +}
1275 +
1276 +int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
1277 +{
1278 +       int ret = -1;
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) ---*/
1283 +               if (work) {
1284 +                       INIT_WORK((struct work_struct *)work, my_wq_function);
1285 +                       work->alsa_stream = alsa_stream;
1286 +                       work->cmd = BCM2835_AUDIO_STOP;
1287 +                       if (queue_work
1288 +                           (alsa_stream->my_wq, (struct work_struct *)work))
1289 +                               ret = 0;
1290 +               } else
1291 +                       LOG_ERR(" .. Error: NULL work kmalloc\n");
1292 +       }
1293 +       LOG_DBG(" .. OUT %d\n", ret);
1294 +       return ret;
1295 +}
1296 +
1297 +int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
1298 +                       uint32_t count, void *src)
1299 +{
1300 +       int ret = -1;
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) ---*/
1305 +               if (work) {
1306 +                       INIT_WORK((struct work_struct *)work, my_wq_function);
1307 +                       work->alsa_stream = alsa_stream;
1308 +                       work->cmd = BCM2835_AUDIO_WRITE;
1309 +                       work->src = src;
1310 +                       work->count = count;
1311 +                       if (queue_work
1312 +                           (alsa_stream->my_wq, (struct work_struct *)work))
1313 +                               ret = 0;
1314 +               } else
1315 +                       LOG_ERR(" .. Error: NULL work kmalloc\n");
1316 +       }
1317 +       LOG_DBG(" .. OUT %d\n", ret);
1318 +       return ret;
1319 +}
1320 +
1321 +void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
1322 +{
1323 +       alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
1324 +       return;
1325 +}
1326 +
1327 +void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream)
1328 +{
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;
1333 +       }
1334 +       return;
1335 +}
1336 +
1337 +static void audio_vchi_callback(void *param,
1338 +                               const VCHI_CALLBACK_REASON_T reason,
1339 +                               void *msg_handle)
1340 +{
1341 +       AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param;
1342 +       int32_t status;
1343 +       int32_t msg_len;
1344 +       VC_AUDIO_MSG_T m;
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);
1347 +
1348 +       if (reason != VCHI_CALLBACK_MSG_AVAILABLE) {
1349 +               return;
1350 +       }
1351 +       if (!instance) {
1352 +               LOG_ERR(" .. instance is null\n");
1353 +               BUG();
1354 +               return;
1355 +  }
1356 +  if (!instance->vchi_handle[0]) {
1357 +               LOG_ERR(" .. instance->vchi_handle[0] is null\n");
1358 +               BUG();
1359 +               return;
1360 +  }
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) {
1364 +               LOG_DBG
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;
1372 +               LOG_DBG
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);
1378 +               } else {
1379 +                       LOG_ERR(" .. unexpected alsa_stream=%p, callback=%p\n",
1380 +                               alsa_stream, callback);
1381 +               }
1382 +       } else {
1383 +               LOG_ERR(" .. unexpected m.type=%d\n", m.type);
1384 +       }
1385 +       LOG_DBG(" .. OUT\n");
1386 +}
1387 +
1388 +static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
1389 +                                           VCHI_CONNECTION_T **
1390 +                                           vchi_connections,
1391 +                                           uint32_t num_connections)
1392 +{
1393 +       uint32_t i;
1394 +       AUDIO_INSTANCE_T *instance;
1395 +       int status;
1396 +
1397 +       LOG_DBG("%s: start", __func__);
1398 +
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);
1402 +
1403 +               return NULL;
1404 +       }
1405 +       /* Allocate memory for this instance */
1406 +       instance = kmalloc(sizeof(*instance), GFP_KERNEL);
1407 +       if (!instance)
1408 +               return NULL;
1409 +
1410 +       memset(instance, 0, sizeof(*instance));
1411 +       instance->num_connections = num_connections;
1412 +
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
1428 +               };
1429 +
1430 +               LOG_DBG("%s: about to open %i\n", __func__, i);
1431 +               status = vchi_service_open(vchi_instance, &params,
1432 +                                          &instance->vchi_handle[i]);
1433 +               LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
1434 +               if (status) {
1435 +                       LOG_ERR
1436 +                           ("%s: failed to open VCHI service connection (status=%d)\n",
1437 +                            __func__, status);
1438 +
1439 +                       goto err_close_services;
1440 +               }
1441 +               /* Finished with the service for now */
1442 +               vchi_service_release(instance->vchi_handle[i]);
1443 +       }
1444 +
1445 +       LOG_DBG("%s: okay\n", __func__);
1446 +       return instance;
1447 +
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]);
1453 +       }
1454 +
1455 +       kfree(instance);
1456 +       LOG_ERR("%s: error\n", __func__);
1457 +
1458 +       return NULL;
1459 +}
1460 +
1461 +static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance)
1462 +{
1463 +       uint32_t i;
1464 +
1465 +       LOG_DBG(" .. IN\n");
1466 +
1467 +       if (instance == NULL) {
1468 +               LOG_ERR("%s: invalid handle %p\n", __func__, instance);
1469 +
1470 +               return -1;
1471 +       }
1472 +
1473 +       LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
1474 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1475 +       {
1476 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1477 +               return -EINTR;
1478 +       }
1479 +
1480 +       /* Close all VCHI service connections */
1481 +       for (i = 0; i < instance->num_connections; i++) {
1482 +               int32_t success;
1483 +               LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
1484 +               vchi_service_use(instance->vchi_handle[i]);
1485 +
1486 +               success = vchi_service_close(instance->vchi_handle[i]);
1487 +               if (success != 0) {
1488 +                       LOG_ERR
1489 +                           ("%s: failed to close VCHI service connection (status=%d)\n",
1490 +                            __func__, success);
1491 +               }
1492 +       }
1493 +
1494 +       mutex_unlock(&instance->vchi_mutex);
1495 +
1496 +       kfree(instance);
1497 +
1498 +       LOG_DBG(" .. OUT\n");
1499 +
1500 +       return 0;
1501 +}
1502 +
1503 +static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream)
1504 +{
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;
1509 +       int ret;
1510 +       LOG_DBG(" .. IN\n");
1511 +
1512 +       LOG_INFO("%s: start\n", __func__);
1513 +       BUG_ON(instance);
1514 +       if (instance) {
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;
1521 +       }
1522 +
1523 +       /* Initialize and create a VCHI connection */
1524 +       if (!initted) {
1525 +         ret = vchi_initialise(&vchi_instance);
1526 +         if (ret != 0) {
1527 +                 LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
1528 +                         __func__, ret);
1529 +
1530 +                 ret = -EIO;
1531 +                 goto err_free_mem;
1532 +         }
1533 +         ret = vchi_connect(NULL, 0, vchi_instance);
1534 +         if (ret != 0) {
1535 +                 LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
1536 +                         __func__, ret);
1537 +
1538 +                 ret = -EIO;
1539 +                 goto err_free_mem;
1540 +         }
1541 +       initted = 1;
1542 +       }
1543 +
1544 +       /* Initialize an instance of the audio service */
1545 +       instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
1546 +
1547 +       if (instance == NULL) {
1548 +               LOG_ERR("%s: failed to initialize audio service\n", __func__);
1549 +
1550 +               ret = -EPERM;
1551 +               goto err_free_mem;
1552 +       }
1553 +
1554 +       instance->alsa_stream = alsa_stream;
1555 +       alsa_stream->instance = instance;
1556 +
1557 +       LOG_DBG(" success !\n");
1558 +err_free_mem:
1559 +       LOG_DBG(" .. OUT\n");
1560 +
1561 +       return ret;
1562 +}
1563 +
1564 +int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
1565 +{
1566 +       AUDIO_INSTANCE_T *instance;
1567 +       VC_AUDIO_MSG_T m;
1568 +       int32_t success;
1569 +       int ret;
1570 +       LOG_DBG(" .. IN\n");
1571 +
1572 +       my_workqueue_init(alsa_stream);
1573 +
1574 +       ret = bcm2835_audio_open_connection(alsa_stream);
1575 +       if (ret != 0) {
1576 +               ret = -1;
1577 +               goto exit;
1578 +       }
1579 +       instance = alsa_stream->instance;
1580 +       LOG_DBG(" instance (%p)\n", instance);
1581 +
1582 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1583 +       {
1584 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1585 +               return -EINTR;
1586 +       }
1587 +       vchi_service_use(instance->vchi_handle[0]);
1588 +
1589 +       m.type = VC_AUDIO_MSG_TYPE_OPEN;
1590 +
1591 +       /* Send the message to the videocore */
1592 +       success = vchi_msg_queue(instance->vchi_handle[0],
1593 +                                &m, sizeof m,
1594 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1595 +
1596 +       if (success != 0) {
1597 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1598 +                       __func__, success);
1599 +
1600 +               ret = -1;
1601 +               goto unlock;
1602 +       }
1603 +
1604 +       ret = 0;
1605 +
1606 +unlock:
1607 +       vchi_service_release(instance->vchi_handle[0]);
1608 +       mutex_unlock(&instance->vchi_mutex);
1609 +exit:
1610 +       LOG_DBG(" .. OUT\n");
1611 +       return ret;
1612 +}
1613 +
1614 +static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
1615 +                                      bcm2835_chip_t * chip)
1616 +{
1617 +       VC_AUDIO_MSG_T m;
1618 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1619 +       int32_t success;
1620 +       int ret;
1621 +       LOG_DBG(" .. IN\n");
1622 +
1623 +       LOG_INFO
1624 +           (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
1625 +
1626 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1627 +       {
1628 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1629 +               return -EINTR;
1630 +       }
1631 +       vchi_service_use(instance->vchi_handle[0]);
1632 +
1633 +       instance->result = -1;
1634 +
1635 +       m.type = VC_AUDIO_MSG_TYPE_CONTROL;
1636 +       m.u.control.dest = chip->dest;
1637 +       m.u.control.volume = chip->volume;
1638 +
1639 +       /* Create the message available completion */
1640 +       init_completion(&instance->msg_avail_comp);
1641 +
1642 +       /* Send the message to the videocore */
1643 +       success = vchi_msg_queue(instance->vchi_handle[0],
1644 +                                &m, sizeof m,
1645 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1646 +
1647 +       if (success != 0) {
1648 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1649 +                       __func__, success);
1650 +
1651 +               ret = -1;
1652 +               goto unlock;
1653 +       }
1654 +
1655 +       /* We are expecting a reply from the videocore */
1656 +       ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1657 +       if (ret) {
1658 +               LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1659 +                       __func__, success);
1660 +               goto unlock;
1661 +       }
1662 +
1663 +       if (instance->result != 0) {
1664 +               LOG_ERR("%s: result=%d\n", __func__, instance->result);
1665 +
1666 +               ret = -1;
1667 +               goto unlock;
1668 +       }
1669 +
1670 +       ret = 0;
1671 +
1672 +unlock:
1673 +       vchi_service_release(instance->vchi_handle[0]);
1674 +       mutex_unlock(&instance->vchi_mutex);
1675 +
1676 +       LOG_DBG(" .. OUT\n");
1677 +       return ret;
1678 +}
1679 +
1680 +int bcm2835_audio_set_ctls(bcm2835_chip_t * chip)
1681 +{
1682 +       int i;
1683 +       int ret = 0;
1684 +       LOG_DBG(" .. IN\n");
1685 +       LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
1686 +
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])
1691 +                       {
1692 +                               LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
1693 +                               ret = 0;
1694 +                       }
1695 +                       else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */
1696 +                                (chip->alsa_stream[i], chip) != 0)
1697 +                                {
1698 +                                       LOG_ERR("Couldn't set the controls for stream %d\n", i);
1699 +                                       ret = -1;
1700 +                                }
1701 +                       else LOG_DBG(" Controls set for stream %d\n", i);
1702 +               }
1703 +       }
1704 +       LOG_DBG(" .. OUT ret=%d\n", ret);
1705 +       return ret;
1706 +}
1707 +
1708 +int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
1709 +                            uint32_t channels, uint32_t samplerate,
1710 +                            uint32_t bps)
1711 +{
1712 +       VC_AUDIO_MSG_T m;
1713 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1714 +       int32_t success;
1715 +       int ret;
1716 +       LOG_DBG(" .. IN\n");
1717 +
1718 +       LOG_INFO
1719 +           (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
1720 +            channels, samplerate, bps);
1721 +
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);
1724 +       if (ret != 0) {
1725 +               LOG_ERR(" Alsa controls not supported\n");
1726 +               return -EINVAL;
1727 +       }
1728 +
1729 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1730 +       {
1731 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1732 +               return -EINTR;
1733 +       }
1734 +       vchi_service_use(instance->vchi_handle[0]);
1735 +
1736 +       instance->result = -1;
1737 +
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;
1742 +
1743 +       /* Create the message available completion */
1744 +       init_completion(&instance->msg_avail_comp);
1745 +
1746 +       /* Send the message to the videocore */
1747 +       success = vchi_msg_queue(instance->vchi_handle[0],
1748 +                                &m, sizeof m,
1749 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1750 +
1751 +       if (success != 0) {
1752 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1753 +                       __func__, success);
1754 +
1755 +               ret = -1;
1756 +               goto unlock;
1757 +       }
1758 +
1759 +       /* We are expecting a reply from the videocore */
1760 +       ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1761 +       if (ret) {
1762 +               LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1763 +                       __func__, success);
1764 +               goto unlock;
1765 +       }
1766 +
1767 +       if (instance->result != 0) {
1768 +               LOG_ERR("%s: result=%d", __func__, instance->result);
1769 +
1770 +               ret = -1;
1771 +               goto unlock;
1772 +       }
1773 +
1774 +       ret = 0;
1775 +
1776 +unlock:
1777 +       vchi_service_release(instance->vchi_handle[0]);
1778 +       mutex_unlock(&instance->vchi_mutex);
1779 +
1780 +       LOG_DBG(" .. OUT\n");
1781 +       return ret;
1782 +}
1783 +
1784 +int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream)
1785 +{
1786 +       LOG_DBG(" .. IN\n");
1787 +
1788 +       LOG_DBG(" .. OUT\n");
1789 +
1790 +       return 0;
1791 +}
1792 +
1793 +static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream)
1794 +{
1795 +       VC_AUDIO_MSG_T m;
1796 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1797 +       int32_t success;
1798 +       int ret;
1799 +       LOG_DBG(" .. IN\n");
1800 +
1801 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1802 +       {
1803 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1804 +               return -EINTR;
1805 +       }
1806 +       vchi_service_use(instance->vchi_handle[0]);
1807 +
1808 +       m.type = VC_AUDIO_MSG_TYPE_START;
1809 +
1810 +       /* Send the message to the videocore */
1811 +       success = vchi_msg_queue(instance->vchi_handle[0],
1812 +                                &m, sizeof m,
1813 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1814 +
1815 +       if (success != 0) {
1816 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1817 +                       __func__, success);
1818 +
1819 +               ret = -1;
1820 +               goto unlock;
1821 +       }
1822 +
1823 +       ret = 0;
1824 +
1825 +unlock:
1826 +       vchi_service_release(instance->vchi_handle[0]);
1827 +       mutex_unlock(&instance->vchi_mutex);
1828 +       LOG_DBG(" .. OUT\n");
1829 +       return ret;
1830 +}
1831 +
1832 +static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream)
1833 +{
1834 +       VC_AUDIO_MSG_T m;
1835 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1836 +       int32_t success;
1837 +       int ret;
1838 +       LOG_DBG(" .. IN\n");
1839 +
1840 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1841 +       {
1842 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1843 +               return -EINTR;
1844 +       }
1845 +       vchi_service_use(instance->vchi_handle[0]);
1846 +
1847 +       m.type = VC_AUDIO_MSG_TYPE_STOP;
1848 +       m.u.stop.draining = alsa_stream->draining;
1849 +
1850 +       /* Send the message to the videocore */
1851 +       success = vchi_msg_queue(instance->vchi_handle[0],
1852 +                                &m, sizeof m,
1853 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1854 +
1855 +       if (success != 0) {
1856 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1857 +                       __func__, success);
1858 +
1859 +               ret = -1;
1860 +               goto unlock;
1861 +       }
1862 +
1863 +       ret = 0;
1864 +
1865 +unlock:
1866 +       vchi_service_release(instance->vchi_handle[0]);
1867 +       mutex_unlock(&instance->vchi_mutex);
1868 +       LOG_DBG(" .. OUT\n");
1869 +       return ret;
1870 +}
1871 +
1872 +int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
1873 +{
1874 +       VC_AUDIO_MSG_T m;
1875 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1876 +       int32_t success;
1877 +       int ret;
1878 +       LOG_DBG(" .. IN\n");
1879 +
1880 +       my_workqueue_quit(alsa_stream);
1881 +
1882 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1883 +       {
1884 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1885 +               return -EINTR;
1886 +       }
1887 +       vchi_service_use(instance->vchi_handle[0]);
1888 +
1889 +       m.type = VC_AUDIO_MSG_TYPE_CLOSE;
1890 +
1891 +       /* Create the message available completion */
1892 +       init_completion(&instance->msg_avail_comp);
1893 +
1894 +       /* Send the message to the videocore */
1895 +       success = vchi_msg_queue(instance->vchi_handle[0],
1896 +                                &m, sizeof m,
1897 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1898 +
1899 +       if (success != 0) {
1900 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1901 +                       __func__, success);
1902 +               ret = -1;
1903 +               goto unlock;
1904 +       }
1905 +
1906 +       ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
1907 +       if (ret) {
1908 +               LOG_ERR("%s: failed on waiting for event (status=%d)\n",
1909 +                       __func__, success);
1910 +               goto unlock;
1911 +       }
1912 +       if (instance->result != 0) {
1913 +               LOG_ERR("%s: failed result (status=%d)\n",
1914 +                       __func__, instance->result);
1915 +
1916 +               ret = -1;
1917 +               goto unlock;
1918 +       }
1919 +
1920 +       ret = 0;
1921 +
1922 +unlock:
1923 +       vchi_service_release(instance->vchi_handle[0]);
1924 +       mutex_unlock(&instance->vchi_mutex);
1925 +
1926 +       /* Stop the audio service */
1927 +       if (instance) {
1928 +               vc_vchi_audio_deinit(instance);
1929 +               alsa_stream->instance = NULL;
1930 +       }
1931 +       LOG_DBG(" .. OUT\n");
1932 +       return ret;
1933 +}
1934 +
1935 +int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
1936 +                              uint32_t count, void *src)
1937 +{
1938 +       VC_AUDIO_MSG_T m;
1939 +       AUDIO_INSTANCE_T *instance = alsa_stream->instance;
1940 +       int32_t success;
1941 +       int ret;
1942 +
1943 +       LOG_DBG(" .. IN\n");
1944 +
1945 +       LOG_INFO(" Writing %d bytes from %p\n", count, src);
1946 +
1947 +       if(mutex_lock_interruptible(&instance->vchi_mutex))
1948 +       {
1949 +               LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
1950 +               return -EINTR;
1951 +       }
1952 +       vchi_service_use(instance->vchi_handle[0]);
1953 +
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);
1956 +       }
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;
1964 +
1965 +       /* Send the message to the videocore */
1966 +       success = vchi_msg_queue(instance->vchi_handle[0],
1967 +                                &m, sizeof m,
1968 +                                VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1969 +
1970 +       if (success != 0) {
1971 +               LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
1972 +                       __func__, success);
1973 +
1974 +               ret = -1;
1975 +               goto unlock;
1976 +       }
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],
1981 +                                                          src, count,
1982 +                                                          0 *
1983 +                                                          VCHI_FLAGS_BLOCK_UNTIL_QUEUED
1984 +                                                          +
1985 +                                                          1 *
1986 +                                                          VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
1987 +                                                          NULL);
1988 +               } else {
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],
1992 +                                                        src, bytes,
1993 +                                                        VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
1994 +                               src = (char *)src + bytes;
1995 +                               count -= bytes;
1996 +                       }
1997 +               }
1998 +               if (success != 0) {
1999 +                       LOG_ERR
2000 +                           ("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
2001 +                            __func__, success);
2002 +
2003 +                       ret = -1;
2004 +                       goto unlock;
2005 +               }
2006 +       }
2007 +       ret = 0;
2008 +
2009 +unlock:
2010 +       vchi_service_release(instance->vchi_handle[0]);
2011 +       mutex_unlock(&instance->vchi_mutex);
2012 +       LOG_DBG(" .. OUT\n");
2013 +       return ret;
2014 +}
2015 +
2016 +/**
2017 +  * Returns all buffers from arm->vc
2018 +  */
2019 +void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream)
2020 +{
2021 +       LOG_DBG(" .. IN\n");
2022 +       LOG_DBG(" .. OUT\n");
2023 +       return;
2024 +}
2025 +
2026 +/**
2027 +  * Forces VC to flush(drop) its filled playback buffers and
2028 +  * return them the us. (VC->ARM)
2029 +  */
2030 +void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream)
2031 +{
2032 +       LOG_DBG(" .. IN\n");
2033 +       LOG_DBG(" .. OUT\n");
2034 +}
2035 +
2036 +uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream)
2037 +{
2038 +       uint32_t count = atomic_read(&alsa_stream->retrieved);
2039 +       atomic_sub(count, &alsa_stream->retrieved);
2040 +       return count;
2041 +}
2042 +
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
2048 --- /dev/null
2049 +++ b/sound/arm/bcm2835.c
2050 @@ -0,0 +1,420 @@
2051 +/*****************************************************************************
2052 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
2053 +*
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").
2058 +*
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
2062 +* consent.
2063 +*****************************************************************************/
2064 +
2065 +#include <linux/platform_device.h>
2066 +
2067 +#include <linux/init.h>
2068 +#include <linux/slab.h>
2069 +#include <linux/module.h>
2070 +
2071 +#include "bcm2835.h"
2072 +
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 };
2078 +
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
2084 + */
2085 +
2086 +static struct snd_card *g_card = NULL;
2087 +static bcm2835_chip_t *g_chip = NULL;
2088 +
2089 +static int snd_bcm2835_free(bcm2835_chip_t * chip)
2090 +{
2091 +       kfree(chip);
2092 +       return 0;
2093 +}
2094 +
2095 +/* component-destructor
2096 + * (see "Management of Cards and Components")
2097 + */
2098 +static int snd_bcm2835_dev_free(struct snd_device *device)
2099 +{
2100 +       return snd_bcm2835_free(device->device_data);
2101 +}
2102 +
2103 +/* chip-specific constructor
2104 + * (see "Management of Cards and Components")
2105 + */
2106 +static int snd_bcm2835_create(struct snd_card *card,
2107 +                                       struct platform_device *pdev,
2108 +                                       bcm2835_chip_t ** rchip)
2109 +{
2110 +       bcm2835_chip_t *chip;
2111 +       int err;
2112 +       static struct snd_device_ops ops = {
2113 +               .dev_free = snd_bcm2835_dev_free,
2114 +       };
2115 +
2116 +       *rchip = NULL;
2117 +
2118 +       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
2119 +       if (chip == NULL)
2120 +               return -ENOMEM;
2121 +
2122 +       chip->card = card;
2123 +
2124 +       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
2125 +       if (err < 0) {
2126 +               snd_bcm2835_free(chip);
2127 +               return err;
2128 +       }
2129 +
2130 +       *rchip = chip;
2131 +       return 0;
2132 +}
2133 +
2134 +static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
2135 +{
2136 +       static int dev;
2137 +       bcm2835_chip_t *chip;
2138 +       struct snd_card *card;
2139 +       int err;
2140 +
2141 +       if (dev >= MAX_SUBSTREAMS)
2142 +               return -ENODEV;
2143 +
2144 +       if (!enable[dev]) {
2145 +               dev++;
2146 +               return -ENOENT;
2147 +       }
2148 +
2149 +       if (dev > 0)
2150 +               goto add_register_map;
2151 +
2152 +       err = snd_card_new(NULL, index[dev], id[dev], THIS_MODULE, 0, &g_card);
2153 +       if (err < 0)
2154 +               goto out;
2155 +
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);
2160 +
2161 +       err = snd_bcm2835_create(g_card, pdev, &chip);
2162 +       if (err < 0) {
2163 +               dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
2164 +               goto out_bcm2835_create;
2165 +       }
2166 +
2167 +       g_chip = chip;
2168 +       err = snd_bcm2835_new_pcm(chip);
2169 +       if (err < 0) {
2170 +               dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
2171 +               goto out_bcm2835_new_pcm;
2172 +       }
2173 +
2174 +       err = snd_bcm2835_new_spdif_pcm(chip);
2175 +       if (err < 0) {
2176 +               dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n");
2177 +               goto out_bcm2835_new_spdif;
2178 +       }
2179 +
2180 +       err = snd_bcm2835_new_ctl(chip);
2181 +       if (err < 0) {
2182 +               dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
2183 +               goto out_bcm2835_new_ctl;
2184 +       }
2185 +
2186 +add_register_map:
2187 +       card = g_card;
2188 +       chip = g_chip;
2189 +
2190 +       BUG_ON(!(card && chip));
2191 +
2192 +       chip->avail_substreams |= (1 << dev);
2193 +       chip->pdev[dev] = pdev;
2194 +
2195 +       if (dev == 0) {
2196 +               err = snd_card_register(card);
2197 +               if (err < 0) {
2198 +                       dev_err(&pdev->dev,
2199 +                               "Failed to register bcm2835 ALSA card \n");
2200 +                       goto out_card_register;
2201 +               }
2202 +               platform_set_drvdata(pdev, card);
2203 +               audio_info("bcm2835 ALSA card created!\n");
2204 +       } else {
2205 +               audio_info("bcm2835 ALSA chip created!\n");
2206 +               platform_set_drvdata(pdev, (void *)dev);
2207 +       }
2208 +
2209 +       dev++;
2210 +
2211 +       return 0;
2212 +
2213 +out_card_register:
2214 +out_bcm2835_new_ctl:
2215 +out_bcm2835_new_spdif:
2216 +out_bcm2835_new_pcm:
2217 +out_bcm2835_create:
2218 +       BUG_ON(!g_card);
2219 +       if (snd_card_free(g_card))
2220 +               dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
2221 +       g_card = NULL;
2222 +out:
2223 +       dev = SNDRV_CARDS;      /* stop more avail_substreams from being probed */
2224 +       dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
2225 +       return err;
2226 +}
2227 +
2228 +static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
2229 +{
2230 +       uint32_t idx;
2231 +       void *drv_data;
2232 +
2233 +       drv_data = platform_get_drvdata(pdev);
2234 +
2235 +       if (drv_data == (void *)g_card) {
2236 +               /* This is the card device */
2237 +               snd_card_free((struct snd_card *)drv_data);
2238 +               g_card = NULL;
2239 +               g_chip = NULL;
2240 +       } else {
2241 +               idx = (uint32_t) drv_data;
2242 +               if (g_card != NULL) {
2243 +                       BUG_ON(!g_chip);
2244 +                       /* We pass chip device numbers in audio ipc devices
2245 +                        * other than the one we registered our card with
2246 +                        */
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
2253 +                        */
2254 +                       BUG_ON(!g_chip->avail_substreams);
2255 +               }
2256 +       }
2257 +
2258 +       platform_set_drvdata(pdev, NULL);
2259 +
2260 +       return 0;
2261 +}
2262 +
2263 +#ifdef CONFIG_PM
2264 +static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
2265 +                                   pm_message_t state)
2266 +{
2267 +       return 0;
2268 +}
2269 +
2270 +static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
2271 +{
2272 +       return 0;
2273 +}
2274 +
2275 +#endif
2276 +
2277 +static struct platform_driver bcm2835_alsa0_driver = {
2278 +       .probe = snd_bcm2835_alsa_probe,
2279 +       .remove = snd_bcm2835_alsa_remove,
2280 +#ifdef CONFIG_PM
2281 +       .suspend = snd_bcm2835_alsa_suspend,
2282 +       .resume = snd_bcm2835_alsa_resume,
2283 +#endif
2284 +       .driver = {
2285 +                  .name = "bcm2835_AUD0",
2286 +                  .owner = THIS_MODULE,
2287 +                  },
2288 +};
2289 +
2290 +static struct platform_driver bcm2835_alsa1_driver = {
2291 +       .probe = snd_bcm2835_alsa_probe,
2292 +       .remove = snd_bcm2835_alsa_remove,
2293 +#ifdef CONFIG_PM
2294 +       .suspend = snd_bcm2835_alsa_suspend,
2295 +       .resume = snd_bcm2835_alsa_resume,
2296 +#endif
2297 +       .driver = {
2298 +                  .name = "bcm2835_AUD1",
2299 +                  .owner = THIS_MODULE,
2300 +                  },
2301 +};
2302 +
2303 +static struct platform_driver bcm2835_alsa2_driver = {
2304 +       .probe = snd_bcm2835_alsa_probe,
2305 +       .remove = snd_bcm2835_alsa_remove,
2306 +#ifdef CONFIG_PM
2307 +       .suspend = snd_bcm2835_alsa_suspend,
2308 +       .resume = snd_bcm2835_alsa_resume,
2309 +#endif
2310 +       .driver = {
2311 +                  .name = "bcm2835_AUD2",
2312 +                  .owner = THIS_MODULE,
2313 +                  },
2314 +};
2315 +
2316 +static struct platform_driver bcm2835_alsa3_driver = {
2317 +       .probe = snd_bcm2835_alsa_probe,
2318 +       .remove = snd_bcm2835_alsa_remove,
2319 +#ifdef CONFIG_PM
2320 +       .suspend = snd_bcm2835_alsa_suspend,
2321 +       .resume = snd_bcm2835_alsa_resume,
2322 +#endif
2323 +       .driver = {
2324 +                  .name = "bcm2835_AUD3",
2325 +                  .owner = THIS_MODULE,
2326 +                  },
2327 +};
2328 +
2329 +static struct platform_driver bcm2835_alsa4_driver = {
2330 +       .probe = snd_bcm2835_alsa_probe,
2331 +       .remove = snd_bcm2835_alsa_remove,
2332 +#ifdef CONFIG_PM
2333 +       .suspend = snd_bcm2835_alsa_suspend,
2334 +       .resume = snd_bcm2835_alsa_resume,
2335 +#endif
2336 +       .driver = {
2337 +                  .name = "bcm2835_AUD4",
2338 +                  .owner = THIS_MODULE,
2339 +                  },
2340 +};
2341 +
2342 +static struct platform_driver bcm2835_alsa5_driver = {
2343 +       .probe = snd_bcm2835_alsa_probe,
2344 +       .remove = snd_bcm2835_alsa_remove,
2345 +#ifdef CONFIG_PM
2346 +       .suspend = snd_bcm2835_alsa_suspend,
2347 +       .resume = snd_bcm2835_alsa_resume,
2348 +#endif
2349 +       .driver = {
2350 +                  .name = "bcm2835_AUD5",
2351 +                  .owner = THIS_MODULE,
2352 +                  },
2353 +};
2354 +
2355 +static struct platform_driver bcm2835_alsa6_driver = {
2356 +       .probe = snd_bcm2835_alsa_probe,
2357 +       .remove = snd_bcm2835_alsa_remove,
2358 +#ifdef CONFIG_PM
2359 +       .suspend = snd_bcm2835_alsa_suspend,
2360 +       .resume = snd_bcm2835_alsa_resume,
2361 +#endif
2362 +       .driver = {
2363 +                  .name = "bcm2835_AUD6",
2364 +                  .owner = THIS_MODULE,
2365 +                  },
2366 +};
2367 +
2368 +static struct platform_driver bcm2835_alsa7_driver = {
2369 +       .probe = snd_bcm2835_alsa_probe,
2370 +       .remove = snd_bcm2835_alsa_remove,
2371 +#ifdef CONFIG_PM
2372 +       .suspend = snd_bcm2835_alsa_suspend,
2373 +       .resume = snd_bcm2835_alsa_resume,
2374 +#endif
2375 +       .driver = {
2376 +                  .name = "bcm2835_AUD7",
2377 +                  .owner = THIS_MODULE,
2378 +                  },
2379 +};
2380 +
2381 +static int bcm2835_alsa_device_init(void)
2382 +{
2383 +       int err;
2384 +       err = platform_driver_register(&bcm2835_alsa0_driver);
2385 +       if (err) {
2386 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2387 +               goto out;
2388 +       }
2389 +
2390 +       err = platform_driver_register(&bcm2835_alsa1_driver);
2391 +       if (err) {
2392 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2393 +               goto unregister_0;
2394 +       }
2395 +
2396 +       err = platform_driver_register(&bcm2835_alsa2_driver);
2397 +       if (err) {
2398 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2399 +               goto unregister_1;
2400 +       }
2401 +
2402 +       err = platform_driver_register(&bcm2835_alsa3_driver);
2403 +       if (err) {
2404 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2405 +               goto unregister_2;
2406 +       }
2407 +
2408 +       err = platform_driver_register(&bcm2835_alsa4_driver);
2409 +       if (err) {
2410 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2411 +               goto unregister_3;
2412 +       }
2413 +
2414 +       err = platform_driver_register(&bcm2835_alsa5_driver);
2415 +       if (err) {
2416 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2417 +               goto unregister_4;
2418 +       }
2419 +
2420 +       err = platform_driver_register(&bcm2835_alsa6_driver);
2421 +       if (err) {
2422 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2423 +               goto unregister_5;
2424 +       }
2425 +
2426 +       err = platform_driver_register(&bcm2835_alsa7_driver);
2427 +       if (err) {
2428 +               pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
2429 +               goto unregister_6;
2430 +       }
2431 +
2432 +       return 0;
2433 +
2434 +unregister_6:
2435 +       platform_driver_unregister(&bcm2835_alsa6_driver);
2436 +unregister_5:
2437 +       platform_driver_unregister(&bcm2835_alsa5_driver);
2438 +unregister_4:
2439 +       platform_driver_unregister(&bcm2835_alsa4_driver);
2440 +unregister_3:
2441 +       platform_driver_unregister(&bcm2835_alsa3_driver);
2442 +unregister_2:
2443 +       platform_driver_unregister(&bcm2835_alsa2_driver);
2444 +unregister_1:
2445 +       platform_driver_unregister(&bcm2835_alsa1_driver);
2446 +unregister_0:
2447 +       platform_driver_unregister(&bcm2835_alsa0_driver);
2448 +out:
2449 +       return err;
2450 +}
2451 +
2452 +static void bcm2835_alsa_device_exit(void)
2453 +{
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);
2462 +}
2463 +
2464 +late_initcall(bcm2835_alsa_device_init);
2465 +module_exit(bcm2835_alsa_device_exit);
2466 +
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
2474 --- /dev/null
2475 +++ b/sound/arm/bcm2835.h
2476 @@ -0,0 +1,167 @@
2477 +/*****************************************************************************
2478 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
2479 +*
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").
2484 +*
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
2488 +* consent.
2489 +*****************************************************************************/
2490 +
2491 +#ifndef __SOUND_ARM_BCM2835_H
2492 +#define __SOUND_ARM_BCM2835_H
2493 +
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>
2504 +
2505 +/*
2506 +#define AUDIO_DEBUG_ENABLE
2507 +#define AUDIO_VERBOSE_DEBUG_ENABLE
2508 +*/
2509 +
2510 +/* Debug macros */
2511 +
2512 +#ifdef AUDIO_DEBUG_ENABLE
2513 +#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
2514 +
2515 +#define audio_debug(fmt, arg...)       \
2516 +       printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
2517 +
2518 +#define audio_info(fmt, arg...)        \
2519 +       printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
2520 +
2521 +#else
2522 +
2523 +#define audio_debug(fmt, arg...)
2524 +
2525 +#define audio_info(fmt, arg...)
2526 +
2527 +#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
2528 +
2529 +#else
2530 +
2531 +#define audio_debug(fmt, arg...)
2532 +
2533 +#define audio_info(fmt, arg...)
2534 +
2535 +#endif /* AUDIO_DEBUG_ENABLE */
2536 +
2537 +#define audio_error(fmt, arg...)       \
2538 +       printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
2539 +
2540 +#define audio_warning(fmt, arg...)     \
2541 +       printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
2542 +
2543 +#define audio_alert(fmt, arg...)       \
2544 +       printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
2545 +
2546 +#define MAX_SUBSTREAMS                 (8)
2547 +#define AVAIL_SUBSTREAMS_MASK          (0xff)
2548 +enum {
2549 +       CTRL_VOL_MUTE,
2550 +       CTRL_VOL_UNMUTE
2551 +};
2552 +
2553 +/* macros for alsa2chip and chip2alsa, instead of functions */
2554 +
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 */
2557 +
2558 +/* Some constants for values .. */
2559 +typedef enum {
2560 +       AUDIO_DEST_AUTO = 0,
2561 +       AUDIO_DEST_HEADPHONES = 1,
2562 +       AUDIO_DEST_HDMI = 2,
2563 +       AUDIO_DEST_MAX,
2564 +} SND_BCM2835_ROUTE_T;
2565 +
2566 +typedef enum {
2567 +       PCM_PLAYBACK_VOLUME,
2568 +       PCM_PLAYBACK_MUTE,
2569 +       PCM_PLAYBACK_DEVICE,
2570 +} SND_BCM2835_CTRL_T;
2571 +
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];
2581 +
2582 +       int volume;
2583 +       int old_volume; /* stores the volume value whist muted */
2584 +       int dest;
2585 +       int mute;
2586 +
2587 +       unsigned int opened;
2588 +       unsigned int spdif_status;
2589 +       struct mutex audio_mutex;
2590 +} bcm2835_chip_t;
2591 +
2592 +typedef struct bcm2835_alsa_stream {
2593 +       bcm2835_chip_t *chip;
2594 +       struct snd_pcm_substream *substream;
2595 +       struct snd_pcm_indirect pcm_indirect;
2596 +
2597 +       struct semaphore buffers_update_sem;
2598 +       struct semaphore control_sem;
2599 +       spinlock_t lock;
2600 +       volatile uint32_t control;
2601 +       volatile uint32_t status;
2602 +
2603 +       int open;
2604 +       int running;
2605 +       int draining;
2606 +
2607 +       int channels;
2608 +       int params_rate;
2609 +       int pcm_format_width;
2610 +
2611 +       unsigned int pos;
2612 +       unsigned int buffer_size;
2613 +       unsigned int period_size;
2614 +
2615 +       uint32_t enable_fifo_irq;
2616 +       irq_handler_t fifo_irq_handler;
2617 +
2618 +       atomic_t retrieved;
2619 +       struct opaque_AUDIO_INSTANCE_T *instance;
2620 +       struct workqueue_struct *my_wq;
2621 +       int idx;
2622 +} bcm2835_alsa_stream_t;
2623 +
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);
2627 +
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,
2632 +                            uint32_t bps);
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,
2638 +                       void *src);
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);
2642 +
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
2647 --- /dev/null
2648 +++ b/sound/arm/vc_vchi_audioserv_defs.h
2649 @@ -0,0 +1,116 @@
2650 +/*****************************************************************************
2651 +* Copyright 2011 Broadcom Corporation.  All rights reserved.
2652 +*
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").
2657 +*
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
2661 +* consent.
2662 +*****************************************************************************/
2663 +
2664 +#ifndef _VC_AUDIO_DEFS_H_
2665 +#define _VC_AUDIO_DEFS_H_
2666 +
2667 +#define VC_AUDIOSERV_MIN_VER 1
2668 +#define VC_AUDIOSERV_VER 2
2669 +
2670 +// FourCC code used for VCHI connection
2671 +#define VC_AUDIO_SERVER_NAME  MAKE_FOURCC("AUDS")
2672 +
2673 +// Maximum message length
2674 +#define VC_AUDIO_MAX_MSG_LEN  (sizeof( VC_AUDIO_MSG_T ))
2675 +
2676 +// List of screens that are currently supported
2677 +// All message types supported for HOST->VC direction
2678 +typedef enum {
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;
2690 +
2691 +// configure the audio
2692 +typedef struct {
2693 +       uint32_t channels;
2694 +       uint32_t samplerate;
2695 +       uint32_t bps;
2696 +
2697 +} VC_AUDIO_CONFIG_T;
2698 +
2699 +typedef struct {
2700 +       uint32_t volume;
2701 +       uint32_t dest;
2702 +
2703 +} VC_AUDIO_CONTROL_T;
2704 +
2705 +// audio
2706 +typedef struct {
2707 +       uint32_t dummy;
2708 +
2709 +} VC_AUDIO_OPEN_T;
2710 +
2711 +// audio
2712 +typedef struct {
2713 +       uint32_t dummy;
2714 +
2715 +} VC_AUDIO_CLOSE_T;
2716 +// audio
2717 +typedef struct {
2718 +       uint32_t dummy;
2719 +
2720 +} VC_AUDIO_START_T;
2721 +// audio
2722 +typedef struct {
2723 +       uint32_t draining;
2724 +
2725 +} VC_AUDIO_STOP_T;
2726 +
2727 +// configure the write audio samples
2728 +typedef struct {
2729 +       uint32_t count;         // in bytes
2730 +       void *callback;
2731 +       void *cookie;
2732 +       uint16_t silence;
2733 +       uint16_t max_packet;
2734 +} VC_AUDIO_WRITE_T;
2735 +
2736 +// Generic result for a request (VC->HOST)
2737 +typedef struct {
2738 +       int32_t success;        // Success value
2739 +
2740 +} VC_AUDIO_RESULT_T;
2741 +
2742 +// Generic result for a request (VC->HOST)
2743 +typedef struct {
2744 +       int32_t count;          // Success value
2745 +       void *callback;
2746 +       void *cookie;
2747 +} VC_AUDIO_COMPLETE_T;
2748 +
2749 +// Message header for all messages in HOST->VC direction
2750 +typedef struct {
2751 +       int32_t type;           // Message type (VC_AUDIO_MSG_TYPE)
2752 +       union {
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;
2762 +       } u;
2763 +} VC_AUDIO_MSG_T;
2764 +
2765 +#endif // _VC_AUDIO_DEFS_H_
2766 -- 
2767 1.8.3.2
2768