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