Commit 133f3759 authored by Timo Wischer's avatar Timo Wischer Committed by Takashi Iwai

ALSA: aloop: Use callback functions for timer specific implementations

This commit only refactors the implementation. It does not change the
behaviour.
It is required to support other timers (e.g sound timer).
Signed-off-by: default avatarTimo Wischer <twischer@de.adit-jv.com>
Signed-off-by: default avatarAndrew Gabbasov <andrew_gabbasov@mentor.com>
Link: https://lore.kernel.org/r/20191120174955.6410-4-andrew_gabbasov@mentor.comSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 09419f1a
...@@ -55,8 +55,39 @@ MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels change ...@@ -55,8 +55,39 @@ MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels change
#define NO_PITCH 100000 #define NO_PITCH 100000
struct loopback_cable;
struct loopback_pcm; struct loopback_pcm;
struct loopback_ops {
/* optional
* call in loopback->cable_lock
*/
int (*open)(struct loopback_pcm *dpcm);
/* required
* call in cable->lock
*/
int (*start)(struct loopback_pcm *dpcm);
/* required
* call in cable->lock
*/
int (*stop)(struct loopback_pcm *dpcm);
/* optional */
int (*stop_sync)(struct loopback_pcm *dpcm);
/* optional */
int (*close_substream)(struct loopback_pcm *dpcm);
/* optional
* call in loopback->cable_lock
*/
int (*close_cable)(struct loopback_pcm *dpcm);
/* optional
* call in cable->lock
*/
unsigned int (*pos_update)(struct loopback_cable *cable);
/* optional */
void (*dpcm_info)(struct loopback_pcm *dpcm,
struct snd_info_buffer *buffer);
};
struct loopback_cable { struct loopback_cable {
spinlock_t lock; spinlock_t lock;
struct loopback_pcm *streams[2]; struct loopback_pcm *streams[2];
...@@ -65,6 +96,8 @@ struct loopback_cable { ...@@ -65,6 +96,8 @@ struct loopback_cable {
unsigned int valid; unsigned int valid;
unsigned int running; unsigned int running;
unsigned int pause; unsigned int pause;
/* timer specific */
struct loopback_ops *ops;
}; };
struct loopback_setup { struct loopback_setup {
...@@ -270,7 +303,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -270,7 +303,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
spin_lock(&cable->lock); spin_lock(&cable->lock);
cable->running |= stream; cable->running |= stream;
cable->pause &= ~stream; cable->pause &= ~stream;
err = loopback_timer_start(dpcm); err = cable->ops->start(dpcm);
spin_unlock(&cable->lock); spin_unlock(&cable->lock);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm); loopback_active_notify(dpcm);
...@@ -279,7 +312,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -279,7 +312,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
spin_lock(&cable->lock); spin_lock(&cable->lock);
cable->running &= ~stream; cable->running &= ~stream;
cable->pause &= ~stream; cable->pause &= ~stream;
err = loopback_timer_stop(dpcm); err = cable->ops->stop(dpcm);
spin_unlock(&cable->lock); spin_unlock(&cable->lock);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm); loopback_active_notify(dpcm);
...@@ -288,7 +321,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -288,7 +321,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
spin_lock(&cable->lock); spin_lock(&cable->lock);
cable->pause |= stream; cable->pause |= stream;
err = loopback_timer_stop(dpcm); err = cable->ops->stop(dpcm);
spin_unlock(&cable->lock); spin_unlock(&cable->lock);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm); loopback_active_notify(dpcm);
...@@ -298,7 +331,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -298,7 +331,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
spin_lock(&cable->lock); spin_lock(&cable->lock);
dpcm->last_jiffies = jiffies; dpcm->last_jiffies = jiffies;
cable->pause &= ~stream; cable->pause &= ~stream;
err = loopback_timer_start(dpcm); err = cable->ops->start(dpcm);
spin_unlock(&cable->lock); spin_unlock(&cable->lock);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
loopback_active_notify(dpcm); loopback_active_notify(dpcm);
...@@ -329,9 +362,11 @@ static int loopback_prepare(struct snd_pcm_substream *substream) ...@@ -329,9 +362,11 @@ static int loopback_prepare(struct snd_pcm_substream *substream)
struct loopback_cable *cable = dpcm->cable; struct loopback_cable *cable = dpcm->cable;
int err, bps, salign; int err, bps, salign;
err = loopback_timer_stop_sync(dpcm); if (cable->ops->stop_sync) {
err = cable->ops->stop_sync(dpcm);
if (err < 0) if (err < 0)
return err; return err;
}
salign = (snd_pcm_format_physical_width(runtime->format) * salign = (snd_pcm_format_physical_width(runtime->format) *
runtime->channels) / 8; runtime->channels) / 8;
...@@ -539,6 +574,18 @@ static void loopback_timer_function(struct timer_list *t) ...@@ -539,6 +574,18 @@ static void loopback_timer_function(struct timer_list *t)
spin_unlock_irqrestore(&dpcm->cable->lock, flags); spin_unlock_irqrestore(&dpcm->cable->lock, flags);
} }
static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm,
struct snd_info_buffer *buffer)
{
snd_iprintf(buffer, " update_pending:\t%u\n",
dpcm->period_update_pending);
snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos);
snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac);
snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n",
dpcm->last_jiffies, jiffies);
snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires);
}
static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
...@@ -546,7 +593,8 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) ...@@ -546,7 +593,8 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
snd_pcm_uframes_t pos; snd_pcm_uframes_t pos;
spin_lock(&dpcm->cable->lock); spin_lock(&dpcm->cable->lock);
loopback_pos_update(dpcm->cable); if (dpcm->cable->ops->pos_update)
dpcm->cable->ops->pos_update(dpcm->cable);
pos = dpcm->buf_pos; pos = dpcm->buf_pos;
spin_unlock(&dpcm->cable->lock); spin_unlock(&dpcm->cable->lock);
return bytes_to_frames(runtime, pos); return bytes_to_frames(runtime, pos);
...@@ -671,12 +719,33 @@ static void free_cable(struct snd_pcm_substream *substream) ...@@ -671,12 +719,33 @@ static void free_cable(struct snd_pcm_substream *substream)
cable->streams[substream->stream] = NULL; cable->streams[substream->stream] = NULL;
spin_unlock_irq(&cable->lock); spin_unlock_irq(&cable->lock);
} else { } else {
struct loopback_pcm *dpcm = substream->runtime->private_data;
if (cable->ops && cable->ops->close_cable && dpcm)
cable->ops->close_cable(dpcm);
/* free the cable */ /* free the cable */
loopback->cables[substream->number][dev] = NULL; loopback->cables[substream->number][dev] = NULL;
kfree(cable); kfree(cable);
} }
} }
static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm)
{
timer_setup(&dpcm->timer, loopback_timer_function, 0);
return 0;
}
static struct loopback_ops loopback_jiffies_timer_ops = {
.open = loopback_jiffies_timer_open,
.start = loopback_timer_start,
.stop = loopback_timer_stop,
.stop_sync = loopback_timer_stop_sync,
.close_substream = loopback_timer_stop_sync,
.pos_update = loopback_pos_update,
.dpcm_info = loopback_jiffies_timer_dpcm_info,
};
static int loopback_open(struct snd_pcm_substream *substream) static int loopback_open(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
...@@ -694,7 +763,6 @@ static int loopback_open(struct snd_pcm_substream *substream) ...@@ -694,7 +763,6 @@ static int loopback_open(struct snd_pcm_substream *substream)
} }
dpcm->loopback = loopback; dpcm->loopback = loopback;
dpcm->substream = substream; dpcm->substream = substream;
timer_setup(&dpcm->timer, loopback_timer_function, 0);
cable = loopback->cables[substream->number][dev]; cable = loopback->cables[substream->number][dev];
if (!cable) { if (!cable) {
...@@ -705,9 +773,17 @@ static int loopback_open(struct snd_pcm_substream *substream) ...@@ -705,9 +773,17 @@ static int loopback_open(struct snd_pcm_substream *substream)
} }
spin_lock_init(&cable->lock); spin_lock_init(&cable->lock);
cable->hw = loopback_pcm_hardware; cable->hw = loopback_pcm_hardware;
cable->ops = &loopback_jiffies_timer_ops;
loopback->cables[substream->number][dev] = cable; loopback->cables[substream->number][dev] = cable;
} }
dpcm->cable = cable; dpcm->cable = cable;
runtime->private_data = dpcm;
if (cable->ops->open) {
err = cable->ops->open(dpcm);
if (err < 0)
goto unlock;
}
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
...@@ -733,7 +809,9 @@ static int loopback_open(struct snd_pcm_substream *substream) ...@@ -733,7 +809,9 @@ static int loopback_open(struct snd_pcm_substream *substream)
if (err < 0) if (err < 0)
goto unlock; goto unlock;
runtime->private_data = dpcm; /* loopback_runtime_free() has not to be called if kfree(dpcm) was
* already called here. Otherwise it will end up with a double free.
*/
runtime->private_free = loopback_runtime_free; runtime->private_free = loopback_runtime_free;
if (get_notify(dpcm)) if (get_notify(dpcm))
runtime->hw = loopback_pcm_hardware; runtime->hw = loopback_pcm_hardware;
...@@ -757,12 +835,14 @@ static int loopback_close(struct snd_pcm_substream *substream) ...@@ -757,12 +835,14 @@ static int loopback_close(struct snd_pcm_substream *substream)
{ {
struct loopback *loopback = substream->private_data; struct loopback *loopback = substream->private_data;
struct loopback_pcm *dpcm = substream->runtime->private_data; struct loopback_pcm *dpcm = substream->runtime->private_data;
int err = 0;
loopback_timer_stop_sync(dpcm); if (dpcm->cable->ops->close_substream)
err = dpcm->cable->ops->close_substream(dpcm);
mutex_lock(&loopback->cable_lock); mutex_lock(&loopback->cable_lock);
free_cable(substream); free_cable(substream);
mutex_unlock(&loopback->cable_lock); mutex_unlock(&loopback->cable_lock);
return 0; return err;
} }
static const struct snd_pcm_ops loopback_pcm_ops = { static const struct snd_pcm_ops loopback_pcm_ops = {
...@@ -1086,13 +1166,8 @@ static void print_dpcm_info(struct snd_info_buffer *buffer, ...@@ -1086,13 +1166,8 @@ static void print_dpcm_info(struct snd_info_buffer *buffer,
snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps); snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps);
snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign); snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign);
snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift); snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift);
snd_iprintf(buffer, " update_pending:\t%u\n", if (dpcm->cable->ops->dpcm_info)
dpcm->period_update_pending); dpcm->cable->ops->dpcm_info(dpcm, buffer);
snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos);
snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac);
snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n",
dpcm->last_jiffies, jiffies);
snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires);
} }
static void print_substream_info(struct snd_info_buffer *buffer, static void print_substream_info(struct snd_info_buffer *buffer,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment