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