linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / sound / core / oss / pcm_oss.c
index 48f7ed4..7fd0723 100644 (file)
@@ -45,7 +45,7 @@
 
 #define OSS_ALSAEMULVER                _SIOR ('M', 249, int)
 
-static int dsp_map[SNDRV_CARDS];
+static int dsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
 static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
 static int nonblock_open = 1;
 
@@ -78,488 +78,6 @@ static inline void snd_leave_user(mm_segment_t fs)
        set_fs(fs);
 }
 
-/*
- * helper functions to process hw_params
- */
-static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin)
-{
-       int changed = 0;
-       if (i->min < min) {
-               i->min = min;
-               i->openmin = openmin;
-               changed = 1;
-       } else if (i->min == min && !i->openmin && openmin) {
-               i->openmin = 1;
-               changed = 1;
-       }
-       if (i->integer) {
-               if (i->openmin) {
-                       i->min++;
-                       i->openmin = 0;
-               }
-       }
-       if (snd_interval_checkempty(i)) {
-               snd_interval_none(i);
-               return -EINVAL;
-       }
-       return changed;
-}
-
-static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax)
-{
-       int changed = 0;
-       if (i->max > max) {
-               i->max = max;
-               i->openmax = openmax;
-               changed = 1;
-       } else if (i->max == max && !i->openmax && openmax) {
-               i->openmax = 1;
-               changed = 1;
-       }
-       if (i->integer) {
-               if (i->openmax) {
-                       i->max--;
-                       i->openmax = 0;
-               }
-       }
-       if (snd_interval_checkempty(i)) {
-               snd_interval_none(i);
-               return -EINVAL;
-       }
-       return changed;
-}
-
-static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
-{
-       struct snd_interval t;
-       t.empty = 0;
-       t.min = t.max = val;
-       t.openmin = t.openmax = 0;
-       t.integer = 1;
-       return snd_interval_refine(i, &t);
-}
-
-/**
- * snd_pcm_hw_param_value_min
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Return the minimum value for field PAR.
- */
-static unsigned int
-snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
-                          snd_pcm_hw_param_t var, int *dir)
-{
-       if (hw_is_mask(var)) {
-               if (dir)
-                       *dir = 0;
-               return snd_mask_min(hw_param_mask_c(params, var));
-       }
-       if (hw_is_interval(var)) {
-               const struct snd_interval *i = hw_param_interval_c(params, var);
-               if (dir)
-                       *dir = i->openmin;
-               return snd_interval_min(i);
-       }
-       return -EINVAL;
-}
-
-/**
- * snd_pcm_hw_param_value_max
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Return the maximum value for field PAR.
- */
-static unsigned int
-snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
-                          snd_pcm_hw_param_t var, int *dir)
-{
-       if (hw_is_mask(var)) {
-               if (dir)
-                       *dir = 0;
-               return snd_mask_max(hw_param_mask_c(params, var));
-       }
-       if (hw_is_interval(var)) {
-               const struct snd_interval *i = hw_param_interval_c(params, var);
-               if (dir)
-                       *dir = - (int) i->openmax;
-               return snd_interval_max(i);
-       }
-       return -EINVAL;
-}
-
-static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params,
-                                 snd_pcm_hw_param_t var,
-                                 const struct snd_mask *val)
-{
-       int changed;
-       changed = snd_mask_refine(hw_param_mask(params, var), val);
-       if (changed) {
-               params->cmask |= 1 << var;
-               params->rmask |= 1 << var;
-       }
-       return changed;
-}
-
-static int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm,
-                                struct snd_pcm_hw_params *params,
-                                snd_pcm_hw_param_t var,
-                                const struct snd_mask *val)
-{
-       int changed = _snd_pcm_hw_param_mask(params, var, val);
-       if (changed < 0)
-               return changed;
-       if (params->rmask) {
-               int err = snd_pcm_hw_refine(pcm, params);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
-                                snd_pcm_hw_param_t var, unsigned int val,
-                                int dir)
-{
-       int changed;
-       int open = 0;
-       if (dir) {
-               if (dir > 0) {
-                       open = 1;
-               } else if (dir < 0) {
-                       if (val > 0) {
-                               open = 1;
-                               val--;
-                       }
-               }
-       }
-       if (hw_is_mask(var))
-               changed = snd_mask_refine_min(hw_param_mask(params, var),
-                                             val + !!open);
-       else if (hw_is_interval(var))
-               changed = snd_interval_refine_min(hw_param_interval(params, var),
-                                                 val, open);
-       else
-               return -EINVAL;
-       if (changed) {
-               params->cmask |= 1 << var;
-               params->rmask |= 1 << var;
-       }
-       return changed;
-}
-
-/**
- * snd_pcm_hw_param_min
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: minimal value
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS remove from PAR all 
- * values < VAL. Reduce configuration space accordingly.
- * Return new minimum or -EINVAL if the configuration space is empty
- */
-static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm,
-                               struct snd_pcm_hw_params *params,
-                               snd_pcm_hw_param_t var, unsigned int val,
-                               int *dir)
-{
-       int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
-       if (changed < 0)
-               return changed;
-       if (params->rmask) {
-               int err = snd_pcm_hw_refine(pcm, params);
-               if (err < 0)
-                       return err;
-       }
-       return snd_pcm_hw_param_value_min(params, var, dir);
-}
-
-static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
-                                snd_pcm_hw_param_t var, unsigned int val,
-                                int dir)
-{
-       int changed;
-       int open = 0;
-       if (dir) {
-               if (dir < 0) {
-                       open = 1;
-               } else if (dir > 0) {
-                       open = 1;
-                       val++;
-               }
-       }
-       if (hw_is_mask(var)) {
-               if (val == 0 && open) {
-                       snd_mask_none(hw_param_mask(params, var));
-                       changed = -EINVAL;
-               } else
-                       changed = snd_mask_refine_max(hw_param_mask(params, var),
-                                                     val - !!open);
-       } else if (hw_is_interval(var))
-               changed = snd_interval_refine_max(hw_param_interval(params, var),
-                                                 val, open);
-       else
-               return -EINVAL;
-       if (changed) {
-               params->cmask |= 1 << var;
-               params->rmask |= 1 << var;
-       }
-       return changed;
-}
-
-/**
- * snd_pcm_hw_param_max
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: maximal value
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS remove from PAR all 
- *  values >= VAL + 1. Reduce configuration space accordingly.
- *  Return new maximum or -EINVAL if the configuration space is empty
- */
-static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm,
-                               struct snd_pcm_hw_params *params,
-                               snd_pcm_hw_param_t var, unsigned int val,
-                               int *dir)
-{
-       int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
-       if (changed < 0)
-               return changed;
-       if (params->rmask) {
-               int err = snd_pcm_hw_refine(pcm, params);
-               if (err < 0)
-                       return err;
-       }
-       return snd_pcm_hw_param_value_max(params, var, dir);
-}
-
-static int boundary_sub(int a, int adir,
-                       int b, int bdir,
-                       int *c, int *cdir)
-{
-       adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
-       bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
-       *c = a - b;
-       *cdir = adir - bdir;
-       if (*cdir == -2) {
-               (*c)--;
-       } else if (*cdir == 2) {
-               (*c)++;
-       }
-       return 0;
-}
-
-static int boundary_lt(unsigned int a, int adir,
-                      unsigned int b, int bdir)
-{
-       if (adir < 0) {
-               a--;
-               adir = 1;
-       } else if (adir > 0)
-               adir = 1;
-       if (bdir < 0) {
-               b--;
-               bdir = 1;
-       } else if (bdir > 0)
-               bdir = 1;
-       return a < b || (a == b && adir < bdir);
-}
-
-/* Return 1 if min is nearer to best than max */
-static int boundary_nearer(int min, int mindir,
-                          int best, int bestdir,
-                          int max, int maxdir)
-{
-       int dmin, dmindir;
-       int dmax, dmaxdir;
-       boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
-       boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
-       return boundary_lt(dmin, dmindir, dmax, dmaxdir);
-}
-
-/**
- * snd_pcm_hw_param_near
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @best: value to set
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS set PAR to the available value
- * nearest to VAL. Reduce configuration space accordingly.
- * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
- * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
- * Return the value found.
-  */
-static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
-                                struct snd_pcm_hw_params *params,
-                                snd_pcm_hw_param_t var, unsigned int best,
-                                int *dir)
-{
-       struct snd_pcm_hw_params *save = NULL;
-       int v;
-       unsigned int saved_min;
-       int last = 0;
-       int min, max;
-       int mindir, maxdir;
-       int valdir = dir ? *dir : 0;
-       /* FIXME */
-       if (best > INT_MAX)
-               best = INT_MAX;
-       min = max = best;
-       mindir = maxdir = valdir;
-       if (maxdir > 0)
-               maxdir = 0;
-       else if (maxdir == 0)
-               maxdir = -1;
-       else {
-               maxdir = 1;
-               max--;
-       }
-       save = kmalloc(sizeof(*save), GFP_KERNEL);
-       if (save == NULL)
-               return -ENOMEM;
-       *save = *params;
-       saved_min = min;
-       min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
-       if (min >= 0) {
-               struct snd_pcm_hw_params *params1;
-               if (max < 0)
-                       goto _end;
-               if ((unsigned int)min == saved_min && mindir == valdir)
-                       goto _end;
-               params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
-               if (params1 == NULL) {
-                       kfree(save);
-                       return -ENOMEM;
-               }
-               *params1 = *save;
-               max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
-               if (max < 0) {
-                       kfree(params1);
-                       goto _end;
-               }
-               if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
-                       *params = *params1;
-                       last = 1;
-               }
-               kfree(params1);
-       } else {
-               *params = *save;
-               max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
-               snd_assert(max >= 0, return -EINVAL);
-               last = 1;
-       }
- _end:
-       kfree(save);
-       if (last)
-               v = snd_pcm_hw_param_last(pcm, params, var, dir);
-       else
-               v = snd_pcm_hw_param_first(pcm, params, var, dir);
-       snd_assert(v >= 0, return -EINVAL);
-       return v;
-}
-
-static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
-                                snd_pcm_hw_param_t var, unsigned int val,
-                                int dir)
-{
-       int changed;
-       if (hw_is_mask(var)) {
-               struct snd_mask *m = hw_param_mask(params, var);
-               if (val == 0 && dir < 0) {
-                       changed = -EINVAL;
-                       snd_mask_none(m);
-               } else {
-                       if (dir > 0)
-                               val++;
-                       else if (dir < 0)
-                               val--;
-                       changed = snd_mask_refine_set(hw_param_mask(params, var), val);
-               }
-       } else if (hw_is_interval(var)) {
-               struct snd_interval *i = hw_param_interval(params, var);
-               if (val == 0 && dir < 0) {
-                       changed = -EINVAL;
-                       snd_interval_none(i);
-               } else if (dir == 0)
-                       changed = snd_interval_refine_set(i, val);
-               else {
-                       struct snd_interval t;
-                       t.openmin = 1;
-                       t.openmax = 1;
-                       t.empty = 0;
-                       t.integer = 0;
-                       if (dir < 0) {
-                               t.min = val - 1;
-                               t.max = val;
-                       } else {
-                               t.min = val;
-                               t.max = val+1;
-                       }
-                       changed = snd_interval_refine(i, &t);
-               }
-       } else
-               return -EINVAL;
-       if (changed) {
-               params->cmask |= 1 << var;
-               params->rmask |= 1 << var;
-       }
-       return changed;
-}
-
-/**
- * snd_pcm_hw_param_set
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: value to set
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS remove from PAR all 
- * values != VAL. Reduce configuration space accordingly.
- *  Return VAL or -EINVAL if the configuration space is empty
- */
-static int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,
-                               struct snd_pcm_hw_params *params,
-                               snd_pcm_hw_param_t var, unsigned int val,
-                               int dir)
-{
-       int changed = _snd_pcm_hw_param_set(params, var, val, dir);
-       if (changed < 0)
-               return changed;
-       if (params->rmask) {
-               int err = snd_pcm_hw_refine(pcm, params);
-               if (err < 0)
-                       return err;
-       }
-       return snd_pcm_hw_param_value(params, var, NULL);
-}
-
-static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
-                                       snd_pcm_hw_param_t var)
-{
-       int changed;
-       changed = snd_interval_setinteger(hw_param_interval(params, var));
-       if (changed) {
-               params->cmask |= 1 << var;
-               params->rmask |= 1 << var;
-       }
-       return changed;
-}
-       
-/*
- * plugin
- */
-
-#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;
@@ -604,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)
 {
@@ -684,13 +201,14 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
        oss_buffer_size = snd_pcm_plug_client_size(substream,
                                                   snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
        oss_buffer_size = 1 << ld2(oss_buffer_size);
-       if (atomic_read(&substream->mmap_count)) {
+       if (atomic_read(&runtime->mmap_count)) {
                if (oss_buffer_size > runtime->oss.mmap_bytes)
                        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)
@@ -732,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)
@@ -819,16 +339,18 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
                goto failure;
        }
 
-       if (atomic_read(&substream->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);
        _snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
        snd_mask_none(&mask);
-       if (atomic_read(&substream->mmap_count))
+       if (atomic_read(&runtime->mmap_count))
                snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
        else {
                snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
@@ -890,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 */
@@ -920,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)
@@ -947,8 +467,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        } else {
                sw_params->start_threshold = runtime->boundary;
        }
-       if (atomic_read(&substream->mmap_count) ||
-           substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+       if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE)
                sw_params->stop_threshold = runtime->boundary;
        else
                sw_params->stop_threshold = runtime->buffer_size;
@@ -958,8 +477,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
                1 : runtime->period_size;
        sw_params->xfer_align = 1;
-       if (atomic_read(&substream->mmap_count) ||
-           substream->oss.setup.nosilence) {
+       if (atomic_read(&runtime->mmap_count) ||
+           (substream->oss.setup && substream->oss.setup->nosilence)) {
                sw_params->silence_threshold = 0;
                sw_params->silence_size = 0;
        } else {
@@ -979,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;
@@ -1267,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;
@@ -1284,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)
@@ -1302,7 +816,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
        ssize_t tmp;
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       if (atomic_read(&substream->mmap_count))
+       if (atomic_read(&runtime->mmap_count))
                return -ENXIO;
 
        if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
@@ -1320,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);
@@ -1332,7 +846,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
                                if (runtime->oss.period_ptr == 0 ||
                                    runtime->oss.period_ptr == runtime->oss.buffer_used)
                                        runtime->oss.buffer_used = 0;
-                               else if ((substream->f_flags & O_NONBLOCK) != 0)
+                               else if ((substream->ffile->f_flags & O_NONBLOCK) != 0)
                                        return xfer > 0 ? xfer : -EAGAIN;
                        }
                } else {
@@ -1345,7 +859,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
                        buf += tmp;
                        bytes -= tmp;
                        xfer += tmp;
-                       if ((substream->f_flags & O_NONBLOCK) != 0 &&
+                       if ((substream->ffile->f_flags & O_NONBLOCK) != 0 &&
                            tmp != runtime->oss.period_bytes)
                                break;
                }
@@ -1357,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;
@@ -1374,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)
@@ -1392,7 +903,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
        ssize_t tmp;
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       if (atomic_read(&substream->mmap_count))
+       if (atomic_read(&runtime->mmap_count))
                return -ENXIO;
 
        if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
@@ -1436,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;
@@ -1456,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 */
@@ -1469,13 +980,6 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
        ssize_t result = 0;
        long res;
        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);
-       }
 
        runtime = substream->runtime;
        init_waitqueue_entry(&wait, current);
@@ -1529,7 +1033,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
        if (substream != NULL) {
                runtime = substream->runtime;
-               if (atomic_read(&substream->mmap_count))
+               if (atomic_read(&runtime->mmap_count))
                        goto __direct;
                if ((err = snd_pcm_oss_make_ready(substream)) < 0)
                        return err;
@@ -1590,10 +1094,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
                 * finish sync: drain the buffer
                 */
              __direct:
-               saved_f_flags = substream->f_flags;
-               substream->f_flags &= ~O_NONBLOCK;
-               err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
-               substream->f_flags = saved_f_flags;
+               saved_f_flags = substream->ffile->f_flags;
+               substream->ffile->f_flags &= ~O_NONBLOCK;
+               err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
+               substream->ffile->f_flags = saved_f_flags;
                if (err < 0)
                        return err;
                runtime->oss.prepare = 1;
@@ -1604,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;
@@ -1698,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->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 |
@@ -1731,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) {
@@ -1908,7 +1412,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
                if (trigger & PCM_ENABLE_OUTPUT) {
                        if (runtime->oss.trigger)
                                goto _skip1;
-                       if (atomic_read(&psubstream->mmap_count))
+                       if (atomic_read(&psubstream->runtime->mmap_count))
                                snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
                        runtime->oss.trigger = 1;
                        runtime->start_threshold = 1;
@@ -1921,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;
        }
@@ -1942,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;
        }
@@ -1979,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)
@@ -2026,7 +1530,7 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
        if (err < 0)
                return err;
        info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
-       if (atomic_read(&substream->mmap_count)) {
+       if (atomic_read(&runtime->mmap_count)) {
                snd_pcm_sframes_t n;
                n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
                if (n < 0)
@@ -2039,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;
@@ -2121,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,
@@ -2170,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->f_flags |= O_NONBLOCK;
-       else if (setup->block)
-               substream->f_flags &= ~O_NONBLOCK;
+       substream->oss.setup = setup;
        runtime = substream->runtime;
        runtime->oss.params = 1;
        runtime->oss.trigger = 1;
@@ -2193,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)
@@ -2202,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;
@@ -2213,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);
@@ -2230,35 +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;
-
-       file->f_flags &= ~O_APPEND;
-       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;
@@ -2283,7 +1838,7 @@ 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;
 
@@ -2304,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) {
@@ -2332,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;
@@ -2367,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);
@@ -2551,7 +2114,6 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
        if (substream == NULL)
                return -ENXIO;
-       substream->f_flags = file->f_flags & O_NONBLOCK;
 #ifndef OSS_DEBUG
        return snd_pcm_oss_read1(substream, buf, count);
 #else
@@ -2573,7 +2135,6 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
        if (substream == NULL)
                return -ENXIO;
-       substream->f_flags = file->f_flags & O_NONBLOCK;
        result = snd_pcm_oss_write1(substream, buf, count);
 #ifdef OSS_DEBUG
        printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
@@ -2584,7 +2145,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
 static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       if (atomic_read(&substream->mmap_count))
+       if (atomic_read(&runtime->mmap_count))
                return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
        else
                return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
@@ -2593,7 +2154,7 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
 static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       if (atomic_read(&substream->mmap_count))
+       if (atomic_read(&runtime->mmap_count))
                return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
        else
                return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
@@ -2685,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;
@@ -2708,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
  */
@@ -2718,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,
@@ -2732,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;
@@ -2757,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) {
@@ -2799,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);
        }
 }
 
@@ -2836,7 +2393,9 @@ static void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
                if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) {
                        entry->content = SNDRV_INFO_CONTENT_TEXT;
                        entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+                       entry->c.text.read_size = 8192;
                        entry->c.text.read = snd_pcm_oss_proc_read;
+                       entry->c.text.write_size = 8192;
                        entry->c.text.write = snd_pcm_oss_proc_write;
                        entry->private_data = pstr;
                        if (snd_info_register(entry) < 0) {
@@ -2860,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