|
@@ -658,12 +658,31 @@ static int rule_channels(struct snd_pcm_hw_params *params,
|
|
|
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
|
|
|
}
|
|
|
|
|
|
+static void free_cable(struct snd_pcm_substream *substream)
|
|
|
+{
|
|
|
+ struct loopback *loopback = substream->private_data;
|
|
|
+ int dev = get_cable_index(substream);
|
|
|
+ struct loopback_cable *cable;
|
|
|
+
|
|
|
+ cable = loopback->cables[substream->number][dev];
|
|
|
+ if (!cable)
|
|
|
+ return;
|
|
|
+ if (cable->streams[!substream->stream]) {
|
|
|
+ /* other stream is still alive */
|
|
|
+ cable->streams[substream->stream] = NULL;
|
|
|
+ } else {
|
|
|
+ /* free the cable */
|
|
|
+ loopback->cables[substream->number][dev] = NULL;
|
|
|
+ kfree(cable);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int loopback_open(struct snd_pcm_substream *substream)
|
|
|
{
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
|
struct loopback *loopback = substream->private_data;
|
|
|
struct loopback_pcm *dpcm;
|
|
|
- struct loopback_cable *cable;
|
|
|
+ struct loopback_cable *cable = NULL;
|
|
|
int err = 0;
|
|
|
int dev = get_cable_index(substream);
|
|
|
|
|
@@ -681,7 +700,6 @@ static int loopback_open(struct snd_pcm_substream *substream)
|
|
|
if (!cable) {
|
|
|
cable = kzalloc(sizeof(*cable), GFP_KERNEL);
|
|
|
if (!cable) {
|
|
|
- kfree(dpcm);
|
|
|
err = -ENOMEM;
|
|
|
goto unlock;
|
|
|
}
|
|
@@ -723,6 +741,10 @@ static int loopback_open(struct snd_pcm_substream *substream)
|
|
|
else
|
|
|
runtime->hw = cable->hw;
|
|
|
unlock:
|
|
|
+ if (err < 0) {
|
|
|
+ free_cable(substream);
|
|
|
+ kfree(dpcm);
|
|
|
+ }
|
|
|
mutex_unlock(&loopback->cable_lock);
|
|
|
return err;
|
|
|
}
|
|
@@ -731,20 +753,10 @@ static int loopback_close(struct snd_pcm_substream *substream)
|
|
|
{
|
|
|
struct loopback *loopback = substream->private_data;
|
|
|
struct loopback_pcm *dpcm = substream->runtime->private_data;
|
|
|
- struct loopback_cable *cable;
|
|
|
- int dev = get_cable_index(substream);
|
|
|
|
|
|
loopback_timer_stop(dpcm);
|
|
|
mutex_lock(&loopback->cable_lock);
|
|
|
- cable = loopback->cables[substream->number][dev];
|
|
|
- if (cable->streams[!substream->stream]) {
|
|
|
- /* other stream is still alive */
|
|
|
- cable->streams[substream->stream] = NULL;
|
|
|
- } else {
|
|
|
- /* free the cable */
|
|
|
- loopback->cables[substream->number][dev] = NULL;
|
|
|
- kfree(cable);
|
|
|
- }
|
|
|
+ free_cable(substream);
|
|
|
mutex_unlock(&loopback->cable_lock);
|
|
|
return 0;
|
|
|
}
|