return -EAGAIN;
 }
 
-/*
- * attach a new PCM stream
- */
-static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
+/* call build_pcms ops of the given codec and set up the default parameters */
+int snd_hda_codec_parse_pcms(struct hda_codec *codec)
 {
-       struct hda_bus *bus = codec->bus;
-       struct hda_pcm_stream *info;
-       int stream, err;
+       unsigned int pcm;
+       int err;
 
-       if (snd_BUG_ON(!pcm->name))
-               return -EINVAL;
-       for (stream = 0; stream < 2; stream++) {
-               info = &pcm->stream[stream];
-               if (info->substreams) {
+       if (codec->num_pcms)
+               return 0; /* already parsed */
+
+       if (!codec->patch_ops.build_pcms)
+               return 0;
+
+       err = codec->patch_ops.build_pcms(codec);
+       if (err < 0) {
+               codec_err(codec, "cannot build PCMs for #%d (error %d)\n",
+                         codec->addr, err);
+               return err;
+       }
+
+       for (pcm = 0; pcm < codec->num_pcms; pcm++) {
+               struct hda_pcm *cpcm = &codec->pcm_info[pcm];
+               int stream;
+
+               for (stream = 0; stream < 2; stream++) {
+                       struct hda_pcm_stream *info = &cpcm->stream[stream];
+
+                       if (!info->substreams)
+                               continue;
+                       if (snd_BUG_ON(!cpcm->name))
+                               return -EINVAL;
                        err = set_pcm_default_values(codec, info);
-                       if (err < 0)
+                       if (err < 0) {
+                               codec_warn(codec,
+                                          "fail to setup default for PCM %s\n",
+                                          cpcm->name);
                                return err;
+                       }
                }
        }
-       return bus->ops.attach_pcm(bus, codec, pcm);
+
+       return 0;
 }
 
 /* assign all PCMs of the given codec */
 int snd_hda_codec_build_pcms(struct hda_codec *codec)
 {
+       struct hda_bus *bus = codec->bus;
        unsigned int pcm;
-       int err;
+       int dev, err;
 
-       if (!codec->num_pcms) {
-               if (!codec->patch_ops.build_pcms)
-                       return 0;
-               err = codec->patch_ops.build_pcms(codec);
-               if (err < 0) {
-                       codec_err(codec,
-                                 "cannot build PCMs for #%d (error %d)\n",
-                                 codec->addr, err);
-                       err = snd_hda_codec_reset(codec);
-                       if (err < 0) {
-                               codec_err(codec,
-                                         "cannot revert codec\n");
-                               return err;
-                       }
-               }
+       if (snd_BUG_ON(!bus->ops.attach_pcm))
+               return -EINVAL;
+
+       err = snd_hda_codec_parse_pcms(codec);
+       if (err < 0) {
+               snd_hda_codec_reset(codec);
+               return err;
        }
+
+       /* attach a new PCM streams */
        for (pcm = 0; pcm < codec->num_pcms; pcm++) {
                struct hda_pcm *cpcm = &codec->pcm_info[pcm];
-               int dev;
 
+               if (cpcm->pcm)
+                       continue; /* already attached */
                if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
                        continue; /* no substreams assigned */
 
-               if (!cpcm->pcm) {
-                       dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type);
-                       if (dev < 0)
-                               continue; /* no fatal error */
-                       cpcm->device = dev;
-                       err = snd_hda_attach_pcm(codec, cpcm);
-                       if (err < 0) {
-                               codec_err(codec,
-                                         "cannot attach PCM stream %d for codec #%d\n",
-                                         dev, codec->addr);
-                               continue; /* no fatal error */
-                       }
+               dev = get_empty_pcm_device(bus, cpcm->pcm_type);
+               if (dev < 0)
+                       continue; /* no fatal error */
+               cpcm->device = dev;
+               err =  bus->ops.attach_pcm(bus, codec, cpcm);
+               if (err < 0) {
+                       codec_err(codec,
+                                 "cannot attach PCM stream %d for codec #%d\n",
+                                 dev, codec->addr);
+                       continue; /* no fatal error */
                }
        }
+
        return 0;
 }