From mboxrd@z Thu Jan 1 00:00:00 1970 From: Knut Petersen Subject: Re: [PATCH] rme96 synchronization support Date: Thu, 08 Aug 2013 12:52:20 +0200 Message-ID: <52037864.9000205@t-online.de> References: <51FF9C55.80701@t-online.de> <51FFA643.7060504@ladisch.de> <52013579.7020304@t-online.de> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------080504010104060907000005" Return-path: Received: from mailout05.t-online.de (mailout05.t-online.de [194.25.134.82]) by alsa0.perex.cz (Postfix) with ESMTP id 2CF272619F6 for ; Thu, 8 Aug 2013 12:52:30 +0200 (CEST) In-Reply-To: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org To: alsa-devel@alsa-project.org Cc: Takashi Iwai , Clemens Ladisch List-Id: alsa-devel@alsa-project.org This is a multi-part message in MIME format. --------------080504010104060907000005 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Hi everybody! Version 2 of the patch adding pcm stream synchronization support to the rme96 driver. cu, Knut --------------080504010104060907000005 Content-Type: text/x-patch; name="0001-alsa-rme96-Add-support-for-synchronized-start-pause-.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0001-alsa-rme96-Add-support-for-synchronized-start-pause-.pa"; filename*1="tch" >>From 015bc7f9ebcbf01ce209a4f859bbfa9c31885483 Mon Sep 17 00:00:00 2001 From: Knut Petersen 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 --- 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 --------------080504010104060907000005 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline --------------080504010104060907000005--