[ALSA] Clean up PCM codes (take 2)

- Clean up initialization and destruction of substream instance
  Now snd_pcm_open_substream() alone does most initialization jobs.
  Add pcm_release callback for cleaning up at snd_pcm_release_substream()
- Tidy up PCM oss code

Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 13efe39..964e4c4 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1995,28 +1995,63 @@
 	}
 }
 
-static int snd_pcm_release_file(struct snd_pcm_file * pcm_file)
+static void pcm_release_private(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_substream *substream;
-	struct snd_pcm_runtime *runtime;
-	struct snd_pcm_str * str;
+	struct snd_pcm_file *pcm_file = substream->file;
 
-	snd_assert(pcm_file != NULL, return -ENXIO);
-	substream = pcm_file->substream;
-	snd_assert(substream != NULL, return -ENXIO);
-	runtime = substream->runtime;
-	str = substream->pstr;
 	snd_pcm_unlink(substream);
-	if (substream->ffile != NULL) {
+	snd_pcm_remove_file(substream->pstr, pcm_file);
+	kfree(pcm_file);
+}
+
+void snd_pcm_release_substream(struct snd_pcm_substream *substream)
+{
+	snd_pcm_drop(substream);
+	if (substream->pcm_release)
+		substream->pcm_release(substream);
+	if (substream->hw_opened) {
 		if (substream->ops->hw_free != NULL)
 			substream->ops->hw_free(substream);
 		substream->ops->close(substream);
-		substream->ffile = NULL;
+		substream->hw_opened = 0;
 	}
-	snd_pcm_remove_file(str, pcm_file);
-	snd_pcm_release_substream(substream);
-	kfree(pcm_file);
+	snd_pcm_detach_substream(substream);
+}
+
+int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
+			   struct file *file,
+			   struct snd_pcm_substream **rsubstream)
+{
+	struct snd_pcm_substream *substream;
+	int err;
+
+	err = snd_pcm_attach_substream(pcm, stream, file, &substream);
+	if (err < 0)
+		return err;
+	substream->no_mmap_ctrl = 0;
+	err = snd_pcm_hw_constraints_init(substream);
+	if (err < 0) {
+		snd_printd("snd_pcm_hw_constraints_init failed\n");
+		goto error;
+	}
+
+	if ((err = substream->ops->open(substream)) < 0)
+		goto error;
+
+	substream->hw_opened = 1;
+
+	err = snd_pcm_hw_constraints_complete(substream);
+	if (err < 0) {
+		snd_printd("snd_pcm_hw_constraints_complete failed\n");
+		goto error;
+	}
+
+	*rsubstream = substream;
 	return 0;
+
+ error:
+	snd_pcm_release_substream(substream);
+	return err;
 }
 
 static int snd_pcm_open_file(struct file *file,
@@ -2024,52 +2059,29 @@
 			     int stream,
 			     struct snd_pcm_file **rpcm_file)
 {
-	int err = 0;
 	struct snd_pcm_file *pcm_file;
 	struct snd_pcm_substream *substream;
 	struct snd_pcm_str *str;
+	int err;
 
 	snd_assert(rpcm_file != NULL, return -EINVAL);
 	*rpcm_file = NULL;
 
+	err = snd_pcm_open_substream(pcm, stream, file, &substream);
+	if (err < 0)
+		return err;
+
 	pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
 	if (pcm_file == NULL) {
+		snd_pcm_release_substream(substream);
 		return -ENOMEM;
 	}
-
-	if ((err = snd_pcm_open_substream(pcm, stream, &substream)) < 0) {
-		kfree(pcm_file);
-		return err;
-	}
-
 	str = substream->pstr;
 	substream->file = pcm_file;
-	substream->no_mmap_ctrl = 0;
-
+	substream->pcm_release = pcm_release_private;
 	pcm_file->substream = substream;
-
 	snd_pcm_add_file(str, pcm_file);
 
-	err = snd_pcm_hw_constraints_init(substream);
-	if (err < 0) {
-		snd_printd("snd_pcm_hw_constraints_init failed\n");
-		snd_pcm_release_file(pcm_file);
-		return err;
-	}
-
-	if ((err = substream->ops->open(substream)) < 0) {
-		snd_pcm_release_file(pcm_file);
-		return err;
-	}
-	substream->ffile = file;
-
-	err = snd_pcm_hw_constraints_complete(substream);
-	if (err < 0) {
-		snd_printd("snd_pcm_hw_constraints_complete failed\n");
-		snd_pcm_release_file(pcm_file);
-		return err;
-	}
-
 	file->private_data = pcm_file;
 	*rpcm_file = pcm_file;
 	return 0;
@@ -2158,10 +2170,9 @@
 	snd_assert(substream != NULL, return -ENXIO);
 	snd_assert(!atomic_read(&substream->runtime->mmap_count), );
 	pcm = substream->pcm;
-	snd_pcm_drop(substream);
 	fasync_helper(-1, file, 0, &substream->runtime->fasync);
 	mutex_lock(&pcm->open_mutex);
-	snd_pcm_release_file(pcm_file);
+	snd_pcm_release_substream(substream);
 	mutex_unlock(&pcm->open_mutex);
 	wake_up(&pcm->open_wait);
 	module_put(pcm->card->module);
@@ -2480,11 +2491,6 @@
 	return 0;
 }
 		
-static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream,
-				   unsigned int cmd, void __user *arg);
-static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream,
-				  unsigned int cmd, void __user *arg);
-
 static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,
 				 unsigned int cmd, void __user *arg)
 {