]> Git Repo - linux.git/blob - sound/core/oss/pcm_oss.c
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[linux.git] / sound / core / oss / pcm_oss.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Digital Audio (PCM) abstract layer / OSS compatible
4  *  Copyright (c) by Jaroslav Kysela <[email protected]>
5  */
6
7 #if 0
8 #define PLUGIN_DEBUG
9 #endif
10 #if 0
11 #define OSS_DEBUG
12 #endif
13
14 #include <linux/init.h>
15 #include <linux/slab.h>
16 #include <linux/sched/signal.h>
17 #include <linux/time.h>
18 #include <linux/vmalloc.h>
19 #include <linux/module.h>
20 #include <linux/math64.h>
21 #include <linux/string.h>
22 #include <linux/compat.h>
23 #include <sound/core.h>
24 #include <sound/minors.h>
25 #include <sound/pcm.h>
26 #include <sound/pcm_params.h>
27 #include "pcm_plugin.h"
28 #include <sound/info.h>
29 #include <linux/soundcard.h>
30 #include <sound/initval.h>
31 #include <sound/mixer_oss.h>
32
33 #define OSS_ALSAEMULVER         _SIOR ('M', 249, int)
34
35 static int dsp_map[SNDRV_CARDS];
36 static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
37 static bool nonblock_open = 1;
38
39 MODULE_AUTHOR("Jaroslav Kysela <[email protected]>, Abramo Bagnara <[email protected]>");
40 MODULE_DESCRIPTION("PCM OSS emulation for ALSA.");
41 MODULE_LICENSE("GPL");
42 module_param_array(dsp_map, int, NULL, 0444);
43 MODULE_PARM_DESC(dsp_map, "PCM device number assigned to 1st OSS device.");
44 module_param_array(adsp_map, int, NULL, 0444);
45 MODULE_PARM_DESC(adsp_map, "PCM device number assigned to 2nd OSS device.");
46 module_param(nonblock_open, bool, 0644);
47 MODULE_PARM_DESC(nonblock_open, "Don't block opening busy PCM devices.");
48 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM);
49 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM1);
50
51 static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file);
52 static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file);
53 static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file);
54
55 /*
56  * helper functions to process hw_params
57  */
58 static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin)
59 {
60         int changed = 0;
61         if (i->min < min) {
62                 i->min = min;
63                 i->openmin = openmin;
64                 changed = 1;
65         } else if (i->min == min && !i->openmin && openmin) {
66                 i->openmin = 1;
67                 changed = 1;
68         }
69         if (i->integer) {
70                 if (i->openmin) {
71                         i->min++;
72                         i->openmin = 0;
73                 }
74         }
75         if (snd_interval_checkempty(i)) {
76                 snd_interval_none(i);
77                 return -EINVAL;
78         }
79         return changed;
80 }
81
82 static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax)
83 {
84         int changed = 0;
85         if (i->max > max) {
86                 i->max = max;
87                 i->openmax = openmax;
88                 changed = 1;
89         } else if (i->max == max && !i->openmax && openmax) {
90                 i->openmax = 1;
91                 changed = 1;
92         }
93         if (i->integer) {
94                 if (i->openmax) {
95                         i->max--;
96                         i->openmax = 0;
97                 }
98         }
99         if (snd_interval_checkempty(i)) {
100                 snd_interval_none(i);
101                 return -EINVAL;
102         }
103         return changed;
104 }
105
106 static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
107 {
108         struct snd_interval t;
109         t.empty = 0;
110         t.min = t.max = val;
111         t.openmin = t.openmax = 0;
112         t.integer = 1;
113         return snd_interval_refine(i, &t);
114 }
115
116 /**
117  * snd_pcm_hw_param_value_min
118  * @params: the hw_params instance
119  * @var: parameter to retrieve
120  * @dir: pointer to the direction (-1,0,1) or NULL
121  *
122  * Return the minimum value for field PAR.
123  */
124 static unsigned int
125 snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
126                            snd_pcm_hw_param_t var, int *dir)
127 {
128         if (hw_is_mask(var)) {
129                 if (dir)
130                         *dir = 0;
131                 return snd_mask_min(hw_param_mask_c(params, var));
132         }
133         if (hw_is_interval(var)) {
134                 const struct snd_interval *i = hw_param_interval_c(params, var);
135                 if (dir)
136                         *dir = i->openmin;
137                 return snd_interval_min(i);
138         }
139         return -EINVAL;
140 }
141
142 /**
143  * snd_pcm_hw_param_value_max
144  * @params: the hw_params instance
145  * @var: parameter to retrieve
146  * @dir: pointer to the direction (-1,0,1) or NULL
147  *
148  * Return the maximum value for field PAR.
149  */
150 static int
151 snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
152                            snd_pcm_hw_param_t var, int *dir)
153 {
154         if (hw_is_mask(var)) {
155                 if (dir)
156                         *dir = 0;
157                 return snd_mask_max(hw_param_mask_c(params, var));
158         }
159         if (hw_is_interval(var)) {
160                 const struct snd_interval *i = hw_param_interval_c(params, var);
161                 if (dir)
162                         *dir = - (int) i->openmax;
163                 return snd_interval_max(i);
164         }
165         return -EINVAL;
166 }
167
168 static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params,
169                                   snd_pcm_hw_param_t var,
170                                   const struct snd_mask *val)
171 {
172         int changed;
173         changed = snd_mask_refine(hw_param_mask(params, var), val);
174         if (changed > 0) {
175                 params->cmask |= 1 << var;
176                 params->rmask |= 1 << var;
177         }
178         return changed;
179 }
180
181 static int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm,
182                                  struct snd_pcm_hw_params *params,
183                                  snd_pcm_hw_param_t var,
184                                  const struct snd_mask *val)
185 {
186         int changed = _snd_pcm_hw_param_mask(params, var, val);
187         if (changed < 0)
188                 return changed;
189         if (params->rmask) {
190                 int err = snd_pcm_hw_refine(pcm, params);
191                 if (err < 0)
192                         return err;
193         }
194         return 0;
195 }
196
197 static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
198                                  snd_pcm_hw_param_t var, unsigned int val,
199                                  int dir)
200 {
201         int changed;
202         int open = 0;
203         if (dir) {
204                 if (dir > 0) {
205                         open = 1;
206                 } else if (dir < 0) {
207                         if (val > 0) {
208                                 open = 1;
209                                 val--;
210                         }
211                 }
212         }
213         if (hw_is_mask(var))
214                 changed = snd_mask_refine_min(hw_param_mask(params, var),
215                                               val + !!open);
216         else if (hw_is_interval(var))
217                 changed = snd_interval_refine_min(hw_param_interval(params, var),
218                                                   val, open);
219         else
220                 return -EINVAL;
221         if (changed > 0) {
222                 params->cmask |= 1 << var;
223                 params->rmask |= 1 << var;
224         }
225         return changed;
226 }
227
228 /**
229  * snd_pcm_hw_param_min
230  * @pcm: PCM instance
231  * @params: the hw_params instance
232  * @var: parameter to retrieve
233  * @val: minimal value
234  * @dir: pointer to the direction (-1,0,1) or NULL
235  *
236  * Inside configuration space defined by PARAMS remove from PAR all 
237  * values < VAL. Reduce configuration space accordingly.
238  * Return new minimum or -EINVAL if the configuration space is empty
239  */
240 static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm,
241                                 struct snd_pcm_hw_params *params,
242                                 snd_pcm_hw_param_t var, unsigned int val,
243                                 int *dir)
244 {
245         int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
246         if (changed < 0)
247                 return changed;
248         if (params->rmask) {
249                 int err = snd_pcm_hw_refine(pcm, params);
250                 if (err < 0)
251                         return err;
252         }
253         return snd_pcm_hw_param_value_min(params, var, dir);
254 }
255
256 static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
257                                  snd_pcm_hw_param_t var, unsigned int val,
258                                  int dir)
259 {
260         int changed;
261         int open = 0;
262         if (dir) {
263                 if (dir < 0) {
264                         open = 1;
265                 } else if (dir > 0) {
266                         open = 1;
267                         val++;
268                 }
269         }
270         if (hw_is_mask(var)) {
271                 if (val == 0 && open) {
272                         snd_mask_none(hw_param_mask(params, var));
273                         changed = -EINVAL;
274                 } else
275                         changed = snd_mask_refine_max(hw_param_mask(params, var),
276                                                       val - !!open);
277         } else if (hw_is_interval(var))
278                 changed = snd_interval_refine_max(hw_param_interval(params, var),
279                                                   val, open);
280         else
281                 return -EINVAL;
282         if (changed > 0) {
283                 params->cmask |= 1 << var;
284                 params->rmask |= 1 << var;
285         }
286         return changed;
287 }
288
289 /**
290  * snd_pcm_hw_param_max
291  * @pcm: PCM instance
292  * @params: the hw_params instance
293  * @var: parameter to retrieve
294  * @val: maximal value
295  * @dir: pointer to the direction (-1,0,1) or NULL
296  *
297  * Inside configuration space defined by PARAMS remove from PAR all 
298  *  values >= VAL + 1. Reduce configuration space accordingly.
299  *  Return new maximum or -EINVAL if the configuration space is empty
300  */
301 static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm,
302                                 struct snd_pcm_hw_params *params,
303                                 snd_pcm_hw_param_t var, unsigned int val,
304                                 int *dir)
305 {
306         int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
307         if (changed < 0)
308                 return changed;
309         if (params->rmask) {
310                 int err = snd_pcm_hw_refine(pcm, params);
311                 if (err < 0)
312                         return err;
313         }
314         return snd_pcm_hw_param_value_max(params, var, dir);
315 }
316
317 static int boundary_sub(int a, int adir,
318                         int b, int bdir,
319                         int *c, int *cdir)
320 {
321         adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
322         bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
323         *c = a - b;
324         *cdir = adir - bdir;
325         if (*cdir == -2) {
326                 (*c)--;
327         } else if (*cdir == 2) {
328                 (*c)++;
329         }
330         return 0;
331 }
332
333 static int boundary_lt(unsigned int a, int adir,
334                        unsigned int b, int bdir)
335 {
336         if (adir < 0) {
337                 a--;
338                 adir = 1;
339         } else if (adir > 0)
340                 adir = 1;
341         if (bdir < 0) {
342                 b--;
343                 bdir = 1;
344         } else if (bdir > 0)
345                 bdir = 1;
346         return a < b || (a == b && adir < bdir);
347 }
348
349 /* Return 1 if min is nearer to best than max */
350 static int boundary_nearer(int min, int mindir,
351                            int best, int bestdir,
352                            int max, int maxdir)
353 {
354         int dmin, dmindir;
355         int dmax, dmaxdir;
356         boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
357         boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
358         return boundary_lt(dmin, dmindir, dmax, dmaxdir);
359 }
360
361 /**
362  * snd_pcm_hw_param_near
363  * @pcm: PCM instance
364  * @params: the hw_params instance
365  * @var: parameter to retrieve
366  * @best: value to set
367  * @dir: pointer to the direction (-1,0,1) or NULL
368  *
369  * Inside configuration space defined by PARAMS set PAR to the available value
370  * nearest to VAL. Reduce configuration space accordingly.
371  * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
372  * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
373  * Return the value found.
374   */
375 static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
376                                  struct snd_pcm_hw_params *params,
377                                  snd_pcm_hw_param_t var, unsigned int best,
378                                  int *dir)
379 {
380         struct snd_pcm_hw_params *save = NULL;
381         int v;
382         unsigned int saved_min;
383         int last = 0;
384         int min, max;
385         int mindir, maxdir;
386         int valdir = dir ? *dir : 0;
387         /* FIXME */
388         if (best > INT_MAX)
389                 best = INT_MAX;
390         min = max = best;
391         mindir = maxdir = valdir;
392         if (maxdir > 0)
393                 maxdir = 0;
394         else if (maxdir == 0)
395                 maxdir = -1;
396         else {
397                 maxdir = 1;
398                 max--;
399         }
400         save = kmalloc(sizeof(*save), GFP_KERNEL);
401         if (save == NULL)
402                 return -ENOMEM;
403         *save = *params;
404         saved_min = min;
405         min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
406         if (min >= 0) {
407                 struct snd_pcm_hw_params *params1;
408                 if (max < 0)
409                         goto _end;
410                 if ((unsigned int)min == saved_min && mindir == valdir)
411                         goto _end;
412                 params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
413                 if (params1 == NULL) {
414                         kfree(save);
415                         return -ENOMEM;
416                 }
417                 *params1 = *save;
418                 max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
419                 if (max < 0) {
420                         kfree(params1);
421                         goto _end;
422                 }
423                 if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
424                         *params = *params1;
425                         last = 1;
426                 }
427                 kfree(params1);
428         } else {
429                 *params = *save;
430                 max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
431                 if (max < 0) {
432                         kfree(save);
433                         return max;
434                 }
435                 last = 1;
436         }
437  _end:
438         kfree(save);
439         if (last)
440                 v = snd_pcm_hw_param_last(pcm, params, var, dir);
441         else
442                 v = snd_pcm_hw_param_first(pcm, params, var, dir);
443         return v;
444 }
445
446 static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
447                                  snd_pcm_hw_param_t var, unsigned int val,
448                                  int dir)
449 {
450         int changed;
451         if (hw_is_mask(var)) {
452                 struct snd_mask *m = hw_param_mask(params, var);
453                 if (val == 0 && dir < 0) {
454                         changed = -EINVAL;
455                         snd_mask_none(m);
456                 } else {
457                         if (dir > 0)
458                                 val++;
459                         else if (dir < 0)
460                                 val--;
461                         changed = snd_mask_refine_set(hw_param_mask(params, var), val);
462                 }
463         } else if (hw_is_interval(var)) {
464                 struct snd_interval *i = hw_param_interval(params, var);
465                 if (val == 0 && dir < 0) {
466                         changed = -EINVAL;
467                         snd_interval_none(i);
468                 } else if (dir == 0)
469                         changed = snd_interval_refine_set(i, val);
470                 else {
471                         struct snd_interval t;
472                         t.openmin = 1;
473                         t.openmax = 1;
474                         t.empty = 0;
475                         t.integer = 0;
476                         if (dir < 0) {
477                                 t.min = val - 1;
478                                 t.max = val;
479                         } else {
480                                 t.min = val;
481                                 t.max = val+1;
482                         }
483                         changed = snd_interval_refine(i, &t);
484                 }
485         } else
486                 return -EINVAL;
487         if (changed > 0) {
488                 params->cmask |= 1 << var;
489                 params->rmask |= 1 << var;
490         }
491         return changed;
492 }
493
494 /**
495  * snd_pcm_hw_param_set
496  * @pcm: PCM instance
497  * @params: the hw_params instance
498  * @var: parameter to retrieve
499  * @val: value to set
500  * @dir: pointer to the direction (-1,0,1) or NULL
501  *
502  * Inside configuration space defined by PARAMS remove from PAR all 
503  * values != VAL. Reduce configuration space accordingly.
504  *  Return VAL or -EINVAL if the configuration space is empty
505  */
506 static int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,
507                                 struct snd_pcm_hw_params *params,
508                                 snd_pcm_hw_param_t var, unsigned int val,
509                                 int dir)
510 {
511         int changed = _snd_pcm_hw_param_set(params, var, val, dir);
512         if (changed < 0)
513                 return changed;
514         if (params->rmask) {
515                 int err = snd_pcm_hw_refine(pcm, params);
516                 if (err < 0)
517                         return err;
518         }
519         return snd_pcm_hw_param_value(params, var, NULL);
520 }
521
522 static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
523                                         snd_pcm_hw_param_t var)
524 {
525         int changed;
526         changed = snd_interval_setinteger(hw_param_interval(params, var));
527         if (changed > 0) {
528                 params->cmask |= 1 << var;
529                 params->rmask |= 1 << var;
530         }
531         return changed;
532 }
533         
534 /*
535  * plugin
536  */
537
538 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
539 static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream)
540 {
541         struct snd_pcm_runtime *runtime = substream->runtime;
542         struct snd_pcm_plugin *plugin, *next;
543         
544         plugin = runtime->oss.plugin_first;
545         while (plugin) {
546                 next = plugin->next;
547                 snd_pcm_plugin_free(plugin);
548                 plugin = next;
549         }
550         runtime->oss.plugin_first = runtime->oss.plugin_last = NULL;
551         return 0;
552 }
553
554 static int snd_pcm_plugin_insert(struct snd_pcm_plugin *plugin)
555 {
556         struct snd_pcm_runtime *runtime = plugin->plug->runtime;
557         plugin->next = runtime->oss.plugin_first;
558         plugin->prev = NULL;
559         if (runtime->oss.plugin_first) {
560                 runtime->oss.plugin_first->prev = plugin;
561                 runtime->oss.plugin_first = plugin;
562         } else {
563                 runtime->oss.plugin_last =
564                 runtime->oss.plugin_first = plugin;
565         }
566         return 0;
567 }
568
569 int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin)
570 {
571         struct snd_pcm_runtime *runtime = plugin->plug->runtime;
572         plugin->next = NULL;
573         plugin->prev = runtime->oss.plugin_last;
574         if (runtime->oss.plugin_last) {
575                 runtime->oss.plugin_last->next = plugin;
576                 runtime->oss.plugin_last = plugin;
577         } else {
578                 runtime->oss.plugin_last =
579                 runtime->oss.plugin_first = plugin;
580         }
581         return 0;
582 }
583 #endif /* CONFIG_SND_PCM_OSS_PLUGINS */
584
585 static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames)
586 {
587         struct snd_pcm_runtime *runtime = substream->runtime;
588         long buffer_size = snd_pcm_lib_buffer_bytes(substream);
589         long bytes = frames_to_bytes(runtime, frames);
590         if (buffer_size == runtime->oss.buffer_bytes)
591                 return bytes;
592 #if BITS_PER_LONG >= 64
593         return runtime->oss.buffer_bytes * bytes / buffer_size;
594 #else
595         {
596                 u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes;
597                 return div_u64(bsize, buffer_size);
598         }
599 #endif
600 }
601
602 static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes)
603 {
604         struct snd_pcm_runtime *runtime = substream->runtime;
605         long buffer_size = snd_pcm_lib_buffer_bytes(substream);
606         if (buffer_size == runtime->oss.buffer_bytes)
607                 return bytes_to_frames(runtime, bytes);
608         return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
609 }
610
611 static inline
612 snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime)
613 {
614         return runtime->hw_ptr_interrupt;
615 }
616
617 /* define extended formats in the recent OSS versions (if any) */
618 /* linear formats */
619 #define AFMT_S32_LE      0x00001000
620 #define AFMT_S32_BE      0x00002000
621 #define AFMT_S24_LE      0x00008000
622 #define AFMT_S24_BE      0x00010000
623 #define AFMT_S24_PACKED  0x00040000
624
625 /* other supported formats */
626 #define AFMT_FLOAT       0x00004000
627 #define AFMT_SPDIF_RAW   0x00020000
628
629 /* unsupported formats */
630 #define AFMT_AC3         0x00000400
631 #define AFMT_VORBIS      0x00000800
632
633 static snd_pcm_format_t snd_pcm_oss_format_from(int format)
634 {
635         switch (format) {
636         case AFMT_MU_LAW:       return SNDRV_PCM_FORMAT_MU_LAW;
637         case AFMT_A_LAW:        return SNDRV_PCM_FORMAT_A_LAW;
638         case AFMT_IMA_ADPCM:    return SNDRV_PCM_FORMAT_IMA_ADPCM;
639         case AFMT_U8:           return SNDRV_PCM_FORMAT_U8;
640         case AFMT_S16_LE:       return SNDRV_PCM_FORMAT_S16_LE;
641         case AFMT_S16_BE:       return SNDRV_PCM_FORMAT_S16_BE;
642         case AFMT_S8:           return SNDRV_PCM_FORMAT_S8;
643         case AFMT_U16_LE:       return SNDRV_PCM_FORMAT_U16_LE;
644         case AFMT_U16_BE:       return SNDRV_PCM_FORMAT_U16_BE;
645         case AFMT_MPEG:         return SNDRV_PCM_FORMAT_MPEG;
646         case AFMT_S32_LE:       return SNDRV_PCM_FORMAT_S32_LE;
647         case AFMT_S32_BE:       return SNDRV_PCM_FORMAT_S32_BE;
648         case AFMT_S24_LE:       return SNDRV_PCM_FORMAT_S24_LE;
649         case AFMT_S24_BE:       return SNDRV_PCM_FORMAT_S24_BE;
650         case AFMT_S24_PACKED:   return SNDRV_PCM_FORMAT_S24_3LE;
651         case AFMT_FLOAT:        return SNDRV_PCM_FORMAT_FLOAT;
652         case AFMT_SPDIF_RAW:    return SNDRV_PCM_FORMAT_IEC958_SUBFRAME;
653         default:                return SNDRV_PCM_FORMAT_U8;
654         }
655 }
656
657 static int snd_pcm_oss_format_to(snd_pcm_format_t format)
658 {
659         switch (format) {
660         case SNDRV_PCM_FORMAT_MU_LAW:   return AFMT_MU_LAW;
661         case SNDRV_PCM_FORMAT_A_LAW:    return AFMT_A_LAW;
662         case SNDRV_PCM_FORMAT_IMA_ADPCM:        return AFMT_IMA_ADPCM;
663         case SNDRV_PCM_FORMAT_U8:               return AFMT_U8;
664         case SNDRV_PCM_FORMAT_S16_LE:   return AFMT_S16_LE;
665         case SNDRV_PCM_FORMAT_S16_BE:   return AFMT_S16_BE;
666         case SNDRV_PCM_FORMAT_S8:               return AFMT_S8;
667         case SNDRV_PCM_FORMAT_U16_LE:   return AFMT_U16_LE;
668         case SNDRV_PCM_FORMAT_U16_BE:   return AFMT_U16_BE;
669         case SNDRV_PCM_FORMAT_MPEG:             return AFMT_MPEG;
670         case SNDRV_PCM_FORMAT_S32_LE:   return AFMT_S32_LE;
671         case SNDRV_PCM_FORMAT_S32_BE:   return AFMT_S32_BE;
672         case SNDRV_PCM_FORMAT_S24_LE:   return AFMT_S24_LE;
673         case SNDRV_PCM_FORMAT_S24_BE:   return AFMT_S24_BE;
674         case SNDRV_PCM_FORMAT_S24_3LE:  return AFMT_S24_PACKED;
675         case SNDRV_PCM_FORMAT_FLOAT:    return AFMT_FLOAT;
676         case SNDRV_PCM_FORMAT_IEC958_SUBFRAME: return AFMT_SPDIF_RAW;
677         default:                        return -EINVAL;
678         }
679 }
680
681 static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, 
682                                    struct snd_pcm_hw_params *oss_params,
683                                    struct snd_pcm_hw_params *slave_params)
684 {
685         ssize_t s;
686         ssize_t oss_buffer_size;
687         ssize_t oss_period_size, oss_periods;
688         ssize_t min_period_size, max_period_size;
689         struct snd_pcm_runtime *runtime = substream->runtime;
690         size_t oss_frame_size;
691
692         oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) *
693                          params_channels(oss_params) / 8;
694
695         oss_buffer_size = snd_pcm_hw_param_value_max(slave_params,
696                                                      SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
697                                                      NULL);
698         if (oss_buffer_size <= 0)
699                 return -EINVAL;
700         oss_buffer_size = snd_pcm_plug_client_size(substream,
701                                                    oss_buffer_size * oss_frame_size);
702         if (oss_buffer_size <= 0)
703                 return -EINVAL;
704         oss_buffer_size = rounddown_pow_of_two(oss_buffer_size);
705         if (atomic_read(&substream->mmap_count)) {
706                 if (oss_buffer_size > runtime->oss.mmap_bytes)
707                         oss_buffer_size = runtime->oss.mmap_bytes;
708         }
709
710         if (substream->oss.setup.period_size > 16)
711                 oss_period_size = substream->oss.setup.period_size;
712         else if (runtime->oss.fragshift) {
713                 oss_period_size = 1 << runtime->oss.fragshift;
714                 if (oss_period_size > oss_buffer_size / 2)
715                         oss_period_size = oss_buffer_size / 2;
716         } else {
717                 int sd;
718                 size_t bytes_per_sec = params_rate(oss_params) * snd_pcm_format_physical_width(params_format(oss_params)) * params_channels(oss_params) / 8;
719
720                 oss_period_size = oss_buffer_size;
721                 do {
722                         oss_period_size /= 2;
723                 } while (oss_period_size > bytes_per_sec);
724                 if (runtime->oss.subdivision == 0) {
725                         sd = 4;
726                         if (oss_period_size / sd > 4096)
727                                 sd *= 2;
728                         if (oss_period_size / sd < 4096)
729                                 sd = 1;
730                 } else
731                         sd = runtime->oss.subdivision;
732                 oss_period_size /= sd;
733                 if (oss_period_size < 16)
734                         oss_period_size = 16;
735         }
736
737         min_period_size = snd_pcm_plug_client_size(substream,
738                                                    snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
739         if (min_period_size > 0) {
740                 min_period_size *= oss_frame_size;
741                 min_period_size = roundup_pow_of_two(min_period_size);
742                 if (oss_period_size < min_period_size)
743                         oss_period_size = min_period_size;
744         }
745
746         max_period_size = snd_pcm_plug_client_size(substream,
747                                                    snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
748         if (max_period_size > 0) {
749                 max_period_size *= oss_frame_size;
750                 max_period_size = rounddown_pow_of_two(max_period_size);
751                 if (oss_period_size > max_period_size)
752                         oss_period_size = max_period_size;
753         }
754
755         oss_periods = oss_buffer_size / oss_period_size;
756
757         if (substream->oss.setup.periods > 1)
758                 oss_periods = substream->oss.setup.periods;
759
760         s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
761         if (s > 0 && runtime->oss.maxfrags && s > runtime->oss.maxfrags)
762                 s = runtime->oss.maxfrags;
763         if (oss_periods > s)
764                 oss_periods = s;
765
766         s = snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
767         if (s < 2)
768                 s = 2;
769         if (oss_periods < s)
770                 oss_periods = s;
771
772         while (oss_period_size * oss_periods > oss_buffer_size)
773                 oss_period_size /= 2;
774
775         if (oss_period_size < 16)
776                 return -EINVAL;
777
778         /* don't allocate too large period; 1MB period must be enough */
779         if (oss_period_size > 1024 * 1024)
780                 return -ENOMEM;
781
782         runtime->oss.period_bytes = oss_period_size;
783         runtime->oss.period_frames = 1;
784         runtime->oss.periods = oss_periods;
785         return 0;
786 }
787
788 static int choose_rate(struct snd_pcm_substream *substream,
789                        struct snd_pcm_hw_params *params, unsigned int best_rate)
790 {
791         const struct snd_interval *it;
792         struct snd_pcm_hw_params *save;
793         unsigned int rate, prev;
794
795         save = kmalloc(sizeof(*save), GFP_KERNEL);
796         if (save == NULL)
797                 return -ENOMEM;
798         *save = *params;
799         it = hw_param_interval_c(save, SNDRV_PCM_HW_PARAM_RATE);
800
801         /* try multiples of the best rate */
802         rate = best_rate;
803         for (;;) {
804                 if (it->max < rate || (it->max == rate && it->openmax))
805                         break;
806                 if (it->min < rate || (it->min == rate && !it->openmin)) {
807                         int ret;
808                         ret = snd_pcm_hw_param_set(substream, params,
809                                                    SNDRV_PCM_HW_PARAM_RATE,
810                                                    rate, 0);
811                         if (ret == (int)rate) {
812                                 kfree(save);
813                                 return rate;
814                         }
815                         *params = *save;
816                 }
817                 prev = rate;
818                 rate += best_rate;
819                 if (rate <= prev)
820                         break;
821         }
822
823         /* not found, use the nearest rate */
824         kfree(save);
825         return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
826 }
827
828 /* parameter locking: returns immediately if tried during streaming */
829 static int lock_params(struct snd_pcm_runtime *runtime)
830 {
831         if (mutex_lock_interruptible(&runtime->oss.params_lock))
832                 return -ERESTARTSYS;
833         if (atomic_read(&runtime->oss.rw_ref)) {
834                 mutex_unlock(&runtime->oss.params_lock);
835                 return -EBUSY;
836         }
837         return 0;
838 }
839
840 static void unlock_params(struct snd_pcm_runtime *runtime)
841 {
842         mutex_unlock(&runtime->oss.params_lock);
843 }
844
845 static void snd_pcm_oss_release_buffers(struct snd_pcm_substream *substream)
846 {
847         struct snd_pcm_runtime *runtime = substream->runtime;
848
849         kvfree(runtime->oss.buffer);
850         runtime->oss.buffer = NULL;
851 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
852         snd_pcm_oss_plugin_clear(substream);
853 #endif
854 }
855
856 /* call with params_lock held */
857 static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
858 {
859         struct snd_pcm_runtime *runtime = substream->runtime;
860         struct snd_pcm_hw_params *params, *sparams;
861         struct snd_pcm_sw_params *sw_params;
862         ssize_t oss_buffer_size, oss_period_size;
863         size_t oss_frame_size;
864         int err;
865         int direct;
866         snd_pcm_format_t format, sformat;
867         int n;
868         const struct snd_mask *sformat_mask;
869         struct snd_mask mask;
870
871         if (!runtime->oss.params)
872                 return 0;
873         sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
874         params = kmalloc(sizeof(*params), GFP_KERNEL);
875         sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
876         if (!sw_params || !params || !sparams) {
877                 err = -ENOMEM;
878                 goto failure;
879         }
880
881         if (atomic_read(&substream->mmap_count))
882                 direct = 1;
883         else
884                 direct = substream->oss.setup.direct;
885
886         _snd_pcm_hw_params_any(sparams);
887         _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
888         _snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
889         snd_mask_none(&mask);
890         if (atomic_read(&substream->mmap_count))
891                 snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
892         else {
893                 snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED);
894                 if (!direct)
895                         snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
896         }
897         err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
898         if (err < 0) {
899                 pcm_dbg(substream->pcm, "No usable accesses\n");
900                 err = -EINVAL;
901                 goto failure;
902         }
903
904         err = choose_rate(substream, sparams, runtime->oss.rate);
905         if (err < 0)
906                 goto failure;
907         err = snd_pcm_hw_param_near(substream, sparams,
908                                     SNDRV_PCM_HW_PARAM_CHANNELS,
909                                     runtime->oss.channels, NULL);
910         if (err < 0)
911                 goto failure;
912
913         format = snd_pcm_oss_format_from(runtime->oss.format);
914
915         sformat_mask = hw_param_mask_c(sparams, SNDRV_PCM_HW_PARAM_FORMAT);
916         if (direct)
917                 sformat = format;
918         else
919                 sformat = snd_pcm_plug_slave_format(format, sformat_mask);
920
921         if ((__force int)sformat < 0 ||
922             !snd_mask_test_format(sformat_mask, sformat)) {
923                 pcm_for_each_format(sformat) {
924                         if (snd_mask_test_format(sformat_mask, sformat) &&
925                             snd_pcm_oss_format_to(sformat) >= 0)
926                                 goto format_found;
927                 }
928                 pcm_dbg(substream->pcm, "Cannot find a format!!!\n");
929                 err = -EINVAL;
930                 goto failure;
931         }
932  format_found:
933         err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, (__force int)sformat, 0);
934         if (err < 0)
935                 goto failure;
936
937         if (direct) {
938                 memcpy(params, sparams, sizeof(*params));
939         } else {
940                 _snd_pcm_hw_params_any(params);
941                 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
942                                       (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
943                 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
944                                       (__force int)snd_pcm_oss_format_from(runtime->oss.format), 0);
945                 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
946                                       runtime->oss.channels, 0);
947                 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
948                                       runtime->oss.rate, 0);
949                 pdprintf("client: access = %i, format = %i, channels = %i, rate = %i\n",
950                          params_access(params), params_format(params),
951                          params_channels(params), params_rate(params));
952         }
953         pdprintf("slave: access = %i, format = %i, channels = %i, rate = %i\n",
954                  params_access(sparams), params_format(sparams),
955                  params_channels(sparams), params_rate(sparams));
956
957         oss_frame_size = snd_pcm_format_physical_width(params_format(params)) *
958                          params_channels(params) / 8;
959
960         err = snd_pcm_oss_period_size(substream, params, sparams);
961         if (err < 0)
962                 goto failure;
963
964         n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);
965         err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL);
966         if (err < 0)
967                 goto failure;
968
969         err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,
970                                      runtime->oss.periods, NULL);
971         if (err < 0)
972                 goto failure;
973
974         snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
975
976         err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams);
977         if (err < 0) {
978                 pcm_dbg(substream->pcm, "HW_PARAMS failed: %i\n", err);
979                 goto failure;
980         }
981
982 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
983         snd_pcm_oss_plugin_clear(substream);
984         if (!direct) {
985                 /* add necessary plugins */
986                 err = snd_pcm_plug_format_plugins(substream, params, sparams);
987                 if (err < 0) {
988                         pcm_dbg(substream->pcm,
989                                 "snd_pcm_plug_format_plugins failed: %i\n", err);
990                         goto failure;
991                 }
992                 if (runtime->oss.plugin_first) {
993                         struct snd_pcm_plugin *plugin;
994                         err = snd_pcm_plugin_build_io(substream, sparams, &plugin);
995                         if (err < 0) {
996                                 pcm_dbg(substream->pcm,
997                                         "snd_pcm_plugin_build_io failed: %i\n", err);
998                                 goto failure;
999                         }
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->state == SNDRV_PCM_STATE_XRUN ||
1241                     runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
1242 #ifdef OSS_DEBUG
1243                         pcm_dbg(substream->pcm,
1244                                 "pcm_oss: write: recovering from %s\n",
1245                                 runtime->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->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->state == SNDRV_PCM_STATE_XRUN ||
1273                     runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
1274 #ifdef OSS_DEBUG
1275                         pcm_dbg(substream->pcm,
1276                                 "pcm_oss: read: recovering from %s\n",
1277                                 runtime->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->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->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->state == SNDRV_PCM_STATE_XRUN ||
1316                     runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
1317 #ifdef OSS_DEBUG
1318                         pcm_dbg(substream->pcm,
1319                                 "pcm_oss: writev: recovering from %s\n",
1320                                 runtime->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->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->state == SNDRV_PCM_STATE_XRUN ||
1345                     runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
1346 #ifdef OSS_DEBUG
1347                         pcm_dbg(substream->pcm,
1348                                 "pcm_oss: readv: recovering from %s\n",
1349                                 runtime->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->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->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->state != SNDRV_PCM_STATE_DRAINING &&
2858                     (runtime->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->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         vm_flags_set(area, 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)
This page took 0.227215 seconds and 4 git commands to generate.