staging: line6: fixed ALSA/PCM interaction

The PCM subsystem in the Line6 driver is mainly used for PCM playback and
capture by ALSA, but also has other tasks, most notably providing a
low-latency software monitor for devices which don't support hardware
monitoring (e.g., the TonePort series). This patch makes ALSA "play nicely"
with the other components, i.e., prevents it from resetting the isochronous
USB transfer while other PCM tasks (software monitoring) are running.

Signed-off-by: Markus Grabner <grabner@icg.tugraz.at>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c
index 9a51b92..4152db2 100644
--- a/drivers/staging/line6/playback.c
+++ b/drivers/staging/line6/playback.c
@@ -351,6 +351,31 @@
 	wait_clear_audio_out_urbs(line6pcm);
 }
 
+int line6_alloc_playback_buffer(struct snd_line6_pcm *line6pcm)
+{
+	/* We may be invoked multiple times in a row so allocate once only */
+	if (line6pcm->buffer_out)
+		return 0;
+
+	line6pcm->buffer_out =
+		kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
+			line6pcm->max_packet_size, GFP_KERNEL);
+
+	if (!line6pcm->buffer_out) {
+		dev_err(line6pcm->line6->ifcdev,
+			"cannot malloc playback buffer\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm)
+{
+	kfree(line6pcm->buffer_out);
+	line6pcm->buffer_out = NULL;
+}
+
 /*
 	Callback for completed playback URB.
 */
@@ -459,16 +484,11 @@
 	}
 	/* -- [FD] end */
 
-	/* We may be invoked multiple times in a row so allocate once only */
-	if (!line6pcm->buffer_out)
-		line6pcm->buffer_out =
-			kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
-				line6pcm->max_packet_size, GFP_KERNEL);
+	if ((line6pcm->flags & MASK_PLAYBACK) == 0) {
+		ret = line6_alloc_playback_buffer(line6pcm);
 
-	if (!line6pcm->buffer_out) {
-		dev_err(line6pcm->line6->ifcdev,
-			"cannot malloc playback buffer\n");
-		return -ENOMEM;
+		if (ret < 0)
+			return ret;
 	}
 
 	ret = snd_pcm_lib_malloc_pages(substream,
@@ -485,9 +505,11 @@
 {
 	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
 
-	line6_unlink_wait_clear_audio_out_urbs(line6pcm);
-	kfree(line6pcm->buffer_out);
-	line6pcm->buffer_out = NULL;
+	if ((line6pcm->flags & MASK_PLAYBACK) == 0) {
+		line6_unlink_wait_clear_audio_out_urbs(line6pcm);
+		line6_free_playback_buffer(line6pcm);
+	}
+
 	return snd_pcm_lib_free_pages(substream);
 }