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