linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / sound / core / oss / pcm_oss.c
index 0691aca..7fd0723 100644 (file)
@@ -78,7 +78,6 @@ static inline void snd_leave_user(mm_segment_t fs)
        set_fs(fs);
 }
 
-#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
@@ -123,7 +122,6 @@ int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin)
        }
        return 0;
 }
-#endif /* CONFIG_SND_PCM_OSS_PLUGINS */
 
 static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames)
 {
@@ -208,8 +206,9 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
                        oss_buffer_size = runtime->oss.mmap_bytes;
        }
 
-       if (substream->oss.setup.period_size > 16)
-               oss_period_size = substream->oss.setup.period_size;
+       if (substream->oss.setup &&
+           substream->oss.setup->period_size > 16)
+               oss_period_size = substream->oss.setup->period_size;
        else if (runtime->oss.fragshift) {
                oss_period_size = 1 << runtime->oss.fragshift;
                if (oss_period_size > oss_buffer_size / 2)
@@ -251,8 +250,10 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
 
        oss_periods = oss_buffer_size / oss_period_size;
 
-       if (substream->oss.setup.periods > 1)
-               oss_periods = substream->oss.setup.periods;
+       if (substream->oss.setup) {
+               if (substream->oss.setup->periods > 1)
+                       oss_periods = substream->oss.setup->periods;
+       }
 
        s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
        if (runtime->oss.maxfrags && s > runtime->oss.maxfrags)
@@ -338,10 +339,12 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
                goto failure;
        }
 
-       if (atomic_read(&runtime->mmap_count))
+       if (atomic_read(&runtime->mmap_count)) {
                direct = 1;
-       else
-               direct = substream->oss.setup.direct;
+       } else {
+               struct snd_pcm_oss_setup *setup = substream->oss.setup;
+               direct = (setup != NULL && setup->direct);
+       }
 
        _snd_pcm_hw_params_any(sparams);
        _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
@@ -409,7 +412,6 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        oss_frame_size = snd_pcm_format_physical_width(params_format(params)) *
                         params_channels(params) / 8;
 
-#ifdef CONFIG_SND_PCM_OSS_PLUGINS
        snd_pcm_oss_plugin_clear(substream);
        if (!direct) {
                /* add necessary plugins */
@@ -439,7 +441,6 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
                        }
                }
        }
-#endif
 
        err = snd_pcm_oss_period_size(substream, params, sparams);
        if (err < 0)
@@ -477,7 +478,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
                1 : runtime->period_size;
        sw_params->xfer_align = 1;
        if (atomic_read(&runtime->mmap_count) ||
-           substream->oss.setup.nosilence) {
+           (substream->oss.setup && substream->oss.setup->nosilence)) {
                sw_params->silence_threshold = 0;
                sw_params->silence_size = 0;
        } else {
@@ -497,13 +498,11 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        runtime->oss.periods = params_periods(sparams);
        oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
        snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);
-#ifdef CONFIG_SND_PCM_OSS_PLUGINS
        if (runtime->oss.plugin_first) {
                err = snd_pcm_plug_alloc(substream, oss_period_size);
                if (err < 0)
                        goto failure;
        }
-#endif
        oss_period_size *= oss_frame_size;
 
        oss_buffer_size = oss_period_size * runtime->oss.periods;
@@ -785,7 +784,6 @@ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const cha
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_sframes_t frames, frames1;
-#ifdef CONFIG_SND_PCM_OSS_PLUGINS
        if (runtime->oss.plugin_first) {
                struct snd_pcm_plugin_channel *channels;
                size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8;
@@ -802,9 +800,7 @@ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const cha
                if (frames1 <= 0)
                        return frames1;
                bytes = frames1 * oss_frame_bytes;
-       } else
-#endif
-       {
+       } else {
                frames = bytes_to_frames(runtime, bytes);
                frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel);
                if (frames1 <= 0)
@@ -838,7 +834,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
                        buf += tmp;
                        bytes -= tmp;
                        xfer += tmp;
-                       if (substream->oss.setup.partialfrag ||
+                       if ((substream->oss.setup != NULL && substream->oss.setup->partialfrag) ||
                            runtime->oss.buffer_used == runtime->oss.period_bytes) {
                                tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr, 
                                                         runtime->oss.buffer_used - runtime->oss.period_ptr, 1);
@@ -875,7 +871,6 @@ static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_sframes_t frames, frames1;
-#ifdef CONFIG_SND_PCM_OSS_PLUGINS
        char __user *final_dst = (char __user *)buf;
        if (runtime->oss.plugin_first) {
                struct snd_pcm_plugin_channel *channels;
@@ -892,9 +887,7 @@ static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf,
                bytes = frames1 * oss_frame_bytes;
                if (!in_kernel && copy_to_user(final_dst, buf, bytes))
                        return -EFAULT;
-       } else
-#endif
-       {
+       } else {
                frames = bytes_to_frames(runtime, bytes);
                frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel);
                if (frames1 <= 0)
@@ -954,12 +947,12 @@ static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file)
 
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
        if (substream != NULL) {
-               snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+               snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
                substream->runtime->oss.prepare = 1;
        }
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
        if (substream != NULL) {
-               snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+               snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
                substream->runtime->oss.prepare = 1;
        }
        return 0;
@@ -974,7 +967,7 @@ static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file)
        if (substream != NULL) {
                if ((err = snd_pcm_oss_make_ready(substream)) < 0)
                        return err;
-               snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
+               snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
        }
        /* note: all errors from the start action are ignored */
        /* OSS apps do not know, how to handle them */
@@ -1103,7 +1096,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
              __direct:
                saved_f_flags = substream->ffile->f_flags;
                substream->ffile->f_flags &= ~O_NONBLOCK;
-               err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
+               err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
                substream->ffile->f_flags = saved_f_flags;
                if (err < 0)
                        return err;
@@ -1115,7 +1108,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
                if ((err = snd_pcm_oss_make_ready(substream)) < 0)
                        return err;
                runtime = substream->runtime;
-               err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+               err = snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
                if (err < 0)
                        return err;
                runtime->oss.buffer_used = 0;
@@ -1209,10 +1202,12 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
 
        if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
                return err;
-       if (atomic_read(&substream->runtime->mmap_count))
+       if (atomic_read(&substream->runtime->mmap_count)) {
                direct = 1;
-       else
-               direct = substream->oss.setup.direct;
+       } else {
+               struct snd_pcm_oss_setup *setup = substream->oss.setup;
+               direct = (setup != NULL && setup->direct);
+       }
        if (!direct)
                return AFMT_MU_LAW | AFMT_U8 |
                       AFMT_S16_LE | AFMT_S16_BE |
@@ -1242,8 +1237,6 @@ static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int for
        
        if (format != AFMT_QUERY) {
                formats = snd_pcm_oss_get_formats(pcm_oss_file);
-               if (formats < 0)
-                       return formats;
                if (!(formats & format))
                        format = AFMT_U8;
                for (idx = 1; idx >= 0; --idx) {
@@ -1432,7 +1425,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
                        cmd = SNDRV_PCM_IOCTL_DROP;
                        runtime->oss.prepare = 1;
                }
-               err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
+               err = snd_pcm_kernel_playback_ioctl(psubstream, cmd, NULL);
                if (err < 0)
                        return err;
        }
@@ -1453,7 +1446,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
                        cmd = SNDRV_PCM_IOCTL_DROP;
                        runtime->oss.prepare = 1;
                }
-               err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
+               err = snd_pcm_kernel_capture_ioctl(csubstream, cmd, NULL);
                if (err < 0)
                        return err;
        }
@@ -1490,7 +1483,7 @@ static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file)
        runtime = substream->runtime;
        if (runtime->oss.params || runtime->oss.prepare)
                return 0;
-       err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
+       err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
        if (err == -EPIPE)
                delay = 0;      /* hack for broken OSS applications */
        else if (err < 0)
@@ -1550,7 +1543,8 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
        } else {
                delay = snd_pcm_oss_bytes(substream, delay);
                if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       if (substream->oss.setup.buggyptr)
+                       struct snd_pcm_oss_setup *setup = substream->oss.setup;
+                       if (setup && setup->buggyptr)
                                info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes;
                        else
                                info.blocks = (delay + fixup) / runtime->oss.period_bytes;
@@ -1632,46 +1626,37 @@ static int snd_pcm_oss_get_mapbuf(struct snd_pcm_oss_file *pcm_oss_file, int str
        return -EINVAL;
 }
 
-static const char *strip_task_path(const char *path)
+static struct snd_pcm_oss_setup *snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream, const char *task_name)
 {
-       const char *ptr, *ptrl = NULL;
-       for (ptr = path; *ptr; ptr++) {
+       const char *ptr, *ptrl;
+       struct snd_pcm_oss_setup *setup;
+
+       down(&pcm->streams[stream].oss.setup_mutex);
+       for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
+               if (!strcmp(setup->task_name, task_name)) {
+                       up(&pcm->streams[stream].oss.setup_mutex);
+                       return setup;
+               }
+       }
+       ptr = ptrl = task_name;
+       while (*ptr) {
                if (*ptr == '/')
                        ptrl = ptr + 1;
+               ptr++;
        }
-       return ptrl;
-}
-
-static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
-                                     const char *task_name,
-                                     struct snd_pcm_oss_setup *rsetup)
-{
-       struct snd_pcm_oss_setup *setup;
-
-       mutex_lock(&pcm->streams[stream].oss.setup_mutex);
-       do {
-               for (setup = pcm->streams[stream].oss.setup_list; setup;
-                    setup = setup->next) {
-                       if (!strcmp(setup->task_name, task_name))
-                               goto out;
+       if (ptrl == task_name) {
+               goto __not_found;
+               return NULL;
+       }
+       for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
+               if (!strcmp(setup->task_name, ptrl)) {
+                       up(&pcm->streams[stream].oss.setup_mutex);
+                       return setup;
                }
-       } while ((task_name = strip_task_path(task_name)) != NULL);
- out:
-       if (setup)
-               *rsetup = *setup;
-       mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
-}
-
-static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime;
-       runtime = substream->runtime;
-       vfree(runtime->oss.buffer);
-       runtime->oss.buffer = NULL;
-#ifdef CONFIG_SND_PCM_OSS_PLUGINS
-       snd_pcm_oss_plugin_clear(substream);
-#endif
-       substream->oss.oss = 0;
+       }
+      __not_found:
+       up(&pcm->streams[stream].oss.setup_mutex);
+       return NULL;
 }
 
 static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
@@ -1681,11 +1666,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime;
 
        substream->oss.oss = 1;
-       substream->oss.setup = *setup;
-       if (setup->nonblock)
-               substream->ffile->f_flags |= O_NONBLOCK;
-       else if (setup->block)
-               substream->ffile->f_flags &= ~O_NONBLOCK;
+       substream->oss.setup = setup;
        runtime = substream->runtime;
        runtime->oss.params = 1;
        runtime->oss.trigger = 1;
@@ -1704,7 +1685,16 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
        runtime->oss.fragshift = 0;
        runtime->oss.maxfrags = 0;
        runtime->oss.subdivision = 0;
-       substream->pcm_release = snd_pcm_oss_release_substream;
+}
+
+static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime;
+       runtime = substream->runtime;
+       vfree(runtime->oss.buffer);
+       snd_pcm_oss_plugin_clear(substream);
+       substream->oss.file = NULL;
+       substream->oss.oss = 0;
 }
 
 static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
@@ -1713,8 +1703,23 @@ static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
        snd_assert(pcm_oss_file != NULL, return -ENXIO);
        for (cidx = 0; cidx < 2; ++cidx) {
                struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx];
-               if (substream)
-                       snd_pcm_release_substream(substream);
+               struct snd_pcm_runtime *runtime;
+               if (substream == NULL)
+                       continue;
+               runtime = substream->runtime;
+               
+               snd_pcm_stream_lock_irq(substream);
+               if (snd_pcm_running(substream))
+                       snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
+               snd_pcm_stream_unlock_irq(substream);
+               if (substream->ffile != NULL) {
+                       if (substream->ops->hw_free != NULL)
+                               substream->ops->hw_free(substream);
+                       substream->ops->close(substream);
+                       substream->ffile = NULL;
+               }
+               snd_pcm_oss_release_substream(substream);
+               snd_pcm_release_substream(substream);
        }
        kfree(pcm_oss_file);
        return 0;
@@ -1724,11 +1729,12 @@ static int snd_pcm_oss_open_file(struct file *file,
                                 struct snd_pcm *pcm,
                                 struct snd_pcm_oss_file **rpcm_oss_file,
                                 int minor,
-                                struct snd_pcm_oss_setup *setup)
+                                struct snd_pcm_oss_setup *psetup,
+                                struct snd_pcm_oss_setup *csetup)
 {
-       int idx, err;
+       int err = 0;
        struct snd_pcm_oss_file *pcm_oss_file;
-       struct snd_pcm_substream *substream;
+       struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
        unsigned int f_mode = file->f_mode;
 
        snd_assert(rpcm_oss_file != NULL, return -EINVAL);
@@ -1741,34 +1747,73 @@ static int snd_pcm_oss_open_file(struct file *file,
        if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) &&
            (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
                f_mode = FMODE_WRITE;
-
-       for (idx = 0; idx < 2; idx++) {
-               if (setup[idx].disable)
-                       continue;
-               if (! pcm->streams[idx].substream_count)
-                       continue; /* no matching substream */
-               if (idx == SNDRV_PCM_STREAM_PLAYBACK) {
-                       if (! (f_mode & FMODE_WRITE))
-                               continue;
-               } else {
-                       if (! (f_mode & FMODE_READ))
-                               continue;
-               }
-               err = snd_pcm_open_substream(pcm, idx, file, &substream);
-               if (err < 0) {
+       if ((f_mode & FMODE_WRITE) && !(psetup && psetup->disable)) {
+               if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                              &psubstream)) < 0) {
                        snd_pcm_oss_release_file(pcm_oss_file);
                        return err;
                }
-
-               pcm_oss_file->streams[idx] = substream;
-               substream->file = pcm_oss_file;
-               snd_pcm_oss_init_substream(substream, &setup[idx], minor);
+               pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK] = psubstream;
+       }
+       if ((f_mode & FMODE_READ) && !(csetup && csetup->disable)) {
+               if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_CAPTURE, 
+                                              &csubstream)) < 0) {
+                       if (!(f_mode & FMODE_WRITE) || err != -ENODEV) {
+                               snd_pcm_oss_release_file(pcm_oss_file);
+                               return err;
+                       } else {
+                               csubstream = NULL;
+                       }
+               }
+               pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE] = csubstream;
        }
        
-       if (!pcm_oss_file->streams[0] && !pcm_oss_file->streams[1]) {
+       if (psubstream == NULL && csubstream == NULL) {
                snd_pcm_oss_release_file(pcm_oss_file);
                return -EINVAL;
        }
+       if (psubstream != NULL) {
+               psubstream->oss.file = pcm_oss_file;
+               err = snd_pcm_hw_constraints_init(psubstream);
+               if (err < 0) {
+                       snd_printd("snd_pcm_hw_constraint_init failed\n");
+                       snd_pcm_oss_release_file(pcm_oss_file);
+                       return err;
+               }
+               if ((err = psubstream->ops->open(psubstream)) < 0) {
+                       snd_pcm_oss_release_file(pcm_oss_file);
+                       return err;
+               }
+               psubstream->ffile = file;
+               err = snd_pcm_hw_constraints_complete(psubstream);
+               if (err < 0) {
+                       snd_printd("snd_pcm_hw_constraint_complete failed\n");
+                       snd_pcm_oss_release_file(pcm_oss_file);
+                       return err;
+               }
+               snd_pcm_oss_init_substream(psubstream, psetup, minor);
+       }
+       if (csubstream != NULL) {
+               csubstream->oss.file = pcm_oss_file;
+               err = snd_pcm_hw_constraints_init(csubstream);
+               if (err < 0) {
+                       snd_printd("snd_pcm_hw_constraint_init failed\n");
+                       snd_pcm_oss_release_file(pcm_oss_file);
+                       return err;
+               }
+               if ((err = csubstream->ops->open(csubstream)) < 0) {
+                       snd_pcm_oss_release_file(pcm_oss_file);
+                       return err;
+               }
+               csubstream->ffile = file;
+               err = snd_pcm_hw_constraints_complete(csubstream);
+               if (err < 0) {
+                       snd_printd("snd_pcm_hw_constraint_complete failed\n");
+                       snd_pcm_oss_release_file(pcm_oss_file);
+                       return err;
+               }
+               snd_pcm_oss_init_substream(csubstream, csetup, minor);
+       }
 
        file->private_data = pcm_oss_file;
        *rpcm_oss_file = pcm_oss_file;
@@ -1793,16 +1838,9 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
        char task_name[32];
        struct snd_pcm *pcm;
        struct snd_pcm_oss_file *pcm_oss_file;
-       struct snd_pcm_oss_setup setup[2];
+       struct snd_pcm_oss_setup *psetup = NULL, *csetup = NULL;
        int nonblock;
        wait_queue_t wait;
-       static char printed_comm[16];
-
-       if (strncmp(printed_comm, current->comm, 16)) {
-               printk(KERN_DEBUG "application %s uses obsolete OSS audio interface\n",
-                      current->comm);
-               memcpy(printed_comm, current->comm, 16);
-       }
 
        pcm = snd_lookup_oss_minor_data(iminor(inode),
                                        SNDRV_OSS_DEVICE_TYPE_PCM);
@@ -1821,24 +1859,32 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
                err = -EFAULT;
                goto __error;
        }
-       memset(setup, 0, sizeof(setup));
        if (file->f_mode & FMODE_WRITE)
-               snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-                                          task_name, &setup[0]);
+               psetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, task_name);
        if (file->f_mode & FMODE_READ)
-               snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE,
-                                          task_name, &setup[1]);
+               csetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE, task_name);
 
        nonblock = !!(file->f_flags & O_NONBLOCK);
+       if (psetup && !psetup->disable) {
+               if (psetup->nonblock)
+                       nonblock = 1;
+               else if (psetup->block)
+                       nonblock = 0;
+       } else if (csetup && !csetup->disable) {
+               if (csetup->nonblock)
+                       nonblock = 1;
+               else if (csetup->block)
+                       nonblock = 0;
+       }
        if (!nonblock)
                nonblock = nonblock_open;
 
        init_waitqueue_entry(&wait, current);
        add_wait_queue(&pcm->open_wait, &wait);
-       mutex_lock(&pcm->open_mutex);
+       down(&pcm->open_mutex);
        while (1) {
                err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
-                                           iminor(inode), setup);
+                                           iminor(inode), psetup, csetup);
                if (err >= 0)
                        break;
                if (err == -EAGAIN) {
@@ -1849,16 +1895,16 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
                } else
                        break;
                set_current_state(TASK_INTERRUPTIBLE);
-               mutex_unlock(&pcm->open_mutex);
+               up(&pcm->open_mutex);
                schedule();
-               mutex_lock(&pcm->open_mutex);
+               down(&pcm->open_mutex);
                if (signal_pending(current)) {
                        err = -ERESTARTSYS;
                        break;
                }
        }
        remove_wait_queue(&pcm->open_wait, &wait);
-       mutex_unlock(&pcm->open_mutex);
+       up(&pcm->open_mutex);
        if (err < 0)
                goto __error;
        return err;
@@ -1884,9 +1930,9 @@ static int snd_pcm_oss_release(struct inode *inode, struct file *file)
        snd_assert(substream != NULL, return -ENXIO);
        pcm = substream->pcm;
        snd_pcm_oss_sync(pcm_oss_file);
-       mutex_lock(&pcm->open_mutex);
+       down(&pcm->open_mutex);
        snd_pcm_oss_release_file(pcm_oss_file);
-       mutex_unlock(&pcm->open_mutex);
+       up(&pcm->open_mutex);
        wake_up(&pcm->open_wait);
        module_put(pcm->card->module);
        snd_card_file_remove(pcm->card, file);
@@ -2200,10 +2246,8 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
                if ((err = snd_pcm_oss_change_params(substream)) < 0)
                        return err;
        }
-#ifdef CONFIG_SND_PCM_OSS_PLUGINS
        if (runtime->oss.plugin_first != NULL)
                return -EIO;
-#endif
 
        if (area->vm_pgoff != 0)
                return -EINVAL;
@@ -2223,7 +2267,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
        return 0;
 }
 
-#ifdef CONFIG_SND_VERBOSE_PROCFS
+#ifdef CONFIG_PROC_FS
 /*
  *  /proc interface
  */
@@ -2233,7 +2277,7 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
 {
        struct snd_pcm_str *pstr = entry->private_data;
        struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
-       mutex_lock(&pstr->oss.setup_mutex);
+       down(&pstr->oss.setup_mutex);
        while (setup) {
                snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
                            setup->task_name,
@@ -2247,13 +2291,18 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
                            setup->nosilence ? " no-silence" : "");
                setup = setup->next;
        }
-       mutex_unlock(&pstr->oss.setup_mutex);
+       up(&pstr->oss.setup_mutex);
 }
 
 static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
 {
+       unsigned int idx;
+       struct snd_pcm_substream *substream;
        struct snd_pcm_oss_setup *setup, *setupn;
 
+       for (idx = 0, substream = pstr->substream;
+            idx < pstr->substream_count; idx++, substream = substream->next)
+               substream->oss.setup = NULL;
        for (setup = pstr->oss.setup_list, pstr->oss.setup_list = NULL;
             setup; setup = setupn) {
                setupn = setup->next;
@@ -2272,12 +2321,12 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
        struct snd_pcm_oss_setup *setup, *setup1, template;
 
        while (!snd_info_get_line(buffer, line, sizeof(line))) {
-               mutex_lock(&pstr->oss.setup_mutex);
+               down(&pstr->oss.setup_mutex);
                memset(&template, 0, sizeof(template));
                ptr = snd_info_get_str(task_name, line, sizeof(task_name));
                if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
                        snd_pcm_oss_proc_free_setup_list(pstr);
-                       mutex_unlock(&pstr->oss.setup_mutex);
+                       up(&pstr->oss.setup_mutex);
                        continue;
                }
                for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
@@ -2314,29 +2363,22 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
                        }
                } while (*str);
                if (setup == NULL) {
-                       setup = kmalloc(sizeof(*setup), GFP_KERNEL);
-                       if (! setup) {
-                               buffer->error = -ENOMEM;
-                               mutex_lock(&pstr->oss.setup_mutex);
-                               return;
-                       }
-                       if (pstr->oss.setup_list == NULL)
-                               pstr->oss.setup_list = setup;
-                       else {
-                               for (setup1 = pstr->oss.setup_list;
-                                    setup1->next; setup1 = setup1->next);
-                               setup1->next = setup;
-                       }
-                       template.task_name = kstrdup(task_name, GFP_KERNEL);
-                       if (! template.task_name) {
-                               kfree(setup);
+                       setup = kmalloc(sizeof(struct snd_pcm_oss_setup), GFP_KERNEL);
+                       if (setup) {
+                               if (pstr->oss.setup_list == NULL) {
+                                       pstr->oss.setup_list = setup;
+                               } else {
+                                       for (setup1 = pstr->oss.setup_list; setup1->next; setup1 = setup1->next);
+                                       setup1->next = setup;
+                               }
+                               template.task_name = kstrdup(task_name, GFP_KERNEL);
+                       } else {
                                buffer->error = -ENOMEM;
-                               mutex_lock(&pstr->oss.setup_mutex);
-                               return;
                        }
                }
-               *setup = template;
-               mutex_unlock(&pstr->oss.setup_mutex);
+               if (setup)
+                       *setup = template;
+               up(&pstr->oss.setup_mutex);
        }
 }
 
@@ -2377,10 +2419,10 @@ static void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
                }
        }
 }
-#else /* !CONFIG_SND_VERBOSE_PROCFS */
+#else /* !CONFIG_PROC_FS */
 #define snd_pcm_oss_proc_init(pcm)
 #define snd_pcm_oss_proc_done(pcm)
-#endif /* CONFIG_SND_VERBOSE_PROCFS */
+#endif /* CONFIG_PROC_FS */
 
 /*
  *  ENTRY functions