From: Knut Petersen <Knut_Petersen@t-online.de>
To: Jaroslav Kysela <perex@perex.cz>
Cc: Takashi Iwai <tiwai@suse.de>, alsa-devel@alsa-project.org
Subject: [PATCH] rme96 synchronization support
Date: Mon, 05 Aug 2013 14:36:37 +0200 [thread overview]
Message-ID: <51FF9C55.80701@t-online.de> (raw)
[-- Attachment #1: Type: text/plain, Size: 598 bytes --]
Hi everybody!
As I need support for synchronized pcm streams on an
RME Digi96/8 PAD I wrote the attached patch.
It does work here. My own program, trying to get synchronized
capture/playback streams, succeeds.
Programs that use either the playback or the capture part of the
hardware are not affected by start / pause/ stop operations of applications
using the other part of the hardware (tested with aplay, arecord, and ecasound).
I wrote the test code and the patch, so it is not impossible that I acted on
wrong assumptions in both places. Please have a close look at the patch.
cu,
knut
[-- Attachment #2: 0001-alsa-Add-support-for-synchronized-start-pause-stop.patch --]
[-- Type: text/x-patch, Size: 8810 bytes --]
>From 861be0a7216b9adfdc1632e6812a71417819c7f0 Mon Sep 17 00:00:00 2001
From: Knut Petersen <Knut_Petersen@t-online.de>
Date: Mon, 5 Aug 2013 13:47:59 +0200
Subject: [PATCH] alsa: Add support for synchronized start/pause/stop of pcm
streams to the rme96 driver.
Signed-off-by: Knut Petersen <Knut_Petersen@t-online.de>
---
sound/pci/rme96.c | 110 ++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 86 insertions(+), 24 deletions(-)
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 5fb88ac..f7e3bd7 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -344,6 +344,7 @@ static struct snd_pcm_hardware snd_rme96_playback_spdif_info =
{
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -373,6 +374,7 @@ static struct snd_pcm_hardware snd_rme96_capture_spdif_info =
{
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -402,6 +404,7 @@ static struct snd_pcm_hardware snd_rme96_playback_adat_info =
{
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -427,6 +430,7 @@ static struct snd_pcm_hardware snd_rme96_capture_adat_info =
{
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -1045,53 +1049,93 @@ snd_rme96_capture_hw_params(struct snd_pcm_substream *substream,
}
static void
-snd_rme96_playback_start(struct rme96 *rme96,
+snd_rme96_playcap_start(struct rme96 *rme96,
int from_pause)
{
if (!from_pause) {
writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
+ writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
}
-
- rme96->wcreg |= RME96_WCR_START;
+ rme96->wcreg |= (RME96_WCR_START | RME96_WCR_START_2);
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
static void
+snd_rme96_playback_start(struct rme96 *rme96,
+ int from_pause)
+{
+ if ((rme96->playback_substream && rme96->capture_substream) &&
+ (rme96->playback_substream->group == rme96->capture_substream->group)) {
+ snd_rme96_playcap_start(rme96,from_pause);
+ } else {
+ if (!from_pause) {
+ writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
+ }
+ rme96->wcreg |= RME96_WCR_START;
+ writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ }
+}
+
+static void
snd_rme96_capture_start(struct rme96 *rme96,
int from_pause)
{
- if (!from_pause) {
- writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
+ if ((rme96->playback_substream && rme96->capture_substream) &&
+ (rme96->playback_substream->group == rme96->capture_substream->group)) {
+ snd_rme96_playcap_start(rme96,from_pause);
+ } else {
+ if (!from_pause) {
+ writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
+ }
+ rme96->wcreg |= RME96_WCR_START_2;
+ writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
-
- rme96->wcreg |= RME96_WCR_START_2;
- writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
static void
-snd_rme96_playback_stop(struct rme96 *rme96)
+snd_rme96_playcap_stop(struct rme96 *rme96)
{
- /*
- * Check if there is an unconfirmed IRQ, if so confirm it, or else
- * the hardware will not stop generating interrupts
- */
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
if (rme96->rcreg & RME96_RCR_IRQ) {
writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ);
- }
- rme96->wcreg &= ~RME96_WCR_START;
+ }
+ if (rme96->rcreg & RME96_RCR_IRQ_2) {
+ writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ);
+ }
+ rme96->wcreg &= ~(RME96_WCR_START | RME96_WCR_START_2);
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
static void
+snd_rme96_playback_stop(struct rme96 *rme96)
+{
+ if ((rme96->playback_substream && rme96->capture_substream) &&
+ (rme96->playback_substream->group == rme96->capture_substream->group)) {
+ snd_rme96_playcap_stop(rme96);
+ } else {
+ rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ if (rme96->rcreg & RME96_RCR_IRQ) {
+ writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ);
+ }
+ rme96->wcreg &= ~RME96_WCR_START;
+ writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ }
+}
+
+static void
snd_rme96_capture_stop(struct rme96 *rme96)
{
- rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
- if (rme96->rcreg & RME96_RCR_IRQ_2) {
- writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ);
- }
- rme96->wcreg &= ~RME96_WCR_START_2;
- writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ if ((rme96->playback_substream && rme96->capture_substream) &&
+ (rme96->playback_substream->group == rme96->capture_substream->group)) {
+ snd_rme96_playcap_stop(rme96);
+ } else {
+ rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ if (rme96->rcreg & RME96_RCR_IRQ_2) {
+ writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ);
+ }
+ rme96->wcreg &= ~RME96_WCR_START_2;
+ writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ }
}
static irqreturn_t
@@ -1155,6 +1199,7 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream)
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_set_sync(substream);
spin_lock_irq(&rme96->lock);
if (rme96->playback_substream != NULL) {
spin_unlock_irq(&rme96->lock);
@@ -1191,6 +1236,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream)
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_set_sync(substream);
runtime->hw = snd_rme96_capture_spdif_info;
if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG &&
(rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0)
@@ -1222,6 +1268,7 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream)
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_set_sync(substream);
spin_lock_irq(&rme96->lock);
if (rme96->playback_substream != NULL) {
spin_unlock_irq(&rme96->lock);
@@ -1253,6 +1300,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream)
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_set_sync(substream);
runtime->hw = snd_rme96_capture_adat_info;
if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) {
/* makes no sense to use analog input. Note that analog
@@ -1306,7 +1354,7 @@ static int
snd_rme96_capture_close(struct snd_pcm_substream *substream)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
-
+
spin_lock_irq(&rme96->lock);
if (RME96_ISRECORDING(rme96)) {
snd_rme96_capture_stop(rme96);
@@ -1321,7 +1369,7 @@ static int
snd_rme96_playback_prepare(struct snd_pcm_substream *substream)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
-
+
spin_lock_irq(&rme96->lock);
if (RME96_ISPLAYING(rme96)) {
snd_rme96_playback_stop(rme96);
@@ -1335,7 +1383,7 @@ static int
snd_rme96_capture_prepare(struct snd_pcm_substream *substream)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
-
+
spin_lock_irq(&rme96->lock);
if (RME96_ISRECORDING(rme96)) {
snd_rme96_capture_stop(rme96);
@@ -1350,6 +1398,13 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
+ struct snd_pcm_substream *s;
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (snd_pcm_substream_chip(s) == rme96) {
+ snd_pcm_trigger_done(s, substream);
+ }
+ }
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -1393,6 +1448,13 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
+ struct snd_pcm_substream *s;
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (snd_pcm_substream_chip(s) == rme96) {
+ snd_pcm_trigger_done(s, substream);
+ }
+ }
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
--
1.8.1.4
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
next reply other threads:[~2013-08-05 12:36 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-05 12:36 Knut Petersen [this message]
2013-08-05 13:18 ` [PATCH] rme96 synchronization support Clemens Ladisch
2013-08-06 17:42 ` Knut Petersen
2013-08-07 7:08 ` Takashi Iwai
2013-08-08 10:52 ` Knut Petersen
2013-08-13 7:19 ` Takashi Iwai
2013-08-13 10:32 ` Knut Petersen
2013-08-13 10:37 ` Takashi Iwai
2013-08-13 21:12 ` [PATCH] rme96 add stream synchronization and PM support Knut Petersen
2013-08-14 15:06 ` Takashi Iwai
2013-08-15 6:01 ` Knut Petersen
2013-08-15 6:22 ` Takashi Iwai
2013-08-15 7:16 ` Knut Petersen
2013-08-15 8:37 ` Takashi Iwai
2013-08-21 7:44 ` Knut Petersen
2013-08-22 8:53 ` Takashi Iwai
[not found] ` <52160CDE.4070306@t-online.de>
2013-08-22 21:25 ` [PATCH] rme96 Add missing vmalloc.h inclusion Takashi Iwai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=51FF9C55.80701@t-online.de \
--to=knut_petersen@t-online.de \
--cc=alsa-devel@alsa-project.org \
--cc=perex@perex.cz \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.