All of lore.kernel.org
 help / color / mirror / Atom feed
* MSM DSP
@ 2009-11-03 16:02 GNUtoo
  2009-11-04 10:49 ` Mark Brown
  0 siblings, 1 reply; 19+ messages in thread
From: GNUtoo @ 2009-11-03 16:02 UTC (permalink / raw)
  To: alsa-devel

hi,
I've bought an HTC dream,before buying I looked at the feasibility  of
porting GNU/Linux on it(so not Android).
There is a patch(for maing the driver standard) or a standard(everything
is non-standard in android) driver for most of the components.
The biggest problem seems the sound.
So knowing that
codeaurora( https://www.codeaurora.org/gitweb/quic/le/?p=kernel/msm.git ) had alsa in its kenrel I first tried to compile that kernel...but due to numerous bugs(It didn't compile and needed too much fixing) in it android-msm-2.6.29 branch I decided to import alsa in the linuxtogo kernel,and I pushed the sources at a temporary htc-alsa branch at git://gitorious.org/replicant/gnulinuxkernel.git (it's called gnulinux in order to differentiate from an android kernel,I didn't find a good name for it)

from the commit message available here :
http://gitorious.org/replicant/gnulinuxkernel/commit/92945ccd0921e940fc2675dc394141db0f7c1386 

I had to change snd_rpc_ids.vers = 0x00020001 into 
snd_rpc_ids.vers = 0xaa2b1a44 ,and to make minor build system changes
and I had aplay working rapidely...
but only aplay...
mplayer was waiting indefinitely for the following system call:
ioctl(6, 0x400c4150
ls -l /proc/$(pido mplayer)/fd/6 gave /dev/snd/pcmC0D0p
and 0x400c4150 gave that:
SNDRV_PCM_IOCTL_WRITEI_FRAMES = _IOW('A', 0x50, struct snd_xferi)

Then with printks(I had no serial cable(I've looked for a
craddle/docking station with the special HTC connector for easy
soldering...but I didn't found one) so I couldn't use kgdb) I went until
that point:
rc = wait_event_interruptible(the_locks.write_wait, (frame->used == 0)||
(prtd->stopped));
That's in the alsa_send_buffer function in /sound/soc/msm/msm-pcm.c
Then I continued the tracing puting printks everywhere...and I found
that:
with aplay:
msm_pcm_playback_copy in the /sound/soc/msm/msm7k-pcm.c was called
rc = alsa_send_buffer(prtd, buf, fbytes, NULL); was called once
inside alsa_send_buffer (in /sound/soc/msm/msm-pcm.c) the count loop was
only executed once because count was exhausted on the first run
then copy_count is incremented and the audio is configured
then at second call of the alsa_send_buffer the audio is configured and
works.
here's an output of the aplay parameters:

$ aplay -v 05\ -\ Jet\ Set.wav 
Playing WAVE '05 - Jet Set.wav' : Signed 16 bit Little Endian, Rate
44100 Hz, Stereo
Plug PCM: Hardware PCM card 0 'msm-audio' device 0 subdevice 0
Its setup is:
  stream       : PLAYBACK
  access       : RW_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 44100
  exact rate   : 44100 (44100/1)
  msbits       : 16
  buffer_size  : 4800
  period_size  : 1200
  period_time  : 27210
  tick_time    : 0
  tstamp_mode  : NONE
  period_step  : 1
  sleep_min    : 0
  avail_min    : 1200
  xfer_align   : 1200
  start_threshold  : 4800
  stop_threshold   : 4800
  silence_threshold: 0
  silence_size : 0
  boundary     : 1258291200

note that frame = prtd->out + prtd->out_tail; makes frame->used have a
bad value the first time it is run but as the count is only run once it
doesn't import.

the next runs prtd->out + prtd->out_tail have a good value

with mplayer the story was quite different,even if the beginning was the
same : 
msm_pcm_playback_copy in the /sound/soc/msm/msm7k-pcm.c was also
called,rc = alsa_send_buffer(prtd, buf, fbytes, NULL); was also called 
inside alsa_send_buffer (in /sound/soc/msm/msm-pcm.c)  but once in
alsa_send_buffer,more precisely under the count loop the story changes:
count is not exhausted the first time,because in "xfer = count >
frame->size ? frame->size : count;" the smallest between count and
frame->size is assigned,and so after it does "count -= xfer" and so
count is not 0,because the buffer size detected by mplayer is 19200
insterad of 4800 so here what it does in detail:
it passes 19200 as count here:
fbytes = frames_to_bytes(runtime, frames);
rc = alsa_send_buffer(prtd, buf, fbytes, NULL);
that goes into that:
ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
size_t count, loff_t *pos)
and then the count variable is 19200 in alsa_send_buffer
then there is xfer = count > frame->size ? frame->size : count;
so it assigns the minimum between count and frame->size to xfer
count is still 19200
frame->size is 4800
so xfer becomes 4800
then count -= xfer decrement count but only of 4800
so count is not exhausted and runs another time then :
frame = prtd->out + prtd->out_tail; makes frame->used have a bad
value,and then it blocks here:
rc = wait_event_interruptible(the_locks.write_wait,(frame->used == 0) ||
(prtd->stopped));
because frame->used is not 0.

here an mplayer output:
Forced audio codec: mad
Opening audio decoder: [pcm] Uncompressed PCM audio decoder
dec_audio: Allocating 2048 + 65536 = 67584 bytes for output buffer.
AUDIO: 44100 Hz, 2 ch, s16le, 1411.2 kbit/100.00% (ratio:
176400->176400)
Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)
==========================================================================
Building audio filter chain for 44100Hz/2ch/s16le -> 0Hz/0ch/??...
[libaf] Adding filter dummy 
[dummy] Was reinitialized: 44100Hz/2ch/s16le
[dummy] Was reinitialized: 44100Hz/2ch/s16le
Trying preferred audio driver 'alsa', options '[none]'
alsa-init: requested format: 44100 Hz, 2 channels, 9
alsa-init: using ALSA 1.0.15
alsa-init: setup for 1/2 channel(s)
alsa-init: using device default
alsa-init: pcm opened in blocking mode
alsa-init: got buffersize=19200
alsa-init: got period size 300
alsa: 44100 Hz/2 channels/4 bpf/19200 bytes buffer/Signed 16 bit Little
Endian
AO: [alsa] 44100Hz 2ch s16le (2 bytes per sample)
AO: Description: ALSA-0.9.x-1.x audio output
AO: Author: Alex Beregszaszi, Zsolt Barat <joy@streamminister.de>
AO: Comment: under developement
Building audio filter chain for 44100Hz/2ch/s16le ->
44100Hz/2ch/s16le...
[dummy] Was reinitialized: 44100Hz/2ch/s16le
[dummy] Was reinitialized: 44100Hz/2ch/s16le
Video: no video
Freeing 0 unused video chunks.
Starting playback...
Increasing filtered audio buffer size from 0 to 21248

so the quick solution was to force mplayer to use 4800 as buffer size
with something like that:

diff --git a/sound/soc/msm/msm7k-pcm.c b/sound/soc/msm/msm7k-pcm.c
index 38e8283..bfbc66d 100644
--- a/sound/soc/msm/msm7k-pcm.c
+++ b/sound/soc/msm/msm7k-pcm.c
@@ -115,7 +115,7 @@ static struct snd_pcm_hardware
msm_pcm_playback_hardware = {
        .rate_max =             USE_RATE_MAX,
        .channels_min =         USE_CHANNELS_MIN,
        .channels_max =         USE_CHANNELS_MAX,
-       .buffer_bytes_max =     MAX_BUFFER_PLAYBACK_SIZE,
+       .buffer_bytes_max =     4800,
        .period_bytes_min =     64,
        .period_bytes_max =     MAX_PERIOD_SIZE,
        .periods_min =          USE_PERIODS_MIN,



but then mplayer seem to loop on an ioctl:
mplayer is frozen here and doesn't respond to other input than ctrl+c:
0.0 (00.0) of 206.0 (03:26.0) ??,?% 
strace shows a lot of :
nanosleep followed by
SNDRV_PCM_IOCTL_STATUS (ioctl(6, 0x806c4120, 0xbe8bc9c8)  = 0)
an analyse of the status shows a constant :
status->delay is 1200,and status->avail is 0,they don't vary over time
and are printed just after that code in snd_pcm_status in
sound/core/pcm_native.c
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING ||
    runtime->status->state == SNDRV_PCM_STATE_DRAINING)
status->delay = runtime->buffer_size - status->avail;
else
status->delay = 0;

I was told in #mplayerdev that it was because the DSP didn't play the
frames...indeed I hear no sound....

So how should I fix that mess?
*did the quick and dirty fix cause the second problem?
*should I use the DSP directly and make a pulseaudio plugin that talks
to the android driver, instead(the driver seems very buggy)
The good would be support for mp3 and similar things within the DSP,and
that it should be more stable.
The bad is that I already spent *a lot* of time with the alsa kernel
driver...and that writing that will also require some userspaces changes
such as:
*modification of the phone routing in the
"FSO" ( http://www.freesmartphone.org/index.php/Main_Page ) dbus
framework to use pulseaudio
*would require changes in the build system for using
pulseaudio(openembedded(http://wiki.openembedded.net/index.php/Main_Page ))
*may be slow...openmoko stopped to use pulseaudio because of speed
issues.

Denis

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: MSM DSP
  2009-11-03 16:02 MSM DSP GNUtoo
@ 2009-11-04 10:49 ` Mark Brown
  2009-11-04 21:29   ` GNUtoo
  2009-11-05 15:17   ` [PATCH] " Denis 'GNUtoo' Carikli
  0 siblings, 2 replies; 19+ messages in thread
From: Mark Brown @ 2009-11-04 10:49 UTC (permalink / raw)
  To: GNUtoo; +Cc: alsa-devel

Please fix your MUA to word wrap at 80 columns, not doing this makes
your posts much harder to read and reply to.  It'd also be helpful to
place blank lines between paragraphs to improve legibility.

On Tue, Nov 03, 2009 at 05:02:22PM +0100, GNUtoo wrote:

> codeaurora(
> https://www.codeaurora.org/gitweb/quic/le/?p=kernel/msm.git ) had alsa
> in its kenrel I first tried to compile that kernel...but due to
> numerous bugs(It didn't compile and needed too much fixing) in it
> android-msm-2.6.29 branch I decided to import alsa in the linuxtogo
> kernel,and I pushed the sources at a temporary htc-alsa branch at
> git://gitorious.org/replicant/gnulinuxkernel.git (it's called gnulinux
> in order to differentiate from an android kernel,I didn't find a good
> name for it)

Please submit any code you have to the mailing list, it's much easier to
review things via the standard workflows and getting the drivers into
mainline would be good.

The problems you're reporting suggest that the driver either isn't
communicating the requirements it has for data buffers to the
applications correctly or it isn't correctly notifying applications when
buffers have drained.  mplayer is much more sensitive to both of these
issues.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: MSM DSP
  2009-11-04 10:49 ` Mark Brown
@ 2009-11-04 21:29   ` GNUtoo
  2009-11-05 15:17   ` [PATCH] " Denis 'GNUtoo' Carikli
  1 sibling, 0 replies; 19+ messages in thread
From: GNUtoo @ 2009-11-04 21:29 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel

On Wed, 2009-11-04 at 10:49 +0000, Mark Brown wrote:
> Please fix your MUA to word wrap at 80 columns, not doing this makes
> your posts much harder to read and reply to.  It'd also be helpful to
> place blank lines between paragraphs to improve legibility.
So sorry,I was told that evolution does it by default.
There must have been a wrong manipulation by me or a bug...
I'm so sorry.

> 
> On Tue, Nov 03, 2009 at 05:02:22PM +0100, GNUtoo wrote:
> 
> > codeaurora(
> > https://www.codeaurora.org/gitweb/quic/le/?p=kernel/msm.git ) had alsa
> > in its kenrel I first tried to compile that kernel...but due to
> > numerous bugs(It didn't compile and needed too much fixing) in it
> > android-msm-2.6.29 branch I decided to import alsa in the linuxtogo
> > kernel,and I pushed the sources at a temporary htc-alsa branch at
> > git://gitorious.org/replicant/gnulinuxkernel.git (it's called gnulinux
> > in order to differentiate from an android kernel,I didn't find a good
> > name for it)
> 
> Please submit any code you have to the mailing list, it's much easier to
> review things via the standard workflows and getting the drivers into
> mainline would be good.
I'll make git send a mail.
But note that the code of the alsa driver depends on a custom android
sound system that is in :
arch/arm/mach-msm/qdsp5/
so it's platform specific.

> The problems you're reporting suggest that the driver either isn't
> communicating the requirements it has for data buffers to the
> applications correctly or it isn't correctly notifying applications when
> buffers have drained.  mplayer is much more sensitive to both of these
> issues.
Thanks a lot

Denis.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH] MSM DSP
  2009-11-04 10:49 ` Mark Brown
  2009-11-04 21:29   ` GNUtoo
@ 2009-11-05 15:17   ` Denis 'GNUtoo' Carikli
  2009-11-05 15:23     ` Mark Brown
  1 sibling, 1 reply; 19+ messages in thread
From: Denis 'GNUtoo' Carikli @ 2009-11-05 15:17 UTC (permalink / raw)
  To: alsa-devel


>Please submit any code you have to the mailing list, it's much easier 
>to review things via the standard workflows and getting the drivers 
>into mainline would be good.
Here it is...I hope it's correct and in the proper format
sorry for the delay.

Denis.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] MSM DSP
  2009-11-05 15:17   ` [PATCH] " Denis 'GNUtoo' Carikli
@ 2009-11-05 15:23     ` Mark Brown
  2009-11-05 15:31       ` GNUtoo
  0 siblings, 1 reply; 19+ messages in thread
From: Mark Brown @ 2009-11-05 15:23 UTC (permalink / raw)
  To: Denis 'GNUtoo' Carikli; +Cc: alsa-devel

On Thu, Nov 05, 2009 at 04:17:24PM +0100, Denis 'GNUtoo' Carikli wrote:
> 
> >Please submit any code you have to the mailing list, it's much easier 
> >to review things via the standard workflows and getting the drivers 
> >into mainline would be good.

> Here it is...I hope it's correct and in the proper format
> sorry for the delay.

You appear to have omitted the actual patch... 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] MSM DSP
  2009-11-05 15:23     ` Mark Brown
@ 2009-11-05 15:31       ` GNUtoo
  2009-11-08 22:46         ` [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora Denis 'GNUtoo' Carikli
  0 siblings, 1 reply; 19+ messages in thread
From: GNUtoo @ 2009-11-05 15:31 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel

On Thu, 2009-11-05 at 15:23 +0000, Mark Brown wrote:
> On Thu, Nov 05, 2009 at 04:17:24PM +0100, Denis 'GNUtoo' Carikli wrote:
> > 
> > >Please submit any code you have to the mailing list, it's much easier 
> > >to review things via the standard workflows and getting the drivers 
> > >into mainline would be good.
> 
> > Here it is...I hope it's correct and in the proper format
> > sorry for the delay.
> 
> You appear to have omitted the actual patch... 
sorry I had that:
Died at /usr/libexec/git-core/git-send-email line 966.

I've bad luck with that mailing list...lol

Denis.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora
  2009-11-05 15:31       ` GNUtoo
@ 2009-11-08 22:46         ` Denis 'GNUtoo' Carikli
  2009-11-09  8:42           ` Pavel Machek
  2009-11-13 14:50           ` Mark Brown
  0 siblings, 2 replies; 19+ messages in thread
From: Denis 'GNUtoo' Carikli @ 2009-11-08 22:46 UTC (permalink / raw)
  To: alsa-devel; +Cc: Denis 'GNUtoo' Carikli, pavel

[-- Attachment #1: Type: text/plain, Size: 2413 bytes --]


I had to make two little change to make it compile:
snd_ep = msm_rpc_connect_compatible(snd_rpc_ids.prog,
became:
snd_ep = msm_rpc_connect(snd_rpc_ids.prog,
and I also changed snd_rpc_ids.vers(with ifdefs)
to a known and working magick number:

I also had to change from ARCH_MSM_ARM11 to ARCH_MSM in the configuration

it still has serious runtime problems such as:
*Can produce kernel oops under theses conditions:
 start alsamixer and if the second bar is on 0 or 4,
 so it can play music with aplay,then increase the routing alsamixer bar
 to the max.
 Then decrease the routing bar to 4 or less
 Then It may have a null pointer problem
 That bug could be because it tries to route to route to speakers and
 handset at the same time(SND_DEVICE_HEADSET_AND_SPEAKER in android):
 that is to say it could be the same bug than here:
http://gitorious.org/replicant/msm7k/commit/370d37a088368ca8cc478e76c928a1ce6589495e
 but I need time to verify that
*can pannick(reboots the phone) if you send things to /dev/dsp when the
 oss emulation is activated
*only aplay works(mplayer,gstreamer don't work) for mplayer an ioctl
 didn't return...so it get stuck before playing.
 The explanation of the bug can be found here:
http://mailman.alsa-project.org/pipermail/alsa-devel/2009-November/022697.html

Note the following things:
*this patch depends on,and doesn't contain arch/arm/mach-msm/qdsp5
*I removed the support for more recents chips because of code-size issue
 in a mailing list

Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@no-log.org>
---
 sound/soc/Kconfig         |    1 +
 sound/soc/Makefile        |    1 +
 sound/soc/msm/Kconfig     |   23 ++
 sound/soc/msm/Makefile    |   11 +
 sound/soc/msm/msm-dai.c   |  143 ++++++++++
 sound/soc/msm/msm-pcm.c   |  643 +++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/msm/msm-pcm.h   |  200 ++++++++++++++
 sound/soc/msm/msm7201.c   |  337 ++++++++++++++++++++++++
 sound/soc/msm/msm7k-pcm.c |  574 ++++++++++++++++++++++++++++++++++++++++
 9 files changed, 1933 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/msm/Kconfig
 create mode 100644 sound/soc/msm/Makefile
 create mode 100644 sound/soc/msm/msm-dai.c
 create mode 100644 sound/soc/msm/msm-pcm.c
 create mode 100644 sound/soc/msm/msm-pcm.h
 create mode 100644 sound/soc/msm/msm7201.c
 create mode 100644 sound/soc/msm/msm7k-pcm.c


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Sound-MSM-soc-imported-alsa-for-the-MSM-from-codeaur.patch --]
[-- Type: text/x-patch; name="0001-Sound-MSM-soc-imported-alsa-for-the-MSM-from-codeaur.patch", Size: 56363 bytes --]

diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index ef025c6..4b1a48f 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -32,6 +32,7 @@ source "sound/soc/omap/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
 source "sound/soc/sh/Kconfig"
+source "sound/soc/msm/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 86a9b1f..ea754e5 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_SND_SOC)	+= omap/
 obj-$(CONFIG_SND_SOC)	+= pxa/
 obj-$(CONFIG_SND_SOC)	+= s3c24xx/
 obj-$(CONFIG_SND_SOC)	+= sh/
+obj-$(CONFIG_SND_SOC)	+= msm/
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
new file mode 100644
index 0000000..70f2f76
--- /dev/null
+++ b/sound/soc/msm/Kconfig
@@ -0,0 +1,23 @@
+menu "MSM SoC Audio support"
+
+config SND_MSM_SOC
+	tristate "SoC Audio for the MSM series chips"
+	depends on ARCH_MSM && SND_SOC
+	select MSM_ADSP
+	help
+	  To add support for ALSA PCM driver for MSM board.
+
+config SND_MSM_DAI_SOC
+	tristate "SoC CPU/CODEC DAI for the MSM chip"
+	depends on SND_MSM_SOC || SND_QSD_SOC
+	help
+	 To add support for ALSA PCM driver for MSM board.
+
+config SND_MSM_SOC_MSM7K
+        tristate "SoC Audio support for MSM7K"
+        depends on SND_MSM_SOC
+        help
+	 To add support for SoC audio on msm7k for msm72x1 or msm7x27
+
+
+endmenu
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
new file mode 100644
index 0000000..d2b38d3
--- /dev/null
+++ b/sound/soc/msm/Makefile
@@ -0,0 +1,11 @@
+# MSM CPU/CODEC DAI Support
+snd-soc-msm-dai-objs := msm-dai.o
+obj-$(CONFIG_SND_MSM_DAI_SOC) += snd-soc-msm-dai.o
+
+# MSM Platform Support
+snd-soc-msm-objs := msm-pcm.o msm7k-pcm.o
+obj-$(CONFIG_SND_MSM_SOC) += snd-soc-msm.o
+
+# MSM Machine Support
+snd-soc-msm7k-objs := msm7201.o
+obj-$(CONFIG_SND_MSM_SOC_MSM7K) += snd-soc-msm7k.o
diff --git a/sound/soc/msm/msm-dai.c b/sound/soc/msm/msm-dai.c
new file mode 100644
index 0000000..564e7fe
--- /dev/null
+++ b/sound/soc/msm/msm-dai.c
@@ -0,0 +1,143 @@
+/* sound/soc/msm/msm-dai.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * Derived from msm-pcm.c and msm7201.c.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include "msm-pcm.h"
+
+struct snd_soc_dai msm_dais[] = {
+{
+	.name = "CODEC_DAI",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = USE_CHANNELS_MIN,
+		.channels_max = USE_CHANNELS_MAX,
+		.rates = USE_RATE,
+		.rate_min = USE_RATE_MIN,
+		.rate_max = USE_RATE_MAX,
+		.formats = USE_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = USE_CHANNELS_MIN,
+		.channels_max = USE_CHANNELS_MAX,
+		.rate_min = USE_RATE_MIN,
+		.rates = USE_RATE,
+		.formats = USE_FORMATS,
+	},
+},
+{
+	.name = "CPU_DAI",
+	.id = 0,
+	.playback = {
+		.channels_min = USE_CHANNELS_MIN,
+		.channels_max = USE_CHANNELS_MAX,
+		.rates = USE_RATE,
+		.rate_min = USE_RATE_MIN,
+		.rate_max = USE_RATE_MAX,
+		.formats = USE_FORMATS,
+	},
+	.capture = {
+		.channels_min = USE_CHANNELS_MIN,
+		.channels_max = USE_CHANNELS_MAX,
+		.rate_min = USE_RATE_MIN,
+		.rates = USE_RATE,
+		.formats = USE_FORMATS,
+	},
+},
+};
+EXPORT_SYMBOL_GPL(msm_dais);
+
+int msm_pcm_probe(struct platform_device *devptr)
+{
+	struct snd_card *card;
+	struct snd_soc_codec *codec;
+	int ret;
+
+	struct snd_soc_device *socdev = platform_get_drvdata(devptr);
+
+	printk(KERN_ERR "msm_soc: create pcms\n");
+	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+	if (codec == NULL)
+		return -ENOMEM;
+
+	codec->name = "MSM-CARD";
+	codec->owner = THIS_MODULE;
+	socdev->codec = codec;
+	mutex_init(&codec->mutex);
+
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	/* register pcms */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		printk(KERN_ERR "msm_soc: failed to create pcms\n");
+		goto __nopcm;
+	}
+
+	card = socdev->codec->card;
+
+	ret = snd_soc_init_card(socdev);
+	if (ret < 0) {
+		printk(KERN_ERR "msm_soc: failed to register card\n");
+		goto __nodev;
+	}
+
+	return 0;
+
+__nodev:
+	snd_soc_free_pcms(socdev);
+__nopcm:
+	kfree(codec);
+	return ret;
+}
+
+struct snd_soc_codec_device soc_codec_dev_msm = {
+	.probe          = msm_pcm_probe,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_msm);
+
+
+static int __init msm_dai_init(void)
+{
+	return snd_soc_register_dais(msm_dais, ARRAY_SIZE(msm_dais));
+}
+
+static void __exit msm_dai_exit(void)
+{
+	snd_soc_unregister_dais(msm_dais, ARRAY_SIZE(msm_dais));
+}
+
+module_init(msm_dai_init);
+module_exit(msm_dai_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MSM Codec/Cpu Dai driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm.c b/sound/soc/msm/msm-pcm.c
new file mode 100644
index 0000000..90e200d
--- /dev/null
+++ b/sound/soc/msm/msm-pcm.c
@@ -0,0 +1,643 @@
+/* sound/soc/msm/msm-pcm.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm.h"
+
+#define MAX_DATA_SIZE 496
+#define AUDPP_ALSA_DECODER	(-1)
+
+#define DB_TABLE_INDEX		(50)
+
+#define audio_send_queue_recbs(prtd, cmd, len) \
+	msm_adsp_write(prtd->audrec, QDSP_uPAudRecBitStreamQueue, cmd, len)
+#define audio_send_queue_rec(prtd, cmd, len) \
+	msm_adsp_write(prtd->audrec, QDSP_uPAudRecCmdQueue, cmd, len)
+
+int intcnt;
+static int audio_dsp_send_buffer(struct msm_audio *prtd,
+			unsigned idx, unsigned len);
+
+struct audio_frame {
+	uint16_t count_low;
+	uint16_t count_high;
+	uint16_t bytes;
+	uint16_t unknown;
+	unsigned char samples[];
+} __attribute__ ((packed));
+
+/* Table contains dB to raw value mapping */
+static const unsigned decoder_db_table[] = {
+
+      31 , /* -50 dB */
+      35 ,      39 ,      44 ,      50 ,      56 ,
+      63 ,      70 ,      79 ,      89 ,      99 ,
+     112 ,     125 ,     141 ,     158 ,     177 ,
+     199 ,     223 ,     251 ,     281 ,     316 ,
+     354 ,     398 ,     446 ,     501 ,     562 ,
+     630 ,     707 ,     794 ,     891 ,     999 ,
+    1122 ,    1258 ,    1412 ,    1584 ,    1778 ,
+    1995 ,    2238 ,    2511 ,    2818 ,    3162 ,
+    3548 ,    3981 ,    4466 ,    5011 ,    5623 ,
+    6309 ,    7079 ,    7943 ,    8912 ,   10000 ,
+   11220 ,   12589 ,   14125 ,   15848 ,   17782 ,
+   19952 ,   22387 ,   25118 ,   28183 ,   31622 ,
+   35481 ,   39810 ,   44668 ,   50118 ,   56234 ,
+   63095 ,   70794 ,   79432 ,   89125 ,  100000 ,
+  112201 ,  125892 ,  141253 ,  158489 ,  177827 ,
+  199526 ,  223872 ,  251188 ,  281838 ,  316227 ,
+  354813 ,  398107 ,  446683 ,  501187 ,  562341 ,
+  630957 ,  707945 ,  794328 ,  891250 , 1000000 ,
+ 1122018 , 1258925 , 1412537 , 1584893 , 1778279 ,
+ 1995262 , 2238721 , 2511886 , 2818382 , 3162277 ,
+ 3548133   /*  51 dB */
+
+};
+
+static unsigned compute_db_raw(int db)
+{
+	unsigned reg_val = 0;        /* Computed result for correspondent db */
+	/* Check if the given db is out of range */
+	if (db <= MIN_DB)
+		return 0;
+	else if (db > MAX_DB)
+		db = MAX_DB;       /* If db is too high then set to max    */
+	reg_val = decoder_db_table[DB_TABLE_INDEX+db];
+	return reg_val;
+}
+
+int msm_audio_volume_update(unsigned id,
+				int volume, int pan)
+{
+	unsigned vol_raw;
+
+	vol_raw = compute_db_raw(volume);
+	printk(KERN_INFO "volume: %8x vol_raw: %8x \n", volume, vol_raw);
+	return audpp_set_volume_and_pan(id, vol_raw, pan);
+}
+EXPORT_SYMBOL(msm_audio_volume_update);
+
+void alsa_dsp_event(void *data, unsigned id, uint16_t *msg)
+{
+	struct msm_audio *prtd = data;
+	struct buffer *frame;
+	unsigned long flag;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:
+		break;
+	case AUDPP_MSG_SPA_BANDS:
+		break;
+	case AUDPP_MSG_HOST_PCM_INTF_MSG:{
+			unsigned id = msg[2];
+			unsigned idx = msg[3] - 1;
+			if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
+				printk(KERN_ERR "bogus id\n");
+				break;
+			}
+			if (idx > 1) {
+				printk(KERN_ERR "bogus buffer idx\n");
+				break;
+			}
+			/* Update with actual sent buffer size */
+			if (prtd->out[idx].used != BUF_INVALID_LEN)
+				prtd->pcm_irq_pos += prtd->out[idx].used;
+
+			if (prtd->pcm_irq_pos > prtd->pcm_size)
+				prtd->pcm_irq_pos = prtd->pcm_count;
+
+			if (prtd->ops->playback)
+				prtd->ops->playback(prtd);
+
+			spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
+			if (prtd->running) {
+				prtd->out[idx].used = 0;
+				frame = prtd->out + prtd->out_tail;
+				if (frame->used) {
+					audio_dsp_send_buffer(prtd,
+							      prtd->out_tail,
+							      frame->used);
+					prtd->out_tail ^= 1;
+				} else {
+					prtd->out_needed++;
+				}
+				wake_up(&the_locks.write_wait);
+			}
+			spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
+			break;
+		}
+	case AUDPP_MSG_PCMDMAMISSED:
+		printk(KERN_ERR "alsa_dsp_event: PCMDMAMISSED %d\n", msg[0]);
+		break;
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			prtd->out_needed = 0;
+			prtd->running = 1;
+			audio_dsp_out_enable(prtd, 1);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			prtd->running = 0;
+		} else {
+			printk(KERN_ERR "alsa_dsp_event:CFG_MSG=%d\n", msg[0]);
+		}
+		break;
+	case EVENT_MSG_ID:
+		printk(KERN_INFO"alsa_dsp_event: arm9 event\n");
+		break;
+	default:
+		printk(KERN_ERR "alsa_dsp_event: UNKNOWN (%d)\n", id);
+	}
+}
+
+void alsa_audpre_dsp_event(void *data, unsigned id, size_t len,
+		      void (*getevent) (void *ptr, size_t len))
+{
+	uint16_t msg[MAX_DATA_SIZE/2];
+
+	if (len > MAX_DATA_SIZE) {
+		printk(KERN_ERR"audpre: event too large(%d bytes)\n", len);
+		return;
+	}
+	getevent(msg, len);
+
+	switch (id) {
+	case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+		break;
+	case AUDPREPROC_MSG_ERROR_MSG_ID:
+		printk(KERN_ERR "audpre: err_index %d\n", msg[0]);
+		break;
+	case EVENT_MSG_ID:
+		printk(KERN_INFO"audpre: arm9 event\n");
+		break;
+	default:
+		printk(KERN_ERR "audpre: unknown event %d\n", id);
+	}
+}
+
+void audrec_dsp_event(void *data, unsigned id, size_t len,
+		      void (*getevent) (void *ptr, size_t len))
+{
+	struct msm_audio *prtd = data;
+	unsigned long flag;
+	uint16_t msg[MAX_DATA_SIZE/2];
+
+	if (len > MAX_DATA_SIZE) {
+		printk(KERN_ERR"audrec: event/msg too large(%d bytes)\n", len);
+		return;
+	}
+	getevent(msg, len);
+
+	switch (id) {
+	case AUDREC_MSG_CMD_CFG_DONE_MSG:
+		if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_UPDATE) {
+			if (msg[0] & AUDREC_MSG_CFG_DONE_TYPE_0_ENA)
+				audrec_encoder_config(prtd);
+			else
+				prtd->running = 0;
+		}
+		break;
+	case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG:{
+			prtd->running = 1;
+			break;
+		}
+	case AUDREC_MSG_FATAL_ERR_MSG:
+		printk(KERN_ERR "audrec: ERROR %x\n", msg[0]);
+		break;
+	case AUDREC_MSG_PACKET_READY_MSG:
+		alsa_get_dsp_frames(prtd);
+		++intcnt;
+		if (prtd->channel_mode == 1) {
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			prtd->pcm_irq_pos += prtd->pcm_count;
+			if (prtd->pcm_irq_pos >= prtd->pcm_size)
+				prtd->pcm_irq_pos = 0;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+
+			if (prtd->ops->capture)
+				prtd->ops->capture(prtd);
+		} else if ((prtd->channel_mode == 0) && (intcnt % 2 == 0)) {
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			prtd->pcm_irq_pos += prtd->pcm_count;
+			if (prtd->pcm_irq_pos >= prtd->pcm_size)
+				prtd->pcm_irq_pos = 0;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+			if (prtd->ops->capture)
+				prtd->ops->capture(prtd);
+		}
+		break;
+	case EVENT_MSG_ID:
+		printk(KERN_INFO"audrec: arm9 event\n");
+		break;
+	default:
+		printk(KERN_ERR "audrec: unknown event %d\n", id);
+	}
+}
+
+struct msm_adsp_ops aud_pre_adsp_ops = {
+	.event = alsa_audpre_dsp_event,
+};
+
+struct msm_adsp_ops aud_rec_adsp_ops = {
+	.event = audrec_dsp_event,
+};
+
+int alsa_adsp_configure(struct msm_audio *prtd)
+{
+	int ret, i;
+
+	if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		prtd->data = prtd->playback_substream->dma_buffer.area;
+		prtd->phys = prtd->playback_substream->dma_buffer.addr;
+	}
+	if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE) {
+		prtd->data = prtd->capture_substream->dma_buffer.area;
+		prtd->phys = prtd->capture_substream->dma_buffer.addr;
+	}
+	if (!prtd->data) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	ret = audmgr_open(&prtd->audmgr);
+	if (ret)
+		goto err2;
+	if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		prtd->out_buffer_size = PLAYBACK_DMASZ;
+		prtd->out_sample_rate = 44100;
+		prtd->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
+		prtd->out_weight = 100;
+
+		prtd->out[0].data = prtd->data + 0;
+		prtd->out[0].addr = prtd->phys + 0;
+		prtd->out[0].size = BUFSZ;
+		prtd->out[1].data = prtd->data + BUFSZ;
+		prtd->out[1].addr = prtd->phys + BUFSZ;
+		prtd->out[1].size = BUFSZ;
+	}
+	if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE) {
+		prtd->samp_rate = RPC_AUD_DEF_SAMPLE_RATE_44100;
+		prtd->samp_rate_index = AUDREC_CMD_SAMP_RATE_INDX_44100;
+		prtd->channel_mode = AUDREC_CMD_STEREO_MODE_STEREO;
+		prtd->buffer_size = STEREO_DATA_SIZE;
+		prtd->type = AUDREC_CMD_TYPE_0_INDEX_WAV;
+		prtd->tx_agc_cfg.cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS;
+		prtd->ns_cfg.cmd_id = AUDPREPROC_CMD_CFG_NS_PARAMS;
+		prtd->iir_cfg.cmd_id =
+		    AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+
+		ret = msm_adsp_get("AUDPREPROCTASK",
+				   &prtd->audpre, &aud_pre_adsp_ops, prtd);
+		if (ret)
+			goto err3;
+		ret = msm_adsp_get("AUDRECTASK",
+				   &prtd->audrec, &aud_rec_adsp_ops, prtd);
+		if (ret) {
+			msm_adsp_put(prtd->audpre);
+			goto err3;
+		}
+		prtd->dsp_cnt = 0;
+		prtd->in_head = 0;
+		prtd->in_tail = 0;
+		prtd->in_count = 0;
+		for (i = 0; i < FRAME_NUM; i++) {
+			prtd->in[i].size = 0;
+			prtd->in[i].read = 0;
+		}
+	}
+
+	return 0;
+
+err3:
+	audmgr_close(&prtd->audmgr);
+
+err2:
+	prtd->data = NULL;
+err1:
+	return ret;
+}
+EXPORT_SYMBOL(alsa_adsp_configure);
+
+int alsa_audio_configure(struct msm_audio *prtd)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	if (prtd->enabled)
+		return 0;
+
+	/* refuse to start if we're not ready with first buffer */
+	if (!prtd->out[0].used)
+		return -EIO;
+
+	cfg.tx_rate = 0;
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+	cfg.def_method = RPC_AUD_DEF_METHOD_HOST_PCM;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+	rc = audmgr_enable(&prtd->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (audpp_enable(AUDPP_ALSA_DECODER, alsa_dsp_event, prtd)) {
+		printk(KERN_ERR "audio: audpp_enable() failed\n");
+		audmgr_disable(&prtd->audmgr);
+		return -ENODEV;
+	}
+
+	prtd->enabled = 1;
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audio_configure);
+
+ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	unsigned long flag;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	int rc = 0;
+
+	mutex_lock(&the_locks.write_lock);
+	while (count > 0) {
+		frame = prtd->out + prtd->out_head;
+		rc = wait_event_interruptible(the_locks.write_wait,
+					      (frame->used == 0)
+					      || (prtd->stopped));
+		if (rc < 0)
+			break;
+		if (prtd->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+		xfer = count > frame->size ? frame->size : count;
+		if (copy_from_user(frame->data, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+		frame->used = xfer;
+		prtd->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+
+		spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
+		frame = prtd->out + prtd->out_tail;
+		if (frame->used && prtd->out_needed) {
+			audio_dsp_send_buffer(prtd, prtd->out_tail,
+					      frame->used);
+			prtd->out_tail ^= 1;
+			prtd->out_needed--;
+		}
+		spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
+	}
+	mutex_unlock(&the_locks.write_lock);
+	if (buf > start)
+		return buf - start;
+	return rc;
+}
+EXPORT_SYMBOL(alsa_send_buffer);
+
+int alsa_audio_disable(struct msm_audio *prtd)
+{
+	if (prtd->enabled) {
+		mutex_lock(&the_locks.lock);
+		prtd->enabled = 0;
+		audio_dsp_out_enable(prtd, 0);
+		wake_up(&the_locks.write_wait);
+		audpp_disable(AUDPP_ALSA_DECODER, prtd);
+		audmgr_disable(&prtd->audmgr);
+		prtd->out_needed = 0;
+		mutex_unlock(&the_locks.lock);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audio_disable);
+
+int alsa_audrec_disable(struct msm_audio *prtd)
+{
+	if (prtd->enabled) {
+		mutex_lock(&the_locks.lock);
+		prtd->enabled = 0;
+		alsa_rec_dsp_enable(prtd, 0);
+		wake_up(&the_locks.read_wait);
+		msm_adsp_disable(prtd->audpre);
+		msm_adsp_disable(prtd->audrec);
+		audmgr_disable(&prtd->audmgr);
+		prtd->out_needed = 0;
+		prtd->opened = 0;
+		mutex_unlock(&the_locks.lock);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(alsa_audrec_disable);
+
+static int audio_dsp_read_buffer(struct msm_audio *prtd, uint32_t read_cnt)
+{
+	audrec_cmd_packet_ext_ptr cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_PACKET_EXT_PTR;
+	/* Both WAV and AAC use AUDREC_CMD_TYPE_0 */
+	cmd.type = AUDREC_CMD_TYPE_0;
+	cmd.curr_rec_count_msw = read_cnt >> 16;
+	cmd.curr_rec_count_lsw = read_cnt;
+
+	return audio_send_queue_recbs(prtd, &cmd, sizeof(cmd));
+}
+
+int audrec_encoder_config(struct msm_audio *prtd)
+{
+	audrec_cmd_arec0param_cfg cmd;
+	uint16_t *data = (void *)prtd->data;
+	unsigned n;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_AREC0PARAM_CFG;
+	cmd.ptr_to_extpkt_buffer_msw = prtd->phys >> 16;
+	cmd.ptr_to_extpkt_buffer_lsw = prtd->phys;
+	cmd.buf_len = FRAME_NUM;	/* Both WAV and AAC use 8 frames */
+	cmd.samp_rate_index = prtd->samp_rate_index;
+	/* 0 for mono, 1 for stereo */
+	cmd.stereo_mode = prtd->channel_mode;
+	cmd.rec_quality = 0x1C00;
+
+	/* prepare buffer pointers:
+	 * Mono: 1024 samples + 4 halfword header
+	 * Stereo: 2048 samples + 4 halfword header
+	 */
+
+	for (n = 0; n < FRAME_NUM; n++) {
+		prtd->in[n].data = data + 4;
+		data += (4 + (prtd->channel_mode ? 2048 : 1024));
+	}
+
+	return audio_send_queue_rec(prtd, &cmd, sizeof(cmd));
+}
+
+int audio_dsp_out_enable(struct msm_audio *prtd, int yes)
+{
+	audpp_cmd_pcm_intf cmd;
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_PCM_INTF_2;
+	cmd.object_num = AUDPP_CMD_PCM_INTF_OBJECT_NUM;
+	cmd.config = AUDPP_CMD_PCM_INTF_CONFIG_CMD_V;
+	cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+
+	if (yes) {
+		cmd.write_buf1LSW = prtd->out[0].addr;
+		cmd.write_buf1MSW = prtd->out[0].addr >> 16;
+		cmd.write_buf1_len = 0;
+		cmd.write_buf2LSW = prtd->out[1].addr;
+		cmd.write_buf2MSW = prtd->out[1].addr >> 16;
+		cmd.write_buf2_len = prtd->out[1].used;
+		cmd.arm_to_rx_flag = AUDPP_CMD_PCM_INTF_ENA_V;
+		cmd.weight_decoder_to_rx = prtd->out_weight;
+		cmd.weight_arm_to_rx = 1;
+		cmd.partition_number_arm_to_dsp = 0;
+		cmd.sample_rate = prtd->out_sample_rate;
+		cmd.channel_mode = prtd->out_channel_mode;
+	}
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
+		      size_t count, loff_t *pos)
+{
+	unsigned long flag;
+	void *data;
+	uint32_t index;
+	uint32_t size;
+	int rc = 0;
+
+	mutex_lock(&the_locks.read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(the_locks.read_wait,
+					      (prtd->in_count > 0)
+					      || prtd->stopped);
+		if (rc < 0)
+			break;
+
+		if (prtd->stopped) {
+			rc = -EBUSY;
+			break;
+		}
+
+		index = prtd->in_tail;
+		data = (uint8_t *) prtd->in[index].data;
+		size = prtd->in[index].size;
+		if (count >= size) {
+			if (copy_to_user(buf, data, size)) {
+				rc = -EFAULT;
+				break;
+			}
+			spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+			if (index != prtd->in_tail) {
+				/* overrun: data is invalid, we need to retry */
+				spin_unlock_irqrestore(&the_locks.read_dsp_lock,
+						       flag);
+				continue;
+			}
+			prtd->in[index].size = 0;
+			prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
+			prtd->in_count--;
+			spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+			count -= size;
+			buf += size;
+		} else {
+			break;
+		}
+	}
+	mutex_unlock(&the_locks.read_lock);
+	return rc;
+}
+EXPORT_SYMBOL(alsa_buffer_read);
+
+static int audio_dsp_send_buffer(struct msm_audio *prtd,
+					unsigned idx, unsigned len)
+{
+	audpp_cmd_pcm_intf_send_buffer cmd;
+	cmd.cmd_id = AUDPP_CMD_PCM_INTF_2;
+	cmd.host_pcm_object = AUDPP_CMD_PCM_INTF_OBJECT_NUM;
+	cmd.config = AUDPP_CMD_PCM_INTF_BUFFER_CMD_V;
+	cmd.intf_type = AUDPP_CMD_PCM_INTF_RX_ENA_ARMTODSP_V;
+	cmd.dsp_to_arm_buf_id = 0;
+	cmd.arm_to_dsp_buf_id = idx + 1;
+	cmd.arm_to_dsp_buf_len = len;
+	return audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+int alsa_rec_dsp_enable(struct msm_audio *prtd, int enable)
+{
+	audrec_cmd_cfg cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDREC_CMD_CFG;
+	cmd.type_0 = enable ? AUDREC_CMD_TYPE_0_ENA : AUDREC_CMD_TYPE_0_DIS;
+	cmd.type_0 |= (AUDREC_CMD_TYPE_0_UPDATE | prtd->type);
+	cmd.type_1 = 0;
+
+	return audio_send_queue_rec(prtd, &cmd, sizeof(cmd));
+}
+EXPORT_SYMBOL(alsa_rec_dsp_enable);
+
+void alsa_get_dsp_frames(struct msm_audio *prtd)
+{
+	struct audio_frame *frame;
+	uint32_t index = 0;
+	unsigned long flag;
+
+	if (prtd->type == AUDREC_CMD_TYPE_0_INDEX_WAV) {
+		index = prtd->in_head;
+
+		frame =
+		    (void *)(((char *)prtd->in[index].data) - sizeof(*frame));
+
+		spin_lock_irqsave(&the_locks.read_dsp_lock, flag);
+		prtd->in[index].size = frame->bytes;
+
+		prtd->in_head = (prtd->in_head + 1) & (FRAME_NUM - 1);
+
+		/* If overflow, move the tail index foward. */
+		if (prtd->in_head == prtd->in_tail)
+			prtd->in_tail = (prtd->in_tail + 1) & (FRAME_NUM - 1);
+		else
+			prtd->in_count++;
+
+		audio_dsp_read_buffer(prtd, prtd->dsp_cnt++);
+		spin_unlock_irqrestore(&the_locks.read_dsp_lock, flag);
+
+		wake_up(&the_locks.read_wait);
+	} else {
+		/* TODO AAC not supported yet. */
+	}
+}
+EXPORT_SYMBOL(alsa_get_dsp_frames);
diff --git a/sound/soc/msm/msm-pcm.h b/sound/soc/msm/msm-pcm.h
new file mode 100644
index 0000000..7563ef0
--- /dev/null
+++ b/sound/soc/msm/msm-pcm.h
@@ -0,0 +1,200 @@
+/* sound/soc/msm/msm-pcm.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#ifndef _MSM_PCM_H
+#define _MSM_PCM_H
+
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5/qdsp5audrecmsg.h>
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+
+#include <../arch/arm/mach-msm/qdsp5/adsp.h>
+#include <../arch/arm/mach-msm/qdsp5/audmgr.h>
+
+
+#define FRAME_NUM               (8)
+#define FRAME_SIZE              (2052 * 2)
+#define MONO_DATA_SIZE          (2048)
+#define STEREO_DATA_SIZE        (MONO_DATA_SIZE * 2)
+#define CAPTURE_DMASZ           (FRAME_SIZE * FRAME_NUM)
+
+#define BUFSZ			(960 * 5)
+#define PLAYBACK_DMASZ 		(BUFSZ * 2)
+
+#define MSM_PLAYBACK_DEFAULT_VOLUME 0 /* 0dB */
+#define MSM_PLAYBACK_DEFAULT_PAN 0
+
+#define USE_FORMATS             SNDRV_PCM_FMTBIT_S16_LE
+#define USE_CHANNELS_MIN        1
+#define USE_CHANNELS_MAX        2
+/* Support unconventional sample rates 12000, 24000 as well */
+#define USE_RATE                \
+			(SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+#define USE_RATE_MIN            8000
+#define USE_RATE_MAX            48000
+#define MAX_BUFFER_PLAYBACK_SIZE \
+				(4800*4)
+/* 2048 frames (Mono), 1024 frames (Stereo) */
+#define CAPTURE_SIZE		4096
+#define MAX_BUFFER_CAPTURE_SIZE (4096*4)
+#define MAX_PERIOD_SIZE         BUFSZ
+#define USE_PERIODS_MAX         1024
+#define USE_PERIODS_MIN		1
+
+
+#define MAX_DB			(16)
+#define MIN_DB			(-50)
+#define PCMPLAYBACK_DECODERID   5
+
+/* 0xFFFFFFFF Indicates not to be used for audio data copy */
+#define	BUF_INVALID_LEN		0xFFFFFFFF
+
+extern int copy_count;
+extern int intcnt;
+
+struct msm_volume {
+	bool update;
+	int volume; /* Volume parameter, in dB Scale */
+	int pan;
+};
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;
+	unsigned addr;
+};
+
+struct buffer_rec {
+	void *data;
+	unsigned int size;
+	unsigned int read;
+	unsigned int addr;
+};
+
+struct audio_locks {
+	struct mutex lock;
+	struct mutex write_lock;
+	struct mutex read_lock;
+	spinlock_t read_dsp_lock;
+	spinlock_t write_dsp_lock;
+	spinlock_t mixer_lock;
+	wait_queue_head_t read_wait;
+	wait_queue_head_t write_wait;
+};
+
+extern struct audio_locks the_locks;
+
+struct msm_audio_event_callbacks {
+	/* event is called from interrupt context when a message
+	 * arrives from the DSP.
+	*/
+	void (*playback)(void *);
+	void (*capture)(void *);
+};
+
+
+struct msm_audio {
+	struct buffer out[2];
+	struct buffer_rec in[8];
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	atomic_t out_bytes;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_weight;
+	uint32_t out_buffer_size;
+
+	struct audmgr audmgr;
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	/* data allocated for various buffers */
+	char *data;
+	dma_addr_t phys;
+
+	unsigned int pcm_size;
+	unsigned int pcm_count;
+	unsigned int pcm_irq_pos;       /* IRQ position */
+	unsigned int pcm_buf_pos;       /* position in buffer */
+
+	struct msm_adsp_module *audpre;
+	struct msm_adsp_module *audrec;
+
+	/* configuration to use on next enable */
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+	uint32_t buffer_size; /* 2048 for mono, 4096 for stereo */
+	uint32_t type; /* 0 for PCM ,1 for AAC */
+	uint32_t dsp_cnt;
+	uint32_t in_head; /* next buffer dsp will write */
+	uint32_t in_tail; /* next buffer read() will read */
+	uint32_t in_count; /* number of buffers available to read() */
+
+	unsigned short samp_rate_index;
+
+	/* audpre settings */
+	audpreproc_cmd_cfg_agc_params tx_agc_cfg;
+	audpreproc_cmd_cfg_ns_params ns_cfg;
+	/* For different sample rate, the coeff might be different. *
+	* All the coeff should be passed from user space           */
+	audpreproc_cmd_cfg_iir_tuning_filter_params iir_cfg;
+
+	struct  msm_audio_event_callbacks *ops;
+
+	int dir;
+	int opened;
+	int enabled;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+};
+
+
+
+/* platform data */
+extern int audio_dsp_out_enable(struct msm_audio *prtd, int yes);
+extern struct snd_soc_platform msm_soc_platform;
+extern struct snd_soc_dai msm_dais[2];
+extern struct snd_soc_codec_device soc_codec_dev_msm;
+
+int audrec_encoder_config(struct msm_audio *prtd);
+extern void alsa_get_dsp_frames(struct msm_audio *prtd);
+extern int alsa_rec_dsp_enable(struct msm_audio *prtd, int enable);
+extern int alsa_audrec_disable(struct msm_audio *prtd);
+extern int alsa_audio_configure(struct msm_audio *prtd);
+extern int alsa_audio_disable(struct msm_audio *prtd);
+extern int alsa_adsp_configure(struct msm_audio *prtd);
+extern int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
+					size_t count, loff_t *pos);
+ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
+					size_t count, loff_t *pos);
+int msm_audio_volume_update(unsigned id,
+				int volume, int pan);
+extern struct audio_locks the_locks;
+extern struct msm_volume msm_vol_ctl;
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/msm7201.c b/sound/soc/msm/msm7201.c
new file mode 100644
index 0000000..977fbac
--- /dev/null
+++ b/sound/soc/msm/msm7201.c
@@ -0,0 +1,337 @@
+/* linux/sound/soc/msm/msm7201.c
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm.h"
+#include <asm/mach-types.h>
+#include <mach/msm_rpcrouter.h>
+
+static struct msm_rpc_endpoint *snd_ep;
+
+struct msm_snd_rpc_ids {
+	unsigned long   prog;
+	unsigned long   vers;
+	unsigned long   rpc_set_snd_device;
+	int device;
+};
+
+static struct msm_snd_rpc_ids snd_rpc_ids;
+
+static struct platform_device *msm_audio_snd_device;
+
+static int snd_msm_volume_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1; /* Volume Param, in dB */
+	uinfo->value.integer.min = MIN_DB;
+	uinfo->value.integer.max = MAX_DB;
+	return 0;
+}
+
+static int snd_msm_volume_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	spin_lock_irq(&the_locks.mixer_lock);
+	ucontrol->value.integer.value[0] = msm_vol_ctl.volume;
+	spin_unlock_irq(&the_locks.mixer_lock);
+	return 0;
+}
+
+static int snd_msm_volume_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int change;
+	int volume;
+
+	volume = ucontrol->value.integer.value[0];
+	spin_lock_irq(&the_locks.mixer_lock);
+	change = (msm_vol_ctl.volume != volume);
+	if (change) {
+		msm_vol_ctl.update = 1;
+		msm_vol_ctl.volume = volume;
+	}
+	spin_unlock_irq(&the_locks.mixer_lock);
+	return change;
+}
+
+static int snd_msm_device_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1; /* Device */
+
+	/*
+	 * The number of devices supported is 26 (0 to 25)
+	 */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 25;
+	return 0;
+}
+
+static int snd_msm_device_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = (uint32_t)snd_rpc_ids.device;
+	return 0;
+}
+
+int msm_snd_init_rpc_ids(void)
+{
+	snd_rpc_ids.prog	= 0x30000002;
+#ifdef CONFIG_MSM_AMSS_VERSION_6225
+	//TODO: complete for other versions
+	snd_rpc_ids.vers	= 0xaa2b1a44;
+#else
+	//seem a new magich number...not in arch/arm/mach-msm and it seem to be for a new amss version
+	snd_rpc_ids.vers	= 0x00020001;
+#endif
+	/*
+	 * The magic number 2 corresponds to the rpc call
+	 * index for snd_set_device
+	 */
+	snd_rpc_ids.rpc_set_snd_device = 2;
+	return 0;
+}
+
+int msm_snd_rpc_connect(void)
+{
+	if (snd_ep) {
+		printk(KERN_INFO "%s: snd_ep already connected\n", __func__);
+		return 0;
+	}
+
+	/* Initialize rpc ids */
+	if (msm_snd_init_rpc_ids()) {
+		printk(KERN_ERR "%s: snd rpc ids initialization failed\n"
+			, __func__);
+		return -ENODATA;
+	}
+
+	snd_ep = msm_rpc_connect(snd_rpc_ids.prog,
+				snd_rpc_ids.vers, 0);
+	if (IS_ERR(snd_ep)) {
+		printk(KERN_ERR "%s: failed (compatible VERS = %ld)\n",
+				__func__, snd_rpc_ids.vers);
+		snd_ep = NULL;
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+int msm_snd_rpc_close(void)
+{
+	int rc = 0;
+
+	if (IS_ERR(snd_ep)) {
+		printk(KERN_ERR "%s: snd handle unavailable, rc = %ld\n",
+				__func__, PTR_ERR(snd_ep));
+		return -EAGAIN;
+	}
+
+	rc = msm_rpc_close(snd_ep);
+	snd_ep = NULL;
+
+	if (rc < 0) {
+		printk(KERN_ERR "%s: close rpc failed! rc = %d\n",
+				__func__, rc);
+		return -EAGAIN;
+	} else
+		printk(KERN_INFO "rpc close success\n");
+
+	return rc;
+}
+
+static int snd_msm_device_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	struct snd_start_req {
+		struct rpc_request_hdr hdr;
+		uint32_t rpc_snd_device;
+		uint32_t snd_mute_ear_mute;
+		uint32_t snd_mute_mic_mute;
+		uint32_t callback_ptr;
+		uint32_t client_data;
+	} req;
+
+	snd_rpc_ids.device = (int)ucontrol->value.integer.value[0];
+	req.hdr.type = 0;
+	req.hdr.rpc_vers = 2;
+
+	req.rpc_snd_device = cpu_to_be32(snd_rpc_ids.device);
+	req.snd_mute_ear_mute = cpu_to_be32(1);
+	req.snd_mute_mic_mute = cpu_to_be32(0);
+	req.callback_ptr = -1;
+	req.client_data = cpu_to_be32(0);
+
+	req.hdr.prog = snd_rpc_ids.prog;
+	req.hdr.vers = snd_rpc_ids.vers;
+
+	rc = msm_rpc_call(snd_ep, snd_rpc_ids.rpc_set_snd_device ,
+			&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0) {
+		printk(KERN_ERR "%s: snd rpc call failed! rc = %d\n",
+			__func__, rc);
+	} else
+		printk(KERN_INFO "snd device connected \n");
+
+	return rc;
+}
+
+/* Supported range -50dB to 18dB */
+static const DECLARE_TLV_DB_LINEAR(db_scale_linear, -5000, 1800);
+
+#define MSM_EXT(xname, xindex, fp_info, fp_get, fp_put, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+  .name = xname, .index = xindex, \
+  .info = fp_info,\
+  .get = fp_get, .put = fp_put, \
+  .private_value = addr, \
+}
+
+#define MSM_EXT_TLV(xname, xindex, fp_info, fp_get, fp_put, addr, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = (SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		SNDRV_CTL_ELEM_ACCESS_READWRITE), \
+  .name = xname, .index = xindex, \
+  .info = fp_info,\
+  .get = fp_get, .put = fp_put, .tlv.p = tlv_array, \
+  .private_value = addr, \
+}
+
+static struct snd_kcontrol_new snd_msm_controls[] = {
+	MSM_EXT_TLV("PCM Playback Volume", 0, snd_msm_volume_info, \
+	snd_msm_volume_get, snd_msm_volume_put, 0, db_scale_linear),
+	MSM_EXT("device", 1, snd_msm_device_info, snd_msm_device_get, \
+						 snd_msm_device_put, 0),
+};
+
+static int msm_new_mixer(struct snd_card *card)
+{
+	unsigned int idx;
+	int err;
+
+	printk(KERN_ERR "msm_soc:ALSA MSM Mixer Setting");
+	strcpy(card->mixername, "MSM Mixer");
+	for (idx = 0; idx < ARRAY_SIZE(snd_msm_controls); idx++) {
+		err = snd_ctl_add(card,
+				snd_ctl_new1(&snd_msm_controls[idx], NULL));
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int msm_soc_dai_init(struct snd_soc_codec *codec)
+{
+
+	int ret = 0;
+	ret = msm_new_mixer(codec->card);
+	if (ret < 0) {
+		printk(KERN_ERR "msm_soc:ALSA MSM Mixer Fail");
+	}
+
+	return ret;
+}
+
+
+static struct snd_soc_dai_link msm_dai = {
+	.name = "ASOC",
+	.stream_name = "ASOC",
+	.codec_dai = &msm_dais[0],
+	.cpu_dai = &msm_dais[1],
+	.init	= msm_soc_dai_init,
+};
+
+struct snd_soc_card snd_soc_card_msm = {
+	.name 		= "msm-audio",
+	.dai_link	= &msm_dai,
+	.num_links = 1,
+	.platform = &msm_soc_platform,
+};
+
+/* msm_audio audio subsystem */
+static struct snd_soc_device msm_audio_snd_devdata = {
+	.card = &snd_soc_card_msm,
+	.codec_dev = &soc_codec_dev_msm,
+};
+
+
+static int __init msm_audio_init(void)
+{
+	int ret;
+
+	msm_audio_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!msm_audio_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(msm_audio_snd_device, &msm_audio_snd_devdata);
+	msm_audio_snd_devdata.dev = &msm_audio_snd_device->dev;
+	ret = platform_device_add(msm_audio_snd_device);
+	if (ret) {
+		platform_device_put(msm_audio_snd_device);
+		return ret;
+	}
+	mutex_init(&the_locks.lock);
+	mutex_init(&the_locks.write_lock);
+	mutex_init(&the_locks.read_lock);
+	spin_lock_init(&the_locks.read_dsp_lock);
+	spin_lock_init(&the_locks.write_dsp_lock);
+	spin_lock_init(&the_locks.mixer_lock);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+	msm_vol_ctl.volume = MSM_PLAYBACK_DEFAULT_VOLUME;
+	msm_vol_ctl.pan = MSM_PLAYBACK_DEFAULT_PAN;
+
+	ret = msm_snd_rpc_connect();
+
+	return ret;
+}
+
+static void __exit msm_audio_exit(void)
+{
+	msm_snd_rpc_close();
+	platform_device_unregister(msm_audio_snd_device);
+}
+
+module_init(msm_audio_init);
+module_exit(msm_audio_exit);
+
+MODULE_DESCRIPTION("PCM module");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm7k-pcm.c b/sound/soc/msm/msm7k-pcm.c
new file mode 100644
index 0000000..38e8283
--- /dev/null
+++ b/sound/soc/msm/msm7k-pcm.c
@@ -0,0 +1,574 @@
+/* linux/sound/soc/msm/msm7k-pcm.c
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm.h"
+
+#define SND_DRIVER        "snd_msm"
+#define MAX_PCM_DEVICES	SNDRV_CARDS
+#define MAX_PCM_SUBSTREAMS 1
+
+struct snd_msm {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+int copy_count;
+
+struct audio_locks the_locks;
+EXPORT_SYMBOL(the_locks);
+struct msm_volume msm_vol_ctl;
+EXPORT_SYMBOL(msm_vol_ctl);
+
+
+static unsigned convert_dsp_samp_index(unsigned index)
+{
+	switch (index) {
+	case 48000:
+		return AUDREC_CMD_SAMP_RATE_INDX_48000;
+	case 44100:
+		return AUDREC_CMD_SAMP_RATE_INDX_44100;
+	case 32000:
+		return AUDREC_CMD_SAMP_RATE_INDX_32000;
+	case 24000:
+		return AUDREC_CMD_SAMP_RATE_INDX_24000;
+	case 22050:
+		return AUDREC_CMD_SAMP_RATE_INDX_22050;
+	case 16000:
+		return AUDREC_CMD_SAMP_RATE_INDX_16000;
+	case 12000:
+		return AUDREC_CMD_SAMP_RATE_INDX_12000;
+	case 11025:
+		return AUDREC_CMD_SAMP_RATE_INDX_11025;
+	case 8000:
+		return AUDREC_CMD_SAMP_RATE_INDX_8000;
+	default:
+		return AUDREC_CMD_SAMP_RATE_INDX_44100;
+	}
+}
+
+static unsigned convert_samp_rate(unsigned hz)
+{
+	switch (hz) {
+	case 48000:
+		return RPC_AUD_DEF_SAMPLE_RATE_48000;
+	case 44100:
+		return RPC_AUD_DEF_SAMPLE_RATE_44100;
+	case 32000:
+		return RPC_AUD_DEF_SAMPLE_RATE_32000;
+	case 24000:
+		return RPC_AUD_DEF_SAMPLE_RATE_24000;
+	case 22050:
+		return RPC_AUD_DEF_SAMPLE_RATE_22050;
+	case 16000:
+		return RPC_AUD_DEF_SAMPLE_RATE_16000;
+	case 12000:
+		return RPC_AUD_DEF_SAMPLE_RATE_12000;
+	case 11025:
+		return RPC_AUD_DEF_SAMPLE_RATE_11025;
+	case 8000:
+		return RPC_AUD_DEF_SAMPLE_RATE_8000;
+	default:
+		return RPC_AUD_DEF_SAMPLE_RATE_44100;
+	}
+}
+
+static struct snd_pcm_hardware msm_pcm_playback_hardware = {
+	.info =                 SNDRV_PCM_INFO_INTERLEAVED,
+	.formats =              USE_FORMATS,
+	.rates =                USE_RATE,
+	.rate_min =             USE_RATE_MIN,
+	.rate_max =             USE_RATE_MAX,
+	.channels_min =         USE_CHANNELS_MIN,
+	.channels_max =         USE_CHANNELS_MAX,
+	.buffer_bytes_max =     MAX_BUFFER_PLAYBACK_SIZE,
+	.period_bytes_min =     64,
+	.period_bytes_max =     MAX_PERIOD_SIZE,
+	.periods_min =          USE_PERIODS_MIN,
+	.periods_max =          USE_PERIODS_MAX,
+	.fifo_size =            0,
+};
+
+static struct snd_pcm_hardware msm_pcm_capture_hardware = {
+	.info =                 SNDRV_PCM_INFO_INTERLEAVED,
+	.formats =		USE_FORMATS,
+	.rates =		USE_RATE,
+	.rate_min =		USE_RATE_MIN,
+	.rate_max =		USE_RATE_MAX,
+	.channels_min =		USE_CHANNELS_MIN,
+	.channels_max =		USE_CHANNELS_MAX,
+	.buffer_bytes_max =	MAX_BUFFER_CAPTURE_SIZE,
+	.period_bytes_min =	CAPTURE_SIZE,
+	.period_bytes_max =	CAPTURE_SIZE,
+	.periods_min =		USE_PERIODS_MIN,
+	.periods_max =		USE_PERIODS_MAX,
+	.fifo_size =		0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void playback_event_handler(void *data)
+{
+	struct msm_audio *prtd = data;
+	snd_pcm_period_elapsed(prtd->playback_substream);
+}
+
+static void capture_event_handler(void *data)
+{
+	struct msm_audio *prtd = data;
+	snd_pcm_period_elapsed(prtd->capture_substream);
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	prtd->pcm_buf_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->out_sample_rate = runtime->rate;
+	prtd->out_channel_mode = runtime->channels;
+
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	struct audmgr_config cfg;
+	int rc;
+
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	prtd->pcm_buf_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = convert_samp_rate(runtime->rate);
+	prtd->samp_rate_index = convert_dsp_samp_index(runtime->rate);
+	prtd->channel_mode = (runtime->channels - 1);
+	prtd->buffer_size = prtd->channel_mode ? STEREO_DATA_SIZE : \
+							MONO_DATA_SIZE;
+
+	if (prtd->enabled == 1)
+		return 0;
+
+	prtd->type = AUDREC_CMD_TYPE_0_INDEX_WAV;
+
+	cfg.tx_rate = convert_samp_rate(runtime->rate);
+	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+	cfg.def_method = RPC_AUD_DEF_METHOD_RECORD;
+	cfg.codec = RPC_AUD_DEF_CODEC_PCM;
+	cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+	rc = audmgr_enable(&prtd->audmgr, &cfg);
+	if (rc < 0)
+		return rc;
+
+	if (msm_adsp_enable(prtd->audpre)) {
+		audmgr_disable(&prtd->audmgr);
+		return -ENODEV;
+	}
+	if (msm_adsp_enable(prtd->audrec)) {
+		msm_adsp_disable(prtd->audpre);
+		audmgr_disable(&prtd->audmgr);
+		return -ENODEV;
+	}
+	prtd->enabled = 1;
+	alsa_rec_dsp_enable(prtd, 1);
+
+	return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t
+msm_pcm_playback_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos == prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+		 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+						 snd_pcm_uframes_t frames)
+{
+	int rc = 0, rc1 = 0, rc2 = 0;
+	int fbytes = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = substream->runtime->private_data;
+
+	int monofbytes = 0;
+	char *bufferp = NULL;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	monofbytes = fbytes / 2;
+	if (runtime->channels == 2) {
+		rc = alsa_buffer_read(prtd, buf, fbytes, NULL);
+	} else {
+		bufferp = buf;
+		rc1 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
+		bufferp = buf + monofbytes ;
+		rc2 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
+		rc = rc1 + rc2;
+	}
+	prtd->pcm_buf_pos += fbytes;
+	return rc;
+}
+
+static snd_pcm_uframes_t
+msm_pcm_capture_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	alsa_audrec_disable(prtd);
+	audmgr_close(&prtd->audmgr);
+	msm_adsp_put(prtd->audrec);
+	msm_adsp_put(prtd->audpre);
+	kfree(prtd);
+
+	return 0;
+}
+
+struct  msm_audio_event_callbacks snd_msm_audio_ops = {
+	.playback = playback_event_handler,
+	.capture = capture_event_handler,
+};
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd;
+	int ret = 0;
+
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		ret = -ENOMEM;
+		return ret;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msm_vol_ctl.update = 1; /* Update Volume, with Cached value */
+		runtime->hw = msm_pcm_playback_hardware;
+		prtd->dir = SNDRV_PCM_STREAM_PLAYBACK;
+		prtd->playback_substream = substream;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		runtime->hw = msm_pcm_capture_hardware;
+		prtd->dir = SNDRV_PCM_STREAM_CAPTURE;
+		prtd->capture_substream = substream;
+	}
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+						SNDRV_PCM_HW_PARAM_RATE,
+						&constraints_sample_rates);
+	if (ret < 0)
+		goto out;
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		goto out;
+
+	prtd->ops = &snd_msm_audio_ops;
+	prtd->out[0].used = BUF_INVALID_LEN;
+	prtd->out_head = 1; /* point to second buffer on startup */
+	runtime->private_data = prtd;
+
+	ret = alsa_adsp_configure(prtd);
+	if (ret)
+		goto out;
+	copy_count = 0;
+	return 0;
+
+ out:
+	kfree(prtd);
+	return ret;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int rc = 1;
+	int fbytes = 0;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	rc = alsa_send_buffer(prtd, buf, fbytes, NULL);
+	++copy_count;
+	prtd->pcm_buf_pos += fbytes;
+	if (copy_count == 1) {
+		mutex_lock(&the_locks.lock);
+		alsa_audio_configure(prtd);
+		mutex_unlock(&the_locks.lock);
+	}
+	if ((prtd->running) && (msm_vol_ctl.update)) {
+		rc = msm_audio_volume_update(PCMPLAYBACK_DECODERID,
+				msm_vol_ctl.volume, msm_vol_ctl.pan);
+		msm_vol_ctl.update = 0;
+	}
+
+	return  rc;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	alsa_audio_disable(prtd);
+	audmgr_close(&prtd->audmgr);
+	kfree(prtd);
+
+	return 0;
+}
+
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+	 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_close(substream);
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	snd_pcm_uframes_t ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_pointer(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_pointer(substream);
+	return ret;
+}
+
+int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (substream->pcm->device & 1) {
+		runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
+		runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
+	}
+	return 0;
+
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.copy		= msm_pcm_copy,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+};
+
+
+
+static int msm_pcm_remove(struct platform_device *devptr)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(devptr);
+	snd_soc_free_pcms(socdev);
+	kfree(socdev->codec);
+	platform_set_drvdata(devptr, NULL);
+	return 0;
+}
+
+static int pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+	int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size;
+	if (!stream)
+		size = PLAYBACK_DMASZ;
+	else
+		size = CAPTURE_DMASZ;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->bytes = size;
+	return 0;
+}
+
+static void msm_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_coherent(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static int msm_pcm_new(struct snd_card *card,
+			struct snd_soc_dai *codec_dai,
+			struct snd_pcm *pcm)
+{
+	int ret;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+	if (codec_dai->playback.channels_min) {
+		ret = pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			return ret;
+	}
+
+	if (codec_dai->capture.channels_min) {
+		ret = pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			msm_pcm_free_dma_buffers(pcm);
+	}
+	return ret;
+}
+
+struct snd_soc_platform msm_soc_platform = {
+	.name		= "msm-audio",
+	.remove         = msm_pcm_remove,
+	.pcm_ops 	= &msm_pcm_ops,
+	.pcm_new	= msm_pcm_new,
+	.pcm_free	= msm_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL(msm_soc_platform);
+
+static int __init msm_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&msm_soc_platform);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&msm_soc_platform);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora
  2009-11-08 22:46         ` [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora Denis 'GNUtoo' Carikli
@ 2009-11-09  8:42           ` Pavel Machek
  2009-11-13 14:50           ` Mark Brown
  1 sibling, 0 replies; 19+ messages in thread
From: Pavel Machek @ 2009-11-09  8:42 UTC (permalink / raw)
  To: Denis 'GNUtoo' Carikli; +Cc: alsa-devel

Hi!

> I had to make two little change to make it compile:
> snd_ep = msm_rpc_connect_compatible(snd_rpc_ids.prog,
> became:
> snd_ep = msm_rpc_connect(snd_rpc_ids.prog,
> and I also changed snd_rpc_ids.vers(with ifdefs)
> to a known and working magick number:
> 
> I also had to change from ARCH_MSM_ARM11 to ARCH_MSM in the configuration

Thanks for pointer.

> it still has serious runtime problems such as:
> *Can produce kernel oops under theses conditions:
>  start alsamixer and if the second bar is on 0 or 4,
>  so it can play music with aplay,then increase the routing alsamixer bar
>  to the max.
>  Then decrease the routing bar to 4 or less
>  Then It may have a null pointer problem
>  That bug could be because it tries to route to route to speakers and
>  handset at the same time(SND_DEVICE_HEADSET_AND_SPEAKER in android):
>  that is to say it could be the same bug than here:
> http://gitorious.org/replicant/msm7k/commit/370d37a088368ca8cc478e76c928a1ce6589495e
>  but I need time to verify that
> *can pannick(reboots the phone) if you send things to /dev/dsp when the
>  oss emulation is activated
> *only aplay works(mplayer,gstreamer don't work) for mplayer an ioctl
>  didn't return...so it get stuck before playing.
>  The explanation of the bug can be found here:
> http://mailman.alsa-project.org/pipermail/alsa-devel/2009-November/022697.html

Perhaps it should go to staging?

> Note the following things:
> *this patch depends on,and doesn't contain arch/arm/mach-msm/qdsp5
> *I removed the support for more recents chips because of code-size issue
>  in a mailing list

I had qdsp5 support in staging tree, check 2.6.31. It is not there
_now_ but I hope to reinstall it.
								Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora
  2009-11-08 22:46         ` [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora Denis 'GNUtoo' Carikli
  2009-11-09  8:42           ` Pavel Machek
@ 2009-11-13 14:50           ` Mark Brown
  2009-11-15 20:06             ` GNUtoo
  2009-11-29 23:16             ` GNUtoo
  1 sibling, 2 replies; 19+ messages in thread
From: Mark Brown @ 2009-11-13 14:50 UTC (permalink / raw)
  To: Denis 'GNUtoo' Carikli; +Cc: alsa-devel, pavel

On Sun, Nov 08, 2009 at 11:46:10PM +0100, Denis 'GNUtoo' Carikli wrote:

Please do try to rememeber to CC maintainers on patches...

I've read some, but not all of this since I really can't follow how the
code is supposed to be constructed.  At the minute there doesn't feel
like there's enough abstraction between the various parts of the code,
with lots of things cropping up in unexpected places and making it
harder to follow.

It would probably be useful to refactor things so that you've got a
support layer for the DSP that deals with any resource sharing issues
and then build more standard-looking CODEC, DAI and DMA drivers (the DAI
driver would probably be largely empty, I guess) with a machine driver
gluing them together.

> it still has serious runtime problems such as:
> *Can produce kernel oops under theses conditions:
>  start alsamixer and if the second bar is on 0 or 4,
>  so it can play music with aplay,then increase the routing alsamixer bar
>  to the max.
>  Then decrease the routing bar to 4 or less

What are "the second bar" and "routing bar"?  Remember, most of the
people reading your mail will never have seen your system running.

> +config SND_MSM_DAI_SOC
> +	tristate "SoC CPU/CODEC DAI for the MSM chip"
> +	depends on SND_MSM_SOC || SND_QSD_SOC
> +	help
> +	 To add support for ALSA PCM driver for MSM board.

No need to make this one uer visible.

> +
> +config SND_MSM_SOC_MSM7K
> +        tristate "SoC Audio support for MSM7K"
> +        depends on SND_MSM_SOC

Or this.  I know some architectures do this but we should probably just
move them to visibly select only boards.

> +	codec->name = "MSM-CARD";

Probably something like "MSM7xxx internal CODEC" or similar.

> +static int __init msm_dai_init(void)
> +{
> +	return snd_soc_register_dais(msm_dais, ARRAY_SIZE(msm_dais));
> +}
> +
> +static void __exit msm_dai_exit(void)
> +{
> +	snd_soc_unregister_dais(msm_dais, ARRAY_SIZE(msm_dais));
> +}

Your DAIs ought to be registered as platform devices under arch/arm,
probe as normal platform devices and then register the DAIs when these
probe.

> +#define audio_send_queue_recbs(prtd, cmd, len) \
> +	msm_adsp_write(prtd->audrec, QDSP_uPAudRecBitStreamQueue, cmd, len)
> +#define audio_send_queue_rec(prtd, cmd, len) \
> +	msm_adsp_write(prtd->audrec, QDSP_uPAudRecCmdQueue, cmd, len)

Inline functions, please.

> +int msm_audio_volume_update(unsigned id,
> +				int volume, int pan)
> +{
> +	unsigned vol_raw;
> +
> +	vol_raw = compute_db_raw(volume);
> +	printk(KERN_INFO "volume: %8x vol_raw: %8x \n", volume, vol_raw);
> +	return audpp_set_volume_and_pan(id, vol_raw, pan);
> +}
> +EXPORT_SYMBOL(msm_audio_volume_update);

Hrm?

> +			unsigned id = msg[2];
> +			unsigned idx = msg[3] - 1;
> +			if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
> +				printk(KERN_ERR "bogus id\n");
> +				break;

With stuff like this displaying what the bogus IDs are would be useful.

> +			/* Update with actual sent buffer size */
> +			if (prtd->out[idx].used != BUF_INVALID_LEN)
> +				prtd->pcm_irq_pos += prtd->out[idx].used;
> +
> +			if (prtd->pcm_irq_pos > prtd->pcm_size)
> +				prtd->pcm_irq_pos = prtd->pcm_count;

This looks suspicious - it looks like what's going on is that you're
getting a notification from the DSP that it has consumed a data buffer
but this might go out of bounds and get clamped.

> +			if (prtd->ops->playback)
> +				prtd->ops->playback(prtd);
> +
> +			spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
> +			if (prtd->running) {
> +				prtd->out[idx].used = 0;
> +				frame = prtd->out + prtd->out_tail;
> +				if (frame->used) {
> +					audio_dsp_send_buffer(prtd,
> +							      prtd->out_tail,
> +							      frame->used);
> +					prtd->out_tail ^= 1;

I've got a feeling that this code would be a lot easier to follow if
you used a linked list of buffers.  You could statically allocate all the
buffers still, but it'd make it much more explicit what was going on if
you had a list of buffers queued for transmission to the DSP and a list
of free buffers.

Given what it looks like this is doing I'd really expect
snd_pcm_period_elapsed to be called directly from here - the playback
and capture code paths appear to be completely separate and the
indirections you're using appear not to be needed.  I'd also expect
it to be called after you've finished updating the buffers rather than
before, especially given that you appear to call it outside the lock on
buffer updates.

> +				} else {
> +					prtd->out_needed++;
> +				}
> +				wake_up(&the_locks.write_wait);

Why this?

> +	if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
> +		prtd->out_buffer_size = PLAYBACK_DMASZ;
> +		prtd->out_sample_rate = 44100;
> +		prtd->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
> +		prtd->out_weight = 100;

You're not setting any 

> +int alsa_audio_configure(struct msm_audio *prtd)
> +{
> +	struct audmgr_config cfg;
> +	int rc;
> +
> +	if (prtd->enabled)
> +		return 0;
> +
> +	/* refuse to start if we're not ready with first buffer */
> +	if (!prtd->out[0].used)
> +		return -EIO;
> +
> +	cfg.tx_rate = 0;
> +	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;

Your code appears to hard code both 44.1k and 48k inconsistently.

> +		audmgr_disable(&prtd->audmgr);
> +		return -ENODEV;
> +	}
> +
> +	prtd->enabled = 1;
> +	return 0;
> +}
> +EXPORT_SYMBOL(alsa_audio_configure);

This looks extremely suspect...

> +ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
> +			  size_t count, loff_t *pos)
> +{
> +	unsigned long flag;
> +	const char __user *start = buf;
> +	struct buffer *frame;
> +	size_t xfer;
> +	int rc = 0;
> +
> +	mutex_lock(&the_locks.write_lock);
> +	while (count > 0) {
> +		frame = prtd->out + prtd->out_head;
> +		rc = wait_event_interruptible(the_locks.write_wait,
> +					      (frame->used == 0)
> +					      || (prtd->stopped));
> +		if (rc < 0)
> +			break;
> +		if (prtd->stopped) {
> +			rc = -EBUSY;
> +			break;
> +		}
> +		xfer = count > frame->size ? frame->size : count;
> +		if (copy_from_user(frame->data, buf, xfer)) {
> +			rc = -EFAULT;
> +			break;
> +		}
> +		frame->used = xfer;
> +		prtd->out_head ^= 1;
> +		count -= xfer;
> +		buf += xfer;
> +
> +		spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
> +		frame = prtd->out + prtd->out_tail;
> +		if (frame->used && prtd->out_needed) {
> +			audio_dsp_send_buffer(prtd, prtd->out_tail,
> +					      frame->used);
> +			prtd->out_tail ^= 1;

These ^s really don't help legibility.

> +			prtd->out_needed--;
> +		}
> +		spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
> +	}
> +	mutex_unlock(&the_locks.write_lock);
> +	if (buf > start)
> +		return buf - start;
> +	return rc;
> +}
> +EXPORT_SYMBOL(alsa_send_buffer);

...as does this.  There should be no need to export all this stuff, and
if you are exporting it it ought to be _GPL since all the ASoC APIs are
_GPL.

I'd also really like to see some explanation of what the locking scheme
is supposed to be - I can't quite follow what's supposed to be protected
against what and when but I suspect there's cases where either read or
write lock is taken and the_locks.lock is really needed.

> +EXPORT_SYMBOL(alsa_audio_disable);

> +#include <../arch/arm/mach-msm/qdsp5/adsp.h>
> +#include <../arch/arm/mach-msm/qdsp5/audmgr.h>

Put these in an include directory.

> +#define FRAME_NUM               (8)
> +#define FRAME_SIZE              (2052 * 2)
> +#define MONO_DATA_SIZE          (2048)
> +#define STEREO_DATA_SIZE        (MONO_DATA_SIZE * 2)
> +#define CAPTURE_DMASZ           (FRAME_SIZE * FRAME_NUM)
> +
> +#define BUFSZ			(960 * 5)
> +#define PLAYBACK_DMASZ 		(BUFSZ * 2)

All this stuff needs namespacing.

> +/* Support unconventional sample rates 12000, 24000 as well */
> +#define USE_RATE                \
> +			(SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)

Your code doesn't appear to actually cope with all these rates.  Also,
these ought to be pushed down into the drivers rather than exported in
the header file - there's no need for other drivers to see them.

> +static int snd_msm_volume_put(struct snd_kcontrol *kcontrol,
> +				struct snd_ctl_elem_value *ucontrol)
> +{
> +	int change;
> +	int volume;
> +
> +	volume = ucontrol->value.integer.value[0];
> +	spin_lock_irq(&the_locks.mixer_lock);
> +	change = (msm_vol_ctl.volume != volume);
> +	if (change) {
> +		msm_vol_ctl.update = 1;
> +		msm_vol_ctl.volume = volume;
> +	}
> +	spin_unlock_irq(&the_locks.mixer_lock);

This doesn't actually appear to do anything to propagate the changes to
the DSP?

> +static struct snd_kcontrol_new snd_msm_controls[] = {
> +	MSM_EXT_TLV("PCM Playback Volume", 0, snd_msm_volume_info, \
> +	snd_msm_volume_get, snd_msm_volume_put, 0, db_scale_linear),
> +	MSM_EXT("device", 1, snd_msm_device_info, snd_msm_device_get, \
> +						 snd_msm_device_put, 0),
> +};

I have no idea what "device" is supposed to be.

> +static struct snd_soc_dai_link msm_dai = {
> +	.name = "ASOC",
> +	.stream_name = "ASOC",
> +	.codec_dai = &msm_dais[0],
> +	.cpu_dai = &msm_dais[1],
> +	.init	= msm_soc_dai_init,
> +};

Please pick some human readable names describing the setup (eg, "MSM7k
internal CODEC").

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora
  2009-11-13 14:50           ` Mark Brown
@ 2009-11-15 20:06             ` GNUtoo
  2009-11-16 11:25               ` Mark Brown
  2009-11-29 23:16             ` GNUtoo
  1 sibling, 1 reply; 19+ messages in thread
From: GNUtoo @ 2009-11-15 20:06 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, pavel

On Fri, 2009-11-13 at 14:50 +0000, Mark Brown wrote:
> On Sun, Nov 08, 2009 at 11:46:10PM +0100, Denis 'GNUtoo' Carikli wrote:
> 
> Please do try to rememeber to CC maintainers on patches...
> 
> I've read some, but not all of this since I really can't follow how the
> code is supposed to be constructed.  At the minute there doesn't feel
> like there's enough abstraction between the various parts of the code,
> with lots of things cropping up in unexpected places and making it
> harder to follow.
> 
> It would probably be useful to refactor things so that you've got a
> support layer for the DSP that deals with any resource sharing issues
> and then build more standard-looking CODEC, DAI and DMA drivers (the DAI
> driver would probably be largely empty, I guess) with a machine driver
> gluing them together.
> 
> > it still has serious runtime problems such as:
> > *Can produce kernel oops under theses conditions:
> >  start alsamixer and if the second bar is on 0 or 4,
> >  so it can play music with aplay,then increase the routing alsamixer bar
> >  to the max.
> >  Then decrease the routing bar to 4 or less
> 
> What are "the second bar" and "routing bar"?  Remember, most of the
> people reading your mail will never have seen your system running.
> 
> > +config SND_MSM_DAI_SOC
> > +	tristate "SoC CPU/CODEC DAI for the MSM chip"
> > +	depends on SND_MSM_SOC || SND_QSD_SOC
> > +	help
> > +	 To add support for ALSA PCM driver for MSM board.
> 
> No need to make this one uer visible.
> 
> > +
> > +config SND_MSM_SOC_MSM7K
> > +        tristate "SoC Audio support for MSM7K"
> > +        depends on SND_MSM_SOC
> 
> Or this.  I know some architectures do this but we should probably just
> move them to visibly select only boards.
> 
> > +	codec->name = "MSM-CARD";
> 
> Probably something like "MSM7xxx internal CODEC" or similar.
> 
> > +static int __init msm_dai_init(void)
> > +{
> > +	return snd_soc_register_dais(msm_dais, ARRAY_SIZE(msm_dais));
> > +}
> > +
> > +static void __exit msm_dai_exit(void)
> > +{
> > +	snd_soc_unregister_dais(msm_dais, ARRAY_SIZE(msm_dais));
> > +}
> 
> Your DAIs ought to be registered as platform devices under arch/arm,
> probe as normal platform devices and then register the DAIs when these
> probe.
> 
> > +#define audio_send_queue_recbs(prtd, cmd, len) \
> > +	msm_adsp_write(prtd->audrec, QDSP_uPAudRecBitStreamQueue, cmd, len)
> > +#define audio_send_queue_rec(prtd, cmd, len) \
> > +	msm_adsp_write(prtd->audrec, QDSP_uPAudRecCmdQueue, cmd, len)
> 
> Inline functions, please.
> 
> > +int msm_audio_volume_update(unsigned id,
> > +				int volume, int pan)
> > +{
> > +	unsigned vol_raw;
> > +
> > +	vol_raw = compute_db_raw(volume);
> > +	printk(KERN_INFO "volume: %8x vol_raw: %8x \n", volume, vol_raw);
> > +	return audpp_set_volume_and_pan(id, vol_raw, pan);
> > +}
> > +EXPORT_SYMBOL(msm_audio_volume_update);
> 
> Hrm?
> 
> > +			unsigned id = msg[2];
> > +			unsigned idx = msg[3] - 1;
> > +			if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
> > +				printk(KERN_ERR "bogus id\n");
> > +				break;
> 
> With stuff like this displaying what the bogus IDs are would be useful.
> 
> > +			/* Update with actual sent buffer size */
> > +			if (prtd->out[idx].used != BUF_INVALID_LEN)
> > +				prtd->pcm_irq_pos += prtd->out[idx].used;
> > +
> > +			if (prtd->pcm_irq_pos > prtd->pcm_size)
> > +				prtd->pcm_irq_pos = prtd->pcm_count;
> 
> This looks suspicious - it looks like what's going on is that you're
> getting a notification from the DSP that it has consumed a data buffer
> but this might go out of bounds and get clamped.
> 
> > +			if (prtd->ops->playback)
> > +				prtd->ops->playback(prtd);
> > +
> > +			spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
> > +			if (prtd->running) {
> > +				prtd->out[idx].used = 0;
> > +				frame = prtd->out + prtd->out_tail;
> > +				if (frame->used) {
> > +					audio_dsp_send_buffer(prtd,
> > +							      prtd->out_tail,
> > +							      frame->used);
> > +					prtd->out_tail ^= 1;
> 
> I've got a feeling that this code would be a lot easier to follow if
> you used a linked list of buffers.  You could statically allocate all the
> buffers still, but it'd make it much more explicit what was going on if
> you had a list of buffers queued for transmission to the DSP and a list
> of free buffers.
> 
> Given what it looks like this is doing I'd really expect
> snd_pcm_period_elapsed to be called directly from here - the playback
> and capture code paths appear to be completely separate and the
> indirections you're using appear not to be needed.  I'd also expect
> it to be called after you've finished updating the buffers rather than
> before, especially given that you appear to call it outside the lock on
> buffer updates.
> 
> > +				} else {
> > +					prtd->out_needed++;
> > +				}
> > +				wake_up(&the_locks.write_wait);
> 
> Why this?
> 
> > +	if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
> > +		prtd->out_buffer_size = PLAYBACK_DMASZ;
> > +		prtd->out_sample_rate = 44100;
> > +		prtd->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
> > +		prtd->out_weight = 100;
> 
> You're not setting any 
> 
> > +int alsa_audio_configure(struct msm_audio *prtd)
> > +{
> > +	struct audmgr_config cfg;
> > +	int rc;
> > +
> > +	if (prtd->enabled)
> > +		return 0;
> > +
> > +	/* refuse to start if we're not ready with first buffer */
> > +	if (!prtd->out[0].used)
> > +		return -EIO;
> > +
> > +	cfg.tx_rate = 0;
> > +	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
> 
> Your code appears to hard code both 44.1k and 48k inconsistently.
> 
> > +		audmgr_disable(&prtd->audmgr);
> > +		return -ENODEV;
> > +	}
> > +
> > +	prtd->enabled = 1;
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(alsa_audio_configure);
> 
> This looks extremely suspect...
> 
> > +ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
> > +			  size_t count, loff_t *pos)
> > +{
> > +	unsigned long flag;
> > +	const char __user *start = buf;
> > +	struct buffer *frame;
> > +	size_t xfer;
> > +	int rc = 0;
> > +
> > +	mutex_lock(&the_locks.write_lock);
> > +	while (count > 0) {
> > +		frame = prtd->out + prtd->out_head;
> > +		rc = wait_event_interruptible(the_locks.write_wait,
> > +					      (frame->used == 0)
> > +					      || (prtd->stopped));
> > +		if (rc < 0)
> > +			break;
> > +		if (prtd->stopped) {
> > +			rc = -EBUSY;
> > +			break;
> > +		}
> > +		xfer = count > frame->size ? frame->size : count;
> > +		if (copy_from_user(frame->data, buf, xfer)) {
> > +			rc = -EFAULT;
> > +			break;
> > +		}
> > +		frame->used = xfer;
> > +		prtd->out_head ^= 1;
> > +		count -= xfer;
> > +		buf += xfer;
> > +
> > +		spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
> > +		frame = prtd->out + prtd->out_tail;
> > +		if (frame->used && prtd->out_needed) {
> > +			audio_dsp_send_buffer(prtd, prtd->out_tail,
> > +					      frame->used);
> > +			prtd->out_tail ^= 1;
> 
> These ^s really don't help legibility.
> 
> > +			prtd->out_needed--;
> > +		}
> > +		spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
> > +	}
> > +	mutex_unlock(&the_locks.write_lock);
> > +	if (buf > start)
> > +		return buf - start;
> > +	return rc;
> > +}
> > +EXPORT_SYMBOL(alsa_send_buffer);
> 
> ...as does this.  There should be no need to export all this stuff, and
> if you are exporting it it ought to be _GPL since all the ASoC APIs are
> _GPL.
> 
> I'd also really like to see some explanation of what the locking scheme
> is supposed to be - I can't quite follow what's supposed to be protected
> against what and when but I suspect there's cases where either read or
> write lock is taken and the_locks.lock is really needed.
> 
> > +EXPORT_SYMBOL(alsa_audio_disable);
> 
> > +#include <../arch/arm/mach-msm/qdsp5/adsp.h>
> > +#include <../arch/arm/mach-msm/qdsp5/audmgr.h>
> 
> Put these in an include directory.
> 
> > +#define FRAME_NUM               (8)
> > +#define FRAME_SIZE              (2052 * 2)
> > +#define MONO_DATA_SIZE          (2048)
> > +#define STEREO_DATA_SIZE        (MONO_DATA_SIZE * 2)
> > +#define CAPTURE_DMASZ           (FRAME_SIZE * FRAME_NUM)
> > +
> > +#define BUFSZ			(960 * 5)
> > +#define PLAYBACK_DMASZ 		(BUFSZ * 2)
> 
> All this stuff needs namespacing.
> 
> > +/* Support unconventional sample rates 12000, 24000 as well */
> > +#define USE_RATE                \
> > +			(SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
> 
> Your code doesn't appear to actually cope with all these rates.  Also,
> these ought to be pushed down into the drivers rather than exported in
> the header file - there's no need for other drivers to see them.
> 
> > +static int snd_msm_volume_put(struct snd_kcontrol *kcontrol,
> > +				struct snd_ctl_elem_value *ucontrol)
> > +{
> > +	int change;
> > +	int volume;
> > +
> > +	volume = ucontrol->value.integer.value[0];
> > +	spin_lock_irq(&the_locks.mixer_lock);
> > +	change = (msm_vol_ctl.volume != volume);
> > +	if (change) {
> > +		msm_vol_ctl.update = 1;
> > +		msm_vol_ctl.volume = volume;
> > +	}
> > +	spin_unlock_irq(&the_locks.mixer_lock);
> 
> This doesn't actually appear to do anything to propagate the changes to
> the DSP?
> 
> > +static struct snd_kcontrol_new snd_msm_controls[] = {
> > +	MSM_EXT_TLV("PCM Playback Volume", 0, snd_msm_volume_info, \
> > +	snd_msm_volume_get, snd_msm_volume_put, 0, db_scale_linear),
> > +	MSM_EXT("device", 1, snd_msm_device_info, snd_msm_device_get, \
> > +						 snd_msm_device_put, 0),
> > +};
> 
> I have no idea what "device" is supposed to be.
> 
> > +static struct snd_soc_dai_link msm_dai = {
> > +	.name = "ASOC",
> > +	.stream_name = "ASOC",
> > +	.codec_dai = &msm_dais[0],
> > +	.cpu_dai = &msm_dais[1],
> > +	.init	= msm_soc_dai_init,
> > +};
> 
> Please pick some human readable names describing the setup (eg, "MSM7k
> internal CODEC").

Thanks a lot!!!
I'll try to fix most of the problems and resend a patch,I'll also
continue the debugging...which will take some time....

About the debugging:
*I noticed that if I change the .buffer_bytes_max to 4800 aplay doesn't
work anymore...I'll try to find the good values...
*I also noticed that aplay doesn't use the SNDRV_PCM_IOCTL_STATUS which
would explain why aplay works and not mplayer... so I'll try to fix that
too...

Denis.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora
  2009-11-15 20:06             ` GNUtoo
@ 2009-11-16 11:25               ` Mark Brown
  2010-01-12 17:48                 ` GNUtoo
  0 siblings, 1 reply; 19+ messages in thread
From: Mark Brown @ 2009-11-16 11:25 UTC (permalink / raw)
  To: GNUtoo; +Cc: alsa-devel, pavel

On Sun, Nov 15, 2009 at 09:06:40PM +0100, GNUtoo wrote:

> About the debugging:
> *I noticed that if I change the .buffer_bytes_max to 4800 aplay doesn't
> work anymore...I'll try to find the good values...
> *I also noticed that aplay doesn't use the SNDRV_PCM_IOCTL_STATUS which
> would explain why aplay works and not mplayer... so I'll try to fix that
> too...

These both sound like the code for managing pushing of the buffers to
the DSP - like I said, it looks suspect on reading too so I'd not be
surprised if fixing the comprehensibility issues also make things work
better.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora
  2009-11-13 14:50           ` Mark Brown
  2009-11-15 20:06             ` GNUtoo
@ 2009-11-29 23:16             ` GNUtoo
  2009-11-29 23:43               ` GNUtoo
  2009-11-30 11:20               ` [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora Mark Brown
  1 sibling, 2 replies; 19+ messages in thread
From: GNUtoo @ 2009-11-29 23:16 UTC (permalink / raw)
  To: alsa-devel, pavel

On Fri, 2009-11-13 at 14:50 +0000, Mark Brown wrote:
> > +                     /* Update with actual sent buffer size */
> > +                     if (prtd->out[idx].used != BUF_INVALID_LEN)
> > +                             prtd->pcm_irq_pos +=
> prtd->out[idx].used;
> > +
> > +                     if (prtd->pcm_irq_pos > prtd->pcm_size)
> > +                             prtd->pcm_irq_pos = prtd->pcm_count;
> 
> This looks suspicious - it looks like what's going on is that you're
> getting a notification from the DSP that it has consumed a data buffer
> but this might go out of bounds and get clamped.

The first time that it's called prtd->out[idx].used = BUF_INVALID_LEN so
it's skipped(it's the same first bogus time than in my previous mails).

The second time prtd->out[idx].used is equal to the period_bytes_max 
which is equal to the .buffer_bytes_max / 2
prtd->pcm_irq_pos is 0 then is incremented to prtd->out[idx].used
So it's clamped only the first time.


By the way I've used that info to skip it in the alsa_send_buffer
so it looks like this:
in alsa_send_buffer I've tried to add a check for the invalid len before
of after the "if (frame->used && prtd->out_needed) {"

here an example of it beeing before "if (frame->used &&
prtd->out_needed) {"
@@ -411,6 +418,10 @@ ssize_t alsa_send_buffer(struct msm_audio *prtd,
const char __user *buf,
 
                spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
                frame = prtd->out + prtd->out_tail;
+               if (frame->used == BUF_INVALID_LEN){
+
spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
+                       break;
+               }
                if (frame->used && prtd->out_needed) {
                        audio_dsp_send_buffer(prtd, prtd->out_tail,
                                              frame->used);
@@ -418,10 +429,12 @@ ssize_t alsa_send_buffer(struct msm_audio *prtd,
const char __user *buf,
                        prtd->out_needed--;
                }

                spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
for the try where it was after the spin_unlock was not necessary because
it was put just after the spin_unlock

Then...
mplayer said:
alsa-init: got buffersize=19200
alsa-init: got period size 600
and it played a song for half a second
and then the kernel panicked

here the code of mplayer:
      // gets buffersize for control
      if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams,
&bufsize)) < 0)
        {
          mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBufferSize,
snd_strerror(err));
          return 0;
        }
      else {
        ao_data.buffersize = bufsize * bytes_per_sample;
          mp_msg(MSGT_AO,MSGL_V,"alsa-init: got buffersize=%i\n",
ao_data.buffersize);
      }

      if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams,
&chunk_size, NULL)) < 0) {
        mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetPeriodSize,
snd_strerror(err));
        return 0;
      } else {
        mp_msg(MSGT_AO,MSGL_V,"alsa-init: got period size %li\n",
chunk_size);
      }
      ao_data.outburst = chunk_size * bytes_per_sample;


a strace shows that:

ioctl(0, TIOCGWINSZ, {ws_row=51, ws_col=202, ws_xpixel=0, ws_ypixel=0})
= 0
) = 401, "A:   0.0 (00.0) of 2.0 (02.0) ??"..., 40A:   0.0 (00.0) of 2.0
(02.0) ??,?% 
gettimeofday({1259531032, 572021}, NULL) = 0
select(1, [0], NULL, NULL, {0, 0})      = 0SNDRV_PCM_IOCTL_STATUS
(Timeout)
ioctl(6, 0x806c4120, 0xbee5dac0)        = 0
nanosleep({0, 27000000}, NULL)          = 0
ioctl(6, 0x806c4120, 0xbee5dac0)        = 0
nanosleep({0, 27000000}, Read from remote host 192.168.0.202: Connection
reset by peer
Connection to 192.168.0.202 closed.

0x806c4120 corresponds to A 0x20 that corresponds to
SNDRV_PCM_IOCTL_STATUS = _IOR('A', 0x20, struct snd_pcm_status) in
asound.h

After that I moved the snd_pcm_period_elapsed like this:

@@ -154,7 +158,10 @@ void alsa_dsp_event(void *data, unsigned id,
uint16_t *msg)
                                wake_up(&the_locks.write_wait);
                        }

spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
+
snd_pcm_period_elapsed(prtd->playback_substream);
                        break;

and removed it from the old location: 

diff --git a/sound/soc/msm/msm7k-pcm.c b/sound/soc/msm/msm7k-pcm.c
index 38e8283..3e54184 100644
--- a/sound/soc/msm/msm7k-pcm.c
+++ b/sound/soc/msm/msm7k-pcm.c
@@ -152,8 +152,6 @@ static struct snd_pcm_hw_constraint_list
constraints_sample_rates = {
 
 static void playback_event_handler(void *data)
 {
-       struct msm_audio *prtd = data;
-       snd_pcm_period_elapsed(prtd->playback_substream);
 }

If I remember well aplay doesn't use the SNDRV_PCM_IOCTL_STATUS

Denis.

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora
  2009-11-29 23:16             ` GNUtoo
@ 2009-11-29 23:43               ` GNUtoo
  2009-11-30  5:08                 ` usb- interface - HID type M R Swami Reddy
  2009-11-30 11:20               ` [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora Mark Brown
  1 sibling, 1 reply; 19+ messages in thread
From: GNUtoo @ 2009-11-29 23:43 UTC (permalink / raw)
  To: alsa-devel; +Cc: pavel

I've tried to limit to 4800 and now it plays for one quarter of seconds
then loop on the status...and so stops playing...

Denis.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* usb- interface - HID type
  2009-11-29 23:43               ` GNUtoo
@ 2009-11-30  5:08                 ` M R Swami Reddy
  2009-11-30  8:19                   ` Daniel Mack
  2009-11-30 12:46                   ` Clemens Ladisch
  0 siblings, 2 replies; 19+ messages in thread
From: M R Swami Reddy @ 2009-11-30  5:08 UTC (permalink / raw)
  To: alsa-devel

Hello,
I have a sound card with I2C/PCM interface supported. I am in the 
process of evaluate
the same using USB interface with HID interface class (ie 
bInterfaceClass ->3 Human Interface Device).
Could you please suggest, if the usb interface HID class could be used 
for sending Audio and PCM
signals?

Thanks
Swami

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: usb- interface - HID type
  2009-11-30  5:08                 ` usb- interface - HID type M R Swami Reddy
@ 2009-11-30  8:19                   ` Daniel Mack
  2009-11-30 12:46                   ` Clemens Ladisch
  1 sibling, 0 replies; 19+ messages in thread
From: Daniel Mack @ 2009-11-30  8:19 UTC (permalink / raw)
  To: M R Swami Reddy; +Cc: alsa-devel

On Mon, Nov 30, 2009 at 10:38:21AM +0530, M R Swami Reddy wrote:
> I have a sound card with I2C/PCM interface supported. I am in the 
> process of evaluate
> the same using USB interface with HID interface class (ie 
> bInterfaceClass ->3 Human Interface Device).
> Could you please suggest, if the usb interface HID class could be used 
> for sending Audio and PCM
> signals?

As of the USB logic, the ALSA driver should grab the audio interface
while at the same time, the HID driver uses the other interface.
Assuming that both interfaces are in the same USB config.

HTH,
Daniel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora
  2009-11-29 23:16             ` GNUtoo
  2009-11-29 23:43               ` GNUtoo
@ 2009-11-30 11:20               ` Mark Brown
  1 sibling, 0 replies; 19+ messages in thread
From: Mark Brown @ 2009-11-30 11:20 UTC (permalink / raw)
  To: GNUtoo; +Cc: alsa-devel, pavel

On Mon, Nov 30, 2009 at 12:16:42AM +0100, GNUtoo wrote:
> On Fri, 2009-11-13 at 14:50 +0000, Mark Brown wrote:

Please remember to keep people CCed on mails.

> > This looks suspicious - it looks like what's going on is that you're
> > getting a notification from the DSP that it has consumed a data buffer
> > but this might go out of bounds and get clamped.

> The first time that it's called prtd->out[idx].used = BUF_INVALID_LEN so
> it's skipped(it's the same first bogus time than in my previous mails).

My more general comment on this stuff was that all the buffer management
code was extremely difficult to follow and hence likely to have errors.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: usb- interface - HID type
  2009-11-30  5:08                 ` usb- interface - HID type M R Swami Reddy
  2009-11-30  8:19                   ` Daniel Mack
@ 2009-11-30 12:46                   ` Clemens Ladisch
  1 sibling, 0 replies; 19+ messages in thread
From: Clemens Ladisch @ 2009-11-30 12:46 UTC (permalink / raw)
  To: M R Swami Reddy; +Cc: alsa-devel

M R Swami Reddy wrote:
> Could you please suggest, if the usb interface HID class could be used 
> for sending Audio and PCM signals?

No; audio data should be transferred using isochronous transfers, and
the HID class does not use those.

Is there any reason why you cannot use a standard audio class interface?


Best regards,
Clemens

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora
  2009-11-16 11:25               ` Mark Brown
@ 2010-01-12 17:48                 ` GNUtoo
  2010-01-17 21:18                   ` gnutoo
  0 siblings, 1 reply; 19+ messages in thread
From: GNUtoo @ 2010-01-12 17:48 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, pavel

Recently I looked again at the code.
And I found this:

prtd->out[0].used = BUF_INVALID_LEN;
prtd->out_head = 1; /* point to second buffer on startup */

in msm_pcm_open in msm7k-pcm.c


So here how it works:
when the sound card is opened the fist buffer is assigned to
BUF_INVALID_LEN and is skipped(prtd->out_head = 1).

Then at a point alsa_send_buffer (in msm-pcm.c) is called.
But because mplayer uses a bigger buffer it goes this way:
The first run goes fine:
rc = wait_event_interruptible(the_locks.write_wait, (frame->used == 0)
|| (prtd->stopped)); is passed.
Then in "xfer = count > frame->size ? frame->size : count;",the minimum
between frame size and count is assigned to xfer.
Then in copy_from_user(frame->data, buf, xfer) the audio frame is copied
from userspace.
Then xfer is assigned to frame->used
Then "prtd->out_head ^= 1;" needs some little explanations:
There are 2 buffers prtd->out[0] and prtd->out[1]
And both out_head and out_tail can only be 0 or 1
So when prtd->out_head is 0,prtd->out_head ^= 1 changes to 1 into a 0
and vice versa.

Note that I recently changed things like  
frame = prtd->out + prtd->out_tail
into that kind of things:
frame = &prtd->out[prtd->out_tail]
which makes it more Readable,and still works.

prtd->out is a struct buffer which is described in msm-pcm.h:
struct msm_audio {
	struct buffer out[2];
...

the struct buffer is also described in msm-pcm.h like this:
struct buffer {
	void *data;
	unsigned size;
	unsigned used;
	unsigned addr;
};


So...prtd->out_head was 1 because it was assigned to 1 in msm_pcm_open
in msm7k-pcm.c
Now it becomes 0

Then it does that:
count -= xfer;
which doesn't zero  count it because mplayer used some big buffer size

Then it sends the data to the dsp...and doesn't exit the "while (count >
0) {" loop because count is not 0

And Finally it reaches that line a second time: 
"rc = wait_event_interruptible(the_locks.write_wait, (frame->used == 0)
|| (prtd->stopped));"
But...frame->used was, and is still BUF_INVALID_LEN so it blocks.


By the way David Lanzendörfer fixed a lot of issues with kernel
oops/panic with the OSS emulation...and merged the adsp and the alsa
layer in one driver(that means that they are in a same directory and
that the resource sharing issues is gone.)

I bet we are close to something working as mplayer can now work trough
oss emulation or trough sdl(tough there are some buffer underrun problem
sometimes with sdl and nearly all the time with oss)
But we still have some work to do in order to clean the driver and fix
the issues you described before re-submiting it.

Denis.


Appendix:
---------

here's the content of alsa_send_buffer:
size_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
size_t count, loff_t *pos)
{
unsigned long flag;
const char __user *start = buf;
struct buffer *frame;
size_t xfer;
int rc = 0;

mutex_lock(&the_locks.write_lock);
while (count > 0) {
frame = &prtd->out[prtd->out_head];
rc = wait_event_interruptible(the_locks.write_wait, (frame->used == 0)
|| (prtd->stopped));
if (rc < 0) break;
if (prtd->stopped) {
rc = -EBUSY;
break;
}
xfer = count > frame->size ? frame->size : count;
if (copy_from_user(frame->data, buf, xfer)) {
rc = -EFAULT;
break;
}
frame->used = xfer;
prtd->out_head ^= 1;
count -= xfer;
buf += xfer;

spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
frame = &prtd->out[prtd->out_tail];
if (frame->used && prtd->out_needed) {
audio_dsp_send_buffer(prtd, prtd->out_tail, frame->used);
prtd->out_tail ^= 1;
prtd->out_needed--;
}
spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
}
mutex_unlock(&the_locks.write_lock);
if (buf > start)
return buf - start;
return rc;

And here's the content of msm_pcm_open:

static int msm_pcm_open(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct msm_audio *prtd;
	int ret = 0;

	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
	if (prtd == NULL) {
		ret = -ENOMEM;
		return ret;
	}
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		msm_vol_ctl.update = 1; /* Update Volume, with Cached value */
		runtime->hw = msm_pcm_playback_hardware;
		prtd->dir = SNDRV_PCM_STREAM_PLAYBACK;
		prtd->playback_substream = substream;
	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
		runtime->hw = msm_pcm_capture_hardware;
		prtd->dir = SNDRV_PCM_STREAM_CAPTURE;
		prtd->capture_substream = substream;
	}

	ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_sample_rates);
	if (ret < 0) goto out;

	/* Ensure that buffer size is a multiple of period size */
	ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
	if (ret < 0) goto out;

	prtd->ops = &snd_msm_audio_ops;
	prtd->out[0].used = BUF_INVALID_LEN;
	prtd->out_head = 1; /* point to second buffer on startup */
	runtime->private_data = prtd;

	ret = alsa_adsp_configure(prtd);
	if (ret) goto out;
	copy_count = 0;
	return 0;

 out:
	kfree(prtd);
	return ret;
}

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora
  2010-01-12 17:48                 ` GNUtoo
@ 2010-01-17 21:18                   ` gnutoo
  0 siblings, 0 replies; 19+ messages in thread
From: gnutoo @ 2010-01-17 21:18 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, pavel

Someone named Thingol in #alsa helped me and told me how to fix it:

<Thingol> if so, then maybe it would help to move the call to
alsa_audio_configure (probably before the end of that while loop), but
you have to make sure it only gets called once.

I did that and it unblocked mplayer...
Audio now works nearly flawlessly(you can still hear some cracks but
that's nearly not noticeable)

We also need to look in the silence callback because for fixing
something, David Lanzendörfer(who fixed the oss emulations problems)
ifdefed the whole content of snd_pcm_format_set_silence.
(maybe that's why there are some cracks in the audio...)

Denis.

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2010-01-17 21:18 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-03 16:02 MSM DSP GNUtoo
2009-11-04 10:49 ` Mark Brown
2009-11-04 21:29   ` GNUtoo
2009-11-05 15:17   ` [PATCH] " Denis 'GNUtoo' Carikli
2009-11-05 15:23     ` Mark Brown
2009-11-05 15:31       ` GNUtoo
2009-11-08 22:46         ` [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora Denis 'GNUtoo' Carikli
2009-11-09  8:42           ` Pavel Machek
2009-11-13 14:50           ` Mark Brown
2009-11-15 20:06             ` GNUtoo
2009-11-16 11:25               ` Mark Brown
2010-01-12 17:48                 ` GNUtoo
2010-01-17 21:18                   ` gnutoo
2009-11-29 23:16             ` GNUtoo
2009-11-29 23:43               ` GNUtoo
2009-11-30  5:08                 ` usb- interface - HID type M R Swami Reddy
2009-11-30  8:19                   ` Daniel Mack
2009-11-30 12:46                   ` Clemens Ladisch
2009-11-30 11:20               ` [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.