Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Digital Audio (PCM) abstract layer / OSS compatible
0004  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0005  */
0006 
0007 #if 0
0008 #define PLUGIN_DEBUG
0009 #endif
0010 #if 0
0011 #define OSS_DEBUG
0012 #endif
0013 
0014 #include <linux/init.h>
0015 #include <linux/slab.h>
0016 #include <linux/sched/signal.h>
0017 #include <linux/time.h>
0018 #include <linux/vmalloc.h>
0019 #include <linux/module.h>
0020 #include <linux/math64.h>
0021 #include <linux/string.h>
0022 #include <linux/compat.h>
0023 #include <sound/core.h>
0024 #include <sound/minors.h>
0025 #include <sound/pcm.h>
0026 #include <sound/pcm_params.h>
0027 #include "pcm_plugin.h"
0028 #include <sound/info.h>
0029 #include <linux/soundcard.h>
0030 #include <sound/initval.h>
0031 #include <sound/mixer_oss.h>
0032 
0033 #define OSS_ALSAEMULVER     _SIOR ('M', 249, int)
0034 
0035 static int dsp_map[SNDRV_CARDS];
0036 static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
0037 static bool nonblock_open = 1;
0038 
0039 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");
0040 MODULE_DESCRIPTION("PCM OSS emulation for ALSA.");
0041 MODULE_LICENSE("GPL");
0042 module_param_array(dsp_map, int, NULL, 0444);
0043 MODULE_PARM_DESC(dsp_map, "PCM device number assigned to 1st OSS device.");
0044 module_param_array(adsp_map, int, NULL, 0444);
0045 MODULE_PARM_DESC(adsp_map, "PCM device number assigned to 2nd OSS device.");
0046 module_param(nonblock_open, bool, 0644);
0047 MODULE_PARM_DESC(nonblock_open, "Don't block opening busy PCM devices.");
0048 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM);
0049 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM1);
0050 
0051 static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file);
0052 static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file);
0053 static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file);
0054 
0055 /*
0056  * helper functions to process hw_params
0057  */
0058 static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin)
0059 {
0060     int changed = 0;
0061     if (i->min < min) {
0062         i->min = min;
0063         i->openmin = openmin;
0064         changed = 1;
0065     } else if (i->min == min && !i->openmin && openmin) {
0066         i->openmin = 1;
0067         changed = 1;
0068     }
0069     if (i->integer) {
0070         if (i->openmin) {
0071             i->min++;
0072             i->openmin = 0;
0073         }
0074     }
0075     if (snd_interval_checkempty(i)) {
0076         snd_interval_none(i);
0077         return -EINVAL;
0078     }
0079     return changed;
0080 }
0081 
0082 static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax)
0083 {
0084     int changed = 0;
0085     if (i->max > max) {
0086         i->max = max;
0087         i->openmax = openmax;
0088         changed = 1;
0089     } else if (i->max == max && !i->openmax && openmax) {
0090         i->openmax = 1;
0091         changed = 1;
0092     }
0093     if (i->integer) {
0094         if (i->openmax) {
0095             i->max--;
0096             i->openmax = 0;
0097         }
0098     }
0099     if (snd_interval_checkempty(i)) {
0100         snd_interval_none(i);
0101         return -EINVAL;
0102     }
0103     return changed;
0104 }
0105 
0106 static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
0107 {
0108     struct snd_interval t;
0109     t.empty = 0;
0110     t.min = t.max = val;
0111     t.openmin = t.openmax = 0;
0112     t.integer = 1;
0113     return snd_interval_refine(i, &t);
0114 }
0115 
0116 /**
0117  * snd_pcm_hw_param_value_min
0118  * @params: the hw_params instance
0119  * @var: parameter to retrieve
0120  * @dir: pointer to the direction (-1,0,1) or NULL
0121  *
0122  * Return the minimum value for field PAR.
0123  */
0124 static unsigned int
0125 snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
0126                snd_pcm_hw_param_t var, int *dir)
0127 {
0128     if (hw_is_mask(var)) {
0129         if (dir)
0130             *dir = 0;
0131         return snd_mask_min(hw_param_mask_c(params, var));
0132     }
0133     if (hw_is_interval(var)) {
0134         const struct snd_interval *i = hw_param_interval_c(params, var);
0135         if (dir)
0136             *dir = i->openmin;
0137         return snd_interval_min(i);
0138     }
0139     return -EINVAL;
0140 }
0141 
0142 /**
0143  * snd_pcm_hw_param_value_max
0144  * @params: the hw_params instance
0145  * @var: parameter to retrieve
0146  * @dir: pointer to the direction (-1,0,1) or NULL
0147  *
0148  * Return the maximum value for field PAR.
0149  */
0150 static int
0151 snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
0152                snd_pcm_hw_param_t var, int *dir)
0153 {
0154     if (hw_is_mask(var)) {
0155         if (dir)
0156             *dir = 0;
0157         return snd_mask_max(hw_param_mask_c(params, var));
0158     }
0159     if (hw_is_interval(var)) {
0160         const struct snd_interval *i = hw_param_interval_c(params, var);
0161         if (dir)
0162             *dir = - (int) i->openmax;
0163         return snd_interval_max(i);
0164     }
0165     return -EINVAL;
0166 }
0167 
0168 static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params,
0169                   snd_pcm_hw_param_t var,
0170                   const struct snd_mask *val)
0171 {
0172     int changed;
0173     changed = snd_mask_refine(hw_param_mask(params, var), val);
0174     if (changed > 0) {
0175         params->cmask |= 1 << var;
0176         params->rmask |= 1 << var;
0177     }
0178     return changed;
0179 }
0180 
0181 static int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm,
0182                  struct snd_pcm_hw_params *params,
0183                  snd_pcm_hw_param_t var,
0184                  const struct snd_mask *val)
0185 {
0186     int changed = _snd_pcm_hw_param_mask(params, var, val);
0187     if (changed < 0)
0188         return changed;
0189     if (params->rmask) {
0190         int err = snd_pcm_hw_refine(pcm, params);
0191         if (err < 0)
0192             return err;
0193     }
0194     return 0;
0195 }
0196 
0197 static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
0198                  snd_pcm_hw_param_t var, unsigned int val,
0199                  int dir)
0200 {
0201     int changed;
0202     int open = 0;
0203     if (dir) {
0204         if (dir > 0) {
0205             open = 1;
0206         } else if (dir < 0) {
0207             if (val > 0) {
0208                 open = 1;
0209                 val--;
0210             }
0211         }
0212     }
0213     if (hw_is_mask(var))
0214         changed = snd_mask_refine_min(hw_param_mask(params, var),
0215                           val + !!open);
0216     else if (hw_is_interval(var))
0217         changed = snd_interval_refine_min(hw_param_interval(params, var),
0218                           val, open);
0219     else
0220         return -EINVAL;
0221     if (changed > 0) {
0222         params->cmask |= 1 << var;
0223         params->rmask |= 1 << var;
0224     }
0225     return changed;
0226 }
0227 
0228 /**
0229  * snd_pcm_hw_param_min
0230  * @pcm: PCM instance
0231  * @params: the hw_params instance
0232  * @var: parameter to retrieve
0233  * @val: minimal value
0234  * @dir: pointer to the direction (-1,0,1) or NULL
0235  *
0236  * Inside configuration space defined by PARAMS remove from PAR all 
0237  * values < VAL. Reduce configuration space accordingly.
0238  * Return new minimum or -EINVAL if the configuration space is empty
0239  */
0240 static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm,
0241                 struct snd_pcm_hw_params *params,
0242                 snd_pcm_hw_param_t var, unsigned int val,
0243                 int *dir)
0244 {
0245     int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
0246     if (changed < 0)
0247         return changed;
0248     if (params->rmask) {
0249         int err = snd_pcm_hw_refine(pcm, params);
0250         if (err < 0)
0251             return err;
0252     }
0253     return snd_pcm_hw_param_value_min(params, var, dir);
0254 }
0255 
0256 static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
0257                  snd_pcm_hw_param_t var, unsigned int val,
0258                  int dir)
0259 {
0260     int changed;
0261     int open = 0;
0262     if (dir) {
0263         if (dir < 0) {
0264             open = 1;
0265         } else if (dir > 0) {
0266             open = 1;
0267             val++;
0268         }
0269     }
0270     if (hw_is_mask(var)) {
0271         if (val == 0 && open) {
0272             snd_mask_none(hw_param_mask(params, var));
0273             changed = -EINVAL;
0274         } else
0275             changed = snd_mask_refine_max(hw_param_mask(params, var),
0276                               val - !!open);
0277     } else if (hw_is_interval(var))
0278         changed = snd_interval_refine_max(hw_param_interval(params, var),
0279                           val, open);
0280     else
0281         return -EINVAL;
0282     if (changed > 0) {
0283         params->cmask |= 1 << var;
0284         params->rmask |= 1 << var;
0285     }
0286     return changed;
0287 }
0288 
0289 /**
0290  * snd_pcm_hw_param_max
0291  * @pcm: PCM instance
0292  * @params: the hw_params instance
0293  * @var: parameter to retrieve
0294  * @val: maximal value
0295  * @dir: pointer to the direction (-1,0,1) or NULL
0296  *
0297  * Inside configuration space defined by PARAMS remove from PAR all 
0298  *  values >= VAL + 1. Reduce configuration space accordingly.
0299  *  Return new maximum or -EINVAL if the configuration space is empty
0300  */
0301 static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm,
0302                 struct snd_pcm_hw_params *params,
0303                 snd_pcm_hw_param_t var, unsigned int val,
0304                 int *dir)
0305 {
0306     int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
0307     if (changed < 0)
0308         return changed;
0309     if (params->rmask) {
0310         int err = snd_pcm_hw_refine(pcm, params);
0311         if (err < 0)
0312             return err;
0313     }
0314     return snd_pcm_hw_param_value_max(params, var, dir);
0315 }
0316 
0317 static int boundary_sub(int a, int adir,
0318             int b, int bdir,
0319             int *c, int *cdir)
0320 {
0321     adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
0322     bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
0323     *c = a - b;
0324     *cdir = adir - bdir;
0325     if (*cdir == -2) {
0326         (*c)--;
0327     } else if (*cdir == 2) {
0328         (*c)++;
0329     }
0330     return 0;
0331 }
0332 
0333 static int boundary_lt(unsigned int a, int adir,
0334                unsigned int b, int bdir)
0335 {
0336     if (adir < 0) {
0337         a--;
0338         adir = 1;
0339     } else if (adir > 0)
0340         adir = 1;
0341     if (bdir < 0) {
0342         b--;
0343         bdir = 1;
0344     } else if (bdir > 0)
0345         bdir = 1;
0346     return a < b || (a == b && adir < bdir);
0347 }
0348 
0349 /* Return 1 if min is nearer to best than max */
0350 static int boundary_nearer(int min, int mindir,
0351                int best, int bestdir,
0352                int max, int maxdir)
0353 {
0354     int dmin, dmindir;
0355     int dmax, dmaxdir;
0356     boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
0357     boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
0358     return boundary_lt(dmin, dmindir, dmax, dmaxdir);
0359 }
0360 
0361 /**
0362  * snd_pcm_hw_param_near
0363  * @pcm: PCM instance
0364  * @params: the hw_params instance
0365  * @var: parameter to retrieve
0366  * @best: value to set
0367  * @dir: pointer to the direction (-1,0,1) or NULL
0368  *
0369  * Inside configuration space defined by PARAMS set PAR to the available value
0370  * nearest to VAL. Reduce configuration space accordingly.
0371  * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
0372  * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
0373  * Return the value found.
0374   */
0375 static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
0376                  struct snd_pcm_hw_params *params,
0377                  snd_pcm_hw_param_t var, unsigned int best,
0378                  int *dir)
0379 {
0380     struct snd_pcm_hw_params *save = NULL;
0381     int v;
0382     unsigned int saved_min;
0383     int last = 0;
0384     int min, max;
0385     int mindir, maxdir;
0386     int valdir = dir ? *dir : 0;
0387     /* FIXME */
0388     if (best > INT_MAX)
0389         best = INT_MAX;
0390     min = max = best;
0391     mindir = maxdir = valdir;
0392     if (maxdir > 0)
0393         maxdir = 0;
0394     else if (maxdir == 0)
0395         maxdir = -1;
0396     else {
0397         maxdir = 1;
0398         max--;
0399     }
0400     save = kmalloc(sizeof(*save), GFP_KERNEL);
0401     if (save == NULL)
0402         return -ENOMEM;
0403     *save = *params;
0404     saved_min = min;
0405     min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
0406     if (min >= 0) {
0407         struct snd_pcm_hw_params *params1;
0408         if (max < 0)
0409             goto _end;
0410         if ((unsigned int)min == saved_min && mindir == valdir)
0411             goto _end;
0412         params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
0413         if (params1 == NULL) {
0414             kfree(save);
0415             return -ENOMEM;
0416         }
0417         *params1 = *save;
0418         max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
0419         if (max < 0) {
0420             kfree(params1);
0421             goto _end;
0422         }
0423         if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
0424             *params = *params1;
0425             last = 1;
0426         }
0427         kfree(params1);
0428     } else {
0429         *params = *save;
0430         max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
0431         if (max < 0) {
0432             kfree(save);
0433             return max;
0434         }
0435         last = 1;
0436     }
0437  _end:
0438     kfree(save);
0439     if (last)
0440         v = snd_pcm_hw_param_last(pcm, params, var, dir);
0441     else
0442         v = snd_pcm_hw_param_first(pcm, params, var, dir);
0443     return v;
0444 }
0445 
0446 static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
0447                  snd_pcm_hw_param_t var, unsigned int val,
0448                  int dir)
0449 {
0450     int changed;
0451     if (hw_is_mask(var)) {
0452         struct snd_mask *m = hw_param_mask(params, var);
0453         if (val == 0 && dir < 0) {
0454             changed = -EINVAL;
0455             snd_mask_none(m);
0456         } else {
0457             if (dir > 0)
0458                 val++;
0459             else if (dir < 0)
0460                 val--;
0461             changed = snd_mask_refine_set(hw_param_mask(params, var), val);
0462         }
0463     } else if (hw_is_interval(var)) {
0464         struct snd_interval *i = hw_param_interval(params, var);
0465         if (val == 0 && dir < 0) {
0466             changed = -EINVAL;
0467             snd_interval_none(i);
0468         } else if (dir == 0)
0469             changed = snd_interval_refine_set(i, val);
0470         else {
0471             struct snd_interval t;
0472             t.openmin = 1;
0473             t.openmax = 1;
0474             t.empty = 0;
0475             t.integer = 0;
0476             if (dir < 0) {
0477                 t.min = val - 1;
0478                 t.max = val;
0479             } else {
0480                 t.min = val;
0481                 t.max = val+1;
0482             }
0483             changed = snd_interval_refine(i, &t);
0484         }
0485     } else
0486         return -EINVAL;
0487     if (changed > 0) {
0488         params->cmask |= 1 << var;
0489         params->rmask |= 1 << var;
0490     }
0491     return changed;
0492 }
0493 
0494 /**
0495  * snd_pcm_hw_param_set
0496  * @pcm: PCM instance
0497  * @params: the hw_params instance
0498  * @var: parameter to retrieve
0499  * @val: value to set
0500  * @dir: pointer to the direction (-1,0,1) or NULL
0501  *
0502  * Inside configuration space defined by PARAMS remove from PAR all 
0503  * values != VAL. Reduce configuration space accordingly.
0504  *  Return VAL or -EINVAL if the configuration space is empty
0505  */
0506 static int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,
0507                 struct snd_pcm_hw_params *params,
0508                 snd_pcm_hw_param_t var, unsigned int val,
0509                 int dir)
0510 {
0511     int changed = _snd_pcm_hw_param_set(params, var, val, dir);
0512     if (changed < 0)
0513         return changed;
0514     if (params->rmask) {
0515         int err = snd_pcm_hw_refine(pcm, params);
0516         if (err < 0)
0517             return err;
0518     }
0519     return snd_pcm_hw_param_value(params, var, NULL);
0520 }
0521 
0522 static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
0523                     snd_pcm_hw_param_t var)
0524 {
0525     int changed;
0526     changed = snd_interval_setinteger(hw_param_interval(params, var));
0527     if (changed > 0) {
0528         params->cmask |= 1 << var;
0529         params->rmask |= 1 << var;
0530     }
0531     return changed;
0532 }
0533     
0534 /*
0535  * plugin
0536  */
0537 
0538 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
0539 static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream)
0540 {
0541     struct snd_pcm_runtime *runtime = substream->runtime;
0542     struct snd_pcm_plugin *plugin, *next;
0543     
0544     plugin = runtime->oss.plugin_first;
0545     while (plugin) {
0546         next = plugin->next;
0547         snd_pcm_plugin_free(plugin);
0548         plugin = next;
0549     }
0550     runtime->oss.plugin_first = runtime->oss.plugin_last = NULL;
0551     return 0;
0552 }
0553 
0554 static int snd_pcm_plugin_insert(struct snd_pcm_plugin *plugin)
0555 {
0556     struct snd_pcm_runtime *runtime = plugin->plug->runtime;
0557     plugin->next = runtime->oss.plugin_first;
0558     plugin->prev = NULL;
0559     if (runtime->oss.plugin_first) {
0560         runtime->oss.plugin_first->prev = plugin;
0561         runtime->oss.plugin_first = plugin;
0562     } else {
0563         runtime->oss.plugin_last =
0564         runtime->oss.plugin_first = plugin;
0565     }
0566     return 0;
0567 }
0568 
0569 int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin)
0570 {
0571     struct snd_pcm_runtime *runtime = plugin->plug->runtime;
0572     plugin->next = NULL;
0573     plugin->prev = runtime->oss.plugin_last;
0574     if (runtime->oss.plugin_last) {
0575         runtime->oss.plugin_last->next = plugin;
0576         runtime->oss.plugin_last = plugin;
0577     } else {
0578         runtime->oss.plugin_last =
0579         runtime->oss.plugin_first = plugin;
0580     }
0581     return 0;
0582 }
0583 #endif /* CONFIG_SND_PCM_OSS_PLUGINS */
0584 
0585 static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames)
0586 {
0587     struct snd_pcm_runtime *runtime = substream->runtime;
0588     long buffer_size = snd_pcm_lib_buffer_bytes(substream);
0589     long bytes = frames_to_bytes(runtime, frames);
0590     if (buffer_size == runtime->oss.buffer_bytes)
0591         return bytes;
0592 #if BITS_PER_LONG >= 64
0593     return runtime->oss.buffer_bytes * bytes / buffer_size;
0594 #else
0595     {
0596         u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes;
0597         return div_u64(bsize, buffer_size);
0598     }
0599 #endif
0600 }
0601 
0602 static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes)
0603 {
0604     struct snd_pcm_runtime *runtime = substream->runtime;
0605     long buffer_size = snd_pcm_lib_buffer_bytes(substream);
0606     if (buffer_size == runtime->oss.buffer_bytes)
0607         return bytes_to_frames(runtime, bytes);
0608     return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
0609 }
0610 
0611 static inline
0612 snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime)
0613 {
0614     return runtime->hw_ptr_interrupt;
0615 }
0616 
0617 /* define extended formats in the recent OSS versions (if any) */
0618 /* linear formats */
0619 #define AFMT_S32_LE      0x00001000
0620 #define AFMT_S32_BE      0x00002000
0621 #define AFMT_S24_LE      0x00008000
0622 #define AFMT_S24_BE      0x00010000
0623 #define AFMT_S24_PACKED  0x00040000
0624 
0625 /* other supported formats */
0626 #define AFMT_FLOAT       0x00004000
0627 #define AFMT_SPDIF_RAW   0x00020000
0628 
0629 /* unsupported formats */
0630 #define AFMT_AC3         0x00000400
0631 #define AFMT_VORBIS      0x00000800
0632 
0633 static snd_pcm_format_t snd_pcm_oss_format_from(int format)
0634 {
0635     switch (format) {
0636     case AFMT_MU_LAW:   return SNDRV_PCM_FORMAT_MU_LAW;
0637     case AFMT_A_LAW:    return SNDRV_PCM_FORMAT_A_LAW;
0638     case AFMT_IMA_ADPCM:    return SNDRV_PCM_FORMAT_IMA_ADPCM;
0639     case AFMT_U8:       return SNDRV_PCM_FORMAT_U8;
0640     case AFMT_S16_LE:   return SNDRV_PCM_FORMAT_S16_LE;
0641     case AFMT_S16_BE:   return SNDRV_PCM_FORMAT_S16_BE;
0642     case AFMT_S8:       return SNDRV_PCM_FORMAT_S8;
0643     case AFMT_U16_LE:   return SNDRV_PCM_FORMAT_U16_LE;
0644     case AFMT_U16_BE:   return SNDRV_PCM_FORMAT_U16_BE;
0645     case AFMT_MPEG:     return SNDRV_PCM_FORMAT_MPEG;
0646     case AFMT_S32_LE:   return SNDRV_PCM_FORMAT_S32_LE;
0647     case AFMT_S32_BE:   return SNDRV_PCM_FORMAT_S32_BE;
0648     case AFMT_S24_LE:   return SNDRV_PCM_FORMAT_S24_LE;
0649     case AFMT_S24_BE:   return SNDRV_PCM_FORMAT_S24_BE;
0650     case AFMT_S24_PACKED:   return SNDRV_PCM_FORMAT_S24_3LE;
0651     case AFMT_FLOAT:    return SNDRV_PCM_FORMAT_FLOAT;
0652     case AFMT_SPDIF_RAW:    return SNDRV_PCM_FORMAT_IEC958_SUBFRAME;
0653     default:        return SNDRV_PCM_FORMAT_U8;
0654     }
0655 }
0656 
0657 static int snd_pcm_oss_format_to(snd_pcm_format_t format)
0658 {
0659     switch (format) {
0660     case SNDRV_PCM_FORMAT_MU_LAW:   return AFMT_MU_LAW;
0661     case SNDRV_PCM_FORMAT_A_LAW:    return AFMT_A_LAW;
0662     case SNDRV_PCM_FORMAT_IMA_ADPCM:    return AFMT_IMA_ADPCM;
0663     case SNDRV_PCM_FORMAT_U8:       return AFMT_U8;
0664     case SNDRV_PCM_FORMAT_S16_LE:   return AFMT_S16_LE;
0665     case SNDRV_PCM_FORMAT_S16_BE:   return AFMT_S16_BE;
0666     case SNDRV_PCM_FORMAT_S8:       return AFMT_S8;
0667     case SNDRV_PCM_FORMAT_U16_LE:   return AFMT_U16_LE;
0668     case SNDRV_PCM_FORMAT_U16_BE:   return AFMT_U16_BE;
0669     case SNDRV_PCM_FORMAT_MPEG:     return AFMT_MPEG;
0670     case SNDRV_PCM_FORMAT_S32_LE:   return AFMT_S32_LE;
0671     case SNDRV_PCM_FORMAT_S32_BE:   return AFMT_S32_BE;
0672     case SNDRV_PCM_FORMAT_S24_LE:   return AFMT_S24_LE;
0673     case SNDRV_PCM_FORMAT_S24_BE:   return AFMT_S24_BE;
0674     case SNDRV_PCM_FORMAT_S24_3LE:  return AFMT_S24_PACKED;
0675     case SNDRV_PCM_FORMAT_FLOAT:    return AFMT_FLOAT;
0676     case SNDRV_PCM_FORMAT_IEC958_SUBFRAME: return AFMT_SPDIF_RAW;
0677     default:            return -EINVAL;
0678     }
0679 }
0680 
0681 static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, 
0682                    struct snd_pcm_hw_params *oss_params,
0683                    struct snd_pcm_hw_params *slave_params)
0684 {
0685     ssize_t s;
0686     ssize_t oss_buffer_size;
0687     ssize_t oss_period_size, oss_periods;
0688     ssize_t min_period_size, max_period_size;
0689     struct snd_pcm_runtime *runtime = substream->runtime;
0690     size_t oss_frame_size;
0691 
0692     oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) *
0693              params_channels(oss_params) / 8;
0694 
0695     oss_buffer_size = snd_pcm_hw_param_value_max(slave_params,
0696                              SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
0697                              NULL);
0698     if (oss_buffer_size <= 0)
0699         return -EINVAL;
0700     oss_buffer_size = snd_pcm_plug_client_size(substream,
0701                            oss_buffer_size * oss_frame_size);
0702     if (oss_buffer_size <= 0)
0703         return -EINVAL;
0704     oss_buffer_size = rounddown_pow_of_two(oss_buffer_size);
0705     if (atomic_read(&substream->mmap_count)) {
0706         if (oss_buffer_size > runtime->oss.mmap_bytes)
0707             oss_buffer_size = runtime->oss.mmap_bytes;
0708     }
0709 
0710     if (substream->oss.setup.period_size > 16)
0711         oss_period_size = substream->oss.setup.period_size;
0712     else if (runtime->oss.fragshift) {
0713         oss_period_size = 1 << runtime->oss.fragshift;
0714         if (oss_period_size > oss_buffer_size / 2)
0715             oss_period_size = oss_buffer_size / 2;
0716     } else {
0717         int sd;
0718         size_t bytes_per_sec = params_rate(oss_params) * snd_pcm_format_physical_width(params_format(oss_params)) * params_channels(oss_params) / 8;
0719 
0720         oss_period_size = oss_buffer_size;
0721         do {
0722             oss_period_size /= 2;
0723         } while (oss_period_size > bytes_per_sec);
0724         if (runtime->oss.subdivision == 0) {
0725             sd = 4;
0726             if (oss_period_size / sd > 4096)
0727                 sd *= 2;
0728             if (oss_period_size / sd < 4096)
0729                 sd = 1;
0730         } else
0731             sd = runtime->oss.subdivision;
0732         oss_period_size /= sd;
0733         if (oss_period_size < 16)
0734             oss_period_size = 16;
0735     }
0736 
0737     min_period_size = snd_pcm_plug_client_size(substream,
0738                            snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
0739     if (min_period_size > 0) {
0740         min_period_size *= oss_frame_size;
0741         min_period_size = roundup_pow_of_two(min_period_size);
0742         if (oss_period_size < min_period_size)
0743             oss_period_size = min_period_size;
0744     }
0745 
0746     max_period_size = snd_pcm_plug_client_size(substream,
0747                            snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
0748     if (max_period_size > 0) {
0749         max_period_size *= oss_frame_size;
0750         max_period_size = rounddown_pow_of_two(max_period_size);
0751         if (oss_period_size > max_period_size)
0752             oss_period_size = max_period_size;
0753     }
0754 
0755     oss_periods = oss_buffer_size / oss_period_size;
0756 
0757     if (substream->oss.setup.periods > 1)
0758         oss_periods = substream->oss.setup.periods;
0759 
0760     s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
0761     if (s > 0 && runtime->oss.maxfrags && s > runtime->oss.maxfrags)
0762         s = runtime->oss.maxfrags;
0763     if (oss_periods > s)
0764         oss_periods = s;
0765 
0766     s = snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
0767     if (s < 2)
0768         s = 2;
0769     if (oss_periods < s)
0770         oss_periods = s;
0771 
0772     while (oss_period_size * oss_periods > oss_buffer_size)
0773         oss_period_size /= 2;
0774 
0775     if (oss_period_size < 16)
0776         return -EINVAL;
0777 
0778     /* don't allocate too large period; 1MB period must be enough */
0779     if (oss_period_size > 1024 * 1024)
0780         return -ENOMEM;
0781 
0782     runtime->oss.period_bytes = oss_period_size;
0783     runtime->oss.period_frames = 1;
0784     runtime->oss.periods = oss_periods;
0785     return 0;
0786 }
0787 
0788 static int choose_rate(struct snd_pcm_substream *substream,
0789                struct snd_pcm_hw_params *params, unsigned int best_rate)
0790 {
0791     const struct snd_interval *it;
0792     struct snd_pcm_hw_params *save;
0793     unsigned int rate, prev;
0794 
0795     save = kmalloc(sizeof(*save), GFP_KERNEL);
0796     if (save == NULL)
0797         return -ENOMEM;
0798     *save = *params;
0799     it = hw_param_interval_c(save, SNDRV_PCM_HW_PARAM_RATE);
0800 
0801     /* try multiples of the best rate */
0802     rate = best_rate;
0803     for (;;) {
0804         if (it->max < rate || (it->max == rate && it->openmax))
0805             break;
0806         if (it->min < rate || (it->min == rate && !it->openmin)) {
0807             int ret;
0808             ret = snd_pcm_hw_param_set(substream, params,
0809                            SNDRV_PCM_HW_PARAM_RATE,
0810                            rate, 0);
0811             if (ret == (int)rate) {
0812                 kfree(save);
0813                 return rate;
0814             }
0815             *params = *save;
0816         }
0817         prev = rate;
0818         rate += best_rate;
0819         if (rate <= prev)
0820             break;
0821     }
0822 
0823     /* not found, use the nearest rate */
0824     kfree(save);
0825     return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
0826 }
0827 
0828 /* parameter locking: returns immediately if tried during streaming */
0829 static int lock_params(struct snd_pcm_runtime *runtime)
0830 {
0831     if (mutex_lock_interruptible(&runtime->oss.params_lock))
0832         return -ERESTARTSYS;
0833     if (atomic_read(&runtime->oss.rw_ref)) {
0834         mutex_unlock(&runtime->oss.params_lock);
0835         return -EBUSY;
0836     }
0837     return 0;
0838 }
0839 
0840 static void unlock_params(struct snd_pcm_runtime *runtime)
0841 {
0842     mutex_unlock(&runtime->oss.params_lock);
0843 }
0844 
0845 static void snd_pcm_oss_release_buffers(struct snd_pcm_substream *substream)
0846 {
0847     struct snd_pcm_runtime *runtime = substream->runtime;
0848 
0849     kvfree(runtime->oss.buffer);
0850     runtime->oss.buffer = NULL;
0851 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
0852     snd_pcm_oss_plugin_clear(substream);
0853 #endif
0854 }
0855 
0856 /* call with params_lock held */
0857 static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
0858 {
0859     struct snd_pcm_runtime *runtime = substream->runtime;
0860     struct snd_pcm_hw_params *params, *sparams;
0861     struct snd_pcm_sw_params *sw_params;
0862     ssize_t oss_buffer_size, oss_period_size;
0863     size_t oss_frame_size;
0864     int err;
0865     int direct;
0866     snd_pcm_format_t format, sformat;
0867     int n;
0868     const struct snd_mask *sformat_mask;
0869     struct snd_mask mask;
0870 
0871     if (!runtime->oss.params)
0872         return 0;
0873     sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
0874     params = kmalloc(sizeof(*params), GFP_KERNEL);
0875     sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
0876     if (!sw_params || !params || !sparams) {
0877         err = -ENOMEM;
0878         goto failure;
0879     }
0880 
0881     if (atomic_read(&substream->mmap_count))
0882         direct = 1;
0883     else
0884         direct = substream->oss.setup.direct;
0885 
0886     _snd_pcm_hw_params_any(sparams);
0887     _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
0888     _snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
0889     snd_mask_none(&mask);
0890     if (atomic_read(&substream->mmap_count))
0891         snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
0892     else {
0893         snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED);
0894         if (!direct)
0895             snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
0896     }
0897     err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
0898     if (err < 0) {
0899         pcm_dbg(substream->pcm, "No usable accesses\n");
0900         err = -EINVAL;
0901         goto failure;
0902     }
0903 
0904     err = choose_rate(substream, sparams, runtime->oss.rate);
0905     if (err < 0)
0906         goto failure;
0907     err = snd_pcm_hw_param_near(substream, sparams,
0908                     SNDRV_PCM_HW_PARAM_CHANNELS,
0909                     runtime->oss.channels, NULL);
0910     if (err < 0)
0911         goto failure;
0912 
0913     format = snd_pcm_oss_format_from(runtime->oss.format);
0914 
0915     sformat_mask = hw_param_mask_c(sparams, SNDRV_PCM_HW_PARAM_FORMAT);
0916     if (direct)
0917         sformat = format;
0918     else
0919         sformat = snd_pcm_plug_slave_format(format, sformat_mask);
0920 
0921     if ((__force int)sformat < 0 ||
0922         !snd_mask_test_format(sformat_mask, sformat)) {
0923         pcm_for_each_format(sformat) {
0924             if (snd_mask_test_format(sformat_mask, sformat) &&
0925                 snd_pcm_oss_format_to(sformat) >= 0)
0926                 goto format_found;
0927         }
0928         pcm_dbg(substream->pcm, "Cannot find a format!!!\n");
0929         err = -EINVAL;
0930         goto failure;
0931     }
0932  format_found:
0933     err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, (__force int)sformat, 0);
0934     if (err < 0)
0935         goto failure;
0936 
0937     if (direct) {
0938         memcpy(params, sparams, sizeof(*params));
0939     } else {
0940         _snd_pcm_hw_params_any(params);
0941         _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
0942                       (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
0943         _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
0944                       (__force int)snd_pcm_oss_format_from(runtime->oss.format), 0);
0945         _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
0946                       runtime->oss.channels, 0);
0947         _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
0948                       runtime->oss.rate, 0);
0949         pdprintf("client: access = %i, format = %i, channels = %i, rate = %i\n",
0950              params_access(params), params_format(params),
0951              params_channels(params), params_rate(params));
0952     }
0953     pdprintf("slave: access = %i, format = %i, channels = %i, rate = %i\n",
0954          params_access(sparams), params_format(sparams),
0955          params_channels(sparams), params_rate(sparams));
0956 
0957     oss_frame_size = snd_pcm_format_physical_width(params_format(params)) *
0958              params_channels(params) / 8;
0959 
0960     err = snd_pcm_oss_period_size(substream, params, sparams);
0961     if (err < 0)
0962         goto failure;
0963 
0964     n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);
0965     err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL);
0966     if (err < 0)
0967         goto failure;
0968 
0969     err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,
0970                      runtime->oss.periods, NULL);
0971     if (err < 0)
0972         goto failure;
0973 
0974     snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
0975 
0976     err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams);
0977     if (err < 0) {
0978         pcm_dbg(substream->pcm, "HW_PARAMS failed: %i\n", err);
0979         goto failure;
0980     }
0981 
0982 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
0983     snd_pcm_oss_plugin_clear(substream);
0984     if (!direct) {
0985         /* add necessary plugins */
0986         err = snd_pcm_plug_format_plugins(substream, params, sparams);
0987         if (err < 0) {
0988             pcm_dbg(substream->pcm,
0989                 "snd_pcm_plug_format_plugins failed: %i\n", err);
0990             goto failure;
0991         }
0992         if (runtime->oss.plugin_first) {
0993             struct snd_pcm_plugin *plugin;
0994             err = snd_pcm_plugin_build_io(substream, sparams, &plugin);
0995             if (err < 0) {
0996                 pcm_dbg(substream->pcm,
0997                     "snd_pcm_plugin_build_io failed: %i\n", err);
0998                 goto failure;
0999             }
1000             if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1001                 err = snd_pcm_plugin_append(plugin);
1002             } else {
1003                 err = snd_pcm_plugin_insert(plugin);
1004             }
1005             if (err < 0)
1006                 goto failure;
1007         }
1008     }
1009 #endif
1010 
1011     if (runtime->oss.trigger) {
1012         sw_params->start_threshold = 1;
1013     } else {
1014         sw_params->start_threshold = runtime->boundary;
1015     }
1016     if (atomic_read(&substream->mmap_count) ||
1017         substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1018         sw_params->stop_threshold = runtime->boundary;
1019     else
1020         sw_params->stop_threshold = runtime->buffer_size;
1021     sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
1022     sw_params->period_step = 1;
1023     sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
1024         1 : runtime->period_size;
1025     if (atomic_read(&substream->mmap_count) ||
1026         substream->oss.setup.nosilence) {
1027         sw_params->silence_threshold = 0;
1028         sw_params->silence_size = 0;
1029     } else {
1030         snd_pcm_uframes_t frames;
1031         frames = runtime->period_size + 16;
1032         if (frames > runtime->buffer_size)
1033             frames = runtime->buffer_size;
1034         sw_params->silence_threshold = frames;
1035         sw_params->silence_size = frames;
1036     }
1037 
1038     err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params);
1039     if (err < 0) {
1040         pcm_dbg(substream->pcm, "SW_PARAMS failed: %i\n", err);
1041         goto failure;
1042     }
1043 
1044     runtime->oss.periods = params_periods(sparams);
1045     oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
1046     if (oss_period_size < 0) {
1047         err = -EINVAL;
1048         goto failure;
1049     }
1050 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
1051     if (runtime->oss.plugin_first) {
1052         err = snd_pcm_plug_alloc(substream, oss_period_size);
1053         if (err < 0)
1054             goto failure;
1055     }
1056 #endif
1057     oss_period_size = array_size(oss_period_size, oss_frame_size);
1058     oss_buffer_size = array_size(oss_period_size, runtime->oss.periods);
1059     if (oss_buffer_size <= 0) {
1060         err = -EINVAL;
1061         goto failure;
1062     }
1063 
1064     runtime->oss.period_bytes = oss_period_size;
1065     runtime->oss.buffer_bytes = oss_buffer_size;
1066 
1067     pdprintf("oss: period bytes = %i, buffer bytes = %i\n",
1068          runtime->oss.period_bytes,
1069          runtime->oss.buffer_bytes);
1070     pdprintf("slave: period_size = %i, buffer_size = %i\n",
1071          params_period_size(sparams),
1072          params_buffer_size(sparams));
1073 
1074     runtime->oss.format = snd_pcm_oss_format_to(params_format(params));
1075     runtime->oss.channels = params_channels(params);
1076     runtime->oss.rate = params_rate(params);
1077 
1078     kvfree(runtime->oss.buffer);
1079     runtime->oss.buffer = kvzalloc(runtime->oss.period_bytes, GFP_KERNEL);
1080     if (!runtime->oss.buffer) {
1081         err = -ENOMEM;
1082         goto failure;
1083     }
1084 
1085     runtime->oss.params = 0;
1086     runtime->oss.prepare = 1;
1087     runtime->oss.buffer_used = 0;
1088     if (runtime->dma_area)
1089         snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
1090 
1091     runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
1092 
1093     err = 0;
1094 failure:
1095     if (err)
1096         snd_pcm_oss_release_buffers(substream);
1097     kfree(sw_params);
1098     kfree(params);
1099     kfree(sparams);
1100     return err;
1101 }
1102 
1103 /* this one takes the lock by itself */
1104 static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
1105                      bool trylock)
1106 {
1107     struct snd_pcm_runtime *runtime = substream->runtime;
1108     int err;
1109 
1110     if (trylock) {
1111         if (!(mutex_trylock(&runtime->oss.params_lock)))
1112             return -EAGAIN;
1113     } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
1114         return -ERESTARTSYS;
1115 
1116     err = snd_pcm_oss_change_params_locked(substream);
1117     mutex_unlock(&runtime->oss.params_lock);
1118     return err;
1119 }
1120 
1121 static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_file, struct snd_pcm_substream **r_substream)
1122 {
1123     int idx, err;
1124     struct snd_pcm_substream *asubstream = NULL, *substream;
1125 
1126     for (idx = 0; idx < 2; idx++) {
1127         substream = pcm_oss_file->streams[idx];
1128         if (substream == NULL)
1129             continue;
1130         if (asubstream == NULL)
1131             asubstream = substream;
1132         if (substream->runtime->oss.params) {
1133             err = snd_pcm_oss_change_params(substream, false);
1134             if (err < 0)
1135                 return err;
1136         }
1137     }
1138     if (!asubstream)
1139         return -EIO;
1140     if (r_substream)
1141         *r_substream = asubstream;
1142     return 0;
1143 }
1144 
1145 /* call with params_lock held */
1146 /* NOTE: this always call PREPARE unconditionally no matter whether
1147  * runtime->oss.prepare is set or not
1148  */
1149 static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
1150 {
1151     int err;
1152     struct snd_pcm_runtime *runtime = substream->runtime;
1153 
1154     err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
1155     if (err < 0) {
1156         pcm_dbg(substream->pcm,
1157             "snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n");
1158         return err;
1159     }
1160     runtime->oss.prepare = 0;
1161     runtime->oss.prev_hw_ptr_period = 0;
1162     runtime->oss.period_ptr = 0;
1163     runtime->oss.buffer_used = 0;
1164 
1165     return 0;
1166 }
1167 
1168 static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream)
1169 {
1170     struct snd_pcm_runtime *runtime;
1171     int err;
1172 
1173     runtime = substream->runtime;
1174     if (runtime->oss.params) {
1175         err = snd_pcm_oss_change_params(substream, false);
1176         if (err < 0)
1177             return err;
1178     }
1179     if (runtime->oss.prepare) {
1180         if (mutex_lock_interruptible(&runtime->oss.params_lock))
1181             return -ERESTARTSYS;
1182         err = snd_pcm_oss_prepare(substream);
1183         mutex_unlock(&runtime->oss.params_lock);
1184         if (err < 0)
1185             return err;
1186     }
1187     return 0;
1188 }
1189 
1190 /* call with params_lock held */
1191 static int snd_pcm_oss_make_ready_locked(struct snd_pcm_substream *substream)
1192 {
1193     struct snd_pcm_runtime *runtime;
1194     int err;
1195 
1196     runtime = substream->runtime;
1197     if (runtime->oss.params) {
1198         err = snd_pcm_oss_change_params_locked(substream);
1199         if (err < 0)
1200             return err;
1201     }
1202     if (runtime->oss.prepare) {
1203         err = snd_pcm_oss_prepare(substream);
1204         if (err < 0)
1205             return err;
1206     }
1207     return 0;
1208 }
1209 
1210 static int snd_pcm_oss_capture_position_fixup(struct snd_pcm_substream *substream, snd_pcm_sframes_t *delay)
1211 {
1212     struct snd_pcm_runtime *runtime;
1213     snd_pcm_uframes_t frames;
1214     int err = 0;
1215 
1216     while (1) {
1217         err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, delay);
1218         if (err < 0)
1219             break;
1220         runtime = substream->runtime;
1221         if (*delay <= (snd_pcm_sframes_t)runtime->buffer_size)
1222             break;
1223         /* in case of overrun, skip whole periods like OSS/Linux driver does */
1224         /* until avail(delay) <= buffer_size */
1225         frames = (*delay - runtime->buffer_size) + runtime->period_size - 1;
1226         frames /= runtime->period_size;
1227         frames *= runtime->period_size;
1228         err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_FORWARD, &frames);
1229         if (err < 0)
1230             break;
1231     }
1232     return err;
1233 }
1234 
1235 snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
1236 {
1237     struct snd_pcm_runtime *runtime = substream->runtime;
1238     int ret;
1239     while (1) {
1240         if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1241             runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1242 #ifdef OSS_DEBUG
1243             pcm_dbg(substream->pcm,
1244                 "pcm_oss: write: recovering from %s\n",
1245                 runtime->status->state == SNDRV_PCM_STATE_XRUN ?
1246                 "XRUN" : "SUSPEND");
1247 #endif
1248             ret = snd_pcm_oss_prepare(substream);
1249             if (ret < 0)
1250                 break;
1251         }
1252         mutex_unlock(&runtime->oss.params_lock);
1253         ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true,
1254                      frames, in_kernel);
1255         mutex_lock(&runtime->oss.params_lock);
1256         if (ret != -EPIPE && ret != -ESTRPIPE)
1257             break;
1258         /* test, if we can't store new data, because the stream */
1259         /* has not been started */
1260         if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
1261             return -EAGAIN;
1262     }
1263     return ret;
1264 }
1265 
1266 snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
1267 {
1268     struct snd_pcm_runtime *runtime = substream->runtime;
1269     snd_pcm_sframes_t delay;
1270     int ret;
1271     while (1) {
1272         if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1273             runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1274 #ifdef OSS_DEBUG
1275             pcm_dbg(substream->pcm,
1276                 "pcm_oss: read: recovering from %s\n",
1277                 runtime->status->state == SNDRV_PCM_STATE_XRUN ?
1278                 "XRUN" : "SUSPEND");
1279 #endif
1280             ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
1281             if (ret < 0)
1282                 break;
1283         } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {
1284             ret = snd_pcm_oss_prepare(substream);
1285             if (ret < 0)
1286                 break;
1287         }
1288         ret = snd_pcm_oss_capture_position_fixup(substream, &delay);
1289         if (ret < 0)
1290             break;
1291         mutex_unlock(&runtime->oss.params_lock);
1292         ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true,
1293                      frames, in_kernel);
1294         mutex_lock(&runtime->oss.params_lock);
1295         if (ret == -EPIPE) {
1296             if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
1297                 ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1298                 if (ret < 0)
1299                     break;
1300             }
1301             continue;
1302         }
1303         if (ret != -ESTRPIPE)
1304             break;
1305     }
1306     return ret;
1307 }
1308 
1309 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
1310 snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
1311 {
1312     struct snd_pcm_runtime *runtime = substream->runtime;
1313     int ret;
1314     while (1) {
1315         if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1316             runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1317 #ifdef OSS_DEBUG
1318             pcm_dbg(substream->pcm,
1319                 "pcm_oss: writev: recovering from %s\n",
1320                 runtime->status->state == SNDRV_PCM_STATE_XRUN ?
1321                 "XRUN" : "SUSPEND");
1322 #endif
1323             ret = snd_pcm_oss_prepare(substream);
1324             if (ret < 0)
1325                 break;
1326         }
1327         ret = snd_pcm_kernel_writev(substream, bufs, frames);
1328         if (ret != -EPIPE && ret != -ESTRPIPE)
1329             break;
1330 
1331         /* test, if we can't store new data, because the stream */
1332         /* has not been started */
1333         if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
1334             return -EAGAIN;
1335     }
1336     return ret;
1337 }
1338     
1339 snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
1340 {
1341     struct snd_pcm_runtime *runtime = substream->runtime;
1342     int ret;
1343     while (1) {
1344         if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1345             runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1346 #ifdef OSS_DEBUG
1347             pcm_dbg(substream->pcm,
1348                 "pcm_oss: readv: recovering from %s\n",
1349                 runtime->status->state == SNDRV_PCM_STATE_XRUN ?
1350                 "XRUN" : "SUSPEND");
1351 #endif
1352             ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
1353             if (ret < 0)
1354                 break;
1355         } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {
1356             ret = snd_pcm_oss_prepare(substream);
1357             if (ret < 0)
1358                 break;
1359         }
1360         ret = snd_pcm_kernel_readv(substream, bufs, frames);
1361         if (ret != -EPIPE && ret != -ESTRPIPE)
1362             break;
1363     }
1364     return ret;
1365 }
1366 #endif /* CONFIG_SND_PCM_OSS_PLUGINS */
1367 
1368 static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel)
1369 {
1370     struct snd_pcm_runtime *runtime = substream->runtime;
1371     snd_pcm_sframes_t frames, frames1;
1372 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
1373     if (runtime->oss.plugin_first) {
1374         struct snd_pcm_plugin_channel *channels;
1375         size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8;
1376         if (!in_kernel) {
1377             if (copy_from_user(runtime->oss.buffer, (const char __force __user *)buf, bytes))
1378                 return -EFAULT;
1379             buf = runtime->oss.buffer;
1380         }
1381         frames = bytes / oss_frame_bytes;
1382         frames1 = snd_pcm_plug_client_channels_buf(substream, (char *)buf, frames, &channels);
1383         if (frames1 < 0)
1384             return frames1;
1385         frames1 = snd_pcm_plug_write_transfer(substream, channels, frames1);
1386         if (frames1 <= 0)
1387             return frames1;
1388         bytes = frames1 * oss_frame_bytes;
1389     } else
1390 #endif
1391     {
1392         frames = bytes_to_frames(runtime, bytes);
1393         frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel);
1394         if (frames1 <= 0)
1395             return frames1;
1396         bytes = frames_to_bytes(runtime, frames1);
1397     }
1398     return bytes;
1399 }
1400 
1401 static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const char __user *buf, size_t bytes)
1402 {
1403     size_t xfer = 0;
1404     ssize_t tmp = 0;
1405     struct snd_pcm_runtime *runtime = substream->runtime;
1406 
1407     if (atomic_read(&substream->mmap_count))
1408         return -ENXIO;
1409 
1410     atomic_inc(&runtime->oss.rw_ref);
1411     while (bytes > 0) {
1412         if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
1413             tmp = -ERESTARTSYS;
1414             break;
1415         }
1416         tmp = snd_pcm_oss_make_ready_locked(substream);
1417         if (tmp < 0)
1418             goto err;
1419         if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
1420             tmp = bytes;
1421             if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
1422                 tmp = runtime->oss.period_bytes - runtime->oss.buffer_used;
1423             if (tmp > 0) {
1424                 if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp)) {
1425                     tmp = -EFAULT;
1426                     goto err;
1427                 }
1428             }
1429             runtime->oss.buffer_used += tmp;
1430             buf += tmp;
1431             bytes -= tmp;
1432             xfer += tmp;
1433             if (substream->oss.setup.partialfrag ||
1434                 runtime->oss.buffer_used == runtime->oss.period_bytes) {
1435                 tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr, 
1436                              runtime->oss.buffer_used - runtime->oss.period_ptr, 1);
1437                 if (tmp <= 0)
1438                     goto err;
1439                 runtime->oss.bytes += tmp;
1440                 runtime->oss.period_ptr += tmp;
1441                 runtime->oss.period_ptr %= runtime->oss.period_bytes;
1442                 if (runtime->oss.period_ptr == 0 ||
1443                     runtime->oss.period_ptr == runtime->oss.buffer_used)
1444                     runtime->oss.buffer_used = 0;
1445                 else if ((substream->f_flags & O_NONBLOCK) != 0) {
1446                     tmp = -EAGAIN;
1447                     goto err;
1448                 }
1449             }
1450         } else {
1451             tmp = snd_pcm_oss_write2(substream,
1452                          (const char __force *)buf,
1453                          runtime->oss.period_bytes, 0);
1454             if (tmp <= 0)
1455                 goto err;
1456             runtime->oss.bytes += tmp;
1457             buf += tmp;
1458             bytes -= tmp;
1459             xfer += tmp;
1460             if ((substream->f_flags & O_NONBLOCK) != 0 &&
1461                 tmp != runtime->oss.period_bytes)
1462                 tmp = -EAGAIN;
1463         }
1464  err:
1465         mutex_unlock(&runtime->oss.params_lock);
1466         if (tmp < 0)
1467             break;
1468         if (signal_pending(current)) {
1469             tmp = -ERESTARTSYS;
1470             break;
1471         }
1472         tmp = 0;
1473     }
1474     atomic_dec(&runtime->oss.rw_ref);
1475     return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
1476 }
1477 
1478 static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf, size_t bytes, int in_kernel)
1479 {
1480     struct snd_pcm_runtime *runtime = substream->runtime;
1481     snd_pcm_sframes_t frames, frames1;
1482 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
1483     char __user *final_dst = (char __force __user *)buf;
1484     if (runtime->oss.plugin_first) {
1485         struct snd_pcm_plugin_channel *channels;
1486         size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8;
1487         if (!in_kernel)
1488             buf = runtime->oss.buffer;
1489         frames = bytes / oss_frame_bytes;
1490         frames1 = snd_pcm_plug_client_channels_buf(substream, buf, frames, &channels);
1491         if (frames1 < 0)
1492             return frames1;
1493         frames1 = snd_pcm_plug_read_transfer(substream, channels, frames1);
1494         if (frames1 <= 0)
1495             return frames1;
1496         bytes = frames1 * oss_frame_bytes;
1497         if (!in_kernel && copy_to_user(final_dst, buf, bytes))
1498             return -EFAULT;
1499     } else
1500 #endif
1501     {
1502         frames = bytes_to_frames(runtime, bytes);
1503         frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel);
1504         if (frames1 <= 0)
1505             return frames1;
1506         bytes = frames_to_bytes(runtime, frames1);
1507     }
1508     return bytes;
1509 }
1510 
1511 static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __user *buf, size_t bytes)
1512 {
1513     size_t xfer = 0;
1514     ssize_t tmp = 0;
1515     struct snd_pcm_runtime *runtime = substream->runtime;
1516 
1517     if (atomic_read(&substream->mmap_count))
1518         return -ENXIO;
1519 
1520     atomic_inc(&runtime->oss.rw_ref);
1521     while (bytes > 0) {
1522         if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
1523             tmp = -ERESTARTSYS;
1524             break;
1525         }
1526         tmp = snd_pcm_oss_make_ready_locked(substream);
1527         if (tmp < 0)
1528             goto err;
1529         if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
1530             if (runtime->oss.buffer_used == 0) {
1531                 tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
1532                 if (tmp <= 0)
1533                     goto err;
1534                 runtime->oss.bytes += tmp;
1535                 runtime->oss.period_ptr = tmp;
1536                 runtime->oss.buffer_used = tmp;
1537             }
1538             tmp = bytes;
1539             if ((size_t) tmp > runtime->oss.buffer_used)
1540                 tmp = runtime->oss.buffer_used;
1541             if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp)) {
1542                 tmp = -EFAULT;
1543                 goto err;
1544             }
1545             buf += tmp;
1546             bytes -= tmp;
1547             xfer += tmp;
1548             runtime->oss.buffer_used -= tmp;
1549         } else {
1550             tmp = snd_pcm_oss_read2(substream, (char __force *)buf,
1551                         runtime->oss.period_bytes, 0);
1552             if (tmp <= 0)
1553                 goto err;
1554             runtime->oss.bytes += tmp;
1555             buf += tmp;
1556             bytes -= tmp;
1557             xfer += tmp;
1558         }
1559  err:
1560         mutex_unlock(&runtime->oss.params_lock);
1561         if (tmp < 0)
1562             break;
1563         if (signal_pending(current)) {
1564             tmp = -ERESTARTSYS;
1565             break;
1566         }
1567         tmp = 0;
1568     }
1569     atomic_dec(&runtime->oss.rw_ref);
1570     return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
1571 }
1572 
1573 static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file)
1574 {
1575     struct snd_pcm_substream *substream;
1576     struct snd_pcm_runtime *runtime;
1577     int i;
1578 
1579     for (i = 0; i < 2; i++) { 
1580         substream = pcm_oss_file->streams[i];
1581         if (!substream)
1582             continue;
1583         runtime = substream->runtime;
1584         snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1585         mutex_lock(&runtime->oss.params_lock);
1586         runtime->oss.prepare = 1;
1587         runtime->oss.buffer_used = 0;
1588         runtime->oss.prev_hw_ptr_period = 0;
1589         runtime->oss.period_ptr = 0;
1590         mutex_unlock(&runtime->oss.params_lock);
1591     }
1592     return 0;
1593 }
1594 
1595 static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file)
1596 {
1597     struct snd_pcm_substream *substream;
1598     int err;
1599 
1600     substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1601     if (substream != NULL) {
1602         err = snd_pcm_oss_make_ready(substream);
1603         if (err < 0)
1604             return err;
1605         snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
1606     }
1607     /* note: all errors from the start action are ignored */
1608     /* OSS apps do not know, how to handle them */
1609     return 0;
1610 }
1611 
1612 static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
1613 {
1614     struct snd_pcm_runtime *runtime;
1615     ssize_t result = 0;
1616     snd_pcm_state_t state;
1617     long res;
1618     wait_queue_entry_t wait;
1619 
1620     runtime = substream->runtime;
1621     init_waitqueue_entry(&wait, current);
1622     add_wait_queue(&runtime->sleep, &wait);
1623 #ifdef OSS_DEBUG
1624     pcm_dbg(substream->pcm, "sync1: size = %li\n", size);
1625 #endif
1626     while (1) {
1627         result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1);
1628         if (result > 0) {
1629             runtime->oss.buffer_used = 0;
1630             result = 0;
1631             break;
1632         }
1633         if (result != 0 && result != -EAGAIN)
1634             break;
1635         result = 0;
1636         set_current_state(TASK_INTERRUPTIBLE);
1637         snd_pcm_stream_lock_irq(substream);
1638         state = runtime->status->state;
1639         snd_pcm_stream_unlock_irq(substream);
1640         if (state != SNDRV_PCM_STATE_RUNNING) {
1641             set_current_state(TASK_RUNNING);
1642             break;
1643         }
1644         res = schedule_timeout(10 * HZ);
1645         if (signal_pending(current)) {
1646             result = -ERESTARTSYS;
1647             break;
1648         }
1649         if (res == 0) {
1650             pcm_err(substream->pcm,
1651                 "OSS sync error - DMA timeout\n");
1652             result = -EIO;
1653             break;
1654         }
1655     }
1656     remove_wait_queue(&runtime->sleep, &wait);
1657     return result;
1658 }
1659 
1660 static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
1661 {
1662     int err = 0;
1663     unsigned int saved_f_flags;
1664     struct snd_pcm_substream *substream;
1665     struct snd_pcm_runtime *runtime;
1666     snd_pcm_format_t format;
1667     unsigned long width;
1668     size_t size;
1669 
1670     substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1671     if (substream != NULL) {
1672         runtime = substream->runtime;
1673         if (atomic_read(&substream->mmap_count))
1674             goto __direct;
1675         atomic_inc(&runtime->oss.rw_ref);
1676         if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
1677             atomic_dec(&runtime->oss.rw_ref);
1678             return -ERESTARTSYS;
1679         }
1680         err = snd_pcm_oss_make_ready_locked(substream);
1681         if (err < 0)
1682             goto unlock;
1683         format = snd_pcm_oss_format_from(runtime->oss.format);
1684         width = snd_pcm_format_physical_width(format);
1685         if (runtime->oss.buffer_used > 0) {
1686 #ifdef OSS_DEBUG
1687             pcm_dbg(substream->pcm, "sync: buffer_used\n");
1688 #endif
1689             size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;
1690             snd_pcm_format_set_silence(format,
1691                            runtime->oss.buffer + runtime->oss.buffer_used,
1692                            size);
1693             err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
1694             if (err < 0)
1695                 goto unlock;
1696         } else if (runtime->oss.period_ptr > 0) {
1697 #ifdef OSS_DEBUG
1698             pcm_dbg(substream->pcm, "sync: period_ptr\n");
1699 #endif
1700             size = runtime->oss.period_bytes - runtime->oss.period_ptr;
1701             snd_pcm_format_set_silence(format,
1702                            runtime->oss.buffer,
1703                            size * 8 / width);
1704             err = snd_pcm_oss_sync1(substream, size);
1705             if (err < 0)
1706                 goto unlock;
1707         }
1708         /*
1709          * The ALSA's period might be a bit large than OSS one.
1710          * Fill the remain portion of ALSA period with zeros.
1711          */
1712         size = runtime->control->appl_ptr % runtime->period_size;
1713         if (size > 0) {
1714             size = runtime->period_size - size;
1715             if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED)
1716                 snd_pcm_lib_write(substream, NULL, size);
1717             else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
1718                 snd_pcm_lib_writev(substream, NULL, size);
1719         }
1720 unlock:
1721         mutex_unlock(&runtime->oss.params_lock);
1722         atomic_dec(&runtime->oss.rw_ref);
1723         if (err < 0)
1724             return err;
1725         /*
1726          * finish sync: drain the buffer
1727          */
1728           __direct:
1729         saved_f_flags = substream->f_flags;
1730         substream->f_flags &= ~O_NONBLOCK;
1731         err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
1732         substream->f_flags = saved_f_flags;
1733         if (err < 0)
1734             return err;
1735         mutex_lock(&runtime->oss.params_lock);
1736         runtime->oss.prepare = 1;
1737         mutex_unlock(&runtime->oss.params_lock);
1738     }
1739 
1740     substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
1741     if (substream != NULL) {
1742         err = snd_pcm_oss_make_ready(substream);
1743         if (err < 0)
1744             return err;
1745         runtime = substream->runtime;
1746         err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1747         if (err < 0)
1748             return err;
1749         mutex_lock(&runtime->oss.params_lock);
1750         runtime->oss.buffer_used = 0;
1751         runtime->oss.prepare = 1;
1752         mutex_unlock(&runtime->oss.params_lock);
1753     }
1754     return 0;
1755 }
1756 
1757 static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate)
1758 {
1759     int idx;
1760 
1761     for (idx = 1; idx >= 0; --idx) {
1762         struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1763         struct snd_pcm_runtime *runtime;
1764         int err;
1765 
1766         if (substream == NULL)
1767             continue;
1768         runtime = substream->runtime;
1769         if (rate < 1000)
1770             rate = 1000;
1771         else if (rate > 192000)
1772             rate = 192000;
1773         err = lock_params(runtime);
1774         if (err < 0)
1775             return err;
1776         if (runtime->oss.rate != rate) {
1777             runtime->oss.params = 1;
1778             runtime->oss.rate = rate;
1779         }
1780         unlock_params(runtime);
1781     }
1782     return snd_pcm_oss_get_rate(pcm_oss_file);
1783 }
1784 
1785 static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file)
1786 {
1787     struct snd_pcm_substream *substream;
1788     int err;
1789     
1790     err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
1791     if (err < 0)
1792         return err;
1793     return substream->runtime->oss.rate;
1794 }
1795 
1796 static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsigned int channels)
1797 {
1798     int idx;
1799     if (channels < 1)
1800         channels = 1;
1801     if (channels > 128)
1802         return -EINVAL;
1803     for (idx = 1; idx >= 0; --idx) {
1804         struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1805         struct snd_pcm_runtime *runtime;
1806         int err;
1807 
1808         if (substream == NULL)
1809             continue;
1810         runtime = substream->runtime;
1811         err = lock_params(runtime);
1812         if (err < 0)
1813             return err;
1814         if (runtime->oss.channels != channels) {
1815             runtime->oss.params = 1;
1816             runtime->oss.channels = channels;
1817         }
1818         unlock_params(runtime);
1819     }
1820     return snd_pcm_oss_get_channels(pcm_oss_file);
1821 }
1822 
1823 static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file)
1824 {
1825     struct snd_pcm_substream *substream;
1826     int err;
1827     
1828     err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
1829     if (err < 0)
1830         return err;
1831     return substream->runtime->oss.channels;
1832 }
1833 
1834 static int snd_pcm_oss_get_block_size(struct snd_pcm_oss_file *pcm_oss_file)
1835 {
1836     struct snd_pcm_substream *substream;
1837     int err;
1838     
1839     err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
1840     if (err < 0)
1841         return err;
1842     return substream->runtime->oss.period_bytes;
1843 }
1844 
1845 static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
1846 {
1847     struct snd_pcm_substream *substream;
1848     int err;
1849     int direct;
1850     struct snd_pcm_hw_params *params;
1851     unsigned int formats = 0;
1852     const struct snd_mask *format_mask;
1853     int fmt;
1854 
1855     err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
1856     if (err < 0)
1857         return err;
1858     if (atomic_read(&substream->mmap_count))
1859         direct = 1;
1860     else
1861         direct = substream->oss.setup.direct;
1862     if (!direct)
1863         return AFMT_MU_LAW | AFMT_U8 |
1864                AFMT_S16_LE | AFMT_S16_BE |
1865                AFMT_S8 | AFMT_U16_LE |
1866                AFMT_U16_BE |
1867             AFMT_S32_LE | AFMT_S32_BE |
1868             AFMT_S24_LE | AFMT_S24_BE |
1869             AFMT_S24_PACKED;
1870     params = kmalloc(sizeof(*params), GFP_KERNEL);
1871     if (!params)
1872         return -ENOMEM;
1873     _snd_pcm_hw_params_any(params);
1874     err = snd_pcm_hw_refine(substream, params);
1875     if (err < 0)
1876         goto error;
1877     format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
1878     for (fmt = 0; fmt < 32; ++fmt) {
1879         if (snd_mask_test(format_mask, fmt)) {
1880             int f = snd_pcm_oss_format_to((__force snd_pcm_format_t)fmt);
1881             if (f >= 0)
1882                 formats |= f;
1883         }
1884     }
1885 
1886  error:
1887     kfree(params);
1888     return err < 0 ? err : formats;
1889 }
1890 
1891 static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
1892 {
1893     int formats, idx;
1894     int err;
1895     
1896     if (format != AFMT_QUERY) {
1897         formats = snd_pcm_oss_get_formats(pcm_oss_file);
1898         if (formats < 0)
1899             return formats;
1900         if (!(formats & format))
1901             format = AFMT_U8;
1902         for (idx = 1; idx >= 0; --idx) {
1903             struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1904             struct snd_pcm_runtime *runtime;
1905             if (substream == NULL)
1906                 continue;
1907             runtime = substream->runtime;
1908             err = lock_params(runtime);
1909             if (err < 0)
1910                 return err;
1911             if (runtime->oss.format != format) {
1912                 runtime->oss.params = 1;
1913                 runtime->oss.format = format;
1914             }
1915             unlock_params(runtime);
1916         }
1917     }
1918     return snd_pcm_oss_get_format(pcm_oss_file);
1919 }
1920 
1921 static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file)
1922 {
1923     struct snd_pcm_substream *substream;
1924     int err;
1925     
1926     err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
1927     if (err < 0)
1928         return err;
1929     return substream->runtime->oss.format;
1930 }
1931 
1932 static int snd_pcm_oss_set_subdivide1(struct snd_pcm_substream *substream, int subdivide)
1933 {
1934     struct snd_pcm_runtime *runtime;
1935 
1936     runtime = substream->runtime;
1937     if (subdivide == 0) {
1938         subdivide = runtime->oss.subdivision;
1939         if (subdivide == 0)
1940             subdivide = 1;
1941         return subdivide;
1942     }
1943     if (runtime->oss.subdivision || runtime->oss.fragshift)
1944         return -EINVAL;
1945     if (subdivide != 1 && subdivide != 2 && subdivide != 4 &&
1946         subdivide != 8 && subdivide != 16)
1947         return -EINVAL;
1948     runtime->oss.subdivision = subdivide;
1949     runtime->oss.params = 1;
1950     return subdivide;
1951 }
1952 
1953 static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int subdivide)
1954 {
1955     int err = -EINVAL, idx;
1956 
1957     for (idx = 1; idx >= 0; --idx) {
1958         struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1959         struct snd_pcm_runtime *runtime;
1960 
1961         if (substream == NULL)
1962             continue;
1963         runtime = substream->runtime;
1964         err = lock_params(runtime);
1965         if (err < 0)
1966             return err;
1967         err = snd_pcm_oss_set_subdivide1(substream, subdivide);
1968         unlock_params(runtime);
1969         if (err < 0)
1970             return err;
1971     }
1972     return err;
1973 }
1974 
1975 static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsigned int val)
1976 {
1977     struct snd_pcm_runtime *runtime;
1978     int fragshift;
1979 
1980     runtime = substream->runtime;
1981     if (runtime->oss.subdivision || runtime->oss.fragshift)
1982         return -EINVAL;
1983     fragshift = val & 0xffff;
1984     if (fragshift >= 25) /* should be large enough */
1985         return -EINVAL;
1986     runtime->oss.fragshift = fragshift;
1987     runtime->oss.maxfrags = (val >> 16) & 0xffff;
1988     if (runtime->oss.fragshift < 4)     /* < 16 */
1989         runtime->oss.fragshift = 4;
1990     if (runtime->oss.maxfrags < 2)
1991         runtime->oss.maxfrags = 2;
1992     runtime->oss.params = 1;
1993     return 0;
1994 }
1995 
1996 static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsigned int val)
1997 {
1998     int err = -EINVAL, idx;
1999 
2000     for (idx = 1; idx >= 0; --idx) {
2001         struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
2002         struct snd_pcm_runtime *runtime;
2003 
2004         if (substream == NULL)
2005             continue;
2006         runtime = substream->runtime;
2007         err = lock_params(runtime);
2008         if (err < 0)
2009             return err;
2010         err = snd_pcm_oss_set_fragment1(substream, val);
2011         unlock_params(runtime);
2012         if (err < 0)
2013             return err;
2014     }
2015     return err;
2016 }
2017 
2018 static int snd_pcm_oss_nonblock(struct file * file)
2019 {
2020     spin_lock(&file->f_lock);
2021     file->f_flags |= O_NONBLOCK;
2022     spin_unlock(&file->f_lock);
2023     return 0;
2024 }
2025 
2026 static int snd_pcm_oss_get_caps1(struct snd_pcm_substream *substream, int res)
2027 {
2028 
2029     if (substream == NULL) {
2030         res &= ~DSP_CAP_DUPLEX;
2031         return res;
2032     }
2033 #ifdef DSP_CAP_MULTI
2034     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
2035         if (substream->pstr->substream_count > 1)
2036             res |= DSP_CAP_MULTI;
2037 #endif
2038     /* DSP_CAP_REALTIME is set all times: */
2039     /* all ALSA drivers can return actual pointer in ring buffer */
2040 #if defined(DSP_CAP_REALTIME) && 0
2041     {
2042         struct snd_pcm_runtime *runtime = substream->runtime;
2043         if (runtime->info & (SNDRV_PCM_INFO_BLOCK_TRANSFER|SNDRV_PCM_INFO_BATCH))
2044             res &= ~DSP_CAP_REALTIME;
2045     }
2046 #endif
2047     return res;
2048 }
2049 
2050 static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file)
2051 {
2052     int result, idx;
2053     
2054     result = DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_DUPLEX | DSP_CAP_REALTIME;
2055     for (idx = 0; idx < 2; idx++) {
2056         struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
2057         result = snd_pcm_oss_get_caps1(substream, result);
2058     }
2059     result |= 0x0001;   /* revision - same as SB AWE 64 */
2060     return result;
2061 }
2062 
2063 static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream,
2064                       snd_pcm_uframes_t hw_ptr)
2065 {
2066     struct snd_pcm_runtime *runtime = substream->runtime;
2067     snd_pcm_uframes_t appl_ptr;
2068     appl_ptr = hw_ptr + runtime->buffer_size;
2069     appl_ptr %= runtime->boundary;
2070     runtime->control->appl_ptr = appl_ptr;
2071 }
2072 
2073 static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int trigger)
2074 {
2075     struct snd_pcm_runtime *runtime;
2076     struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
2077     int err, cmd;
2078 
2079 #ifdef OSS_DEBUG
2080     pr_debug("pcm_oss: trigger = 0x%x\n", trigger);
2081 #endif
2082     
2083     psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2084     csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2085 
2086     if (psubstream) {
2087         err = snd_pcm_oss_make_ready(psubstream);
2088         if (err < 0)
2089             return err;
2090     }
2091     if (csubstream) {
2092         err = snd_pcm_oss_make_ready(csubstream);
2093         if (err < 0)
2094             return err;
2095     }
2096         if (psubstream) {
2097             runtime = psubstream->runtime;
2098         cmd = 0;
2099         if (mutex_lock_interruptible(&runtime->oss.params_lock))
2100             return -ERESTARTSYS;
2101         if (trigger & PCM_ENABLE_OUTPUT) {
2102             if (runtime->oss.trigger)
2103                 goto _skip1;
2104             if (atomic_read(&psubstream->mmap_count))
2105                 snd_pcm_oss_simulate_fill(psubstream,
2106                         get_hw_ptr_period(runtime));
2107             runtime->oss.trigger = 1;
2108             runtime->start_threshold = 1;
2109             cmd = SNDRV_PCM_IOCTL_START;
2110         } else {
2111             if (!runtime->oss.trigger)
2112                 goto _skip1;
2113             runtime->oss.trigger = 0;
2114             runtime->start_threshold = runtime->boundary;
2115             cmd = SNDRV_PCM_IOCTL_DROP;
2116             runtime->oss.prepare = 1;
2117         }
2118  _skip1:
2119         mutex_unlock(&runtime->oss.params_lock);
2120         if (cmd) {
2121             err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
2122             if (err < 0)
2123                 return err;
2124         }
2125     }
2126     if (csubstream) {
2127             runtime = csubstream->runtime;
2128         cmd = 0;
2129         if (mutex_lock_interruptible(&runtime->oss.params_lock))
2130             return -ERESTARTSYS;
2131         if (trigger & PCM_ENABLE_INPUT) {
2132             if (runtime->oss.trigger)
2133                 goto _skip2;
2134             runtime->oss.trigger = 1;
2135             runtime->start_threshold = 1;
2136             cmd = SNDRV_PCM_IOCTL_START;
2137         } else {
2138             if (!runtime->oss.trigger)
2139                 goto _skip2;
2140             runtime->oss.trigger = 0;
2141             runtime->start_threshold = runtime->boundary;
2142             cmd = SNDRV_PCM_IOCTL_DROP;
2143             runtime->oss.prepare = 1;
2144         }
2145  _skip2:
2146         mutex_unlock(&runtime->oss.params_lock);
2147         if (cmd) {
2148             err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
2149             if (err < 0)
2150                 return err;
2151         }
2152     }
2153     return 0;
2154 }
2155 
2156 static int snd_pcm_oss_get_trigger(struct snd_pcm_oss_file *pcm_oss_file)
2157 {
2158     struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
2159     int result = 0;
2160 
2161     psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2162     csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2163     if (psubstream && psubstream->runtime && psubstream->runtime->oss.trigger)
2164         result |= PCM_ENABLE_OUTPUT;
2165     if (csubstream && csubstream->runtime && csubstream->runtime->oss.trigger)
2166         result |= PCM_ENABLE_INPUT;
2167     return result;
2168 }
2169 
2170 static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file)
2171 {
2172     struct snd_pcm_substream *substream;
2173     struct snd_pcm_runtime *runtime;
2174     snd_pcm_sframes_t delay;
2175     int err;
2176 
2177     substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2178     if (substream == NULL)
2179         return -EINVAL;
2180     err = snd_pcm_oss_make_ready(substream);
2181     if (err < 0)
2182         return err;
2183     runtime = substream->runtime;
2184     if (runtime->oss.params || runtime->oss.prepare)
2185         return 0;
2186     err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
2187     if (err == -EPIPE)
2188         delay = 0;  /* hack for broken OSS applications */
2189     else if (err < 0)
2190         return err;
2191     return snd_pcm_oss_bytes(substream, delay);
2192 }
2193 
2194 static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct count_info __user * _info)
2195 {   
2196     struct snd_pcm_substream *substream;
2197     struct snd_pcm_runtime *runtime;
2198     snd_pcm_sframes_t delay;
2199     int fixup;
2200     struct count_info info;
2201     int err;
2202 
2203     if (_info == NULL)
2204         return -EFAULT;
2205     substream = pcm_oss_file->streams[stream];
2206     if (substream == NULL)
2207         return -EINVAL;
2208     err = snd_pcm_oss_make_ready(substream);
2209     if (err < 0)
2210         return err;
2211     runtime = substream->runtime;
2212     if (runtime->oss.params || runtime->oss.prepare) {
2213         memset(&info, 0, sizeof(info));
2214         if (copy_to_user(_info, &info, sizeof(info)))
2215             return -EFAULT;
2216         return 0;
2217     }
2218     if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2219         err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
2220         if (err == -EPIPE || err == -ESTRPIPE || (! err && delay < 0)) {
2221             err = 0;
2222             delay = 0;
2223             fixup = 0;
2224         } else {
2225             fixup = runtime->oss.buffer_used;
2226         }
2227     } else {
2228         err = snd_pcm_oss_capture_position_fixup(substream, &delay);
2229         fixup = -runtime->oss.buffer_used;
2230     }
2231     if (err < 0)
2232         return err;
2233     info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
2234     if (atomic_read(&substream->mmap_count)) {
2235         snd_pcm_sframes_t n;
2236         delay = get_hw_ptr_period(runtime);
2237         n = delay - runtime->oss.prev_hw_ptr_period;
2238         if (n < 0)
2239             n += runtime->boundary;
2240         info.blocks = n / runtime->period_size;
2241         runtime->oss.prev_hw_ptr_period = delay;
2242         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
2243             snd_pcm_oss_simulate_fill(substream, delay);
2244         info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
2245     } else {
2246         delay = snd_pcm_oss_bytes(substream, delay);
2247         if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2248             if (substream->oss.setup.buggyptr)
2249                 info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes;
2250             else
2251                 info.blocks = (delay + fixup) / runtime->oss.period_bytes;
2252             info.bytes = (runtime->oss.bytes - delay) & INT_MAX;
2253         } else {
2254             delay += fixup;
2255             info.blocks = delay / runtime->oss.period_bytes;
2256             info.bytes = (runtime->oss.bytes + delay) & INT_MAX;
2257         }
2258     }
2259     if (copy_to_user(_info, &info, sizeof(info)))
2260         return -EFAULT;
2261     return 0;
2262 }
2263 
2264 static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct audio_buf_info __user *_info)
2265 {
2266     struct snd_pcm_substream *substream;
2267     struct snd_pcm_runtime *runtime;
2268     snd_pcm_sframes_t avail;
2269     int fixup;
2270     struct audio_buf_info info;
2271     int err;
2272 
2273     if (_info == NULL)
2274         return -EFAULT;
2275     substream = pcm_oss_file->streams[stream];
2276     if (substream == NULL)
2277         return -EINVAL;
2278     runtime = substream->runtime;
2279 
2280     if (runtime->oss.params) {
2281         err = snd_pcm_oss_change_params(substream, false);
2282         if (err < 0)
2283             return err;
2284     }
2285 
2286     info.fragsize = runtime->oss.period_bytes;
2287     info.fragstotal = runtime->periods;
2288     if (runtime->oss.prepare) {
2289         if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2290             info.bytes = runtime->oss.period_bytes * runtime->oss.periods;
2291             info.fragments = runtime->oss.periods;
2292         } else {
2293             info.bytes = 0;
2294             info.fragments = 0;
2295         }
2296     } else {
2297         if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2298             err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &avail);
2299             if (err == -EPIPE || err == -ESTRPIPE || (! err && avail < 0)) {
2300                 avail = runtime->buffer_size;
2301                 err = 0;
2302                 fixup = 0;
2303             } else {
2304                 avail = runtime->buffer_size - avail;
2305                 fixup = -runtime->oss.buffer_used;
2306             }
2307         } else {
2308             err = snd_pcm_oss_capture_position_fixup(substream, &avail);
2309             fixup = runtime->oss.buffer_used;
2310         }
2311         if (err < 0)
2312             return err;
2313         info.bytes = snd_pcm_oss_bytes(substream, avail) + fixup;
2314         info.fragments = info.bytes / runtime->oss.period_bytes;
2315     }
2316 
2317 #ifdef OSS_DEBUG
2318     pcm_dbg(substream->pcm,
2319         "pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n",
2320         info.bytes, info.fragments, info.fragstotal, info.fragsize);
2321 #endif
2322     if (copy_to_user(_info, &info, sizeof(info)))
2323         return -EFAULT;
2324     return 0;
2325 }
2326 
2327 static int snd_pcm_oss_get_mapbuf(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct buffmem_desc __user * _info)
2328 {
2329     // it won't be probably implemented
2330     // pr_debug("TODO: snd_pcm_oss_get_mapbuf\n");
2331     return -EINVAL;
2332 }
2333 
2334 static const char *strip_task_path(const char *path)
2335 {
2336     const char *ptr, *ptrl = NULL;
2337     for (ptr = path; *ptr; ptr++) {
2338         if (*ptr == '/')
2339             ptrl = ptr + 1;
2340     }
2341     return ptrl;
2342 }
2343 
2344 static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
2345                       const char *task_name,
2346                       struct snd_pcm_oss_setup *rsetup)
2347 {
2348     struct snd_pcm_oss_setup *setup;
2349 
2350     mutex_lock(&pcm->streams[stream].oss.setup_mutex);
2351     do {
2352         for (setup = pcm->streams[stream].oss.setup_list; setup;
2353              setup = setup->next) {
2354             if (!strcmp(setup->task_name, task_name))
2355                 goto out;
2356         }
2357     } while ((task_name = strip_task_path(task_name)) != NULL);
2358  out:
2359     if (setup)
2360         *rsetup = *setup;
2361     mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
2362 }
2363 
2364 static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
2365 {
2366     snd_pcm_oss_release_buffers(substream);
2367     substream->oss.oss = 0;
2368 }
2369 
2370 static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
2371                        struct snd_pcm_oss_setup *setup,
2372                        int minor)
2373 {
2374     struct snd_pcm_runtime *runtime;
2375 
2376     substream->oss.oss = 1;
2377     substream->oss.setup = *setup;
2378     if (setup->nonblock)
2379         substream->f_flags |= O_NONBLOCK;
2380     else if (setup->block)
2381         substream->f_flags &= ~O_NONBLOCK;
2382     runtime = substream->runtime;
2383     runtime->oss.params = 1;
2384     runtime->oss.trigger = 1;
2385     runtime->oss.rate = 8000;
2386     mutex_init(&runtime->oss.params_lock);
2387     switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
2388     case SNDRV_MINOR_OSS_PCM_8:
2389         runtime->oss.format = AFMT_U8;
2390         break;
2391     case SNDRV_MINOR_OSS_PCM_16:
2392         runtime->oss.format = AFMT_S16_LE;
2393         break;
2394     default:
2395         runtime->oss.format = AFMT_MU_LAW;
2396     }
2397     runtime->oss.channels = 1;
2398     runtime->oss.fragshift = 0;
2399     runtime->oss.maxfrags = 0;
2400     runtime->oss.subdivision = 0;
2401     substream->pcm_release = snd_pcm_oss_release_substream;
2402     atomic_set(&runtime->oss.rw_ref, 0);
2403 }
2404 
2405 static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
2406 {
2407     int cidx;
2408     if (!pcm_oss_file)
2409         return 0;
2410     for (cidx = 0; cidx < 2; ++cidx) {
2411         struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx];
2412         if (substream)
2413             snd_pcm_release_substream(substream);
2414     }
2415     kfree(pcm_oss_file);
2416     return 0;
2417 }
2418 
2419 static int snd_pcm_oss_open_file(struct file *file,
2420                  struct snd_pcm *pcm,
2421                  struct snd_pcm_oss_file **rpcm_oss_file,
2422                  int minor,
2423                  struct snd_pcm_oss_setup *setup)
2424 {
2425     int idx, err;
2426     struct snd_pcm_oss_file *pcm_oss_file;
2427     struct snd_pcm_substream *substream;
2428     fmode_t f_mode = file->f_mode;
2429 
2430     if (rpcm_oss_file)
2431         *rpcm_oss_file = NULL;
2432 
2433     pcm_oss_file = kzalloc(sizeof(*pcm_oss_file), GFP_KERNEL);
2434     if (pcm_oss_file == NULL)
2435         return -ENOMEM;
2436 
2437     if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) &&
2438         (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
2439         f_mode = FMODE_WRITE;
2440 
2441     file->f_flags &= ~O_APPEND;
2442     for (idx = 0; idx < 2; idx++) {
2443         if (setup[idx].disable)
2444             continue;
2445         if (! pcm->streams[idx].substream_count)
2446             continue; /* no matching substream */
2447         if (idx == SNDRV_PCM_STREAM_PLAYBACK) {
2448             if (! (f_mode & FMODE_WRITE))
2449                 continue;
2450         } else {
2451             if (! (f_mode & FMODE_READ))
2452                 continue;
2453         }
2454         err = snd_pcm_open_substream(pcm, idx, file, &substream);
2455         if (err < 0) {
2456             snd_pcm_oss_release_file(pcm_oss_file);
2457             return err;
2458         }
2459 
2460         pcm_oss_file->streams[idx] = substream;
2461         snd_pcm_oss_init_substream(substream, &setup[idx], minor);
2462     }
2463     
2464     if (!pcm_oss_file->streams[0] && !pcm_oss_file->streams[1]) {
2465         snd_pcm_oss_release_file(pcm_oss_file);
2466         return -EINVAL;
2467     }
2468 
2469     file->private_data = pcm_oss_file;
2470     if (rpcm_oss_file)
2471         *rpcm_oss_file = pcm_oss_file;
2472     return 0;
2473 }
2474 
2475 
2476 static int snd_task_name(struct task_struct *task, char *name, size_t size)
2477 {
2478     unsigned int idx;
2479 
2480     if (snd_BUG_ON(!task || !name || size < 2))
2481         return -EINVAL;
2482     for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++)
2483         name[idx] = task->comm[idx];
2484     name[idx] = '\0';
2485     return 0;
2486 }
2487 
2488 static int snd_pcm_oss_open(struct inode *inode, struct file *file)
2489 {
2490     int err;
2491     char task_name[32];
2492     struct snd_pcm *pcm;
2493     struct snd_pcm_oss_file *pcm_oss_file;
2494     struct snd_pcm_oss_setup setup[2];
2495     int nonblock;
2496     wait_queue_entry_t wait;
2497 
2498     err = nonseekable_open(inode, file);
2499     if (err < 0)
2500         return err;
2501 
2502     pcm = snd_lookup_oss_minor_data(iminor(inode),
2503                     SNDRV_OSS_DEVICE_TYPE_PCM);
2504     if (pcm == NULL) {
2505         err = -ENODEV;
2506         goto __error1;
2507     }
2508     err = snd_card_file_add(pcm->card, file);
2509     if (err < 0)
2510         goto __error1;
2511     if (!try_module_get(pcm->card->module)) {
2512         err = -EFAULT;
2513         goto __error2;
2514     }
2515     if (snd_task_name(current, task_name, sizeof(task_name)) < 0) {
2516         err = -EFAULT;
2517         goto __error;
2518     }
2519     memset(setup, 0, sizeof(setup));
2520     if (file->f_mode & FMODE_WRITE)
2521         snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK,
2522                        task_name, &setup[0]);
2523     if (file->f_mode & FMODE_READ)
2524         snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE,
2525                        task_name, &setup[1]);
2526 
2527     nonblock = !!(file->f_flags & O_NONBLOCK);
2528     if (!nonblock)
2529         nonblock = nonblock_open;
2530 
2531     init_waitqueue_entry(&wait, current);
2532     add_wait_queue(&pcm->open_wait, &wait);
2533     mutex_lock(&pcm->open_mutex);
2534     while (1) {
2535         err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
2536                         iminor(inode), setup);
2537         if (err >= 0)
2538             break;
2539         if (err == -EAGAIN) {
2540             if (nonblock) {
2541                 err = -EBUSY;
2542                 break;
2543             }
2544         } else
2545             break;
2546         set_current_state(TASK_INTERRUPTIBLE);
2547         mutex_unlock(&pcm->open_mutex);
2548         schedule();
2549         mutex_lock(&pcm->open_mutex);
2550         if (pcm->card->shutdown) {
2551             err = -ENODEV;
2552             break;
2553         }
2554         if (signal_pending(current)) {
2555             err = -ERESTARTSYS;
2556             break;
2557         }
2558     }
2559     remove_wait_queue(&pcm->open_wait, &wait);
2560     mutex_unlock(&pcm->open_mutex);
2561     if (err < 0)
2562         goto __error;
2563     snd_card_unref(pcm->card);
2564     return err;
2565 
2566       __error:
2567         module_put(pcm->card->module);
2568       __error2:
2569         snd_card_file_remove(pcm->card, file);
2570       __error1:
2571     if (pcm)
2572         snd_card_unref(pcm->card);
2573     return err;
2574 }
2575 
2576 static int snd_pcm_oss_release(struct inode *inode, struct file *file)
2577 {
2578     struct snd_pcm *pcm;
2579     struct snd_pcm_substream *substream;
2580     struct snd_pcm_oss_file *pcm_oss_file;
2581 
2582     pcm_oss_file = file->private_data;
2583     substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2584     if (substream == NULL)
2585         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2586     if (snd_BUG_ON(!substream))
2587         return -ENXIO;
2588     pcm = substream->pcm;
2589     if (!pcm->card->shutdown)
2590         snd_pcm_oss_sync(pcm_oss_file);
2591     mutex_lock(&pcm->open_mutex);
2592     snd_pcm_oss_release_file(pcm_oss_file);
2593     mutex_unlock(&pcm->open_mutex);
2594     wake_up(&pcm->open_wait);
2595     module_put(pcm->card->module);
2596     snd_card_file_remove(pcm->card, file);
2597     return 0;
2598 }
2599 
2600 static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2601 {
2602     struct snd_pcm_oss_file *pcm_oss_file;
2603     int __user *p = (int __user *)arg;
2604     int res;
2605 
2606     pcm_oss_file = file->private_data;
2607     if (cmd == OSS_GETVERSION)
2608         return put_user(SNDRV_OSS_VERSION, p);
2609     if (cmd == OSS_ALSAEMULVER)
2610         return put_user(1, p);
2611 #if IS_REACHABLE(CONFIG_SND_MIXER_OSS)
2612     if (((cmd >> 8) & 0xff) == 'M') {   /* mixer ioctl - for OSS compatibility */
2613         struct snd_pcm_substream *substream;
2614         int idx;
2615         for (idx = 0; idx < 2; ++idx) {
2616             substream = pcm_oss_file->streams[idx];
2617             if (substream != NULL)
2618                 break;
2619         }
2620         if (snd_BUG_ON(idx >= 2))
2621             return -ENXIO;
2622         return snd_mixer_oss_ioctl_card(substream->pcm->card, cmd, arg);
2623     }
2624 #endif
2625     if (((cmd >> 8) & 0xff) != 'P')
2626         return -EINVAL;
2627 #ifdef OSS_DEBUG
2628     pr_debug("pcm_oss: ioctl = 0x%x\n", cmd);
2629 #endif
2630     switch (cmd) {
2631     case SNDCTL_DSP_RESET:
2632         return snd_pcm_oss_reset(pcm_oss_file);
2633     case SNDCTL_DSP_SYNC:
2634         return snd_pcm_oss_sync(pcm_oss_file);
2635     case SNDCTL_DSP_SPEED:
2636         if (get_user(res, p))
2637             return -EFAULT;
2638         res = snd_pcm_oss_set_rate(pcm_oss_file, res);
2639         if (res < 0)
2640             return res;
2641         return put_user(res, p);
2642     case SOUND_PCM_READ_RATE:
2643         res = snd_pcm_oss_get_rate(pcm_oss_file);
2644         if (res < 0)
2645             return res;
2646         return put_user(res, p);
2647     case SNDCTL_DSP_STEREO:
2648         if (get_user(res, p))
2649             return -EFAULT;
2650         res = res > 0 ? 2 : 1;
2651         res = snd_pcm_oss_set_channels(pcm_oss_file, res);
2652         if (res < 0)
2653             return res;
2654         return put_user(--res, p);
2655     case SNDCTL_DSP_GETBLKSIZE:
2656         res = snd_pcm_oss_get_block_size(pcm_oss_file);
2657         if (res < 0)
2658             return res;
2659         return put_user(res, p);
2660     case SNDCTL_DSP_SETFMT:
2661         if (get_user(res, p))
2662             return -EFAULT;
2663         res = snd_pcm_oss_set_format(pcm_oss_file, res);
2664         if (res < 0)
2665             return res;
2666         return put_user(res, p);
2667     case SOUND_PCM_READ_BITS:
2668         res = snd_pcm_oss_get_format(pcm_oss_file);
2669         if (res < 0)
2670             return res;
2671         return put_user(res, p);
2672     case SNDCTL_DSP_CHANNELS:
2673         if (get_user(res, p))
2674             return -EFAULT;
2675         res = snd_pcm_oss_set_channels(pcm_oss_file, res);
2676         if (res < 0)
2677             return res;
2678         return put_user(res, p);
2679     case SOUND_PCM_READ_CHANNELS:
2680         res = snd_pcm_oss_get_channels(pcm_oss_file);
2681         if (res < 0)
2682             return res;
2683         return put_user(res, p);
2684     case SOUND_PCM_WRITE_FILTER:
2685     case SOUND_PCM_READ_FILTER:
2686         return -EIO;
2687     case SNDCTL_DSP_POST:
2688         return snd_pcm_oss_post(pcm_oss_file);
2689     case SNDCTL_DSP_SUBDIVIDE:
2690         if (get_user(res, p))
2691             return -EFAULT;
2692         res = snd_pcm_oss_set_subdivide(pcm_oss_file, res);
2693         if (res < 0)
2694             return res;
2695         return put_user(res, p);
2696     case SNDCTL_DSP_SETFRAGMENT:
2697         if (get_user(res, p))
2698             return -EFAULT;
2699         return snd_pcm_oss_set_fragment(pcm_oss_file, res);
2700     case SNDCTL_DSP_GETFMTS:
2701         res = snd_pcm_oss_get_formats(pcm_oss_file);
2702         if (res < 0)
2703             return res;
2704         return put_user(res, p);
2705     case SNDCTL_DSP_GETOSPACE:
2706     case SNDCTL_DSP_GETISPACE:
2707         return snd_pcm_oss_get_space(pcm_oss_file,
2708             cmd == SNDCTL_DSP_GETISPACE ?
2709                 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2710             (struct audio_buf_info __user *) arg);
2711     case SNDCTL_DSP_NONBLOCK:
2712         return snd_pcm_oss_nonblock(file);
2713     case SNDCTL_DSP_GETCAPS:
2714         res = snd_pcm_oss_get_caps(pcm_oss_file);
2715         if (res < 0)
2716             return res;
2717         return put_user(res, p);
2718     case SNDCTL_DSP_GETTRIGGER:
2719         res = snd_pcm_oss_get_trigger(pcm_oss_file);
2720         if (res < 0)
2721             return res;
2722         return put_user(res, p);
2723     case SNDCTL_DSP_SETTRIGGER:
2724         if (get_user(res, p))
2725             return -EFAULT;
2726         return snd_pcm_oss_set_trigger(pcm_oss_file, res);
2727     case SNDCTL_DSP_GETIPTR:
2728     case SNDCTL_DSP_GETOPTR:
2729         return snd_pcm_oss_get_ptr(pcm_oss_file,
2730             cmd == SNDCTL_DSP_GETIPTR ?
2731                 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2732             (struct count_info __user *) arg);
2733     case SNDCTL_DSP_MAPINBUF:
2734     case SNDCTL_DSP_MAPOUTBUF:
2735         return snd_pcm_oss_get_mapbuf(pcm_oss_file,
2736             cmd == SNDCTL_DSP_MAPINBUF ?
2737                 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2738             (struct buffmem_desc __user *) arg);
2739     case SNDCTL_DSP_SETSYNCRO:
2740         /* stop DMA now.. */
2741         return 0;
2742     case SNDCTL_DSP_SETDUPLEX:
2743         if (snd_pcm_oss_get_caps(pcm_oss_file) & DSP_CAP_DUPLEX)
2744             return 0;
2745         return -EIO;
2746     case SNDCTL_DSP_GETODELAY:
2747         res = snd_pcm_oss_get_odelay(pcm_oss_file);
2748         if (res < 0) {
2749             /* it's for sure, some broken apps don't check for error codes */
2750             put_user(0, p);
2751             return res;
2752         }
2753         return put_user(res, p);
2754     case SNDCTL_DSP_PROFILE:
2755         return 0;   /* silently ignore */
2756     default:
2757         pr_debug("pcm_oss: unknown command = 0x%x\n", cmd);
2758     }
2759     return -EINVAL;
2760 }
2761 
2762 #ifdef CONFIG_COMPAT
2763 /* all compatible */
2764 static long snd_pcm_oss_ioctl_compat(struct file *file, unsigned int cmd,
2765                      unsigned long arg)
2766 {
2767     /*
2768      * Everything is compatbile except SNDCTL_DSP_MAPINBUF/SNDCTL_DSP_MAPOUTBUF,
2769      * which are not implemented for the native case either
2770      */
2771     return snd_pcm_oss_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
2772 }
2773 #else
2774 #define snd_pcm_oss_ioctl_compat    NULL
2775 #endif
2776 
2777 static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
2778 {
2779     struct snd_pcm_oss_file *pcm_oss_file;
2780     struct snd_pcm_substream *substream;
2781 
2782     pcm_oss_file = file->private_data;
2783     substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2784     if (substream == NULL)
2785         return -ENXIO;
2786     substream->f_flags = file->f_flags & O_NONBLOCK;
2787 #ifndef OSS_DEBUG
2788     return snd_pcm_oss_read1(substream, buf, count);
2789 #else
2790     {
2791         ssize_t res = snd_pcm_oss_read1(substream, buf, count);
2792         pcm_dbg(substream->pcm,
2793             "pcm_oss: read %li bytes (returned %li bytes)\n",
2794             (long)count, (long)res);
2795         return res;
2796     }
2797 #endif
2798 }
2799 
2800 static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
2801 {
2802     struct snd_pcm_oss_file *pcm_oss_file;
2803     struct snd_pcm_substream *substream;
2804     long result;
2805 
2806     pcm_oss_file = file->private_data;
2807     substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2808     if (substream == NULL)
2809         return -ENXIO;
2810     substream->f_flags = file->f_flags & O_NONBLOCK;
2811     result = snd_pcm_oss_write1(substream, buf, count);
2812 #ifdef OSS_DEBUG
2813     pcm_dbg(substream->pcm, "pcm_oss: write %li bytes (wrote %li bytes)\n",
2814            (long)count, (long)result);
2815 #endif
2816     return result;
2817 }
2818 
2819 static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
2820 {
2821     struct snd_pcm_runtime *runtime = substream->runtime;
2822     if (atomic_read(&substream->mmap_count))
2823         return runtime->oss.prev_hw_ptr_period !=
2824                         get_hw_ptr_period(runtime);
2825     else
2826         return snd_pcm_playback_avail(runtime) >=
2827                         runtime->oss.period_frames;
2828 }
2829 
2830 static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
2831 {
2832     struct snd_pcm_runtime *runtime = substream->runtime;
2833     if (atomic_read(&substream->mmap_count))
2834         return runtime->oss.prev_hw_ptr_period !=
2835                         get_hw_ptr_period(runtime);
2836     else
2837         return snd_pcm_capture_avail(runtime) >=
2838                         runtime->oss.period_frames;
2839 }
2840 
2841 static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
2842 {
2843     struct snd_pcm_oss_file *pcm_oss_file;
2844     __poll_t mask;
2845     struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
2846     
2847     pcm_oss_file = file->private_data;
2848 
2849     psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2850     csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2851 
2852     mask = 0;
2853     if (psubstream != NULL) {
2854         struct snd_pcm_runtime *runtime = psubstream->runtime;
2855         poll_wait(file, &runtime->sleep, wait);
2856         snd_pcm_stream_lock_irq(psubstream);
2857         if (runtime->status->state != SNDRV_PCM_STATE_DRAINING &&
2858             (runtime->status->state != SNDRV_PCM_STATE_RUNNING ||
2859              snd_pcm_oss_playback_ready(psubstream)))
2860             mask |= EPOLLOUT | EPOLLWRNORM;
2861         snd_pcm_stream_unlock_irq(psubstream);
2862     }
2863     if (csubstream != NULL) {
2864         struct snd_pcm_runtime *runtime = csubstream->runtime;
2865         snd_pcm_state_t ostate;
2866         poll_wait(file, &runtime->sleep, wait);
2867         snd_pcm_stream_lock_irq(csubstream);
2868         ostate = runtime->status->state;
2869         if (ostate != SNDRV_PCM_STATE_RUNNING ||
2870             snd_pcm_oss_capture_ready(csubstream))
2871             mask |= EPOLLIN | EPOLLRDNORM;
2872         snd_pcm_stream_unlock_irq(csubstream);
2873         if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
2874             struct snd_pcm_oss_file ofile;
2875             memset(&ofile, 0, sizeof(ofile));
2876             ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2877             runtime->oss.trigger = 0;
2878             snd_pcm_oss_set_trigger(&ofile, PCM_ENABLE_INPUT);
2879         }
2880     }
2881 
2882     return mask;
2883 }
2884 
2885 static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
2886 {
2887     struct snd_pcm_oss_file *pcm_oss_file;
2888     struct snd_pcm_substream *substream = NULL;
2889     struct snd_pcm_runtime *runtime;
2890     int err;
2891 
2892 #ifdef OSS_DEBUG
2893     pr_debug("pcm_oss: mmap begin\n");
2894 #endif
2895     pcm_oss_file = file->private_data;
2896     switch ((area->vm_flags & (VM_READ | VM_WRITE))) {
2897     case VM_READ | VM_WRITE:
2898         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2899         if (substream)
2900             break;
2901         fallthrough;
2902     case VM_READ:
2903         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2904         break;
2905     case VM_WRITE:
2906         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2907         break;
2908     default:
2909         return -EINVAL;
2910     }
2911     /* set VM_READ access as well to fix memset() routines that do
2912        reads before writes (to improve performance) */
2913     area->vm_flags |= VM_READ;
2914     if (substream == NULL)
2915         return -ENXIO;
2916     runtime = substream->runtime;
2917     if (!(runtime->info & SNDRV_PCM_INFO_MMAP_VALID))
2918         return -EIO;
2919     if (runtime->info & SNDRV_PCM_INFO_INTERLEAVED)
2920         runtime->access = SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;
2921     else
2922         return -EIO;
2923     
2924     if (runtime->oss.params) {
2925         /* use mutex_trylock() for params_lock for avoiding a deadlock
2926          * between mmap_lock and params_lock taken by
2927          * copy_from/to_user() in snd_pcm_oss_write/read()
2928          */
2929         err = snd_pcm_oss_change_params(substream, true);
2930         if (err < 0)
2931             return err;
2932     }
2933 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
2934     if (runtime->oss.plugin_first != NULL)
2935         return -EIO;
2936 #endif
2937 
2938     if (area->vm_pgoff != 0)
2939         return -EINVAL;
2940 
2941     err = snd_pcm_mmap_data(substream, file, area);
2942     if (err < 0)
2943         return err;
2944     runtime->oss.mmap_bytes = area->vm_end - area->vm_start;
2945     runtime->silence_threshold = 0;
2946     runtime->silence_size = 0;
2947 #ifdef OSS_DEBUG
2948     pr_debug("pcm_oss: mmap ok, bytes = 0x%x\n",
2949            runtime->oss.mmap_bytes);
2950 #endif
2951     /* In mmap mode we never stop */
2952     runtime->stop_threshold = runtime->boundary;
2953 
2954     return 0;
2955 }
2956 
2957 #ifdef CONFIG_SND_VERBOSE_PROCFS
2958 /*
2959  *  /proc interface
2960  */
2961 
2962 static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
2963                   struct snd_info_buffer *buffer)
2964 {
2965     struct snd_pcm_str *pstr = entry->private_data;
2966     struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
2967     mutex_lock(&pstr->oss.setup_mutex);
2968     while (setup) {
2969         snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
2970                 setup->task_name,
2971                 setup->periods,
2972                 setup->period_size,
2973                 setup->disable ? " disable" : "",
2974                 setup->direct ? " direct" : "",
2975                 setup->block ? " block" : "",
2976                 setup->nonblock ? " non-block" : "",
2977                 setup->partialfrag ? " partial-frag" : "",
2978                 setup->nosilence ? " no-silence" : "");
2979         setup = setup->next;
2980     }
2981     mutex_unlock(&pstr->oss.setup_mutex);
2982 }
2983 
2984 static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
2985 {
2986     struct snd_pcm_oss_setup *setup, *setupn;
2987 
2988     for (setup = pstr->oss.setup_list, pstr->oss.setup_list = NULL;
2989          setup; setup = setupn) {
2990         setupn = setup->next;
2991         kfree(setup->task_name);
2992         kfree(setup);
2993     }
2994     pstr->oss.setup_list = NULL;
2995 }
2996 
2997 static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
2998                    struct snd_info_buffer *buffer)
2999 {
3000     struct snd_pcm_str *pstr = entry->private_data;
3001     char line[128], str[32], task_name[32];
3002     const char *ptr;
3003     int idx1;
3004     struct snd_pcm_oss_setup *setup, *setup1, template;
3005 
3006     while (!snd_info_get_line(buffer, line, sizeof(line))) {
3007         mutex_lock(&pstr->oss.setup_mutex);
3008         memset(&template, 0, sizeof(template));
3009         ptr = snd_info_get_str(task_name, line, sizeof(task_name));
3010         if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
3011             snd_pcm_oss_proc_free_setup_list(pstr);
3012             mutex_unlock(&pstr->oss.setup_mutex);
3013             continue;
3014         }
3015         for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
3016             if (!strcmp(setup->task_name, task_name)) {
3017                 template = *setup;
3018                 break;
3019             }
3020         }
3021         ptr = snd_info_get_str(str, ptr, sizeof(str));
3022         template.periods = simple_strtoul(str, NULL, 10);
3023         ptr = snd_info_get_str(str, ptr, sizeof(str));
3024         template.period_size = simple_strtoul(str, NULL, 10);
3025         for (idx1 = 31; idx1 >= 0; idx1--)
3026             if (template.period_size & (1 << idx1))
3027                 break;
3028         for (idx1--; idx1 >= 0; idx1--)
3029             template.period_size &= ~(1 << idx1);
3030         do {
3031             ptr = snd_info_get_str(str, ptr, sizeof(str));
3032             if (!strcmp(str, "disable")) {
3033                 template.disable = 1;
3034             } else if (!strcmp(str, "direct")) {
3035                 template.direct = 1;
3036             } else if (!strcmp(str, "block")) {
3037                 template.block = 1;
3038             } else if (!strcmp(str, "non-block")) {
3039                 template.nonblock = 1;
3040             } else if (!strcmp(str, "partial-frag")) {
3041                 template.partialfrag = 1;
3042             } else if (!strcmp(str, "no-silence")) {
3043                 template.nosilence = 1;
3044             } else if (!strcmp(str, "buggy-ptr")) {
3045                 template.buggyptr = 1;
3046             }
3047         } while (*str);
3048         if (setup == NULL) {
3049             setup = kmalloc(sizeof(*setup), GFP_KERNEL);
3050             if (! setup) {
3051                 buffer->error = -ENOMEM;
3052                 mutex_unlock(&pstr->oss.setup_mutex);
3053                 return;
3054             }
3055             if (pstr->oss.setup_list == NULL)
3056                 pstr->oss.setup_list = setup;
3057             else {
3058                 for (setup1 = pstr->oss.setup_list;
3059                      setup1->next; setup1 = setup1->next);
3060                 setup1->next = setup;
3061             }
3062             template.task_name = kstrdup(task_name, GFP_KERNEL);
3063             if (! template.task_name) {
3064                 kfree(setup);
3065                 buffer->error = -ENOMEM;
3066                 mutex_unlock(&pstr->oss.setup_mutex);
3067                 return;
3068             }
3069         }
3070         *setup = template;
3071         mutex_unlock(&pstr->oss.setup_mutex);
3072     }
3073 }
3074 
3075 static void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
3076 {
3077     int stream;
3078     for (stream = 0; stream < 2; ++stream) {
3079         struct snd_info_entry *entry;
3080         struct snd_pcm_str *pstr = &pcm->streams[stream];
3081         if (pstr->substream_count == 0)
3082             continue;
3083         entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root);
3084         if (entry) {
3085             entry->content = SNDRV_INFO_CONTENT_TEXT;
3086             entry->mode = S_IFREG | 0644;
3087             entry->c.text.read = snd_pcm_oss_proc_read;
3088             entry->c.text.write = snd_pcm_oss_proc_write;
3089             entry->private_data = pstr;
3090             if (snd_info_register(entry) < 0) {
3091                 snd_info_free_entry(entry);
3092                 entry = NULL;
3093             }
3094         }
3095         pstr->oss.proc_entry = entry;
3096     }
3097 }
3098 
3099 static void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
3100 {
3101     int stream;
3102     for (stream = 0; stream < 2; ++stream) {
3103         struct snd_pcm_str *pstr = &pcm->streams[stream];
3104         snd_info_free_entry(pstr->oss.proc_entry);
3105         pstr->oss.proc_entry = NULL;
3106         snd_pcm_oss_proc_free_setup_list(pstr);
3107     }
3108 }
3109 #else /* !CONFIG_SND_VERBOSE_PROCFS */
3110 static inline void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
3111 {
3112 }
3113 static inline void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
3114 {
3115 }
3116 #endif /* CONFIG_SND_VERBOSE_PROCFS */
3117 
3118 /*
3119  *  ENTRY functions
3120  */
3121 
3122 static const struct file_operations snd_pcm_oss_f_reg =
3123 {
3124     .owner =    THIS_MODULE,
3125     .read =     snd_pcm_oss_read,
3126     .write =    snd_pcm_oss_write,
3127     .open =     snd_pcm_oss_open,
3128     .release =  snd_pcm_oss_release,
3129     .llseek =   no_llseek,
3130     .poll =     snd_pcm_oss_poll,
3131     .unlocked_ioctl =   snd_pcm_oss_ioctl,
3132     .compat_ioctl = snd_pcm_oss_ioctl_compat,
3133     .mmap =     snd_pcm_oss_mmap,
3134 };
3135 
3136 static void register_oss_dsp(struct snd_pcm *pcm, int index)
3137 {
3138     if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
3139                     pcm->card, index, &snd_pcm_oss_f_reg,
3140                     pcm) < 0) {
3141         pcm_err(pcm, "unable to register OSS PCM device %i:%i\n",
3142                pcm->card->number, pcm->device);
3143     }
3144 }
3145 
3146 static int snd_pcm_oss_register_minor(struct snd_pcm *pcm)
3147 {
3148     pcm->oss.reg = 0;
3149     if (dsp_map[pcm->card->number] == (int)pcm->device) {
3150         char name[128];
3151         int duplex;
3152         register_oss_dsp(pcm, 0);
3153         duplex = (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count > 0 && 
3154                   pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count && 
3155                   !(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX));
3156         sprintf(name, "%s%s", pcm->name, duplex ? " (DUPLEX)" : "");
3157 #ifdef SNDRV_OSS_INFO_DEV_AUDIO
3158         snd_oss_info_register(SNDRV_OSS_INFO_DEV_AUDIO,
3159                       pcm->card->number,
3160                       name);
3161 #endif
3162         pcm->oss.reg++;
3163         pcm->oss.reg_mask |= 1;
3164     }
3165     if (adsp_map[pcm->card->number] == (int)pcm->device) {
3166         register_oss_dsp(pcm, 1);
3167         pcm->oss.reg++;
3168         pcm->oss.reg_mask |= 2;
3169     }
3170 
3171     if (pcm->oss.reg)
3172         snd_pcm_oss_proc_init(pcm);
3173 
3174     return 0;
3175 }
3176 
3177 static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm)
3178 {
3179     if (pcm->oss.reg) {
3180         if (pcm->oss.reg_mask & 1) {
3181             pcm->oss.reg_mask &= ~1;
3182             snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
3183                           pcm->card, 0);
3184         }
3185         if (pcm->oss.reg_mask & 2) {
3186             pcm->oss.reg_mask &= ~2;
3187             snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
3188                           pcm->card, 1);
3189         }
3190         if (dsp_map[pcm->card->number] == (int)pcm->device) {
3191 #ifdef SNDRV_OSS_INFO_DEV_AUDIO
3192             snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
3193 #endif
3194         }
3195         pcm->oss.reg = 0;
3196     }
3197     return 0;
3198 }
3199 
3200 static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
3201 {
3202     snd_pcm_oss_disconnect_minor(pcm);
3203     snd_pcm_oss_proc_done(pcm);
3204     return 0;
3205 }
3206 
3207 static struct snd_pcm_notify snd_pcm_oss_notify =
3208 {
3209     .n_register =   snd_pcm_oss_register_minor,
3210     .n_disconnect = snd_pcm_oss_disconnect_minor,
3211     .n_unregister = snd_pcm_oss_unregister_minor,
3212 };
3213 
3214 static int __init alsa_pcm_oss_init(void)
3215 {
3216     int i;
3217     int err;
3218 
3219     /* check device map table */
3220     for (i = 0; i < SNDRV_CARDS; i++) {
3221         if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) {
3222             pr_err("ALSA: pcm_oss: invalid dsp_map[%d] = %d\n",
3223                    i, dsp_map[i]);
3224             dsp_map[i] = 0;
3225         }
3226         if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_PCM_DEVICES) {
3227             pr_err("ALSA: pcm_oss: invalid adsp_map[%d] = %d\n",
3228                    i, adsp_map[i]);
3229             adsp_map[i] = 1;
3230         }
3231     }
3232     err = snd_pcm_notify(&snd_pcm_oss_notify, 0);
3233     if (err < 0)
3234         return err;
3235     return 0;
3236 }
3237 
3238 static void __exit alsa_pcm_oss_exit(void)
3239 {
3240     snd_pcm_notify(&snd_pcm_oss_notify, 1);
3241 }
3242 
3243 module_init(alsa_pcm_oss_init)
3244 module_exit(alsa_pcm_oss_exit)