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