All of lore.kernel.org
 help / color / mirror / Atom feed
From: Oleksandr Andrushchenko <andr2000@gmail.com>
To: alsa-devel@alsa-project.org, xen-devel@lists.xen.org,
	linux-kernel@vger.kernel.org
Cc: perex@perex.cz, tiwai@suse.com, andr2000@gmail.com,
	Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
Subject: [PATCH RESEND 08/11] ALSA: vsnd: Add timer for period interrupt emulation
Date: Mon,  7 Aug 2017 14:50:42 +0300	[thread overview]
Message-ID: <1502106645-6731-9-git-send-email-andr2000@gmail.com> (raw)
In-Reply-To: <1502106645-6731-1-git-send-email-andr2000@gmail.com>

From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>

Front sound driver has no real interrupts, so
playback/capture period passed interrupt needs to be emulated:
this is done via timer. Add required timer operations,
this is based on sound/drivers/dummy.c.

Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
---
 sound/drivers/xen-front.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)

diff --git a/sound/drivers/xen-front.c b/sound/drivers/xen-front.c
index 9f31e6832086..507c5eb343c8 100644
--- a/sound/drivers/xen-front.c
+++ b/sound/drivers/xen-front.c
@@ -67,12 +67,29 @@ struct sh_buf_info {
 	size_t vbuffer_sz;
 };
 
+struct sdev_alsa_timer_info {
+	spinlock_t lock;
+	struct timer_list timer;
+	unsigned long base_time;
+	/* fractional sample position (based HZ) */
+	unsigned int frac_pos;
+	unsigned int frac_period_rest;
+	/* buffer_size * HZ */
+	unsigned int frac_buffer_size;
+	/* period_size * HZ */
+	unsigned int frac_period_size;
+	unsigned int rate;
+	int elapsed;
+	struct snd_pcm_substream *substream;
+};
+
 struct sdev_pcm_stream_info {
 	int unique_id;
 	struct snd_pcm_hardware pcm_hw;
 	struct xdrv_evtchnl_info *evt_chnl;
 	bool is_open;
 	uint8_t req_next_id;
+	struct sdev_alsa_timer_info timer;
 	struct sh_buf_info sh_buf;
 };
 
@@ -148,6 +165,110 @@ static struct sdev_pcm_stream_info *sdrv_stream_get(
 	return stream;
 }
 
+static inline void sdrv_alsa_timer_rearm(struct sdev_alsa_timer_info *dpcm)
+{
+	mod_timer(&dpcm->timer, jiffies +
+		(dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate);
+}
+
+static void sdrv_alsa_timer_update(struct sdev_alsa_timer_info *dpcm)
+{
+	unsigned long delta;
+
+	delta = jiffies - dpcm->base_time;
+	if (!delta)
+		return;
+	dpcm->base_time += delta;
+	delta *= dpcm->rate;
+	dpcm->frac_pos += delta;
+	while (dpcm->frac_pos >= dpcm->frac_buffer_size)
+		dpcm->frac_pos -= dpcm->frac_buffer_size;
+	while (dpcm->frac_period_rest <= delta) {
+		dpcm->elapsed++;
+		dpcm->frac_period_rest += dpcm->frac_period_size;
+	}
+	dpcm->frac_period_rest -= delta;
+}
+
+static int sdrv_alsa_timer_start(struct snd_pcm_substream *substream)
+{
+	struct sdev_pcm_stream_info *stream = sdrv_stream_get(substream);
+	struct sdev_alsa_timer_info *dpcm = &stream->timer;
+
+	spin_lock(&dpcm->lock);
+	dpcm->base_time = jiffies;
+	sdrv_alsa_timer_rearm(dpcm);
+	spin_unlock(&dpcm->lock);
+	return 0;
+}
+
+static int sdrv_alsa_timer_stop(struct snd_pcm_substream *substream)
+{
+	struct sdev_pcm_stream_info *stream = sdrv_stream_get(substream);
+	struct sdev_alsa_timer_info *dpcm = &stream->timer;
+
+	spin_lock(&dpcm->lock);
+	del_timer(&dpcm->timer);
+	spin_unlock(&dpcm->lock);
+	return 0;
+}
+
+static int sdrv_alsa_timer_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sdev_pcm_stream_info *stream = sdrv_stream_get(substream);
+	struct sdev_alsa_timer_info *dpcm = &stream->timer;
+
+	dpcm->frac_pos = 0;
+	dpcm->rate = runtime->rate;
+	dpcm->frac_buffer_size = runtime->buffer_size * HZ;
+	dpcm->frac_period_size = runtime->period_size * HZ;
+	dpcm->frac_period_rest = dpcm->frac_period_size;
+	dpcm->elapsed = 0;
+	return 0;
+}
+
+static void sdrv_alsa_timer_callback(unsigned long data)
+{
+	struct sdev_alsa_timer_info *dpcm = (struct sdev_alsa_timer_info *)data;
+	int elapsed;
+
+	spin_lock(&dpcm->lock);
+	sdrv_alsa_timer_update(dpcm);
+	sdrv_alsa_timer_rearm(dpcm);
+	elapsed = dpcm->elapsed;
+	dpcm->elapsed = 0;
+	spin_unlock(&dpcm->lock);
+	if (elapsed)
+		snd_pcm_period_elapsed(dpcm->substream);
+}
+
+static snd_pcm_uframes_t sdrv_alsa_timer_pointer(
+	struct snd_pcm_substream *substream)
+{
+	struct sdev_pcm_stream_info *stream = sdrv_stream_get(substream);
+	struct sdev_alsa_timer_info *dpcm = &stream->timer;
+	snd_pcm_uframes_t pos;
+
+	spin_lock(&dpcm->lock);
+	sdrv_alsa_timer_update(dpcm);
+	pos = dpcm->frac_pos / HZ;
+	spin_unlock(&dpcm->lock);
+	return pos;
+}
+
+static int sdrv_alsa_timer_create(struct snd_pcm_substream *substream)
+{
+	struct sdev_pcm_stream_info *stream = sdrv_stream_get(substream);
+	struct sdev_alsa_timer_info *dpcm = &stream->timer;
+
+	spin_lock_init(&dpcm->lock);
+	dpcm->substream = substream;
+	setup_timer(&dpcm->timer, sdrv_alsa_timer_callback,
+		(unsigned long) dpcm);
+	return 0;
+}
+
 static void sdrv_copy_pcm_hw(struct snd_pcm_hardware *dst,
 	struct snd_pcm_hardware *src,
 	struct snd_pcm_hardware *ref_pcm_hw)
-- 
2.7.4

WARNING: multiple messages have this Message-ID (diff)
From: Oleksandr Andrushchenko <andr2000@gmail.com>
To: alsa-devel@alsa-project.org, xen-devel@lists.xen.org,
	linux-kernel@vger.kernel.org
Cc: andr2000@gmail.com,
	Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>,
	tiwai@suse.com, perex@perex.cz
Subject: [PATCH RESEND 08/11] ALSA: vsnd: Add timer for period interrupt emulation
Date: Mon,  7 Aug 2017 14:50:42 +0300	[thread overview]
Message-ID: <1502106645-6731-9-git-send-email-andr2000@gmail.com> (raw)
In-Reply-To: <1502106645-6731-1-git-send-email-andr2000@gmail.com>

From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>

Front sound driver has no real interrupts, so
playback/capture period passed interrupt needs to be emulated:
this is done via timer. Add required timer operations,
this is based on sound/drivers/dummy.c.

Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
---
 sound/drivers/xen-front.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)

diff --git a/sound/drivers/xen-front.c b/sound/drivers/xen-front.c
index 9f31e6832086..507c5eb343c8 100644
--- a/sound/drivers/xen-front.c
+++ b/sound/drivers/xen-front.c
@@ -67,12 +67,29 @@ struct sh_buf_info {
 	size_t vbuffer_sz;
 };
 
+struct sdev_alsa_timer_info {
+	spinlock_t lock;
+	struct timer_list timer;
+	unsigned long base_time;
+	/* fractional sample position (based HZ) */
+	unsigned int frac_pos;
+	unsigned int frac_period_rest;
+	/* buffer_size * HZ */
+	unsigned int frac_buffer_size;
+	/* period_size * HZ */
+	unsigned int frac_period_size;
+	unsigned int rate;
+	int elapsed;
+	struct snd_pcm_substream *substream;
+};
+
 struct sdev_pcm_stream_info {
 	int unique_id;
 	struct snd_pcm_hardware pcm_hw;
 	struct xdrv_evtchnl_info *evt_chnl;
 	bool is_open;
 	uint8_t req_next_id;
+	struct sdev_alsa_timer_info timer;
 	struct sh_buf_info sh_buf;
 };
 
@@ -148,6 +165,110 @@ static struct sdev_pcm_stream_info *sdrv_stream_get(
 	return stream;
 }
 
+static inline void sdrv_alsa_timer_rearm(struct sdev_alsa_timer_info *dpcm)
+{
+	mod_timer(&dpcm->timer, jiffies +
+		(dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate);
+}
+
+static void sdrv_alsa_timer_update(struct sdev_alsa_timer_info *dpcm)
+{
+	unsigned long delta;
+
+	delta = jiffies - dpcm->base_time;
+	if (!delta)
+		return;
+	dpcm->base_time += delta;
+	delta *= dpcm->rate;
+	dpcm->frac_pos += delta;
+	while (dpcm->frac_pos >= dpcm->frac_buffer_size)
+		dpcm->frac_pos -= dpcm->frac_buffer_size;
+	while (dpcm->frac_period_rest <= delta) {
+		dpcm->elapsed++;
+		dpcm->frac_period_rest += dpcm->frac_period_size;
+	}
+	dpcm->frac_period_rest -= delta;
+}
+
+static int sdrv_alsa_timer_start(struct snd_pcm_substream *substream)
+{
+	struct sdev_pcm_stream_info *stream = sdrv_stream_get(substream);
+	struct sdev_alsa_timer_info *dpcm = &stream->timer;
+
+	spin_lock(&dpcm->lock);
+	dpcm->base_time = jiffies;
+	sdrv_alsa_timer_rearm(dpcm);
+	spin_unlock(&dpcm->lock);
+	return 0;
+}
+
+static int sdrv_alsa_timer_stop(struct snd_pcm_substream *substream)
+{
+	struct sdev_pcm_stream_info *stream = sdrv_stream_get(substream);
+	struct sdev_alsa_timer_info *dpcm = &stream->timer;
+
+	spin_lock(&dpcm->lock);
+	del_timer(&dpcm->timer);
+	spin_unlock(&dpcm->lock);
+	return 0;
+}
+
+static int sdrv_alsa_timer_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct sdev_pcm_stream_info *stream = sdrv_stream_get(substream);
+	struct sdev_alsa_timer_info *dpcm = &stream->timer;
+
+	dpcm->frac_pos = 0;
+	dpcm->rate = runtime->rate;
+	dpcm->frac_buffer_size = runtime->buffer_size * HZ;
+	dpcm->frac_period_size = runtime->period_size * HZ;
+	dpcm->frac_period_rest = dpcm->frac_period_size;
+	dpcm->elapsed = 0;
+	return 0;
+}
+
+static void sdrv_alsa_timer_callback(unsigned long data)
+{
+	struct sdev_alsa_timer_info *dpcm = (struct sdev_alsa_timer_info *)data;
+	int elapsed;
+
+	spin_lock(&dpcm->lock);
+	sdrv_alsa_timer_update(dpcm);
+	sdrv_alsa_timer_rearm(dpcm);
+	elapsed = dpcm->elapsed;
+	dpcm->elapsed = 0;
+	spin_unlock(&dpcm->lock);
+	if (elapsed)
+		snd_pcm_period_elapsed(dpcm->substream);
+}
+
+static snd_pcm_uframes_t sdrv_alsa_timer_pointer(
+	struct snd_pcm_substream *substream)
+{
+	struct sdev_pcm_stream_info *stream = sdrv_stream_get(substream);
+	struct sdev_alsa_timer_info *dpcm = &stream->timer;
+	snd_pcm_uframes_t pos;
+
+	spin_lock(&dpcm->lock);
+	sdrv_alsa_timer_update(dpcm);
+	pos = dpcm->frac_pos / HZ;
+	spin_unlock(&dpcm->lock);
+	return pos;
+}
+
+static int sdrv_alsa_timer_create(struct snd_pcm_substream *substream)
+{
+	struct sdev_pcm_stream_info *stream = sdrv_stream_get(substream);
+	struct sdev_alsa_timer_info *dpcm = &stream->timer;
+
+	spin_lock_init(&dpcm->lock);
+	dpcm->substream = substream;
+	setup_timer(&dpcm->timer, sdrv_alsa_timer_callback,
+		(unsigned long) dpcm);
+	return 0;
+}
+
 static void sdrv_copy_pcm_hw(struct snd_pcm_hardware *dst,
 	struct snd_pcm_hardware *src,
 	struct snd_pcm_hardware *ref_pcm_hw)
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

  parent reply	other threads:[~2017-08-07 11:53 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-07 11:50 [PATCH RESEND 00/11] ALSA: vsnd: Add Xen para-virtualized frontend driver Oleksandr Andrushchenko
2017-08-07 11:50 ` Oleksandr Andrushchenko
2017-08-07 11:50 ` [PATCH RESEND 01/11] ALSA: vsnd: Implement driver's probe/remove Oleksandr Andrushchenko
2017-08-07 11:50 ` Oleksandr Andrushchenko
2017-08-07 11:50 ` [PATCH RESEND 02/11] ALSA: vsnd: Implement Xen bus state handling Oleksandr Andrushchenko
2017-08-07 11:50   ` Oleksandr Andrushchenko
2017-08-07 11:50 ` [PATCH RESEND 03/11] ALSA: vsnd: Read sound driver configuration from Xen store Oleksandr Andrushchenko
2017-08-07 11:50 ` Oleksandr Andrushchenko
2017-08-07 11:50 ` [PATCH RESEND 04/11] ALSA: vsnd: Implement Xen event channel handling Oleksandr Andrushchenko
2017-08-07 11:50 ` Oleksandr Andrushchenko
2017-08-07 11:50 ` [PATCH RESEND 05/11] ALSA: vsnd: Implement handling of shared buffers Oleksandr Andrushchenko
2017-08-07 11:50   ` Oleksandr Andrushchenko
2017-08-07 11:50 ` [PATCH RESEND 06/11] ALSA: vsnd: Introduce ALSA virtual sound driver Oleksandr Andrushchenko
2017-08-07 11:50 ` Oleksandr Andrushchenko
2017-08-07 11:50 ` [PATCH RESEND 07/11] ALSA: vsnd: Initialize virtul sound card Oleksandr Andrushchenko
2017-08-07 11:50 ` Oleksandr Andrushchenko
2017-08-07 11:50 ` Oleksandr Andrushchenko [this message]
2017-08-07 11:50   ` [PATCH RESEND 08/11] ALSA: vsnd: Add timer for period interrupt emulation Oleksandr Andrushchenko
2017-08-07 11:50 ` [PATCH RESEND 09/11] ALSA: vsnd: Implement ALSA PCM operations Oleksandr Andrushchenko
2017-08-07 11:50   ` Oleksandr Andrushchenko
2017-08-07 11:50 ` [PATCH RESEND 10/11] ALSA: vsnd: Implement communication with backend Oleksandr Andrushchenko
2017-08-07 11:50   ` Oleksandr Andrushchenko
2017-08-07 11:50 ` [PATCH RESEND 11/11] ALSA: vsnd: Introduce Kconfig option to enable Xen PV sound Oleksandr Andrushchenko
2017-08-07 11:50 ` Oleksandr Andrushchenko
2017-08-07 12:09 ` [PATCH RESEND 00/11] ALSA: vsnd: Add Xen para-virtualized frontend driver Takashi Sakamoto
2017-08-07 12:18   ` Oleksandr Andrushchenko
2017-08-07 12:30     ` Takashi Sakamoto
2017-08-07 12:33       ` Oleksandr Andrushchenko
2017-08-07 12:33       ` Oleksandr Andrushchenko
2017-08-07 12:30     ` Takashi Sakamoto
2017-08-07 12:18   ` Oleksandr Andrushchenko
2017-08-07 12:09 ` Takashi Sakamoto

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=1502106645-6731-9-git-send-email-andr2000@gmail.com \
    --to=andr2000@gmail.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=oleksandr_andrushchenko@epam.com \
    --cc=perex@perex.cz \
    --cc=tiwai@suse.com \
    --cc=xen-devel@lists.xen.org \
    /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.