alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
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 --]



             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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).