From: Knut Petersen <Knut_Petersen@t-online.de>
To: alsa-devel@alsa-project.org
Cc: Takashi Iwai <tiwai@suse.de>, Clemens Ladisch <clemens@ladisch.de>
Subject: Re: [PATCH] rme96 synchronization support
Date: Thu, 08 Aug 2013 12:52:20 +0200 [thread overview]
Message-ID: <52037864.9000205@t-online.de> (raw)
In-Reply-To: <s5h4nb2asg5.wl%tiwai@suse.de>
[-- Attachment #1: Type: text/plain, Size: 113 bytes --]
Hi everybody!
Version 2 of the patch adding pcm stream synchronization support
to the rme96 driver.
cu,
Knut
[-- Attachment #2: 0001-alsa-rme96-Add-support-for-synchronized-start-pause-.patch --]
[-- Type: text/x-patch, Size: 12109 bytes --]
>From 015bc7f9ebcbf01ce209a4f859bbfa9c31885483 Mon Sep 17 00:00:00 2001
From: Knut Petersen <Knut_Petersen@t-online.de>
Date: Thu, 8 Aug 2013 11:59:27 +0200
Subject: [PATCH] alsa/rme96: Add support for synchronized start/pause/stop of
pcm streams to the rme96 driver. 2nd version.
Signed-off-by: Knut Petersen <Knut_Petersen@t-online.de>
---
sound/pci/rme96.c | 145 +++++++++++++++++++++++++++++++++---------------------
1 file changed, 90 insertions(+), 55 deletions(-)
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 5fb88ac..35651c5 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -198,6 +198,24 @@ MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard.");
#define RME96_AD1852_VOL_BITS 14
#define RME96_AD1855_VOL_BITS 10
+/* Defines for snd_rme96_trigger */
+#define RME96_TB_START_PLAYBACK 1
+#define RME96_TB_START_CAPTURE 2
+#define RME96_TB_STOP_PLAYBACK 4
+#define RME96_TB_STOP_CAPTURE 8
+#define RME96_TB_RESET_PLAYPOS 16
+#define RME96_TB_RESET_CAPTUREPOS 32
+#define RME96_TB_CLEAR_PLAYBACK_IRQ 64
+#define RME96_TB_CLEAR_CAPTURE_IRQ 128
+#define RME96_RESUME_PLAYBACK (RME96_TB_START_PLAYBACK)
+#define RME96_RESUME_CAPTURE (RME96_TB_START_CAPTURE)
+#define RME96_RESUME_BOTH (RME96_RESUME_PLAYBACK | RME96_RESUME_CAPTURE)
+#define RME96_START_PLAYBACK (RME96_TB_START_PLAYBACK | RME96_TB_RESET_PLAYPOS)
+#define RME96_START_CAPTURE (RME96_TB_START_CAPTURE | RME96_TB_RESET_CAPTUREPOS)
+#define RME96_START_BOTH (RME96_START_PLAYBACK | RME96_START_CAPTURE)
+#define RME96_STOP_PLAYBACK (RME96_TB_STOP_PLAYBACK | RME96_TB_CLEAR_PLAYBACK_IRQ)
+#define RME96_STOP_CAPTURE (RME96_TB_STOP_CAPTURE | RME96_TB_CLEAR_CAPTURE_IRQ)
+#define RME96_STOP_BOTH (RME96_STOP_PLAYBACK | RME96_STOP_CAPTURE)
struct rme96 {
spinlock_t lock;
@@ -344,6 +362,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 +392,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 +422,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 +448,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,54 +1067,43 @@ snd_rme96_capture_hw_params(struct snd_pcm_substream *substream,
}
static void
-snd_rme96_playback_start(struct rme96 *rme96,
- int from_pause)
+snd_rme96_trigger(struct rme96 *rme96,
+ int op)
{
- if (!from_pause) {
+ if (op & RME96_TB_RESET_PLAYPOS) {
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) {
+ if (op & RME96_TB_RESET_CAPTUREPOS) {
writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
}
-
- rme96->wcreg |= RME96_WCR_START_2;
+ if(op & RME96_TB_CLEAR_PLAYBACK_IRQ) {
+ rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ if (rme96->rcreg & RME96_RCR_IRQ) {
+ writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ);
+ }
+ }
+ if(op & RME96_TB_CLEAR_CAPTURE_IRQ) {
+ 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);
+ }
+ }
+ if (op & RME96_TB_START_PLAYBACK) {
+ rme96->wcreg |= RME96_WCR_START;
+ }
+ if (op & RME96_TB_STOP_PLAYBACK) {
+ rme96->wcreg &= ~RME96_WCR_START;
+ }
+ if (op & RME96_TB_START_CAPTURE) {
+ rme96->wcreg |= RME96_WCR_START_2;
+ }
+ if (op & RME96_TB_STOP_CAPTURE) {
+ rme96->wcreg &= ~RME96_WCR_START_2;
+ }
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
-static void
-snd_rme96_playback_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;
- 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);
-}
static irqreturn_t
snd_rme96_interrupt(int irq,
@@ -1155,6 +1166,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 +1203,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 +1235,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 +1267,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
@@ -1288,7 +1303,7 @@ snd_rme96_playback_close(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISPLAYING(rme96)) {
- snd_rme96_playback_stop(rme96);
+ snd_rme96_trigger(rme96,RME96_STOP_PLAYBACK);
}
rme96->playback_substream = NULL;
rme96->playback_periodsize = 0;
@@ -1309,7 +1324,7 @@ snd_rme96_capture_close(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISRECORDING(rme96)) {
- snd_rme96_capture_stop(rme96);
+ snd_rme96_trigger(rme96,RME96_STOP_CAPTURE);
}
rme96->capture_substream = NULL;
rme96->capture_periodsize = 0;
@@ -1324,7 +1339,7 @@ snd_rme96_playback_prepare(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISPLAYING(rme96)) {
- snd_rme96_playback_stop(rme96);
+ snd_rme96_trigger(rme96,RME96_STOP_PLAYBACK);
}
writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
spin_unlock_irq(&rme96->lock);
@@ -1338,7 +1353,7 @@ snd_rme96_capture_prepare(struct snd_pcm_substream *substream)
spin_lock_irq(&rme96->lock);
if (RME96_ISRECORDING(rme96)) {
- snd_rme96_capture_stop(rme96);
+ snd_rme96_trigger(rme96,RME96_STOP_CAPTURE);
}
writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
spin_unlock_irq(&rme96->lock);
@@ -1350,6 +1365,17 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
+ struct snd_pcm_substream *s;
+ bool sync;
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (snd_pcm_substream_chip(s) == rme96) {
+ snd_pcm_trigger_done(s, substream);
+ }
+ }
+
+ sync = (rme96->playback_substream && rme96->capture_substream) &&
+ (rme96->playback_substream->group == rme96->capture_substream->group);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -1357,7 +1383,7 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream,
if (substream != rme96->playback_substream) {
return -EBUSY;
}
- snd_rme96_playback_start(rme96, 0);
+ snd_rme96_trigger(rme96, sync ? RME96_START_BOTH : RME96_START_PLAYBACK);
}
break;
@@ -1366,19 +1392,19 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream,
if (substream != rme96->playback_substream) {
return -EBUSY;
}
- snd_rme96_playback_stop(rme96);
+ snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH : RME96_STOP_PLAYBACK);
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (RME96_ISPLAYING(rme96)) {
- snd_rme96_playback_stop(rme96);
+ snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH : RME96_STOP_PLAYBACK);
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (!RME96_ISPLAYING(rme96)) {
- snd_rme96_playback_start(rme96, 1);
+ snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH : RME96_RESUME_PLAYBACK);
}
break;
@@ -1393,6 +1419,17 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
+ struct snd_pcm_substream *s;
+ bool sync;
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (snd_pcm_substream_chip(s) == rme96) {
+ snd_pcm_trigger_done(s, substream);
+ }
+ }
+
+ sync = (rme96->playback_substream && rme96->capture_substream) &&
+ (rme96->playback_substream->group == rme96->capture_substream->group);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -1400,7 +1437,7 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream,
if (substream != rme96->capture_substream) {
return -EBUSY;
}
- snd_rme96_capture_start(rme96, 0);
+ snd_rme96_trigger(rme96, sync ? RME96_START_BOTH : RME96_START_CAPTURE);
}
break;
@@ -1409,19 +1446,19 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream,
if (substream != rme96->capture_substream) {
return -EBUSY;
}
- snd_rme96_capture_stop(rme96);
+ snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH : RME96_STOP_CAPTURE);
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (RME96_ISRECORDING(rme96)) {
- snd_rme96_capture_stop(rme96);
+ snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH : RME96_STOP_CAPTURE);
}
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (!RME96_ISRECORDING(rme96)) {
- snd_rme96_capture_start(rme96, 1);
+ snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH : RME96_RESUME_CAPTURE);
}
break;
@@ -1505,8 +1542,7 @@ snd_rme96_free(void *private_data)
return;
}
if (rme96->irq >= 0) {
- snd_rme96_playback_stop(rme96);
- snd_rme96_capture_stop(rme96);
+ snd_rme96_trigger(rme96,RME96_STOP_BOTH);
rme96->areg &= ~RME96_AR_DAC_EN;
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
free_irq(rme96->irq, (void *)rme96);
@@ -1606,8 +1642,7 @@ snd_rme96_create(struct rme96 *rme96)
rme96->capture_periodsize = 0;
/* make sure playback/capture is stopped, if by some reason active */
- snd_rme96_playback_stop(rme96);
- snd_rme96_capture_stop(rme96);
+ snd_rme96_trigger(rme96,RME96_STOP_BOTH);
/* set default values in registers */
rme96->wcreg =
--
1.8.1.4
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
next prev parent reply other threads:[~2013-08-08 10:52 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-05 12:36 [PATCH] rme96 synchronization support Knut Petersen
2013-08-05 13:18 ` Clemens Ladisch
2013-08-06 17:42 ` Knut Petersen
2013-08-07 7:08 ` Takashi Iwai
2013-08-08 10:52 ` Knut Petersen [this message]
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=52037864.9000205@t-online.de \
--to=knut_petersen@t-online.de \
--cc=alsa-devel@alsa-project.org \
--cc=clemens@ladisch.de \
--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).