]> git.karo-electronics.de Git - linux-beck.git/blob - sound/core/oss/pcm_oss.c
[ALSA] Remove PCM xfer_align sw params
[linux-beck.git] / sound / core / oss / pcm_oss.c
1 /*
2  *  Digital Audio (PCM) abstract layer / OSS compatible
3  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4  *
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19  *
20  */
21
22 #if 0
23 #define PLUGIN_DEBUG
24 #endif
25 #if 0
26 #define OSS_DEBUG
27 #endif
28
29 #include <sound/driver.h>
30 #include <linux/init.h>
31 #include <linux/slab.h>
32 #include <linux/time.h>
33 #include <linux/vmalloc.h>
34 #include <linux/moduleparam.h>
35 #include <linux/string.h>
36 #include <sound/core.h>
37 #include <sound/minors.h>
38 #include <sound/pcm.h>
39 #include <sound/pcm_params.h>
40 #include "pcm_plugin.h"
41 #include <sound/info.h>
42 #include <linux/soundcard.h>
43 #include <sound/initval.h>
44
45 #define OSS_ALSAEMULVER         _SIOR ('M', 249, int)
46
47 static int dsp_map[SNDRV_CARDS];
48 static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
49 static int nonblock_open = 1;
50
51 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");
52 MODULE_DESCRIPTION("PCM OSS emulation for ALSA.");
53 MODULE_LICENSE("GPL");
54 module_param_array(dsp_map, int, NULL, 0444);
55 MODULE_PARM_DESC(dsp_map, "PCM device number assigned to 1st OSS device.");
56 module_param_array(adsp_map, int, NULL, 0444);
57 MODULE_PARM_DESC(adsp_map, "PCM device number assigned to 2nd OSS device.");
58 module_param(nonblock_open, bool, 0644);
59 MODULE_PARM_DESC(nonblock_open, "Don't block opening busy PCM devices.");
60 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM);
61 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM1);
62
63 extern int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg);
64 static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file);
65 static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file);
66 static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file);
67
68 static inline mm_segment_t snd_enter_user(void)
69 {
70         mm_segment_t fs = get_fs();
71         set_fs(get_ds());
72         return fs;
73 }
74
75 static inline void snd_leave_user(mm_segment_t fs)
76 {
77         set_fs(fs);
78 }
79
80 /*
81  * helper functions to process hw_params
82  */
83 static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin)
84 {
85         int changed = 0;
86         if (i->min < min) {
87                 i->min = min;
88                 i->openmin = openmin;
89                 changed = 1;
90         } else if (i->min == min && !i->openmin && openmin) {
91                 i->openmin = 1;
92                 changed = 1;
93         }
94         if (i->integer) {
95                 if (i->openmin) {
96                         i->min++;
97                         i->openmin = 0;
98                 }
99         }
100         if (snd_interval_checkempty(i)) {
101                 snd_interval_none(i);
102                 return -EINVAL;
103         }
104         return changed;
105 }
106
107 static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax)
108 {
109         int changed = 0;
110         if (i->max > max) {
111                 i->max = max;
112                 i->openmax = openmax;
113                 changed = 1;
114         } else if (i->max == max && !i->openmax && openmax) {
115                 i->openmax = 1;
116                 changed = 1;
117         }
118         if (i->integer) {
119                 if (i->openmax) {
120                         i->max--;
121                         i->openmax = 0;
122                 }
123         }
124         if (snd_interval_checkempty(i)) {
125                 snd_interval_none(i);
126                 return -EINVAL;
127         }
128         return changed;
129 }
130
131 static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
132 {
133         struct snd_interval t;
134         t.empty = 0;
135         t.min = t.max = val;
136         t.openmin = t.openmax = 0;
137         t.integer = 1;
138         return snd_interval_refine(i, &t);
139 }
140
141 /**
142  * snd_pcm_hw_param_value_min
143  * @params: the hw_params instance
144  * @var: parameter to retrieve
145  * @dir: pointer to the direction (-1,0,1) or NULL
146  *
147  * Return the minimum value for field PAR.
148  */
149 static unsigned int
150 snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
151                            snd_pcm_hw_param_t var, int *dir)
152 {
153         if (hw_is_mask(var)) {
154                 if (dir)
155                         *dir = 0;
156                 return snd_mask_min(hw_param_mask_c(params, var));
157         }
158         if (hw_is_interval(var)) {
159                 const struct snd_interval *i = hw_param_interval_c(params, var);
160                 if (dir)
161                         *dir = i->openmin;
162                 return snd_interval_min(i);
163         }
164         return -EINVAL;
165 }
166
167 /**
168  * snd_pcm_hw_param_value_max
169  * @params: the hw_params instance
170  * @var: parameter to retrieve
171  * @dir: pointer to the direction (-1,0,1) or NULL
172  *
173  * Return the maximum value for field PAR.
174  */
175 static unsigned int
176 snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
177                            snd_pcm_hw_param_t var, int *dir)
178 {
179         if (hw_is_mask(var)) {
180                 if (dir)
181                         *dir = 0;
182                 return snd_mask_max(hw_param_mask_c(params, var));
183         }
184         if (hw_is_interval(var)) {
185                 const struct snd_interval *i = hw_param_interval_c(params, var);
186                 if (dir)
187                         *dir = - (int) i->openmax;
188                 return snd_interval_max(i);
189         }
190         return -EINVAL;
191 }
192
193 static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params,
194                                   snd_pcm_hw_param_t var,
195                                   const struct snd_mask *val)
196 {
197         int changed;
198         changed = snd_mask_refine(hw_param_mask(params, var), val);
199         if (changed) {
200                 params->cmask |= 1 << var;
201                 params->rmask |= 1 << var;
202         }
203         return changed;
204 }
205
206 static int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm,
207                                  struct snd_pcm_hw_params *params,
208                                  snd_pcm_hw_param_t var,
209                                  const struct snd_mask *val)
210 {
211         int changed = _snd_pcm_hw_param_mask(params, var, val);
212         if (changed < 0)
213                 return changed;
214         if (params->rmask) {
215                 int err = snd_pcm_hw_refine(pcm, params);
216                 if (err < 0)
217                         return err;
218         }
219         return 0;
220 }
221
222 static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
223                                  snd_pcm_hw_param_t var, unsigned int val,
224                                  int dir)
225 {
226         int changed;
227         int open = 0;
228         if (dir) {
229                 if (dir > 0) {
230                         open = 1;
231                 } else if (dir < 0) {
232                         if (val > 0) {
233                                 open = 1;
234                                 val--;
235                         }
236                 }
237         }
238         if (hw_is_mask(var))
239                 changed = snd_mask_refine_min(hw_param_mask(params, var),
240                                               val + !!open);
241         else if (hw_is_interval(var))
242                 changed = snd_interval_refine_min(hw_param_interval(params, var),
243                                                   val, open);
244         else
245                 return -EINVAL;
246         if (changed) {
247                 params->cmask |= 1 << var;
248                 params->rmask |= 1 << var;
249         }
250         return changed;
251 }
252
253 /**
254  * snd_pcm_hw_param_min
255  * @pcm: PCM instance
256  * @params: the hw_params instance
257  * @var: parameter to retrieve
258  * @val: minimal value
259  * @dir: pointer to the direction (-1,0,1) or NULL
260  *
261  * Inside configuration space defined by PARAMS remove from PAR all 
262  * values < VAL. Reduce configuration space accordingly.
263  * Return new minimum or -EINVAL if the configuration space is empty
264  */
265 static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm,
266                                 struct snd_pcm_hw_params *params,
267                                 snd_pcm_hw_param_t var, unsigned int val,
268                                 int *dir)
269 {
270         int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
271         if (changed < 0)
272                 return changed;
273         if (params->rmask) {
274                 int err = snd_pcm_hw_refine(pcm, params);
275                 if (err < 0)
276                         return err;
277         }
278         return snd_pcm_hw_param_value_min(params, var, dir);
279 }
280
281 static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
282                                  snd_pcm_hw_param_t var, unsigned int val,
283                                  int dir)
284 {
285         int changed;
286         int open = 0;
287         if (dir) {
288                 if (dir < 0) {
289                         open = 1;
290                 } else if (dir > 0) {
291                         open = 1;
292                         val++;
293                 }
294         }
295         if (hw_is_mask(var)) {
296                 if (val == 0 && open) {
297                         snd_mask_none(hw_param_mask(params, var));
298                         changed = -EINVAL;
299                 } else
300                         changed = snd_mask_refine_max(hw_param_mask(params, var),
301                                                       val - !!open);
302         } else if (hw_is_interval(var))
303                 changed = snd_interval_refine_max(hw_param_interval(params, var),
304                                                   val, open);
305         else
306                 return -EINVAL;
307         if (changed) {
308                 params->cmask |= 1 << var;
309                 params->rmask |= 1 << var;
310         }
311         return changed;
312 }
313
314 /**
315  * snd_pcm_hw_param_max
316  * @pcm: PCM instance
317  * @params: the hw_params instance
318  * @var: parameter to retrieve
319  * @val: maximal value
320  * @dir: pointer to the direction (-1,0,1) or NULL
321  *
322  * Inside configuration space defined by PARAMS remove from PAR all 
323  *  values >= VAL + 1. Reduce configuration space accordingly.
324  *  Return new maximum or -EINVAL if the configuration space is empty
325  */
326 static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm,
327                                 struct snd_pcm_hw_params *params,
328                                 snd_pcm_hw_param_t var, unsigned int val,
329                                 int *dir)
330 {
331         int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
332         if (changed < 0)
333                 return changed;
334         if (params->rmask) {
335                 int err = snd_pcm_hw_refine(pcm, params);
336                 if (err < 0)
337                         return err;
338         }
339         return snd_pcm_hw_param_value_max(params, var, dir);
340 }
341
342 static int boundary_sub(int a, int adir,
343                         int b, int bdir,
344                         int *c, int *cdir)
345 {
346         adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
347         bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
348         *c = a - b;
349         *cdir = adir - bdir;
350         if (*cdir == -2) {
351                 (*c)--;
352         } else if (*cdir == 2) {
353                 (*c)++;
354         }
355         return 0;
356 }
357
358 static int boundary_lt(unsigned int a, int adir,
359                        unsigned int b, int bdir)
360 {
361         if (adir < 0) {
362                 a--;
363                 adir = 1;
364         } else if (adir > 0)
365                 adir = 1;
366         if (bdir < 0) {
367                 b--;
368                 bdir = 1;
369         } else if (bdir > 0)
370                 bdir = 1;
371         return a < b || (a == b && adir < bdir);
372 }
373
374 /* Return 1 if min is nearer to best than max */
375 static int boundary_nearer(int min, int mindir,
376                            int best, int bestdir,
377                            int max, int maxdir)
378 {
379         int dmin, dmindir;
380         int dmax, dmaxdir;
381         boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
382         boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
383         return boundary_lt(dmin, dmindir, dmax, dmaxdir);
384 }
385
386 /**
387  * snd_pcm_hw_param_near
388  * @pcm: PCM instance
389  * @params: the hw_params instance
390  * @var: parameter to retrieve
391  * @best: value to set
392  * @dir: pointer to the direction (-1,0,1) or NULL
393  *
394  * Inside configuration space defined by PARAMS set PAR to the available value
395  * nearest to VAL. Reduce configuration space accordingly.
396  * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
397  * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
398  * Return the value found.
399   */
400 static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
401                                  struct snd_pcm_hw_params *params,
402                                  snd_pcm_hw_param_t var, unsigned int best,
403                                  int *dir)
404 {
405         struct snd_pcm_hw_params *save = NULL;
406         int v;
407         unsigned int saved_min;
408         int last = 0;
409         int min, max;
410         int mindir, maxdir;
411         int valdir = dir ? *dir : 0;
412         /* FIXME */
413         if (best > INT_MAX)
414                 best = INT_MAX;
415         min = max = best;
416         mindir = maxdir = valdir;
417         if (maxdir > 0)
418                 maxdir = 0;
419         else if (maxdir == 0)
420                 maxdir = -1;
421         else {
422                 maxdir = 1;
423                 max--;
424         }
425         save = kmalloc(sizeof(*save), GFP_KERNEL);
426         if (save == NULL)
427                 return -ENOMEM;
428         *save = *params;
429         saved_min = min;
430         min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
431         if (min >= 0) {
432                 struct snd_pcm_hw_params *params1;
433                 if (max < 0)
434                         goto _end;
435                 if ((unsigned int)min == saved_min && mindir == valdir)
436                         goto _end;
437                 params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
438                 if (params1 == NULL) {
439                         kfree(save);
440                         return -ENOMEM;
441                 }
442                 *params1 = *save;
443                 max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
444                 if (max < 0) {
445                         kfree(params1);
446                         goto _end;
447                 }
448                 if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
449                         *params = *params1;
450                         last = 1;
451                 }
452                 kfree(params1);
453         } else {
454                 *params = *save;
455                 max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
456                 snd_assert(max >= 0, return -EINVAL);
457                 last = 1;
458         }
459  _end:
460         kfree(save);
461         if (last)
462                 v = snd_pcm_hw_param_last(pcm, params, var, dir);
463         else
464                 v = snd_pcm_hw_param_first(pcm, params, var, dir);
465         snd_assert(v >= 0, return -EINVAL);
466         return v;
467 }
468
469 static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
470                                  snd_pcm_hw_param_t var, unsigned int val,
471                                  int dir)
472 {
473         int changed;
474         if (hw_is_mask(var)) {
475                 struct snd_mask *m = hw_param_mask(params, var);
476                 if (val == 0 && dir < 0) {
477                         changed = -EINVAL;
478                         snd_mask_none(m);
479                 } else {
480                         if (dir > 0)
481                                 val++;
482                         else if (dir < 0)
483                                 val--;
484                         changed = snd_mask_refine_set(hw_param_mask(params, var), val);
485                 }
486         } else if (hw_is_interval(var)) {
487                 struct snd_interval *i = hw_param_interval(params, var);
488                 if (val == 0 && dir < 0) {
489                         changed = -EINVAL;
490                         snd_interval_none(i);
491                 } else if (dir == 0)
492                         changed = snd_interval_refine_set(i, val);
493                 else {
494                         struct snd_interval t;
495                         t.openmin = 1;
496                         t.openmax = 1;
497                         t.empty = 0;
498                         t.integer = 0;
499                         if (dir < 0) {
500                                 t.min = val - 1;
501                                 t.max = val;
502                         } else {
503                                 t.min = val;
504                                 t.max = val+1;
505                         }
506                         changed = snd_interval_refine(i, &t);
507                 }
508         } else
509                 return -EINVAL;
510         if (changed) {
511                 params->cmask |= 1 << var;
512                 params->rmask |= 1 << var;
513         }
514         return changed;
515 }
516
517 /**
518  * snd_pcm_hw_param_set
519  * @pcm: PCM instance
520  * @params: the hw_params instance
521  * @var: parameter to retrieve
522  * @val: value to set
523  * @dir: pointer to the direction (-1,0,1) or NULL
524  *
525  * Inside configuration space defined by PARAMS remove from PAR all 
526  * values != VAL. Reduce configuration space accordingly.
527  *  Return VAL or -EINVAL if the configuration space is empty
528  */
529 static int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,
530                                 struct snd_pcm_hw_params *params,
531                                 snd_pcm_hw_param_t var, unsigned int val,
532                                 int dir)
533 {
534         int changed = _snd_pcm_hw_param_set(params, var, val, dir);
535         if (changed < 0)
536                 return changed;
537         if (params->rmask) {
538                 int err = snd_pcm_hw_refine(pcm, params);
539                 if (err < 0)
540                         return err;
541         }
542         return snd_pcm_hw_param_value(params, var, NULL);
543 }
544
545 static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
546                                         snd_pcm_hw_param_t var)
547 {
548         int changed;
549         changed = snd_interval_setinteger(hw_param_interval(params, var));
550         if (changed) {
551                 params->cmask |= 1 << var;
552                 params->rmask |= 1 << var;
553         }
554         return changed;
555 }
556         
557 /*
558  * plugin
559  */
560
561 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
562 static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream)
563 {
564         struct snd_pcm_runtime *runtime = substream->runtime;
565         struct snd_pcm_plugin *plugin, *next;
566         
567         plugin = runtime->oss.plugin_first;
568         while (plugin) {
569                 next = plugin->next;
570                 snd_pcm_plugin_free(plugin);
571                 plugin = next;
572         }
573         runtime->oss.plugin_first = runtime->oss.plugin_last = NULL;
574         return 0;
575 }
576
577 static int snd_pcm_plugin_insert(struct snd_pcm_plugin *plugin)
578 {
579         struct snd_pcm_runtime *runtime = plugin->plug->runtime;
580         plugin->next = runtime->oss.plugin_first;
581         plugin->prev = NULL;
582         if (runtime->oss.plugin_first) {
583                 runtime->oss.plugin_first->prev = plugin;
584                 runtime->oss.plugin_first = plugin;
585         } else {
586                 runtime->oss.plugin_last =
587                 runtime->oss.plugin_first = plugin;
588         }
589         return 0;
590 }
591
592 int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin)
593 {
594         struct snd_pcm_runtime *runtime = plugin->plug->runtime;
595         plugin->next = NULL;
596         plugin->prev = runtime->oss.plugin_last;
597         if (runtime->oss.plugin_last) {
598                 runtime->oss.plugin_last->next = plugin;
599                 runtime->oss.plugin_last = plugin;
600         } else {
601                 runtime->oss.plugin_last =
602                 runtime->oss.plugin_first = plugin;
603         }
604         return 0;
605 }
606 #endif /* CONFIG_SND_PCM_OSS_PLUGINS */
607
608 static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames)
609 {
610         struct snd_pcm_runtime *runtime = substream->runtime;
611         long buffer_size = snd_pcm_lib_buffer_bytes(substream);
612         long bytes = frames_to_bytes(runtime, frames);
613         if (buffer_size == runtime->oss.buffer_bytes)
614                 return bytes;
615 #if BITS_PER_LONG >= 64
616         return runtime->oss.buffer_bytes * bytes / buffer_size;
617 #else
618         {
619                 u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes;
620                 u32 rem;
621                 div64_32(&bsize, buffer_size, &rem);
622                 return (long)bsize;
623         }
624 #endif
625 }
626
627 static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes)
628 {
629         struct snd_pcm_runtime *runtime = substream->runtime;
630         long buffer_size = snd_pcm_lib_buffer_bytes(substream);
631         if (buffer_size == runtime->oss.buffer_bytes)
632                 return bytes_to_frames(runtime, bytes);
633         return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
634 }
635
636 /* define extended formats in the recent OSS versions (if any) */
637 /* linear formats */
638 #define AFMT_S32_LE      0x00001000
639 #define AFMT_S32_BE      0x00002000
640 #define AFMT_S24_LE      0x00008000
641 #define AFMT_S24_BE      0x00010000
642 #define AFMT_S24_PACKED  0x00040000
643
644 /* other supported formats */
645 #define AFMT_FLOAT       0x00004000
646 #define AFMT_SPDIF_RAW   0x00020000
647
648 /* unsupported formats */
649 #define AFMT_AC3         0x00000400
650 #define AFMT_VORBIS      0x00000800
651
652 static int snd_pcm_oss_format_from(int format)
653 {
654         switch (format) {
655         case AFMT_MU_LAW:       return SNDRV_PCM_FORMAT_MU_LAW;
656         case AFMT_A_LAW:        return SNDRV_PCM_FORMAT_A_LAW;
657         case AFMT_IMA_ADPCM:    return SNDRV_PCM_FORMAT_IMA_ADPCM;
658         case AFMT_U8:           return SNDRV_PCM_FORMAT_U8;
659         case AFMT_S16_LE:       return SNDRV_PCM_FORMAT_S16_LE;
660         case AFMT_S16_BE:       return SNDRV_PCM_FORMAT_S16_BE;
661         case AFMT_S8:           return SNDRV_PCM_FORMAT_S8;
662         case AFMT_U16_LE:       return SNDRV_PCM_FORMAT_U16_LE;
663         case AFMT_U16_BE:       return SNDRV_PCM_FORMAT_U16_BE;
664         case AFMT_MPEG:         return SNDRV_PCM_FORMAT_MPEG;
665         case AFMT_S32_LE:       return SNDRV_PCM_FORMAT_S32_LE;
666         case AFMT_S32_BE:       return SNDRV_PCM_FORMAT_S32_BE;
667         case AFMT_S24_LE:       return SNDRV_PCM_FORMAT_S24_LE;
668         case AFMT_S24_BE:       return SNDRV_PCM_FORMAT_S24_BE;
669         case AFMT_S24_PACKED:   return SNDRV_PCM_FORMAT_S24_3LE;
670         case AFMT_FLOAT:        return SNDRV_PCM_FORMAT_FLOAT;
671         case AFMT_SPDIF_RAW:    return SNDRV_PCM_FORMAT_IEC958_SUBFRAME;
672         default:                return SNDRV_PCM_FORMAT_U8;
673         }
674 }
675
676 static int snd_pcm_oss_format_to(int format)
677 {
678         switch (format) {
679         case SNDRV_PCM_FORMAT_MU_LAW:   return AFMT_MU_LAW;
680         case SNDRV_PCM_FORMAT_A_LAW:    return AFMT_A_LAW;
681         case SNDRV_PCM_FORMAT_IMA_ADPCM:        return AFMT_IMA_ADPCM;
682         case SNDRV_PCM_FORMAT_U8:               return AFMT_U8;
683         case SNDRV_PCM_FORMAT_S16_LE:   return AFMT_S16_LE;
684         case SNDRV_PCM_FORMAT_S16_BE:   return AFMT_S16_BE;
685         case SNDRV_PCM_FORMAT_S8:               return AFMT_S8;
686         case SNDRV_PCM_FORMAT_U16_LE:   return AFMT_U16_LE;
687         case SNDRV_PCM_FORMAT_U16_BE:   return AFMT_U16_BE;
688         case SNDRV_PCM_FORMAT_MPEG:             return AFMT_MPEG;
689         case SNDRV_PCM_FORMAT_S32_LE:   return AFMT_S32_LE;
690         case SNDRV_PCM_FORMAT_S32_BE:   return AFMT_S32_BE;
691         case SNDRV_PCM_FORMAT_S24_LE:   return AFMT_S24_LE;
692         case SNDRV_PCM_FORMAT_S24_BE:   return AFMT_S24_BE;
693         case SNDRV_PCM_FORMAT_S24_3LE:  return AFMT_S24_PACKED;
694         case SNDRV_PCM_FORMAT_FLOAT:    return AFMT_FLOAT;
695         case SNDRV_PCM_FORMAT_IEC958_SUBFRAME: return AFMT_SPDIF_RAW;
696         default:                        return -EINVAL;
697         }
698 }
699
700 static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, 
701                                    struct snd_pcm_hw_params *oss_params,
702                                    struct snd_pcm_hw_params *slave_params)
703 {
704         size_t s;
705         size_t oss_buffer_size, oss_period_size, oss_periods;
706         size_t min_period_size, max_period_size;
707         struct snd_pcm_runtime *runtime = substream->runtime;
708         size_t oss_frame_size;
709
710         oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) *
711                          params_channels(oss_params) / 8;
712
713         oss_buffer_size = snd_pcm_plug_client_size(substream,
714                                                    snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
715         oss_buffer_size = 1 << ld2(oss_buffer_size);
716         if (atomic_read(&substream->mmap_count)) {
717                 if (oss_buffer_size > runtime->oss.mmap_bytes)
718                         oss_buffer_size = runtime->oss.mmap_bytes;
719         }
720
721         if (substream->oss.setup.period_size > 16)
722                 oss_period_size = substream->oss.setup.period_size;
723         else if (runtime->oss.fragshift) {
724                 oss_period_size = 1 << runtime->oss.fragshift;
725                 if (oss_period_size > oss_buffer_size / 2)
726                         oss_period_size = oss_buffer_size / 2;
727         } else {
728                 int sd;
729                 size_t bytes_per_sec = params_rate(oss_params) * snd_pcm_format_physical_width(params_format(oss_params)) * params_channels(oss_params) / 8;
730
731                 oss_period_size = oss_buffer_size;
732                 do {
733                         oss_period_size /= 2;
734                 } while (oss_period_size > bytes_per_sec);
735                 if (runtime->oss.subdivision == 0) {
736                         sd = 4;
737                         if (oss_period_size / sd > 4096)
738                                 sd *= 2;
739                         if (oss_period_size / sd < 4096)
740                                 sd = 1;
741                 } else
742                         sd = runtime->oss.subdivision;
743                 oss_period_size /= sd;
744                 if (oss_period_size < 16)
745                         oss_period_size = 16;
746         }
747
748         min_period_size = snd_pcm_plug_client_size(substream,
749                                                    snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
750         min_period_size *= oss_frame_size;
751         min_period_size = 1 << (ld2(min_period_size - 1) + 1);
752         if (oss_period_size < min_period_size)
753                 oss_period_size = min_period_size;
754
755         max_period_size = snd_pcm_plug_client_size(substream,
756                                                    snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
757         max_period_size *= oss_frame_size;
758         max_period_size = 1 << ld2(max_period_size);
759         if (oss_period_size > max_period_size)
760                 oss_period_size = max_period_size;
761
762         oss_periods = oss_buffer_size / oss_period_size;
763
764         if (substream->oss.setup.periods > 1)
765                 oss_periods = substream->oss.setup.periods;
766
767         s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
768         if (runtime->oss.maxfrags && s > runtime->oss.maxfrags)
769                 s = runtime->oss.maxfrags;
770         if (oss_periods > s)
771                 oss_periods = s;
772
773         s = snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
774         if (s < 2)
775                 s = 2;
776         if (oss_periods < s)
777                 oss_periods = s;
778
779         while (oss_period_size * oss_periods > oss_buffer_size)
780                 oss_period_size /= 2;
781
782         snd_assert(oss_period_size >= 16, return -EINVAL);
783         runtime->oss.period_bytes = oss_period_size;
784         runtime->oss.period_frames = 1;
785         runtime->oss.periods = oss_periods;
786         return 0;
787 }
788
789 static int choose_rate(struct snd_pcm_substream *substream,
790                        struct snd_pcm_hw_params *params, unsigned int best_rate)
791 {
792         struct snd_interval *it;
793         struct snd_pcm_hw_params *save;
794         unsigned int rate, prev;
795
796         save = kmalloc(sizeof(*save), GFP_KERNEL);
797         if (save == NULL)
798                 return -ENOMEM;
799         *save = *params;
800         it = hw_param_interval(save, SNDRV_PCM_HW_PARAM_RATE);
801
802         /* try multiples of the best rate */
803         rate = best_rate;
804         for (;;) {
805                 if (it->max < rate || (it->max == rate && it->openmax))
806                         break;
807                 if (it->min < rate || (it->min == rate && !it->openmin)) {
808                         int ret;
809                         ret = snd_pcm_hw_param_set(substream, params,
810                                                    SNDRV_PCM_HW_PARAM_RATE,
811                                                    rate, 0);
812                         if (ret == (int)rate) {
813                                 kfree(save);
814                                 return rate;
815                         }
816                         *params = *save;
817                 }
818                 prev = rate;
819                 rate += best_rate;
820                 if (rate <= prev)
821                         break;
822         }
823
824         /* not found, use the nearest rate */
825         kfree(save);
826         return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
827 }
828
829 static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
830 {
831         struct snd_pcm_runtime *runtime = substream->runtime;
832         struct snd_pcm_hw_params *params, *sparams;
833         struct snd_pcm_sw_params *sw_params;
834         ssize_t oss_buffer_size, oss_period_size;
835         size_t oss_frame_size;
836         int err;
837         int direct;
838         int format, sformat, n;
839         struct snd_mask sformat_mask;
840         struct snd_mask mask;
841
842         if (mutex_lock_interruptible(&runtime->oss.params_lock))
843                 return -EINTR;
844         sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL);
845         params = kmalloc(sizeof(*params), GFP_KERNEL);
846         sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
847         if (!sw_params || !params || !sparams) {
848                 snd_printd("No memory\n");
849                 err = -ENOMEM;
850                 goto failure;
851         }
852
853         if (atomic_read(&substream->mmap_count))
854                 direct = 1;
855         else
856                 direct = substream->oss.setup.direct;
857
858         _snd_pcm_hw_params_any(sparams);
859         _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
860         _snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
861         snd_mask_none(&mask);
862         if (atomic_read(&substream->mmap_count))
863                 snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
864         else {
865                 snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
866                 if (!direct)
867                         snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
868         }
869         err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
870         if (err < 0) {
871                 snd_printd("No usable accesses\n");
872                 err = -EINVAL;
873                 goto failure;
874         }
875         choose_rate(substream, sparams, runtime->oss.rate);
876         snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, NULL);
877
878         format = snd_pcm_oss_format_from(runtime->oss.format);
879
880         sformat_mask = *hw_param_mask(sparams, SNDRV_PCM_HW_PARAM_FORMAT);
881         if (direct)
882                 sformat = format;
883         else
884                 sformat = snd_pcm_plug_slave_format(format, &sformat_mask);
885
886         if (sformat < 0 || !snd_mask_test(&sformat_mask, sformat)) {
887                 for (sformat = 0; sformat <= SNDRV_PCM_FORMAT_LAST; sformat++) {
888                         if (snd_mask_test(&sformat_mask, sformat) &&
889                             snd_pcm_oss_format_to(sformat) >= 0)
890                                 break;
891                 }
892                 if (sformat > SNDRV_PCM_FORMAT_LAST) {
893                         snd_printd("Cannot find a format!!!\n");
894                         err = -EINVAL;
895                         goto failure;
896                 }
897         }
898         err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);
899         snd_assert(err >= 0, goto failure);
900
901         if (direct) {
902                 memcpy(params, sparams, sizeof(*params));
903         } else {
904                 _snd_pcm_hw_params_any(params);
905                 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
906                                       SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
907                 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
908                                       snd_pcm_oss_format_from(runtime->oss.format), 0);
909                 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
910                                       runtime->oss.channels, 0);
911                 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
912                                       runtime->oss.rate, 0);
913                 pdprintf("client: access = %i, format = %i, channels = %i, rate = %i\n",
914                          params_access(params), params_format(params),
915                          params_channels(params), params_rate(params));
916         }
917         pdprintf("slave: access = %i, format = %i, channels = %i, rate = %i\n",
918                  params_access(sparams), params_format(sparams),
919                  params_channels(sparams), params_rate(sparams));
920
921         oss_frame_size = snd_pcm_format_physical_width(params_format(params)) *
922                          params_channels(params) / 8;
923
924 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
925         snd_pcm_oss_plugin_clear(substream);
926         if (!direct) {
927                 /* add necessary plugins */
928                 snd_pcm_oss_plugin_clear(substream);
929                 if ((err = snd_pcm_plug_format_plugins(substream,
930                                                        params, 
931                                                        sparams)) < 0) {
932                         snd_printd("snd_pcm_plug_format_plugins failed: %i\n", err);
933                         snd_pcm_oss_plugin_clear(substream);
934                         goto failure;
935                 }
936                 if (runtime->oss.plugin_first) {
937                         struct snd_pcm_plugin *plugin;
938                         if ((err = snd_pcm_plugin_build_io(substream, sparams, &plugin)) < 0) {
939                                 snd_printd("snd_pcm_plugin_build_io failed: %i\n", err);
940                                 snd_pcm_oss_plugin_clear(substream);
941                                 goto failure;
942                         }
943                         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
944                                 err = snd_pcm_plugin_append(plugin);
945                         } else {
946                                 err = snd_pcm_plugin_insert(plugin);
947                         }
948                         if (err < 0) {
949                                 snd_pcm_oss_plugin_clear(substream);
950                                 goto failure;
951                         }
952                 }
953         }
954 #endif
955
956         err = snd_pcm_oss_period_size(substream, params, sparams);
957         if (err < 0)
958                 goto failure;
959
960         n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);
961         err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL);
962         snd_assert(err >= 0, goto failure);
963
964         err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,
965                                      runtime->oss.periods, NULL);
966         snd_assert(err >= 0, goto failure);
967
968         snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
969
970         if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams)) < 0) {
971                 snd_printd("HW_PARAMS failed: %i\n", err);
972                 goto failure;
973         }
974
975         memset(sw_params, 0, sizeof(*sw_params));
976         if (runtime->oss.trigger) {
977                 sw_params->start_threshold = 1;
978         } else {
979                 sw_params->start_threshold = runtime->boundary;
980         }
981         if (atomic_read(&substream->mmap_count) ||
982             substream->stream == SNDRV_PCM_STREAM_CAPTURE)
983                 sw_params->stop_threshold = runtime->boundary;
984         else
985                 sw_params->stop_threshold = runtime->buffer_size;
986         sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
987         sw_params->period_step = 1;
988         sw_params->sleep_min = 0;
989         sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
990                 1 : runtime->period_size;
991         if (atomic_read(&substream->mmap_count) ||
992             substream->oss.setup.nosilence) {
993                 sw_params->silence_threshold = 0;
994                 sw_params->silence_size = 0;
995         } else {
996                 snd_pcm_uframes_t frames;
997                 frames = runtime->period_size + 16;
998                 if (frames > runtime->buffer_size)
999                         frames = runtime->buffer_size;
1000                 sw_params->silence_threshold = frames;
1001                 sw_params->silence_size = frames;
1002         }
1003
1004         if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
1005                 snd_printd("SW_PARAMS failed: %i\n", err);
1006                 goto failure;
1007         }
1008
1009         runtime->oss.periods = params_periods(sparams);
1010         oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
1011         snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);
1012 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
1013         if (runtime->oss.plugin_first) {
1014                 err = snd_pcm_plug_alloc(substream, oss_period_size);
1015                 if (err < 0)
1016                         goto failure;
1017         }
1018 #endif
1019         oss_period_size *= oss_frame_size;
1020
1021         oss_buffer_size = oss_period_size * runtime->oss.periods;
1022         snd_assert(oss_buffer_size >= 0, err = -EINVAL; goto failure);
1023
1024         runtime->oss.period_bytes = oss_period_size;
1025         runtime->oss.buffer_bytes = oss_buffer_size;
1026
1027         pdprintf("oss: period bytes = %i, buffer bytes = %i\n",
1028                  runtime->oss.period_bytes,
1029                  runtime->oss.buffer_bytes);
1030         pdprintf("slave: period_size = %i, buffer_size = %i\n",
1031                  params_period_size(sparams),
1032                  params_buffer_size(sparams));
1033
1034         runtime->oss.format = snd_pcm_oss_format_to(params_format(params));
1035         runtime->oss.channels = params_channels(params);
1036         runtime->oss.rate = params_rate(params);
1037
1038         runtime->oss.params = 0;
1039         runtime->oss.prepare = 1;
1040         vfree(runtime->oss.buffer);
1041         runtime->oss.buffer = vmalloc(runtime->oss.period_bytes);
1042         runtime->oss.buffer_used = 0;
1043         if (runtime->dma_area)
1044                 snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
1045
1046         runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
1047
1048         err = 0;
1049 failure:
1050         kfree(sw_params);
1051         kfree(params);
1052         kfree(sparams);
1053         mutex_unlock(&runtime->oss.params_lock);
1054         return err;
1055 }
1056
1057 static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_file, struct snd_pcm_substream **r_substream)
1058 {
1059         int idx, err;
1060         struct snd_pcm_substream *asubstream = NULL, *substream;
1061
1062         for (idx = 0; idx < 2; idx++) {
1063                 substream = pcm_oss_file->streams[idx];
1064                 if (substream == NULL)
1065                         continue;
1066                 if (asubstream == NULL)
1067                         asubstream = substream;
1068                 if (substream->runtime->oss.params) {
1069                         err = snd_pcm_oss_change_params(substream);
1070                         if (err < 0)
1071                                 return err;
1072                 }
1073         }
1074         snd_assert(asubstream != NULL, return -EIO);
1075         if (r_substream)
1076                 *r_substream = asubstream;
1077         return 0;
1078 }
1079
1080 static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
1081 {
1082         int err;
1083         struct snd_pcm_runtime *runtime = substream->runtime;
1084
1085         err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
1086         if (err < 0) {
1087                 snd_printd("snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n");
1088                 return err;
1089         }
1090         runtime->oss.prepare = 0;
1091         runtime->oss.prev_hw_ptr_interrupt = 0;
1092         runtime->oss.period_ptr = 0;
1093         runtime->oss.buffer_used = 0;
1094
1095         return 0;
1096 }
1097
1098 static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream)
1099 {
1100         struct snd_pcm_runtime *runtime;
1101         int err;
1102
1103         if (substream == NULL)
1104                 return 0;
1105         runtime = substream->runtime;
1106         if (runtime->oss.params) {
1107                 err = snd_pcm_oss_change_params(substream);
1108                 if (err < 0)
1109                         return err;
1110         }
1111         if (runtime->oss.prepare) {
1112                 err = snd_pcm_oss_prepare(substream);
1113                 if (err < 0)
1114                         return err;
1115         }
1116         return 0;
1117 }
1118
1119 static int snd_pcm_oss_capture_position_fixup(struct snd_pcm_substream *substream, snd_pcm_sframes_t *delay)
1120 {
1121         struct snd_pcm_runtime *runtime;
1122         snd_pcm_uframes_t frames;
1123         int err = 0;
1124
1125         while (1) {
1126                 err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, delay);
1127                 if (err < 0)
1128                         break;
1129                 runtime = substream->runtime;
1130                 if (*delay <= (snd_pcm_sframes_t)runtime->buffer_size)
1131                         break;
1132                 /* in case of overrun, skip whole periods like OSS/Linux driver does */
1133                 /* until avail(delay) <= buffer_size */
1134                 frames = (*delay - runtime->buffer_size) + runtime->period_size - 1;
1135                 frames /= runtime->period_size;
1136                 frames *= runtime->period_size;
1137                 err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_FORWARD, &frames);
1138                 if (err < 0)
1139                         break;
1140         }
1141         return err;
1142 }
1143
1144 snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
1145 {
1146         struct snd_pcm_runtime *runtime = substream->runtime;
1147         int ret;
1148         while (1) {
1149                 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1150                     runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1151 #ifdef OSS_DEBUG
1152                         if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
1153                                 printk("pcm_oss: write: recovering from XRUN\n");
1154                         else
1155                                 printk("pcm_oss: write: recovering from SUSPEND\n");
1156 #endif
1157                         ret = snd_pcm_oss_prepare(substream);
1158                         if (ret < 0)
1159                                 break;
1160                 }
1161                 if (in_kernel) {
1162                         mm_segment_t fs;
1163                         fs = snd_enter_user();
1164                         ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
1165                         snd_leave_user(fs);
1166                 } else {
1167                         ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
1168                 }
1169                 if (ret != -EPIPE && ret != -ESTRPIPE)
1170                         break;
1171                 /* test, if we can't store new data, because the stream */
1172                 /* has not been started */
1173                 if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
1174                         return -EAGAIN;
1175         }
1176         return ret;
1177 }
1178
1179 snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
1180 {
1181         struct snd_pcm_runtime *runtime = substream->runtime;
1182         snd_pcm_sframes_t delay;
1183         int ret;
1184         while (1) {
1185                 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1186                     runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1187 #ifdef OSS_DEBUG
1188                         if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
1189                                 printk("pcm_oss: read: recovering from XRUN\n");
1190                         else
1191                                 printk("pcm_oss: read: recovering from SUSPEND\n");
1192 #endif
1193                         ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
1194                         if (ret < 0)
1195                                 break;
1196                 } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {
1197                         ret = snd_pcm_oss_prepare(substream);
1198                         if (ret < 0)
1199                                 break;
1200                 }
1201                 ret = snd_pcm_oss_capture_position_fixup(substream, &delay);
1202                 if (ret < 0)
1203                         break;
1204                 if (in_kernel) {
1205                         mm_segment_t fs;
1206                         fs = snd_enter_user();
1207                         ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
1208                         snd_leave_user(fs);
1209                 } else {
1210                         ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
1211                 }
1212                 if (ret == -EPIPE) {
1213                         if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
1214                                 ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1215                                 if (ret < 0)
1216                                         break;
1217                         }
1218                         continue;
1219                 }
1220                 if (ret != -ESTRPIPE)
1221                         break;
1222         }
1223         return ret;
1224 }
1225
1226 snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
1227 {
1228         struct snd_pcm_runtime *runtime = substream->runtime;
1229         int ret;
1230         while (1) {
1231                 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1232                     runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1233 #ifdef OSS_DEBUG
1234                         if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
1235                                 printk("pcm_oss: writev: recovering from XRUN\n");
1236                         else
1237                                 printk("pcm_oss: writev: recovering from SUSPEND\n");
1238 #endif
1239                         ret = snd_pcm_oss_prepare(substream);
1240                         if (ret < 0)
1241                                 break;
1242                 }
1243                 if (in_kernel) {
1244                         mm_segment_t fs;
1245                         fs = snd_enter_user();
1246                         ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
1247                         snd_leave_user(fs);
1248                 } else {
1249                         ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
1250                 }
1251                 if (ret != -EPIPE && ret != -ESTRPIPE)
1252                         break;
1253
1254                 /* test, if we can't store new data, because the stream */
1255                 /* has not been started */
1256                 if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
1257                         return -EAGAIN;
1258         }
1259         return ret;
1260 }
1261         
1262 snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
1263 {
1264         struct snd_pcm_runtime *runtime = substream->runtime;
1265         int ret;
1266         while (1) {
1267                 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1268                     runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1269 #ifdef OSS_DEBUG
1270                         if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
1271                                 printk("pcm_oss: readv: recovering from XRUN\n");
1272                         else
1273                                 printk("pcm_oss: readv: recovering from SUSPEND\n");
1274 #endif
1275                         ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
1276                         if (ret < 0)
1277                                 break;
1278                 } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {
1279                         ret = snd_pcm_oss_prepare(substream);
1280                         if (ret < 0)
1281                                 break;
1282                 }
1283                 if (in_kernel) {
1284                         mm_segment_t fs;
1285                         fs = snd_enter_user();
1286                         ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
1287                         snd_leave_user(fs);
1288                 } else {
1289                         ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
1290                 }
1291                 if (ret != -EPIPE && ret != -ESTRPIPE)
1292                         break;
1293         }
1294         return ret;
1295 }
1296
1297 static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel)
1298 {
1299         struct snd_pcm_runtime *runtime = substream->runtime;
1300         snd_pcm_sframes_t frames, frames1;
1301 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
1302         if (runtime->oss.plugin_first) {
1303                 struct snd_pcm_plugin_channel *channels;
1304                 size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8;
1305                 if (!in_kernel) {
1306                         if (copy_from_user(runtime->oss.buffer, (const char __user *)buf, bytes))
1307                                 return -EFAULT;
1308                         buf = runtime->oss.buffer;
1309                 }
1310                 frames = bytes / oss_frame_bytes;
1311                 frames1 = snd_pcm_plug_client_channels_buf(substream, (char *)buf, frames, &channels);
1312                 if (frames1 < 0)
1313                         return frames1;
1314                 frames1 = snd_pcm_plug_write_transfer(substream, channels, frames1);
1315                 if (frames1 <= 0)
1316                         return frames1;
1317                 bytes = frames1 * oss_frame_bytes;
1318         } else
1319 #endif
1320         {
1321                 frames = bytes_to_frames(runtime, bytes);
1322                 frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel);
1323                 if (frames1 <= 0)
1324                         return frames1;
1325                 bytes = frames_to_bytes(runtime, frames1);
1326         }
1327         return bytes;
1328 }
1329
1330 static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const char __user *buf, size_t bytes)
1331 {
1332         size_t xfer = 0;
1333         ssize_t tmp;
1334         struct snd_pcm_runtime *runtime = substream->runtime;
1335
1336         if (atomic_read(&substream->mmap_count))
1337                 return -ENXIO;
1338
1339         if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
1340                 return tmp;
1341         mutex_lock(&runtime->oss.params_lock);
1342         while (bytes > 0) {
1343                 if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
1344                         tmp = bytes;
1345                         if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
1346                                 tmp = runtime->oss.period_bytes - runtime->oss.buffer_used;
1347                         if (tmp > 0) {
1348                                 if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp)) {
1349                                         tmp = -EFAULT;
1350                                         goto err;
1351                                 }
1352                         }
1353                         runtime->oss.buffer_used += tmp;
1354                         buf += tmp;
1355                         bytes -= tmp;
1356                         xfer += tmp;
1357                         if (substream->oss.setup.partialfrag ||
1358                             runtime->oss.buffer_used == runtime->oss.period_bytes) {
1359                                 tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr, 
1360                                                          runtime->oss.buffer_used - runtime->oss.period_ptr, 1);
1361                                 if (tmp <= 0)
1362                                         goto err;
1363                                 runtime->oss.bytes += tmp;
1364                                 runtime->oss.period_ptr += tmp;
1365                                 runtime->oss.period_ptr %= runtime->oss.period_bytes;
1366                                 if (runtime->oss.period_ptr == 0 ||
1367                                     runtime->oss.period_ptr == runtime->oss.buffer_used)
1368                                         runtime->oss.buffer_used = 0;
1369                                 else if ((substream->f_flags & O_NONBLOCK) != 0) {
1370                                         tmp = -EAGAIN;
1371                                         goto err;
1372                                 }
1373                         }
1374                 } else {
1375                         tmp = snd_pcm_oss_write2(substream,
1376                                                  (const char __force *)buf,
1377                                                  runtime->oss.period_bytes, 0);
1378                         if (tmp <= 0)
1379                                 goto err;
1380                         runtime->oss.bytes += tmp;
1381                         buf += tmp;
1382                         bytes -= tmp;
1383                         xfer += tmp;
1384                         if ((substream->f_flags & O_NONBLOCK) != 0 &&
1385                             tmp != runtime->oss.period_bytes)
1386                                 break;
1387                 }
1388         }
1389         mutex_unlock(&runtime->oss.params_lock);
1390         return xfer;
1391
1392  err:
1393         mutex_unlock(&runtime->oss.params_lock);
1394         return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
1395 }
1396
1397 static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf, size_t bytes, int in_kernel)
1398 {
1399         struct snd_pcm_runtime *runtime = substream->runtime;
1400         snd_pcm_sframes_t frames, frames1;
1401 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
1402         char __user *final_dst = (char __user *)buf;
1403         if (runtime->oss.plugin_first) {
1404                 struct snd_pcm_plugin_channel *channels;
1405                 size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8;
1406                 if (!in_kernel)
1407                         buf = runtime->oss.buffer;
1408                 frames = bytes / oss_frame_bytes;
1409                 frames1 = snd_pcm_plug_client_channels_buf(substream, buf, frames, &channels);
1410                 if (frames1 < 0)
1411                         return frames1;
1412                 frames1 = snd_pcm_plug_read_transfer(substream, channels, frames1);
1413                 if (frames1 <= 0)
1414                         return frames1;
1415                 bytes = frames1 * oss_frame_bytes;
1416                 if (!in_kernel && copy_to_user(final_dst, buf, bytes))
1417                         return -EFAULT;
1418         } else
1419 #endif
1420         {
1421                 frames = bytes_to_frames(runtime, bytes);
1422                 frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel);
1423                 if (frames1 <= 0)
1424                         return frames1;
1425                 bytes = frames_to_bytes(runtime, frames1);
1426         }
1427         return bytes;
1428 }
1429
1430 static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __user *buf, size_t bytes)
1431 {
1432         size_t xfer = 0;
1433         ssize_t tmp;
1434         struct snd_pcm_runtime *runtime = substream->runtime;
1435
1436         if (atomic_read(&substream->mmap_count))
1437                 return -ENXIO;
1438
1439         if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
1440                 return tmp;
1441         mutex_lock(&runtime->oss.params_lock);
1442         while (bytes > 0) {
1443                 if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
1444                         if (runtime->oss.buffer_used == 0) {
1445                                 tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
1446                                 if (tmp <= 0)
1447                                         goto err;
1448                                 runtime->oss.bytes += tmp;
1449                                 runtime->oss.period_ptr = tmp;
1450                                 runtime->oss.buffer_used = tmp;
1451                         }
1452                         tmp = bytes;
1453                         if ((size_t) tmp > runtime->oss.buffer_used)
1454                                 tmp = runtime->oss.buffer_used;
1455                         if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp)) {
1456                                 tmp = -EFAULT;
1457                                 goto err;
1458                         }
1459                         buf += tmp;
1460                         bytes -= tmp;
1461                         xfer += tmp;
1462                         runtime->oss.buffer_used -= tmp;
1463                 } else {
1464                         tmp = snd_pcm_oss_read2(substream, (char __force *)buf,
1465                                                 runtime->oss.period_bytes, 0);
1466                         if (tmp <= 0)
1467                                 goto err;
1468                         runtime->oss.bytes += tmp;
1469                         buf += tmp;
1470                         bytes -= tmp;
1471                         xfer += tmp;
1472                 }
1473         }
1474         mutex_unlock(&runtime->oss.params_lock);
1475         return xfer;
1476
1477  err:
1478         mutex_unlock(&runtime->oss.params_lock);
1479         return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
1480 }
1481
1482 static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file)
1483 {
1484         struct snd_pcm_substream *substream;
1485
1486         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1487         if (substream != NULL) {
1488                 snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1489                 substream->runtime->oss.prepare = 1;
1490         }
1491         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
1492         if (substream != NULL) {
1493                 snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1494                 substream->runtime->oss.prepare = 1;
1495         }
1496         return 0;
1497 }
1498
1499 static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file)
1500 {
1501         struct snd_pcm_substream *substream;
1502         int err;
1503
1504         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1505         if (substream != NULL) {
1506                 if ((err = snd_pcm_oss_make_ready(substream)) < 0)
1507                         return err;
1508                 snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
1509         }
1510         /* note: all errors from the start action are ignored */
1511         /* OSS apps do not know, how to handle them */
1512         return 0;
1513 }
1514
1515 static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
1516 {
1517         struct snd_pcm_runtime *runtime;
1518         ssize_t result = 0;
1519         long res;
1520         wait_queue_t wait;
1521
1522         runtime = substream->runtime;
1523         init_waitqueue_entry(&wait, current);
1524         add_wait_queue(&runtime->sleep, &wait);
1525 #ifdef OSS_DEBUG
1526         printk("sync1: size = %li\n", size);
1527 #endif
1528         while (1) {
1529                 result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1);
1530                 if (result > 0) {
1531                         runtime->oss.buffer_used = 0;
1532                         result = 0;
1533                         break;
1534                 }
1535                 if (result != 0 && result != -EAGAIN)
1536                         break;
1537                 result = 0;
1538                 set_current_state(TASK_INTERRUPTIBLE);
1539                 snd_pcm_stream_lock_irq(substream);
1540                 res = runtime->status->state;
1541                 snd_pcm_stream_unlock_irq(substream);
1542                 if (res != SNDRV_PCM_STATE_RUNNING) {
1543                         set_current_state(TASK_RUNNING);
1544                         break;
1545                 }
1546                 res = schedule_timeout(10 * HZ);
1547                 if (signal_pending(current)) {
1548                         result = -ERESTARTSYS;
1549                         break;
1550                 }
1551                 if (res == 0) {
1552                         snd_printk(KERN_ERR "OSS sync error - DMA timeout\n");
1553                         result = -EIO;
1554                         break;
1555                 }
1556         }
1557         remove_wait_queue(&runtime->sleep, &wait);
1558         return result;
1559 }
1560
1561 static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
1562 {
1563         int err = 0;
1564         unsigned int saved_f_flags;
1565         struct snd_pcm_substream *substream;
1566         struct snd_pcm_runtime *runtime;
1567         snd_pcm_format_t format;
1568         unsigned long width;
1569         size_t size;
1570
1571         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1572         if (substream != NULL) {
1573                 runtime = substream->runtime;
1574                 if (atomic_read(&substream->mmap_count))
1575                         goto __direct;
1576                 if ((err = snd_pcm_oss_make_ready(substream)) < 0)
1577                         return err;
1578                 format = snd_pcm_oss_format_from(runtime->oss.format);
1579                 width = snd_pcm_format_physical_width(format);
1580                 mutex_lock(&runtime->oss.params_lock);
1581                 if (runtime->oss.buffer_used > 0) {
1582 #ifdef OSS_DEBUG
1583                         printk("sync: buffer_used\n");
1584 #endif
1585                         size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;
1586                         snd_pcm_format_set_silence(format,
1587                                                    runtime->oss.buffer + runtime->oss.buffer_used,
1588                                                    size);
1589                         err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
1590                         if (err < 0) {
1591                                 mutex_unlock(&runtime->oss.params_lock);
1592                                 return err;
1593                         }
1594                 } else if (runtime->oss.period_ptr > 0) {
1595 #ifdef OSS_DEBUG
1596                         printk("sync: period_ptr\n");
1597 #endif
1598                         size = runtime->oss.period_bytes - runtime->oss.period_ptr;
1599                         snd_pcm_format_set_silence(format,
1600                                                    runtime->oss.buffer,
1601                                                    size * 8 / width);
1602                         err = snd_pcm_oss_sync1(substream, size);
1603                         if (err < 0) {
1604                                 mutex_unlock(&runtime->oss.params_lock);
1605                                 return err;
1606                         }
1607                 }
1608                 /*
1609                  * The ALSA's period might be a bit large than OSS one.
1610                  * Fill the remain portion of ALSA period with zeros.
1611                  */
1612                 size = runtime->control->appl_ptr % runtime->period_size;
1613                 if (size > 0) {
1614                         size = runtime->period_size - size;
1615                         if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
1616                                 size = (runtime->frame_bits * size) / 8;
1617                                 while (size > 0) {
1618                                         mm_segment_t fs;
1619                                         size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes;
1620                                         size -= size1;
1621                                         size1 *= 8;
1622                                         size1 /= runtime->sample_bits;
1623                                         snd_pcm_format_set_silence(runtime->format,
1624                                                                    runtime->oss.buffer,
1625                                                                    size1);
1626                                         fs = snd_enter_user();
1627                                         snd_pcm_lib_write(substream, (void __user *)runtime->oss.buffer, size1);
1628                                         snd_leave_user(fs);
1629                                 }
1630                         } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
1631                                 void __user *buffers[runtime->channels];
1632                                 memset(buffers, 0, runtime->channels * sizeof(void *));
1633                                 snd_pcm_lib_writev(substream, buffers, size);
1634                         }
1635                 }
1636                 mutex_unlock(&runtime->oss.params_lock);
1637                 /*
1638                  * finish sync: drain the buffer
1639                  */
1640               __direct:
1641                 saved_f_flags = substream->f_flags;
1642                 substream->f_flags &= ~O_NONBLOCK;
1643                 err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
1644                 substream->f_flags = saved_f_flags;
1645                 if (err < 0)
1646                         return err;
1647                 runtime->oss.prepare = 1;
1648         }
1649
1650         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
1651         if (substream != NULL) {
1652                 if ((err = snd_pcm_oss_make_ready(substream)) < 0)
1653                         return err;
1654                 runtime = substream->runtime;
1655                 err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1656                 if (err < 0)
1657                         return err;
1658                 runtime->oss.buffer_used = 0;
1659                 runtime->oss.prepare = 1;
1660         }
1661         return 0;
1662 }
1663
1664 static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate)
1665 {
1666         int idx;
1667
1668         for (idx = 1; idx >= 0; --idx) {
1669                 struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1670                 struct snd_pcm_runtime *runtime;
1671                 if (substream == NULL)
1672                         continue;
1673                 runtime = substream->runtime;
1674                 if (rate < 1000)
1675                         rate = 1000;
1676                 else if (rate > 192000)
1677                         rate = 192000;
1678                 if (runtime->oss.rate != rate) {
1679                         runtime->oss.params = 1;
1680                         runtime->oss.rate = rate;
1681                 }
1682         }
1683         return snd_pcm_oss_get_rate(pcm_oss_file);
1684 }
1685
1686 static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file)
1687 {
1688         struct snd_pcm_substream *substream;
1689         int err;
1690         
1691         if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1692                 return err;
1693         return substream->runtime->oss.rate;
1694 }
1695
1696 static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsigned int channels)
1697 {
1698         int idx;
1699         if (channels < 1)
1700                 channels = 1;
1701         if (channels > 128)
1702                 return -EINVAL;
1703         for (idx = 1; idx >= 0; --idx) {
1704                 struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1705                 struct snd_pcm_runtime *runtime;
1706                 if (substream == NULL)
1707                         continue;
1708                 runtime = substream->runtime;
1709                 if (runtime->oss.channels != channels) {
1710                         runtime->oss.params = 1;
1711                         runtime->oss.channels = channels;
1712                 }
1713         }
1714         return snd_pcm_oss_get_channels(pcm_oss_file);
1715 }
1716
1717 static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file)
1718 {
1719         struct snd_pcm_substream *substream;
1720         int err;
1721         
1722         if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1723                 return err;
1724         return substream->runtime->oss.channels;
1725 }
1726
1727 static int snd_pcm_oss_get_block_size(struct snd_pcm_oss_file *pcm_oss_file)
1728 {
1729         struct snd_pcm_substream *substream;
1730         int err;
1731         
1732         if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1733                 return err;
1734         return substream->runtime->oss.period_bytes;
1735 }
1736
1737 static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
1738 {
1739         struct snd_pcm_substream *substream;
1740         int err;
1741         int direct;
1742         struct snd_pcm_hw_params *params;
1743         unsigned int formats = 0;
1744         struct snd_mask format_mask;
1745         int fmt;
1746
1747         if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1748                 return err;
1749         if (atomic_read(&substream->mmap_count))
1750                 direct = 1;
1751         else
1752                 direct = substream->oss.setup.direct;
1753         if (!direct)
1754                 return AFMT_MU_LAW | AFMT_U8 |
1755                        AFMT_S16_LE | AFMT_S16_BE |
1756                        AFMT_S8 | AFMT_U16_LE |
1757                        AFMT_U16_BE |
1758                         AFMT_S32_LE | AFMT_S32_BE |
1759                         AFMT_S24_LE | AFMT_S24_LE |
1760                         AFMT_S24_PACKED;
1761         params = kmalloc(sizeof(*params), GFP_KERNEL);
1762         if (!params)
1763                 return -ENOMEM;
1764         _snd_pcm_hw_params_any(params);
1765         err = snd_pcm_hw_refine(substream, params);
1766         format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 
1767         kfree(params);
1768         snd_assert(err >= 0, return err);
1769         for (fmt = 0; fmt < 32; ++fmt) {
1770                 if (snd_mask_test(&format_mask, fmt)) {
1771                         int f = snd_pcm_oss_format_to(fmt);
1772                         if (f >= 0)
1773                                 formats |= f;
1774                 }
1775         }
1776         return formats;
1777 }
1778
1779 static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
1780 {
1781         int formats, idx;
1782         
1783         if (format != AFMT_QUERY) {
1784                 formats = snd_pcm_oss_get_formats(pcm_oss_file);
1785                 if (formats < 0)
1786                         return formats;
1787                 if (!(formats & format))
1788                         format = AFMT_U8;
1789                 for (idx = 1; idx >= 0; --idx) {
1790                         struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1791                         struct snd_pcm_runtime *runtime;
1792                         if (substream == NULL)
1793                                 continue;
1794                         runtime = substream->runtime;
1795                         if (runtime->oss.format != format) {
1796                                 runtime->oss.params = 1;
1797                                 runtime->oss.format = format;
1798                         }
1799                 }
1800         }
1801         return snd_pcm_oss_get_format(pcm_oss_file);
1802 }
1803
1804 static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file)
1805 {
1806         struct snd_pcm_substream *substream;
1807         int err;
1808         
1809         if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1810                 return err;
1811         return substream->runtime->oss.format;
1812 }
1813
1814 static int snd_pcm_oss_set_subdivide1(struct snd_pcm_substream *substream, int subdivide)
1815 {
1816         struct snd_pcm_runtime *runtime;
1817
1818         if (substream == NULL)
1819                 return 0;
1820         runtime = substream->runtime;
1821         if (subdivide == 0) {
1822                 subdivide = runtime->oss.subdivision;
1823                 if (subdivide == 0)
1824                         subdivide = 1;
1825                 return subdivide;
1826         }
1827         if (runtime->oss.subdivision || runtime->oss.fragshift)
1828                 return -EINVAL;
1829         if (subdivide != 1 && subdivide != 2 && subdivide != 4 &&
1830             subdivide != 8 && subdivide != 16)
1831                 return -EINVAL;
1832         runtime->oss.subdivision = subdivide;
1833         runtime->oss.params = 1;
1834         return subdivide;
1835 }
1836
1837 static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int subdivide)
1838 {
1839         int err = -EINVAL, idx;
1840
1841         for (idx = 1; idx >= 0; --idx) {
1842                 struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1843                 if (substream == NULL)
1844                         continue;
1845                 if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0)
1846                         return err;
1847         }
1848         return err;
1849 }
1850
1851 static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsigned int val)
1852 {
1853         struct snd_pcm_runtime *runtime;
1854
1855         if (substream == NULL)
1856                 return 0;
1857         runtime = substream->runtime;
1858         if (runtime->oss.subdivision || runtime->oss.fragshift)
1859                 return -EINVAL;
1860         runtime->oss.fragshift = val & 0xffff;
1861         runtime->oss.maxfrags = (val >> 16) & 0xffff;
1862         if (runtime->oss.fragshift < 4)         /* < 16 */
1863                 runtime->oss.fragshift = 4;
1864         if (runtime->oss.maxfrags < 2)
1865                 runtime->oss.maxfrags = 2;
1866         runtime->oss.params = 1;
1867         return 0;
1868 }
1869
1870 static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsigned int val)
1871 {
1872         int err = -EINVAL, idx;
1873
1874         for (idx = 1; idx >= 0; --idx) {
1875                 struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1876                 if (substream == NULL)
1877                         continue;
1878                 if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0)
1879                         return err;
1880         }
1881         return err;
1882 }
1883
1884 static int snd_pcm_oss_nonblock(struct file * file)
1885 {
1886         file->f_flags |= O_NONBLOCK;
1887         return 0;
1888 }
1889
1890 static int snd_pcm_oss_get_caps1(struct snd_pcm_substream *substream, int res)
1891 {
1892
1893         if (substream == NULL) {
1894                 res &= ~DSP_CAP_DUPLEX;
1895                 return res;
1896         }
1897 #ifdef DSP_CAP_MULTI
1898         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1899                 if (substream->pstr->substream_count > 1)
1900                         res |= DSP_CAP_MULTI;
1901 #endif
1902         /* DSP_CAP_REALTIME is set all times: */
1903         /* all ALSA drivers can return actual pointer in ring buffer */
1904 #if defined(DSP_CAP_REALTIME) && 0
1905         {
1906                 struct snd_pcm_runtime *runtime = substream->runtime;
1907                 if (runtime->info & (SNDRV_PCM_INFO_BLOCK_TRANSFER|SNDRV_PCM_INFO_BATCH))
1908                         res &= ~DSP_CAP_REALTIME;
1909         }
1910 #endif
1911         return res;
1912 }
1913
1914 static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file)
1915 {
1916         int result, idx;
1917         
1918         result = DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_DUPLEX | DSP_CAP_REALTIME;
1919         for (idx = 0; idx < 2; idx++) {
1920                 struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1921                 result = snd_pcm_oss_get_caps1(substream, result);
1922         }
1923         result |= 0x0001;       /* revision - same as SB AWE 64 */
1924         return result;
1925 }
1926
1927 static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr)
1928 {
1929         struct snd_pcm_runtime *runtime = substream->runtime;
1930         snd_pcm_uframes_t appl_ptr;
1931         appl_ptr = hw_ptr + runtime->buffer_size;
1932         appl_ptr %= runtime->boundary;
1933         runtime->control->appl_ptr = appl_ptr;
1934 }
1935
1936 static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int trigger)
1937 {
1938         struct snd_pcm_runtime *runtime;
1939         struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
1940         int err, cmd;
1941
1942 #ifdef OSS_DEBUG
1943         printk("pcm_oss: trigger = 0x%x\n", trigger);
1944 #endif
1945         
1946         psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1947         csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
1948
1949         if (psubstream) {
1950                 if ((err = snd_pcm_oss_make_ready(psubstream)) < 0)
1951                         return err;
1952         }
1953         if (csubstream) {
1954                 if ((err = snd_pcm_oss_make_ready(csubstream)) < 0)
1955                         return err;
1956         }
1957         if (psubstream) {
1958                 runtime = psubstream->runtime;
1959                 if (trigger & PCM_ENABLE_OUTPUT) {
1960                         if (runtime->oss.trigger)
1961                                 goto _skip1;
1962                         if (atomic_read(&psubstream->mmap_count))
1963                                 snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
1964                         runtime->oss.trigger = 1;
1965                         runtime->start_threshold = 1;
1966                         cmd = SNDRV_PCM_IOCTL_START;
1967                 } else {
1968                         if (!runtime->oss.trigger)
1969                                 goto _skip1;
1970                         runtime->oss.trigger = 0;
1971                         runtime->start_threshold = runtime->boundary;
1972                         cmd = SNDRV_PCM_IOCTL_DROP;
1973                         runtime->oss.prepare = 1;
1974                 }
1975                 err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
1976                 if (err < 0)
1977                         return err;
1978         }
1979  _skip1:
1980         if (csubstream) {
1981                 runtime = csubstream->runtime;
1982                 if (trigger & PCM_ENABLE_INPUT) {
1983                         if (runtime->oss.trigger)
1984                                 goto _skip2;
1985                         runtime->oss.trigger = 1;
1986                         runtime->start_threshold = 1;
1987                         cmd = SNDRV_PCM_IOCTL_START;
1988                 } else {
1989                         if (!runtime->oss.trigger)
1990                                 goto _skip2;
1991                         runtime->oss.trigger = 0;
1992                         runtime->start_threshold = runtime->boundary;
1993                         cmd = SNDRV_PCM_IOCTL_DROP;
1994                         runtime->oss.prepare = 1;
1995                 }
1996                 err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
1997                 if (err < 0)
1998                         return err;
1999         }
2000  _skip2:
2001         return 0;
2002 }
2003
2004 static int snd_pcm_oss_get_trigger(struct snd_pcm_oss_file *pcm_oss_file)
2005 {
2006         struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
2007         int result = 0;
2008
2009         psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2010         csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2011         if (psubstream && psubstream->runtime && psubstream->runtime->oss.trigger)
2012                 result |= PCM_ENABLE_OUTPUT;
2013         if (csubstream && csubstream->runtime && csubstream->runtime->oss.trigger)
2014                 result |= PCM_ENABLE_INPUT;
2015         return result;
2016 }
2017
2018 static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file)
2019 {
2020         struct snd_pcm_substream *substream;
2021         struct snd_pcm_runtime *runtime;
2022         snd_pcm_sframes_t delay;
2023         int err;
2024
2025         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2026         if (substream == NULL)
2027                 return -EINVAL;
2028         if ((err = snd_pcm_oss_make_ready(substream)) < 0)
2029                 return err;
2030         runtime = substream->runtime;
2031         if (runtime->oss.params || runtime->oss.prepare)
2032                 return 0;
2033         err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
2034         if (err == -EPIPE)
2035                 delay = 0;      /* hack for broken OSS applications */
2036         else if (err < 0)
2037                 return err;
2038         return snd_pcm_oss_bytes(substream, delay);
2039 }
2040
2041 static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct count_info __user * _info)
2042 {       
2043         struct snd_pcm_substream *substream;
2044         struct snd_pcm_runtime *runtime;
2045         snd_pcm_sframes_t delay;
2046         int fixup;
2047         struct count_info info;
2048         int err;
2049
2050         if (_info == NULL)
2051                 return -EFAULT;
2052         substream = pcm_oss_file->streams[stream];
2053         if (substream == NULL)
2054                 return -EINVAL;
2055         if ((err = snd_pcm_oss_make_ready(substream)) < 0)
2056                 return err;
2057         runtime = substream->runtime;
2058         if (runtime->oss.params || runtime->oss.prepare) {
2059                 memset(&info, 0, sizeof(info));
2060                 if (copy_to_user(_info, &info, sizeof(info)))
2061                         return -EFAULT;
2062                 return 0;
2063         }
2064         if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2065                 err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
2066                 if (err == -EPIPE || err == -ESTRPIPE || (! err && delay < 0)) {
2067                         err = 0;
2068                         delay = 0;
2069                         fixup = 0;
2070                 } else {
2071                         fixup = runtime->oss.buffer_used;
2072                 }
2073         } else {
2074                 err = snd_pcm_oss_capture_position_fixup(substream, &delay);
2075                 fixup = -runtime->oss.buffer_used;
2076         }
2077         if (err < 0)
2078                 return err;
2079         info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
2080         if (atomic_read(&substream->mmap_count)) {
2081                 snd_pcm_sframes_t n;
2082                 n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
2083                 if (n < 0)
2084                         n += runtime->boundary;
2085                 info.blocks = n / runtime->period_size;
2086                 runtime->oss.prev_hw_ptr_interrupt = delay;
2087                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
2088                         snd_pcm_oss_simulate_fill(substream, delay);
2089                 info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
2090         } else {
2091                 delay = snd_pcm_oss_bytes(substream, delay);
2092                 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2093                         if (substream->oss.setup.buggyptr)
2094                                 info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes;
2095                         else
2096                                 info.blocks = (delay + fixup) / runtime->oss.period_bytes;
2097                         info.bytes = (runtime->oss.bytes - delay) & INT_MAX;
2098                 } else {
2099                         delay += fixup;
2100                         info.blocks = delay / runtime->oss.period_bytes;
2101                         info.bytes = (runtime->oss.bytes + delay) & INT_MAX;
2102                 }
2103         }
2104         if (copy_to_user(_info, &info, sizeof(info)))
2105                 return -EFAULT;
2106         return 0;
2107 }
2108
2109 static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct audio_buf_info __user *_info)
2110 {
2111         struct snd_pcm_substream *substream;
2112         struct snd_pcm_runtime *runtime;
2113         snd_pcm_sframes_t avail;
2114         int fixup;
2115         struct audio_buf_info info;
2116         int err;
2117
2118         if (_info == NULL)
2119                 return -EFAULT;
2120         substream = pcm_oss_file->streams[stream];
2121         if (substream == NULL)
2122                 return -EINVAL;
2123         runtime = substream->runtime;
2124
2125         if (runtime->oss.params &&
2126             (err = snd_pcm_oss_change_params(substream)) < 0)
2127                 return err;
2128
2129         info.fragsize = runtime->oss.period_bytes;
2130         info.fragstotal = runtime->periods;
2131         if (runtime->oss.prepare) {
2132                 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2133                         info.bytes = runtime->oss.period_bytes * runtime->oss.periods;
2134                         info.fragments = runtime->oss.periods;
2135                 } else {
2136                         info.bytes = 0;
2137                         info.fragments = 0;
2138                 }
2139         } else {
2140                 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2141                         err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &avail);
2142                         if (err == -EPIPE || err == -ESTRPIPE || (! err && avail < 0)) {
2143                                 avail = runtime->buffer_size;
2144                                 err = 0;
2145                                 fixup = 0;
2146                         } else {
2147                                 avail = runtime->buffer_size - avail;
2148                                 fixup = -runtime->oss.buffer_used;
2149                         }
2150                 } else {
2151                         err = snd_pcm_oss_capture_position_fixup(substream, &avail);
2152                         fixup = runtime->oss.buffer_used;
2153                 }
2154                 if (err < 0)
2155                         return err;
2156                 info.bytes = snd_pcm_oss_bytes(substream, avail) + fixup;
2157                 info.fragments = info.bytes / runtime->oss.period_bytes;
2158         }
2159
2160 #ifdef OSS_DEBUG
2161         printk("pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.fragments, info.fragstotal, info.fragsize);
2162 #endif
2163         if (copy_to_user(_info, &info, sizeof(info)))
2164                 return -EFAULT;
2165         return 0;
2166 }
2167
2168 static int snd_pcm_oss_get_mapbuf(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct buffmem_desc __user * _info)
2169 {
2170         // it won't be probably implemented
2171         // snd_printd("TODO: snd_pcm_oss_get_mapbuf\n");
2172         return -EINVAL;
2173 }
2174
2175 static const char *strip_task_path(const char *path)
2176 {
2177         const char *ptr, *ptrl = NULL;
2178         for (ptr = path; *ptr; ptr++) {
2179                 if (*ptr == '/')
2180                         ptrl = ptr + 1;
2181         }
2182         return ptrl;
2183 }
2184
2185 static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
2186                                       const char *task_name,
2187                                       struct snd_pcm_oss_setup *rsetup)
2188 {
2189         struct snd_pcm_oss_setup *setup;
2190
2191         mutex_lock(&pcm->streams[stream].oss.setup_mutex);
2192         do {
2193                 for (setup = pcm->streams[stream].oss.setup_list; setup;
2194                      setup = setup->next) {
2195                         if (!strcmp(setup->task_name, task_name))
2196                                 goto out;
2197                 }
2198         } while ((task_name = strip_task_path(task_name)) != NULL);
2199  out:
2200         if (setup)
2201                 *rsetup = *setup;
2202         mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
2203 }
2204
2205 static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
2206 {
2207         struct snd_pcm_runtime *runtime;
2208         runtime = substream->runtime;
2209         vfree(runtime->oss.buffer);
2210         runtime->oss.buffer = NULL;
2211 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
2212         snd_pcm_oss_plugin_clear(substream);
2213 #endif
2214         substream->oss.oss = 0;
2215 }
2216
2217 static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
2218                                        struct snd_pcm_oss_setup *setup,
2219                                        int minor)
2220 {
2221         struct snd_pcm_runtime *runtime;
2222
2223         substream->oss.oss = 1;
2224         substream->oss.setup = *setup;
2225         if (setup->nonblock)
2226                 substream->f_flags |= O_NONBLOCK;
2227         else if (setup->block)
2228                 substream->f_flags &= ~O_NONBLOCK;
2229         runtime = substream->runtime;
2230         runtime->oss.params = 1;
2231         runtime->oss.trigger = 1;
2232         runtime->oss.rate = 8000;
2233         mutex_init(&runtime->oss.params_lock);
2234         switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
2235         case SNDRV_MINOR_OSS_PCM_8:
2236                 runtime->oss.format = AFMT_U8;
2237                 break;
2238         case SNDRV_MINOR_OSS_PCM_16:
2239                 runtime->oss.format = AFMT_S16_LE;
2240                 break;
2241         default:
2242                 runtime->oss.format = AFMT_MU_LAW;
2243         }
2244         runtime->oss.channels = 1;
2245         runtime->oss.fragshift = 0;
2246         runtime->oss.maxfrags = 0;
2247         runtime->oss.subdivision = 0;
2248         substream->pcm_release = snd_pcm_oss_release_substream;
2249 }
2250
2251 static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
2252 {
2253         int cidx;
2254         snd_assert(pcm_oss_file != NULL, return -ENXIO);
2255         for (cidx = 0; cidx < 2; ++cidx) {
2256                 struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx];
2257                 if (substream)
2258                         snd_pcm_release_substream(substream);
2259         }
2260         kfree(pcm_oss_file);
2261         return 0;
2262 }
2263
2264 static int snd_pcm_oss_open_file(struct file *file,
2265                                  struct snd_pcm *pcm,
2266                                  struct snd_pcm_oss_file **rpcm_oss_file,
2267                                  int minor,
2268                                  struct snd_pcm_oss_setup *setup)
2269 {
2270         int idx, err;
2271         struct snd_pcm_oss_file *pcm_oss_file;
2272         struct snd_pcm_substream *substream;
2273         unsigned int f_mode = file->f_mode;
2274
2275         snd_assert(rpcm_oss_file != NULL, return -EINVAL);
2276         *rpcm_oss_file = NULL;
2277
2278         pcm_oss_file = kzalloc(sizeof(*pcm_oss_file), GFP_KERNEL);
2279         if (pcm_oss_file == NULL)
2280                 return -ENOMEM;
2281
2282         if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) &&
2283             (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
2284                 f_mode = FMODE_WRITE;
2285
2286         file->f_flags &= ~O_APPEND;
2287         for (idx = 0; idx < 2; idx++) {
2288                 if (setup[idx].disable)
2289                         continue;
2290                 if (! pcm->streams[idx].substream_count)
2291                         continue; /* no matching substream */
2292                 if (idx == SNDRV_PCM_STREAM_PLAYBACK) {
2293                         if (! (f_mode & FMODE_WRITE))
2294                                 continue;
2295                 } else {
2296                         if (! (f_mode & FMODE_READ))
2297                                 continue;
2298                 }
2299                 err = snd_pcm_open_substream(pcm, idx, file, &substream);
2300                 if (err < 0) {
2301                         snd_pcm_oss_release_file(pcm_oss_file);
2302                         return err;
2303                 }
2304
2305                 pcm_oss_file->streams[idx] = substream;
2306                 substream->file = pcm_oss_file;
2307                 snd_pcm_oss_init_substream(substream, &setup[idx], minor);
2308         }
2309         
2310         if (!pcm_oss_file->streams[0] && !pcm_oss_file->streams[1]) {
2311                 snd_pcm_oss_release_file(pcm_oss_file);
2312                 return -EINVAL;
2313         }
2314
2315         file->private_data = pcm_oss_file;
2316         *rpcm_oss_file = pcm_oss_file;
2317         return 0;
2318 }
2319
2320
2321 static int snd_task_name(struct task_struct *task, char *name, size_t size)
2322 {
2323         unsigned int idx;
2324
2325         snd_assert(task != NULL && name != NULL && size >= 2, return -EINVAL);
2326         for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++)
2327                 name[idx] = task->comm[idx];
2328         name[idx] = '\0';
2329         return 0;
2330 }
2331
2332 static int snd_pcm_oss_open(struct inode *inode, struct file *file)
2333 {
2334         int err;
2335         char task_name[32];
2336         struct snd_pcm *pcm;
2337         struct snd_pcm_oss_file *pcm_oss_file;
2338         struct snd_pcm_oss_setup setup[2];
2339         int nonblock;
2340         wait_queue_t wait;
2341
2342         pcm = snd_lookup_oss_minor_data(iminor(inode),
2343                                         SNDRV_OSS_DEVICE_TYPE_PCM);
2344         if (pcm == NULL) {
2345                 err = -ENODEV;
2346                 goto __error1;
2347         }
2348         err = snd_card_file_add(pcm->card, file);
2349         if (err < 0)
2350                 goto __error1;
2351         if (!try_module_get(pcm->card->module)) {
2352                 err = -EFAULT;
2353                 goto __error2;
2354         }
2355         if (snd_task_name(current, task_name, sizeof(task_name)) < 0) {
2356                 err = -EFAULT;
2357                 goto __error;
2358         }
2359         memset(setup, 0, sizeof(setup));
2360         if (file->f_mode & FMODE_WRITE)
2361                 snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK,
2362                                            task_name, &setup[0]);
2363         if (file->f_mode & FMODE_READ)
2364                 snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE,
2365                                            task_name, &setup[1]);
2366
2367         nonblock = !!(file->f_flags & O_NONBLOCK);
2368         if (!nonblock)
2369                 nonblock = nonblock_open;
2370
2371         init_waitqueue_entry(&wait, current);
2372         add_wait_queue(&pcm->open_wait, &wait);
2373         mutex_lock(&pcm->open_mutex);
2374         while (1) {
2375                 err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
2376                                             iminor(inode), setup);
2377                 if (err >= 0)
2378                         break;
2379                 if (err == -EAGAIN) {
2380                         if (nonblock) {
2381                                 err = -EBUSY;
2382                                 break;
2383                         }
2384                 } else
2385                         break;
2386                 set_current_state(TASK_INTERRUPTIBLE);
2387                 mutex_unlock(&pcm->open_mutex);
2388                 schedule();
2389                 mutex_lock(&pcm->open_mutex);
2390                 if (signal_pending(current)) {
2391                         err = -ERESTARTSYS;
2392                         break;
2393                 }
2394         }
2395         remove_wait_queue(&pcm->open_wait, &wait);
2396         mutex_unlock(&pcm->open_mutex);
2397         if (err < 0)
2398                 goto __error;
2399         return err;
2400
2401       __error:
2402         module_put(pcm->card->module);
2403       __error2:
2404         snd_card_file_remove(pcm->card, file);
2405       __error1:
2406         return err;
2407 }
2408
2409 static int snd_pcm_oss_release(struct inode *inode, struct file *file)
2410 {
2411         struct snd_pcm *pcm;
2412         struct snd_pcm_substream *substream;
2413         struct snd_pcm_oss_file *pcm_oss_file;
2414
2415         pcm_oss_file = file->private_data;
2416         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2417         if (substream == NULL)
2418                 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2419         snd_assert(substream != NULL, return -ENXIO);
2420         pcm = substream->pcm;
2421         if (!pcm->card->shutdown)
2422                 snd_pcm_oss_sync(pcm_oss_file);
2423         mutex_lock(&pcm->open_mutex);
2424         snd_pcm_oss_release_file(pcm_oss_file);
2425         mutex_unlock(&pcm->open_mutex);
2426         wake_up(&pcm->open_wait);
2427         module_put(pcm->card->module);
2428         snd_card_file_remove(pcm->card, file);
2429         return 0;
2430 }
2431
2432 static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2433 {
2434         struct snd_pcm_oss_file *pcm_oss_file;
2435         int __user *p = (int __user *)arg;
2436         int res;
2437
2438         pcm_oss_file = file->private_data;
2439         if (cmd == OSS_GETVERSION)
2440                 return put_user(SNDRV_OSS_VERSION, p);
2441         if (cmd == OSS_ALSAEMULVER)
2442                 return put_user(1, p);
2443 #if defined(CONFIG_SND_MIXER_OSS) || (defined(MODULE) && defined(CONFIG_SND_MIXER_OSS_MODULE))
2444         if (((cmd >> 8) & 0xff) == 'M') {       /* mixer ioctl - for OSS compatibility */
2445                 struct snd_pcm_substream *substream;
2446                 int idx;
2447                 for (idx = 0; idx < 2; ++idx) {
2448                         substream = pcm_oss_file->streams[idx];
2449                         if (substream != NULL)
2450                                 break;
2451                 }
2452                 snd_assert(substream != NULL, return -ENXIO);
2453                 return snd_mixer_oss_ioctl_card(substream->pcm->card, cmd, arg);
2454         }
2455 #endif
2456         if (((cmd >> 8) & 0xff) != 'P')
2457                 return -EINVAL;
2458 #ifdef OSS_DEBUG
2459         printk("pcm_oss: ioctl = 0x%x\n", cmd);
2460 #endif
2461         switch (cmd) {
2462         case SNDCTL_DSP_RESET:
2463                 return snd_pcm_oss_reset(pcm_oss_file);
2464         case SNDCTL_DSP_SYNC:
2465                 return snd_pcm_oss_sync(pcm_oss_file);
2466         case SNDCTL_DSP_SPEED:
2467                 if (get_user(res, p))
2468                         return -EFAULT;
2469                 if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0)
2470                         return res;
2471                 return put_user(res, p);
2472         case SOUND_PCM_READ_RATE:
2473                 res = snd_pcm_oss_get_rate(pcm_oss_file);
2474                 if (res < 0)
2475                         return res;
2476                 return put_user(res, p);
2477         case SNDCTL_DSP_STEREO:
2478                 if (get_user(res, p))
2479                         return -EFAULT;
2480                 res = res > 0 ? 2 : 1;
2481                 if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0)
2482                         return res;
2483                 return put_user(--res, p);
2484         case SNDCTL_DSP_GETBLKSIZE:
2485                 res = snd_pcm_oss_get_block_size(pcm_oss_file);
2486                 if (res < 0)
2487                         return res;
2488                 return put_user(res, p);
2489         case SNDCTL_DSP_SETFMT:
2490                 if (get_user(res, p))
2491                         return -EFAULT;
2492                 res = snd_pcm_oss_set_format(pcm_oss_file, res);
2493                 if (res < 0)
2494                         return res;
2495                 return put_user(res, p);
2496         case SOUND_PCM_READ_BITS:
2497                 res = snd_pcm_oss_get_format(pcm_oss_file);
2498                 if (res < 0)
2499                         return res;
2500                 return put_user(res, p);
2501         case SNDCTL_DSP_CHANNELS:
2502                 if (get_user(res, p))
2503                         return -EFAULT;
2504                 res = snd_pcm_oss_set_channels(pcm_oss_file, res);
2505                 if (res < 0)
2506                         return res;
2507                 return put_user(res, p);
2508         case SOUND_PCM_READ_CHANNELS:
2509                 res = snd_pcm_oss_get_channels(pcm_oss_file);
2510                 if (res < 0)
2511                         return res;
2512                 return put_user(res, p);
2513         case SOUND_PCM_WRITE_FILTER:
2514         case SOUND_PCM_READ_FILTER:
2515                 return -EIO;
2516         case SNDCTL_DSP_POST:
2517                 return snd_pcm_oss_post(pcm_oss_file);
2518         case SNDCTL_DSP_SUBDIVIDE:
2519                 if (get_user(res, p))
2520                         return -EFAULT;
2521                 res = snd_pcm_oss_set_subdivide(pcm_oss_file, res);
2522                 if (res < 0)
2523                         return res;
2524                 return put_user(res, p);
2525         case SNDCTL_DSP_SETFRAGMENT:
2526                 if (get_user(res, p))
2527                         return -EFAULT;
2528                 return snd_pcm_oss_set_fragment(pcm_oss_file, res);
2529         case SNDCTL_DSP_GETFMTS:
2530                 res = snd_pcm_oss_get_formats(pcm_oss_file);
2531                 if (res < 0)
2532                         return res;
2533                 return put_user(res, p);
2534         case SNDCTL_DSP_GETOSPACE:
2535         case SNDCTL_DSP_GETISPACE:
2536                 return snd_pcm_oss_get_space(pcm_oss_file,
2537                         cmd == SNDCTL_DSP_GETISPACE ?
2538                                 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2539                         (struct audio_buf_info __user *) arg);
2540         case SNDCTL_DSP_NONBLOCK:
2541                 return snd_pcm_oss_nonblock(file);
2542         case SNDCTL_DSP_GETCAPS:
2543                 res = snd_pcm_oss_get_caps(pcm_oss_file);
2544                 if (res < 0)
2545                         return res;
2546                 return put_user(res, p);
2547         case SNDCTL_DSP_GETTRIGGER:
2548                 res = snd_pcm_oss_get_trigger(pcm_oss_file);
2549                 if (res < 0)
2550                         return res;
2551                 return put_user(res, p);
2552         case SNDCTL_DSP_SETTRIGGER:
2553                 if (get_user(res, p))
2554                         return -EFAULT;
2555                 return snd_pcm_oss_set_trigger(pcm_oss_file, res);
2556         case SNDCTL_DSP_GETIPTR:
2557         case SNDCTL_DSP_GETOPTR:
2558                 return snd_pcm_oss_get_ptr(pcm_oss_file,
2559                         cmd == SNDCTL_DSP_GETIPTR ?
2560                                 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2561                         (struct count_info __user *) arg);
2562         case SNDCTL_DSP_MAPINBUF:
2563         case SNDCTL_DSP_MAPOUTBUF:
2564                 return snd_pcm_oss_get_mapbuf(pcm_oss_file,
2565                         cmd == SNDCTL_DSP_MAPINBUF ?
2566                                 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2567                         (struct buffmem_desc __user *) arg);
2568         case SNDCTL_DSP_SETSYNCRO:
2569                 /* stop DMA now.. */
2570                 return 0;
2571         case SNDCTL_DSP_SETDUPLEX:
2572                 if (snd_pcm_oss_get_caps(pcm_oss_file) & DSP_CAP_DUPLEX)
2573                         return 0;
2574                 return -EIO;
2575         case SNDCTL_DSP_GETODELAY:
2576                 res = snd_pcm_oss_get_odelay(pcm_oss_file);
2577                 if (res < 0) {
2578                         /* it's for sure, some broken apps don't check for error codes */
2579                         put_user(0, p);
2580                         return res;
2581                 }
2582                 return put_user(res, p);
2583         case SNDCTL_DSP_PROFILE:
2584                 return 0;       /* silently ignore */
2585         default:
2586                 snd_printd("pcm_oss: unknown command = 0x%x\n", cmd);
2587         }
2588         return -EINVAL;
2589 }
2590
2591 #ifdef CONFIG_COMPAT
2592 /* all compatible */
2593 #define snd_pcm_oss_ioctl_compat        snd_pcm_oss_ioctl
2594 #else
2595 #define snd_pcm_oss_ioctl_compat        NULL
2596 #endif
2597
2598 static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
2599 {
2600         struct snd_pcm_oss_file *pcm_oss_file;
2601         struct snd_pcm_substream *substream;
2602
2603         pcm_oss_file = file->private_data;
2604         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2605         if (substream == NULL)
2606                 return -ENXIO;
2607         substream->f_flags = file->f_flags & O_NONBLOCK;
2608 #ifndef OSS_DEBUG
2609         return snd_pcm_oss_read1(substream, buf, count);
2610 #else
2611         {
2612                 ssize_t res = snd_pcm_oss_read1(substream, buf, count);
2613                 printk("pcm_oss: read %li bytes (returned %li bytes)\n", (long)count, (long)res);
2614                 return res;
2615         }
2616 #endif
2617 }
2618
2619 static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
2620 {
2621         struct snd_pcm_oss_file *pcm_oss_file;
2622         struct snd_pcm_substream *substream;
2623         long result;
2624
2625         pcm_oss_file = file->private_data;
2626         substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2627         if (substream == NULL)
2628                 return -ENXIO;
2629         substream->f_flags = file->f_flags & O_NONBLOCK;
2630         result = snd_pcm_oss_write1(substream, buf, count);
2631 #ifdef OSS_DEBUG
2632         printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
2633 #endif
2634         return result;
2635 }
2636
2637 static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
2638 {
2639         struct snd_pcm_runtime *runtime = substream->runtime;
2640         if (atomic_read(&substream->mmap_count))
2641                 return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
2642         else
2643                 return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
2644 }
2645
2646 static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
2647 {
2648         struct snd_pcm_runtime *runtime = substream->runtime;
2649         if (atomic_read(&substream->mmap_count))
2650                 return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
2651         else
2652                 return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
2653 }
2654
2655 static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
2656 {
2657         struct snd_pcm_oss_file *pcm_oss_file;
2658         unsigned int mask;
2659         struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
2660         
2661         pcm_oss_file = file->private_data;
2662
2663         psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2664         csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2665
2666         mask = 0;
2667         if (psubstream != NULL) {
2668                 struct snd_pcm_runtime *runtime = psubstream->runtime;
2669                 poll_wait(file, &runtime->sleep, wait);
2670                 snd_pcm_stream_lock_irq(psubstream);
2671                 if (runtime->status->state != SNDRV_PCM_STATE_DRAINING &&
2672                     (runtime->status->state != SNDRV_PCM_STATE_RUNNING ||
2673                      snd_pcm_oss_playback_ready(psubstream)))
2674                         mask |= POLLOUT | POLLWRNORM;
2675                 snd_pcm_stream_unlock_irq(psubstream);
2676         }
2677         if (csubstream != NULL) {
2678                 struct snd_pcm_runtime *runtime = csubstream->runtime;
2679                 snd_pcm_state_t ostate;
2680                 poll_wait(file, &runtime->sleep, wait);
2681                 snd_pcm_stream_lock_irq(csubstream);
2682                 if ((ostate = runtime->status->state) != SNDRV_PCM_STATE_RUNNING ||
2683                     snd_pcm_oss_capture_ready(csubstream))
2684                         mask |= POLLIN | POLLRDNORM;
2685                 snd_pcm_stream_unlock_irq(csubstream);
2686                 if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
2687                         struct snd_pcm_oss_file ofile;
2688                         memset(&ofile, 0, sizeof(ofile));
2689                         ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2690                         runtime->oss.trigger = 0;
2691                         snd_pcm_oss_set_trigger(&ofile, PCM_ENABLE_INPUT);
2692                 }
2693         }
2694
2695         return mask;
2696 }
2697
2698 static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
2699 {
2700         struct snd_pcm_oss_file *pcm_oss_file;
2701         struct snd_pcm_substream *substream = NULL;
2702         struct snd_pcm_runtime *runtime;
2703         int err;
2704
2705 #ifdef OSS_DEBUG
2706         printk("pcm_oss: mmap begin\n");
2707 #endif
2708         pcm_oss_file = file->private_data;
2709         switch ((area->vm_flags & (VM_READ | VM_WRITE))) {
2710         case VM_READ | VM_WRITE:
2711                 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2712                 if (substream)
2713                         break;
2714                 /* Fall through */
2715         case VM_READ:
2716                 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2717                 break;
2718         case VM_WRITE:
2719                 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2720                 break;
2721         default:
2722                 return -EINVAL;
2723         }
2724         /* set VM_READ access as well to fix memset() routines that do
2725            reads before writes (to improve performance) */
2726         area->vm_flags |= VM_READ;
2727         if (substream == NULL)
2728                 return -ENXIO;
2729         runtime = substream->runtime;
2730         if (!(runtime->info & SNDRV_PCM_INFO_MMAP_VALID))
2731                 return -EIO;
2732         if (runtime->info & SNDRV_PCM_INFO_INTERLEAVED)
2733                 runtime->access = SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;
2734         else
2735                 return -EIO;
2736         
2737         if (runtime->oss.params) {
2738                 if ((err = snd_pcm_oss_change_params(substream)) < 0)
2739                         return err;
2740         }
2741 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
2742         if (runtime->oss.plugin_first != NULL)
2743                 return -EIO;
2744 #endif
2745
2746         if (area->vm_pgoff != 0)
2747                 return -EINVAL;
2748
2749         err = snd_pcm_mmap_data(substream, file, area);
2750         if (err < 0)
2751                 return err;
2752         runtime->oss.mmap_bytes = area->vm_end - area->vm_start;
2753         runtime->silence_threshold = 0;
2754         runtime->silence_size = 0;
2755 #ifdef OSS_DEBUG
2756         printk("pcm_oss: mmap ok, bytes = 0x%x\n", runtime->oss.mmap_bytes);
2757 #endif
2758         /* In mmap mode we never stop */
2759         runtime->stop_threshold = runtime->boundary;
2760
2761         return 0;
2762 }
2763
2764 #ifdef CONFIG_SND_VERBOSE_PROCFS
2765 /*
2766  *  /proc interface
2767  */
2768
2769 static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
2770                                   struct snd_info_buffer *buffer)
2771 {
2772         struct snd_pcm_str *pstr = entry->private_data;
2773         struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
2774         mutex_lock(&pstr->oss.setup_mutex);
2775         while (setup) {
2776                 snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
2777                             setup->task_name,
2778                             setup->periods,
2779                             setup->period_size,
2780                             setup->disable ? " disable" : "",
2781                             setup->direct ? " direct" : "",
2782                             setup->block ? " block" : "",
2783                             setup->nonblock ? " non-block" : "",
2784                             setup->partialfrag ? " partial-frag" : "",
2785                             setup->nosilence ? " no-silence" : "");
2786                 setup = setup->next;
2787         }
2788         mutex_unlock(&pstr->oss.setup_mutex);
2789 }
2790
2791 static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
2792 {
2793         struct snd_pcm_oss_setup *setup, *setupn;
2794
2795         for (setup = pstr->oss.setup_list, pstr->oss.setup_list = NULL;
2796              setup; setup = setupn) {
2797                 setupn = setup->next;
2798                 kfree(setup->task_name);
2799                 kfree(setup);
2800         }
2801         pstr->oss.setup_list = NULL;
2802 }
2803
2804 static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
2805                                    struct snd_info_buffer *buffer)
2806 {
2807         struct snd_pcm_str *pstr = entry->private_data;
2808         char line[128], str[32], task_name[32], *ptr;
2809         int idx1;
2810         struct snd_pcm_oss_setup *setup, *setup1, template;
2811
2812         while (!snd_info_get_line(buffer, line, sizeof(line))) {
2813                 mutex_lock(&pstr->oss.setup_mutex);
2814                 memset(&template, 0, sizeof(template));
2815                 ptr = snd_info_get_str(task_name, line, sizeof(task_name));
2816                 if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
2817                         snd_pcm_oss_proc_free_setup_list(pstr);
2818                         mutex_unlock(&pstr->oss.setup_mutex);
2819                         continue;
2820                 }
2821                 for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
2822                         if (!strcmp(setup->task_name, task_name)) {
2823                                 template = *setup;
2824                                 break;
2825                         }
2826                 }
2827                 ptr = snd_info_get_str(str, ptr, sizeof(str));
2828                 template.periods = simple_strtoul(str, NULL, 10);
2829                 ptr = snd_info_get_str(str, ptr, sizeof(str));
2830                 template.period_size = simple_strtoul(str, NULL, 10);
2831                 for (idx1 = 31; idx1 >= 0; idx1--)
2832                         if (template.period_size & (1 << idx1))
2833                                 break;
2834                 for (idx1--; idx1 >= 0; idx1--)
2835                         template.period_size &= ~(1 << idx1);
2836                 do {
2837                         ptr = snd_info_get_str(str, ptr, sizeof(str));
2838                         if (!strcmp(str, "disable")) {
2839                                 template.disable = 1;
2840                         } else if (!strcmp(str, "direct")) {
2841                                 template.direct = 1;
2842                         } else if (!strcmp(str, "block")) {
2843                                 template.block = 1;
2844                         } else if (!strcmp(str, "non-block")) {
2845                                 template.nonblock = 1;
2846                         } else if (!strcmp(str, "partial-frag")) {
2847                                 template.partialfrag = 1;
2848                         } else if (!strcmp(str, "no-silence")) {
2849                                 template.nosilence = 1;
2850                         } else if (!strcmp(str, "buggy-ptr")) {
2851                                 template.buggyptr = 1;
2852                         }
2853                 } while (*str);
2854                 if (setup == NULL) {
2855                         setup = kmalloc(sizeof(*setup), GFP_KERNEL);
2856                         if (! setup) {
2857                                 buffer->error = -ENOMEM;
2858                                 mutex_lock(&pstr->oss.setup_mutex);
2859                                 return;
2860                         }
2861                         if (pstr->oss.setup_list == NULL)
2862                                 pstr->oss.setup_list = setup;
2863                         else {
2864                                 for (setup1 = pstr->oss.setup_list;
2865                                      setup1->next; setup1 = setup1->next);
2866                                 setup1->next = setup;
2867                         }
2868                         template.task_name = kstrdup(task_name, GFP_KERNEL);
2869                         if (! template.task_name) {
2870                                 kfree(setup);
2871                                 buffer->error = -ENOMEM;
2872                                 mutex_lock(&pstr->oss.setup_mutex);
2873                                 return;
2874                         }
2875                 }
2876                 *setup = template;
2877                 mutex_unlock(&pstr->oss.setup_mutex);
2878         }
2879 }
2880
2881 static void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
2882 {
2883         int stream;
2884         for (stream = 0; stream < 2; ++stream) {
2885                 struct snd_info_entry *entry;
2886                 struct snd_pcm_str *pstr = &pcm->streams[stream];
2887                 if (pstr->substream_count == 0)
2888                         continue;
2889                 if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) {
2890                         entry->content = SNDRV_INFO_CONTENT_TEXT;
2891                         entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
2892                         entry->c.text.read = snd_pcm_oss_proc_read;
2893                         entry->c.text.write = snd_pcm_oss_proc_write;
2894                         entry->private_data = pstr;
2895                         if (snd_info_register(entry) < 0) {
2896                                 snd_info_free_entry(entry);
2897                                 entry = NULL;
2898                         }
2899                 }
2900                 pstr->oss.proc_entry = entry;
2901         }
2902 }
2903
2904 static void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
2905 {
2906         int stream;
2907         for (stream = 0; stream < 2; ++stream) {
2908                 struct snd_pcm_str *pstr = &pcm->streams[stream];
2909                 snd_info_free_entry(pstr->oss.proc_entry);
2910                 pstr->oss.proc_entry = NULL;
2911                 snd_pcm_oss_proc_free_setup_list(pstr);
2912         }
2913 }
2914 #else /* !CONFIG_SND_VERBOSE_PROCFS */
2915 #define snd_pcm_oss_proc_init(pcm)
2916 #define snd_pcm_oss_proc_done(pcm)
2917 #endif /* CONFIG_SND_VERBOSE_PROCFS */
2918
2919 /*
2920  *  ENTRY functions
2921  */
2922
2923 static const struct file_operations snd_pcm_oss_f_reg =
2924 {
2925         .owner =        THIS_MODULE,
2926         .read =         snd_pcm_oss_read,
2927         .write =        snd_pcm_oss_write,
2928         .open =         snd_pcm_oss_open,
2929         .release =      snd_pcm_oss_release,
2930         .poll =         snd_pcm_oss_poll,
2931         .unlocked_ioctl =       snd_pcm_oss_ioctl,
2932         .compat_ioctl = snd_pcm_oss_ioctl_compat,
2933         .mmap =         snd_pcm_oss_mmap,
2934 };
2935
2936 static void register_oss_dsp(struct snd_pcm *pcm, int index)
2937 {
2938         char name[128];
2939         sprintf(name, "dsp%i%i", pcm->card->number, pcm->device);
2940         if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
2941                                     pcm->card, index, &snd_pcm_oss_f_reg,
2942                                     pcm, name) < 0) {
2943                 snd_printk(KERN_ERR "unable to register OSS PCM device %i:%i\n",
2944                            pcm->card->number, pcm->device);
2945         }
2946 }
2947
2948 static int snd_pcm_oss_register_minor(struct snd_pcm *pcm)
2949 {
2950         pcm->oss.reg = 0;
2951         if (dsp_map[pcm->card->number] == (int)pcm->device) {
2952                 char name[128];
2953                 int duplex;
2954                 register_oss_dsp(pcm, 0);
2955                 duplex = (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count > 0 && 
2956                               pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count && 
2957                               !(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX));
2958                 sprintf(name, "%s%s", pcm->name, duplex ? " (DUPLEX)" : "");
2959 #ifdef SNDRV_OSS_INFO_DEV_AUDIO
2960                 snd_oss_info_register(SNDRV_OSS_INFO_DEV_AUDIO,
2961                                       pcm->card->number,
2962                                       name);
2963 #endif
2964                 pcm->oss.reg++;
2965                 pcm->oss.reg_mask |= 1;
2966         }
2967         if (adsp_map[pcm->card->number] == (int)pcm->device) {
2968                 register_oss_dsp(pcm, 1);
2969                 pcm->oss.reg++;
2970                 pcm->oss.reg_mask |= 2;
2971         }
2972
2973         if (pcm->oss.reg)
2974                 snd_pcm_oss_proc_init(pcm);
2975
2976         return 0;
2977 }
2978
2979 static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm)
2980 {
2981         if (pcm->oss.reg) {
2982                 if (pcm->oss.reg_mask & 1) {
2983                         pcm->oss.reg_mask &= ~1;
2984                         snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
2985                                                   pcm->card, 0);
2986                 }
2987                 if (pcm->oss.reg_mask & 2) {
2988                         pcm->oss.reg_mask &= ~2;
2989                         snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
2990                                                   pcm->card, 1);
2991                 }
2992                 if (dsp_map[pcm->card->number] == (int)pcm->device) {
2993 #ifdef SNDRV_OSS_INFO_DEV_AUDIO
2994                         snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
2995 #endif
2996                 }
2997                 pcm->oss.reg = 0;
2998         }
2999         return 0;
3000 }
3001
3002 static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
3003 {
3004         snd_pcm_oss_disconnect_minor(pcm);
3005         snd_pcm_oss_proc_done(pcm);
3006         return 0;
3007 }
3008
3009 static struct snd_pcm_notify snd_pcm_oss_notify =
3010 {
3011         .n_register =   snd_pcm_oss_register_minor,
3012         .n_disconnect = snd_pcm_oss_disconnect_minor,
3013         .n_unregister = snd_pcm_oss_unregister_minor,
3014 };
3015
3016 static int __init alsa_pcm_oss_init(void)
3017 {
3018         int i;
3019         int err;
3020
3021         /* check device map table */
3022         for (i = 0; i < SNDRV_CARDS; i++) {
3023                 if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) {
3024                         snd_printk(KERN_ERR "invalid dsp_map[%d] = %d\n",
3025                                    i, dsp_map[i]);
3026                         dsp_map[i] = 0;
3027                 }
3028                 if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_PCM_DEVICES) {
3029                         snd_printk(KERN_ERR "invalid adsp_map[%d] = %d\n",
3030                                    i, adsp_map[i]);
3031                         adsp_map[i] = 1;
3032                 }
3033         }
3034         if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0)
3035                 return err;
3036         return 0;
3037 }
3038
3039 static void __exit alsa_pcm_oss_exit(void)
3040 {
3041         snd_pcm_notify(&snd_pcm_oss_notify, 1);
3042 }
3043
3044 module_init(alsa_pcm_oss_init)
3045 module_exit(alsa_pcm_oss_exit)