OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [sound/] [core/] [oss/] [pcm_oss.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
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
        sw_params->xfer_align = 1;
992
        if (atomic_read(&substream->mmap_count) ||
993
            substream->oss.setup.nosilence) {
994
                sw_params->silence_threshold = 0;
995
                sw_params->silence_size = 0;
996
        } else {
997
                snd_pcm_uframes_t frames;
998
                frames = runtime->period_size + 16;
999
                if (frames > runtime->buffer_size)
1000
                        frames = runtime->buffer_size;
1001
                sw_params->silence_threshold = frames;
1002
                sw_params->silence_size = frames;
1003
        }
1004
 
1005
        if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
1006
                snd_printd("SW_PARAMS failed: %i\n", err);
1007
                goto failure;
1008
        }
1009
 
1010
        runtime->oss.periods = params_periods(sparams);
1011
        oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
1012
        snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);
1013
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
1014
        if (runtime->oss.plugin_first) {
1015
                err = snd_pcm_plug_alloc(substream, oss_period_size);
1016
                if (err < 0)
1017
                        goto failure;
1018
        }
1019
#endif
1020
        oss_period_size *= oss_frame_size;
1021
 
1022
        oss_buffer_size = oss_period_size * runtime->oss.periods;
1023
        snd_assert(oss_buffer_size >= 0, err = -EINVAL; goto failure);
1024
 
1025
        runtime->oss.period_bytes = oss_period_size;
1026
        runtime->oss.buffer_bytes = oss_buffer_size;
1027
 
1028
        pdprintf("oss: period bytes = %i, buffer bytes = %i\n",
1029
                 runtime->oss.period_bytes,
1030
                 runtime->oss.buffer_bytes);
1031
        pdprintf("slave: period_size = %i, buffer_size = %i\n",
1032
                 params_period_size(sparams),
1033
                 params_buffer_size(sparams));
1034
 
1035
        runtime->oss.format = snd_pcm_oss_format_to(params_format(params));
1036
        runtime->oss.channels = params_channels(params);
1037
        runtime->oss.rate = params_rate(params);
1038
 
1039
        runtime->oss.params = 0;
1040
        runtime->oss.prepare = 1;
1041
        vfree(runtime->oss.buffer);
1042
        runtime->oss.buffer = vmalloc(runtime->oss.period_bytes);
1043
        runtime->oss.buffer_used = 0;
1044
        if (runtime->dma_area)
1045
                snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
1046
 
1047
        runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
1048
 
1049
        err = 0;
1050
failure:
1051
        kfree(sw_params);
1052
        kfree(params);
1053
        kfree(sparams);
1054
        mutex_unlock(&runtime->oss.params_lock);
1055
        return err;
1056
}
1057
 
1058
static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_file, struct snd_pcm_substream **r_substream)
1059
{
1060
        int idx, err;
1061
        struct snd_pcm_substream *asubstream = NULL, *substream;
1062
 
1063
        for (idx = 0; idx < 2; idx++) {
1064
                substream = pcm_oss_file->streams[idx];
1065
                if (substream == NULL)
1066
                        continue;
1067
                if (asubstream == NULL)
1068
                        asubstream = substream;
1069
                if (substream->runtime->oss.params) {
1070
                        err = snd_pcm_oss_change_params(substream);
1071
                        if (err < 0)
1072
                                return err;
1073
                }
1074
        }
1075
        snd_assert(asubstream != NULL, return -EIO);
1076
        if (r_substream)
1077
                *r_substream = asubstream;
1078
        return 0;
1079
}
1080
 
1081
static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
1082
{
1083
        int err;
1084
        struct snd_pcm_runtime *runtime = substream->runtime;
1085
 
1086
        err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
1087
        if (err < 0) {
1088
                snd_printd("snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n");
1089
                return err;
1090
        }
1091
        runtime->oss.prepare = 0;
1092
        runtime->oss.prev_hw_ptr_interrupt = 0;
1093
        runtime->oss.period_ptr = 0;
1094
        runtime->oss.buffer_used = 0;
1095
 
1096
        return 0;
1097
}
1098
 
1099
static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream)
1100
{
1101
        struct snd_pcm_runtime *runtime;
1102
        int err;
1103
 
1104
        if (substream == NULL)
1105
                return 0;
1106
        runtime = substream->runtime;
1107
        if (runtime->oss.params) {
1108
                err = snd_pcm_oss_change_params(substream);
1109
                if (err < 0)
1110
                        return err;
1111
        }
1112
        if (runtime->oss.prepare) {
1113
                err = snd_pcm_oss_prepare(substream);
1114
                if (err < 0)
1115
                        return err;
1116
        }
1117
        return 0;
1118
}
1119
 
1120
static int snd_pcm_oss_capture_position_fixup(struct snd_pcm_substream *substream, snd_pcm_sframes_t *delay)
1121
{
1122
        struct snd_pcm_runtime *runtime;
1123
        snd_pcm_uframes_t frames;
1124
        int err = 0;
1125
 
1126
        while (1) {
1127
                err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, delay);
1128
                if (err < 0)
1129
                        break;
1130
                runtime = substream->runtime;
1131
                if (*delay <= (snd_pcm_sframes_t)runtime->buffer_size)
1132
                        break;
1133
                /* in case of overrun, skip whole periods like OSS/Linux driver does */
1134
                /* until avail(delay) <= buffer_size */
1135
                frames = (*delay - runtime->buffer_size) + runtime->period_size - 1;
1136
                frames /= runtime->period_size;
1137
                frames *= runtime->period_size;
1138
                err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_FORWARD, &frames);
1139
                if (err < 0)
1140
                        break;
1141
        }
1142
        return err;
1143
}
1144
 
1145
snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
1146
{
1147
        struct snd_pcm_runtime *runtime = substream->runtime;
1148
        int ret;
1149
        while (1) {
1150
                if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1151
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1152
#ifdef OSS_DEBUG
1153
                        if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
1154
                                printk("pcm_oss: write: recovering from XRUN\n");
1155
                        else
1156
                                printk("pcm_oss: write: recovering from SUSPEND\n");
1157
#endif
1158
                        ret = snd_pcm_oss_prepare(substream);
1159
                        if (ret < 0)
1160
                                break;
1161
                }
1162
                if (in_kernel) {
1163
                        mm_segment_t fs;
1164
                        fs = snd_enter_user();
1165
                        ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
1166
                        snd_leave_user(fs);
1167
                } else {
1168
                        ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
1169
                }
1170
                if (ret != -EPIPE && ret != -ESTRPIPE)
1171
                        break;
1172
                /* test, if we can't store new data, because the stream */
1173
                /* has not been started */
1174
                if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
1175
                        return -EAGAIN;
1176
        }
1177
        return ret;
1178
}
1179
 
1180
snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
1181
{
1182
        struct snd_pcm_runtime *runtime = substream->runtime;
1183
        snd_pcm_sframes_t delay;
1184
        int ret;
1185
        while (1) {
1186
                if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1187
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1188
#ifdef OSS_DEBUG
1189
                        if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
1190
                                printk("pcm_oss: read: recovering from XRUN\n");
1191
                        else
1192
                                printk("pcm_oss: read: recovering from SUSPEND\n");
1193
#endif
1194
                        ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
1195
                        if (ret < 0)
1196
                                break;
1197
                } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {
1198
                        ret = snd_pcm_oss_prepare(substream);
1199
                        if (ret < 0)
1200
                                break;
1201
                }
1202
                ret = snd_pcm_oss_capture_position_fixup(substream, &delay);
1203
                if (ret < 0)
1204
                        break;
1205
                if (in_kernel) {
1206
                        mm_segment_t fs;
1207
                        fs = snd_enter_user();
1208
                        ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
1209
                        snd_leave_user(fs);
1210
                } else {
1211
                        ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
1212
                }
1213
                if (ret == -EPIPE) {
1214
                        if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
1215
                                ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1216
                                if (ret < 0)
1217
                                        break;
1218
                        }
1219
                        continue;
1220
                }
1221
                if (ret != -ESTRPIPE)
1222
                        break;
1223
        }
1224
        return ret;
1225
}
1226
 
1227
snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
1228
{
1229
        struct snd_pcm_runtime *runtime = substream->runtime;
1230
        int ret;
1231
        while (1) {
1232
                if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1233
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1234
#ifdef OSS_DEBUG
1235
                        if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
1236
                                printk("pcm_oss: writev: recovering from XRUN\n");
1237
                        else
1238
                                printk("pcm_oss: writev: recovering from SUSPEND\n");
1239
#endif
1240
                        ret = snd_pcm_oss_prepare(substream);
1241
                        if (ret < 0)
1242
                                break;
1243
                }
1244
                if (in_kernel) {
1245
                        mm_segment_t fs;
1246
                        fs = snd_enter_user();
1247
                        ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
1248
                        snd_leave_user(fs);
1249
                } else {
1250
                        ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
1251
                }
1252
                if (ret != -EPIPE && ret != -ESTRPIPE)
1253
                        break;
1254
 
1255
                /* test, if we can't store new data, because the stream */
1256
                /* has not been started */
1257
                if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
1258
                        return -EAGAIN;
1259
        }
1260
        return ret;
1261
}
1262
 
1263
snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
1264
{
1265
        struct snd_pcm_runtime *runtime = substream->runtime;
1266
        int ret;
1267
        while (1) {
1268
                if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
1269
                    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1270
#ifdef OSS_DEBUG
1271
                        if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
1272
                                printk("pcm_oss: readv: recovering from XRUN\n");
1273
                        else
1274
                                printk("pcm_oss: readv: recovering from SUSPEND\n");
1275
#endif
1276
                        ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
1277
                        if (ret < 0)
1278
                                break;
1279
                } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {
1280
                        ret = snd_pcm_oss_prepare(substream);
1281
                        if (ret < 0)
1282
                                break;
1283
                }
1284
                if (in_kernel) {
1285
                        mm_segment_t fs;
1286
                        fs = snd_enter_user();
1287
                        ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
1288
                        snd_leave_user(fs);
1289
                } else {
1290
                        ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
1291
                }
1292
                if (ret != -EPIPE && ret != -ESTRPIPE)
1293
                        break;
1294
        }
1295
        return ret;
1296
}
1297
 
1298
static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel)
1299
{
1300
        struct snd_pcm_runtime *runtime = substream->runtime;
1301
        snd_pcm_sframes_t frames, frames1;
1302
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
1303
        if (runtime->oss.plugin_first) {
1304
                struct snd_pcm_plugin_channel *channels;
1305
                size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8;
1306
                if (!in_kernel) {
1307
                        if (copy_from_user(runtime->oss.buffer, (const char __user *)buf, bytes))
1308
                                return -EFAULT;
1309
                        buf = runtime->oss.buffer;
1310
                }
1311
                frames = bytes / oss_frame_bytes;
1312
                frames1 = snd_pcm_plug_client_channels_buf(substream, (char *)buf, frames, &channels);
1313
                if (frames1 < 0)
1314
                        return frames1;
1315
                frames1 = snd_pcm_plug_write_transfer(substream, channels, frames1);
1316
                if (frames1 <= 0)
1317
                        return frames1;
1318
                bytes = frames1 * oss_frame_bytes;
1319
        } else
1320
#endif
1321
        {
1322
                frames = bytes_to_frames(runtime, bytes);
1323
                frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel);
1324
                if (frames1 <= 0)
1325
                        return frames1;
1326
                bytes = frames_to_bytes(runtime, frames1);
1327
        }
1328
        return bytes;
1329
}
1330
 
1331
static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const char __user *buf, size_t bytes)
1332
{
1333
        size_t xfer = 0;
1334
        ssize_t tmp;
1335
        struct snd_pcm_runtime *runtime = substream->runtime;
1336
 
1337
        if (atomic_read(&substream->mmap_count))
1338
                return -ENXIO;
1339
 
1340
        if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
1341
                return tmp;
1342
        mutex_lock(&runtime->oss.params_lock);
1343
        while (bytes > 0) {
1344
                if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
1345
                        tmp = bytes;
1346
                        if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
1347
                                tmp = runtime->oss.period_bytes - runtime->oss.buffer_used;
1348
                        if (tmp > 0) {
1349
                                if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp)) {
1350
                                        tmp = -EFAULT;
1351
                                        goto err;
1352
                                }
1353
                        }
1354
                        runtime->oss.buffer_used += tmp;
1355
                        buf += tmp;
1356
                        bytes -= tmp;
1357
                        xfer += tmp;
1358
                        if (substream->oss.setup.partialfrag ||
1359
                            runtime->oss.buffer_used == runtime->oss.period_bytes) {
1360
                                tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr,
1361
                                                         runtime->oss.buffer_used - runtime->oss.period_ptr, 1);
1362
                                if (tmp <= 0)
1363
                                        goto err;
1364
                                runtime->oss.bytes += tmp;
1365
                                runtime->oss.period_ptr += tmp;
1366
                                runtime->oss.period_ptr %= runtime->oss.period_bytes;
1367
                                if (runtime->oss.period_ptr == 0 ||
1368
                                    runtime->oss.period_ptr == runtime->oss.buffer_used)
1369
                                        runtime->oss.buffer_used = 0;
1370
                                else if ((substream->f_flags & O_NONBLOCK) != 0) {
1371
                                        tmp = -EAGAIN;
1372
                                        goto err;
1373
                                }
1374
                        }
1375
                } else {
1376
                        tmp = snd_pcm_oss_write2(substream,
1377
                                                 (const char __force *)buf,
1378
                                                 runtime->oss.period_bytes, 0);
1379
                        if (tmp <= 0)
1380
                                goto err;
1381
                        runtime->oss.bytes += tmp;
1382
                        buf += tmp;
1383
                        bytes -= tmp;
1384
                        xfer += tmp;
1385
                        if ((substream->f_flags & O_NONBLOCK) != 0 &&
1386
                            tmp != runtime->oss.period_bytes)
1387
                                break;
1388
                }
1389
        }
1390
        mutex_unlock(&runtime->oss.params_lock);
1391
        return xfer;
1392
 
1393
 err:
1394
        mutex_unlock(&runtime->oss.params_lock);
1395
        return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
1396
}
1397
 
1398
static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf, size_t bytes, int in_kernel)
1399
{
1400
        struct snd_pcm_runtime *runtime = substream->runtime;
1401
        snd_pcm_sframes_t frames, frames1;
1402
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
1403
        char __user *final_dst = (char __user *)buf;
1404
        if (runtime->oss.plugin_first) {
1405
                struct snd_pcm_plugin_channel *channels;
1406
                size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8;
1407
                if (!in_kernel)
1408
                        buf = runtime->oss.buffer;
1409
                frames = bytes / oss_frame_bytes;
1410
                frames1 = snd_pcm_plug_client_channels_buf(substream, buf, frames, &channels);
1411
                if (frames1 < 0)
1412
                        return frames1;
1413
                frames1 = snd_pcm_plug_read_transfer(substream, channels, frames1);
1414
                if (frames1 <= 0)
1415
                        return frames1;
1416
                bytes = frames1 * oss_frame_bytes;
1417
                if (!in_kernel && copy_to_user(final_dst, buf, bytes))
1418
                        return -EFAULT;
1419
        } else
1420
#endif
1421
        {
1422
                frames = bytes_to_frames(runtime, bytes);
1423
                frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel);
1424
                if (frames1 <= 0)
1425
                        return frames1;
1426
                bytes = frames_to_bytes(runtime, frames1);
1427
        }
1428
        return bytes;
1429
}
1430
 
1431
static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __user *buf, size_t bytes)
1432
{
1433
        size_t xfer = 0;
1434
        ssize_t tmp;
1435
        struct snd_pcm_runtime *runtime = substream->runtime;
1436
 
1437
        if (atomic_read(&substream->mmap_count))
1438
                return -ENXIO;
1439
 
1440
        if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
1441
                return tmp;
1442
        mutex_lock(&runtime->oss.params_lock);
1443
        while (bytes > 0) {
1444
                if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
1445
                        if (runtime->oss.buffer_used == 0) {
1446
                                tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
1447
                                if (tmp <= 0)
1448
                                        goto err;
1449
                                runtime->oss.bytes += tmp;
1450
                                runtime->oss.period_ptr = tmp;
1451
                                runtime->oss.buffer_used = tmp;
1452
                        }
1453
                        tmp = bytes;
1454
                        if ((size_t) tmp > runtime->oss.buffer_used)
1455
                                tmp = runtime->oss.buffer_used;
1456
                        if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp)) {
1457
                                tmp = -EFAULT;
1458
                                goto err;
1459
                        }
1460
                        buf += tmp;
1461
                        bytes -= tmp;
1462
                        xfer += tmp;
1463
                        runtime->oss.buffer_used -= tmp;
1464
                } else {
1465
                        tmp = snd_pcm_oss_read2(substream, (char __force *)buf,
1466
                                                runtime->oss.period_bytes, 0);
1467
                        if (tmp <= 0)
1468
                                goto err;
1469
                        runtime->oss.bytes += tmp;
1470
                        buf += tmp;
1471
                        bytes -= tmp;
1472
                        xfer += tmp;
1473
                }
1474
        }
1475
        mutex_unlock(&runtime->oss.params_lock);
1476
        return xfer;
1477
 
1478
 err:
1479
        mutex_unlock(&runtime->oss.params_lock);
1480
        return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
1481
}
1482
 
1483
static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file)
1484
{
1485
        struct snd_pcm_substream *substream;
1486
 
1487
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1488
        if (substream != NULL) {
1489
                snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1490
                substream->runtime->oss.prepare = 1;
1491
        }
1492
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
1493
        if (substream != NULL) {
1494
                snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1495
                substream->runtime->oss.prepare = 1;
1496
        }
1497
        return 0;
1498
}
1499
 
1500
static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file)
1501
{
1502
        struct snd_pcm_substream *substream;
1503
        int err;
1504
 
1505
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1506
        if (substream != NULL) {
1507
                if ((err = snd_pcm_oss_make_ready(substream)) < 0)
1508
                        return err;
1509
                snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
1510
        }
1511
        /* note: all errors from the start action are ignored */
1512
        /* OSS apps do not know, how to handle them */
1513
        return 0;
1514
}
1515
 
1516
static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
1517
{
1518
        struct snd_pcm_runtime *runtime;
1519
        ssize_t result = 0;
1520
        long res;
1521
        wait_queue_t wait;
1522
 
1523
        runtime = substream->runtime;
1524
        init_waitqueue_entry(&wait, current);
1525
        add_wait_queue(&runtime->sleep, &wait);
1526
#ifdef OSS_DEBUG
1527
        printk("sync1: size = %li\n", size);
1528
#endif
1529
        while (1) {
1530
                result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1);
1531
                if (result > 0) {
1532
                        runtime->oss.buffer_used = 0;
1533
                        result = 0;
1534
                        break;
1535
                }
1536
                if (result != 0 && result != -EAGAIN)
1537
                        break;
1538
                result = 0;
1539
                set_current_state(TASK_INTERRUPTIBLE);
1540
                snd_pcm_stream_lock_irq(substream);
1541
                res = runtime->status->state;
1542
                snd_pcm_stream_unlock_irq(substream);
1543
                if (res != SNDRV_PCM_STATE_RUNNING) {
1544
                        set_current_state(TASK_RUNNING);
1545
                        break;
1546
                }
1547
                res = schedule_timeout(10 * HZ);
1548
                if (signal_pending(current)) {
1549
                        result = -ERESTARTSYS;
1550
                        break;
1551
                }
1552
                if (res == 0) {
1553
                        snd_printk(KERN_ERR "OSS sync error - DMA timeout\n");
1554
                        result = -EIO;
1555
                        break;
1556
                }
1557
        }
1558
        remove_wait_queue(&runtime->sleep, &wait);
1559
        return result;
1560
}
1561
 
1562
static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
1563
{
1564
        int err = 0;
1565
        unsigned int saved_f_flags;
1566
        struct snd_pcm_substream *substream;
1567
        struct snd_pcm_runtime *runtime;
1568
        snd_pcm_format_t format;
1569
        unsigned long width;
1570
        size_t size;
1571
 
1572
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1573
        if (substream != NULL) {
1574
                runtime = substream->runtime;
1575
                if (atomic_read(&substream->mmap_count))
1576
                        goto __direct;
1577
                if ((err = snd_pcm_oss_make_ready(substream)) < 0)
1578
                        return err;
1579
                format = snd_pcm_oss_format_from(runtime->oss.format);
1580
                width = snd_pcm_format_physical_width(format);
1581
                mutex_lock(&runtime->oss.params_lock);
1582
                if (runtime->oss.buffer_used > 0) {
1583
#ifdef OSS_DEBUG
1584
                        printk("sync: buffer_used\n");
1585
#endif
1586
                        size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;
1587
                        snd_pcm_format_set_silence(format,
1588
                                                   runtime->oss.buffer + runtime->oss.buffer_used,
1589
                                                   size);
1590
                        err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
1591
                        if (err < 0) {
1592
                                mutex_unlock(&runtime->oss.params_lock);
1593
                                return err;
1594
                        }
1595
                } else if (runtime->oss.period_ptr > 0) {
1596
#ifdef OSS_DEBUG
1597
                        printk("sync: period_ptr\n");
1598
#endif
1599
                        size = runtime->oss.period_bytes - runtime->oss.period_ptr;
1600
                        snd_pcm_format_set_silence(format,
1601
                                                   runtime->oss.buffer,
1602
                                                   size * 8 / width);
1603
                        err = snd_pcm_oss_sync1(substream, size);
1604
                        if (err < 0) {
1605
                                mutex_unlock(&runtime->oss.params_lock);
1606
                                return err;
1607
                        }
1608
                }
1609
                /*
1610
                 * The ALSA's period might be a bit large than OSS one.
1611
                 * Fill the remain portion of ALSA period with zeros.
1612
                 */
1613
                size = runtime->control->appl_ptr % runtime->period_size;
1614
                if (size > 0) {
1615
                        size = runtime->period_size - size;
1616
                        if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
1617
                                size = (runtime->frame_bits * size) / 8;
1618
                                while (size > 0) {
1619
                                        mm_segment_t fs;
1620
                                        size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes;
1621
                                        size -= size1;
1622
                                        size1 *= 8;
1623
                                        size1 /= runtime->sample_bits;
1624
                                        snd_pcm_format_set_silence(runtime->format,
1625
                                                                   runtime->oss.buffer,
1626
                                                                   size1);
1627
                                        fs = snd_enter_user();
1628
                                        snd_pcm_lib_write(substream, (void __user *)runtime->oss.buffer, size1);
1629
                                        snd_leave_user(fs);
1630
                                }
1631
                        } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
1632
                                void __user *buffers[runtime->channels];
1633
                                memset(buffers, 0, runtime->channels * sizeof(void *));
1634
                                snd_pcm_lib_writev(substream, buffers, size);
1635
                        }
1636
                }
1637
                mutex_unlock(&runtime->oss.params_lock);
1638
                /*
1639
                 * finish sync: drain the buffer
1640
                 */
1641
              __direct:
1642
                saved_f_flags = substream->f_flags;
1643
                substream->f_flags &= ~O_NONBLOCK;
1644
                err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
1645
                substream->f_flags = saved_f_flags;
1646
                if (err < 0)
1647
                        return err;
1648
                runtime->oss.prepare = 1;
1649
        }
1650
 
1651
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
1652
        if (substream != NULL) {
1653
                if ((err = snd_pcm_oss_make_ready(substream)) < 0)
1654
                        return err;
1655
                runtime = substream->runtime;
1656
                err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1657
                if (err < 0)
1658
                        return err;
1659
                runtime->oss.buffer_used = 0;
1660
                runtime->oss.prepare = 1;
1661
        }
1662
        return 0;
1663
}
1664
 
1665
static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate)
1666
{
1667
        int idx;
1668
 
1669
        for (idx = 1; idx >= 0; --idx) {
1670
                struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1671
                struct snd_pcm_runtime *runtime;
1672
                if (substream == NULL)
1673
                        continue;
1674
                runtime = substream->runtime;
1675
                if (rate < 1000)
1676
                        rate = 1000;
1677
                else if (rate > 192000)
1678
                        rate = 192000;
1679
                if (runtime->oss.rate != rate) {
1680
                        runtime->oss.params = 1;
1681
                        runtime->oss.rate = rate;
1682
                }
1683
        }
1684
        return snd_pcm_oss_get_rate(pcm_oss_file);
1685
}
1686
 
1687
static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file)
1688
{
1689
        struct snd_pcm_substream *substream;
1690
        int err;
1691
 
1692
        if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1693
                return err;
1694
        return substream->runtime->oss.rate;
1695
}
1696
 
1697
static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsigned int channels)
1698
{
1699
        int idx;
1700
        if (channels < 1)
1701
                channels = 1;
1702
        if (channels > 128)
1703
                return -EINVAL;
1704
        for (idx = 1; idx >= 0; --idx) {
1705
                struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1706
                struct snd_pcm_runtime *runtime;
1707
                if (substream == NULL)
1708
                        continue;
1709
                runtime = substream->runtime;
1710
                if (runtime->oss.channels != channels) {
1711
                        runtime->oss.params = 1;
1712
                        runtime->oss.channels = channels;
1713
                }
1714
        }
1715
        return snd_pcm_oss_get_channels(pcm_oss_file);
1716
}
1717
 
1718
static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file)
1719
{
1720
        struct snd_pcm_substream *substream;
1721
        int err;
1722
 
1723
        if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1724
                return err;
1725
        return substream->runtime->oss.channels;
1726
}
1727
 
1728
static int snd_pcm_oss_get_block_size(struct snd_pcm_oss_file *pcm_oss_file)
1729
{
1730
        struct snd_pcm_substream *substream;
1731
        int err;
1732
 
1733
        if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1734
                return err;
1735
        return substream->runtime->oss.period_bytes;
1736
}
1737
 
1738
static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
1739
{
1740
        struct snd_pcm_substream *substream;
1741
        int err;
1742
        int direct;
1743
        struct snd_pcm_hw_params *params;
1744
        unsigned int formats = 0;
1745
        struct snd_mask format_mask;
1746
        int fmt;
1747
 
1748
        if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1749
                return err;
1750
        if (atomic_read(&substream->mmap_count))
1751
                direct = 1;
1752
        else
1753
                direct = substream->oss.setup.direct;
1754
        if (!direct)
1755
                return AFMT_MU_LAW | AFMT_U8 |
1756
                       AFMT_S16_LE | AFMT_S16_BE |
1757
                       AFMT_S8 | AFMT_U16_LE |
1758
                       AFMT_U16_BE |
1759
                        AFMT_S32_LE | AFMT_S32_BE |
1760
                        AFMT_S24_LE | AFMT_S24_LE |
1761
                        AFMT_S24_PACKED;
1762
        params = kmalloc(sizeof(*params), GFP_KERNEL);
1763
        if (!params)
1764
                return -ENOMEM;
1765
        _snd_pcm_hw_params_any(params);
1766
        err = snd_pcm_hw_refine(substream, params);
1767
        format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
1768
        kfree(params);
1769
        snd_assert(err >= 0, return err);
1770
        for (fmt = 0; fmt < 32; ++fmt) {
1771
                if (snd_mask_test(&format_mask, fmt)) {
1772
                        int f = snd_pcm_oss_format_to(fmt);
1773
                        if (f >= 0)
1774
                                formats |= f;
1775
                }
1776
        }
1777
        return formats;
1778
}
1779
 
1780
static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
1781
{
1782
        int formats, idx;
1783
 
1784
        if (format != AFMT_QUERY) {
1785
                formats = snd_pcm_oss_get_formats(pcm_oss_file);
1786
                if (formats < 0)
1787
                        return formats;
1788
                if (!(formats & format))
1789
                        format = AFMT_U8;
1790
                for (idx = 1; idx >= 0; --idx) {
1791
                        struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1792
                        struct snd_pcm_runtime *runtime;
1793
                        if (substream == NULL)
1794
                                continue;
1795
                        runtime = substream->runtime;
1796
                        if (runtime->oss.format != format) {
1797
                                runtime->oss.params = 1;
1798
                                runtime->oss.format = format;
1799
                        }
1800
                }
1801
        }
1802
        return snd_pcm_oss_get_format(pcm_oss_file);
1803
}
1804
 
1805
static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file)
1806
{
1807
        struct snd_pcm_substream *substream;
1808
        int err;
1809
 
1810
        if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1811
                return err;
1812
        return substream->runtime->oss.format;
1813
}
1814
 
1815
static int snd_pcm_oss_set_subdivide1(struct snd_pcm_substream *substream, int subdivide)
1816
{
1817
        struct snd_pcm_runtime *runtime;
1818
 
1819
        if (substream == NULL)
1820
                return 0;
1821
        runtime = substream->runtime;
1822
        if (subdivide == 0) {
1823
                subdivide = runtime->oss.subdivision;
1824
                if (subdivide == 0)
1825
                        subdivide = 1;
1826
                return subdivide;
1827
        }
1828
        if (runtime->oss.subdivision || runtime->oss.fragshift)
1829
                return -EINVAL;
1830
        if (subdivide != 1 && subdivide != 2 && subdivide != 4 &&
1831
            subdivide != 8 && subdivide != 16)
1832
                return -EINVAL;
1833
        runtime->oss.subdivision = subdivide;
1834
        runtime->oss.params = 1;
1835
        return subdivide;
1836
}
1837
 
1838
static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int subdivide)
1839
{
1840
        int err = -EINVAL, idx;
1841
 
1842
        for (idx = 1; idx >= 0; --idx) {
1843
                struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1844
                if (substream == NULL)
1845
                        continue;
1846
                if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0)
1847
                        return err;
1848
        }
1849
        return err;
1850
}
1851
 
1852
static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsigned int val)
1853
{
1854
        struct snd_pcm_runtime *runtime;
1855
 
1856
        if (substream == NULL)
1857
                return 0;
1858
        runtime = substream->runtime;
1859
        if (runtime->oss.subdivision || runtime->oss.fragshift)
1860
                return -EINVAL;
1861
        runtime->oss.fragshift = val & 0xffff;
1862
        runtime->oss.maxfrags = (val >> 16) & 0xffff;
1863
        if (runtime->oss.fragshift < 4)         /* < 16 */
1864
                runtime->oss.fragshift = 4;
1865
        if (runtime->oss.maxfrags < 2)
1866
                runtime->oss.maxfrags = 2;
1867
        runtime->oss.params = 1;
1868
        return 0;
1869
}
1870
 
1871
static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsigned int val)
1872
{
1873
        int err = -EINVAL, idx;
1874
 
1875
        for (idx = 1; idx >= 0; --idx) {
1876
                struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1877
                if (substream == NULL)
1878
                        continue;
1879
                if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0)
1880
                        return err;
1881
        }
1882
        return err;
1883
}
1884
 
1885
static int snd_pcm_oss_nonblock(struct file * file)
1886
{
1887
        file->f_flags |= O_NONBLOCK;
1888
        return 0;
1889
}
1890
 
1891
static int snd_pcm_oss_get_caps1(struct snd_pcm_substream *substream, int res)
1892
{
1893
 
1894
        if (substream == NULL) {
1895
                res &= ~DSP_CAP_DUPLEX;
1896
                return res;
1897
        }
1898
#ifdef DSP_CAP_MULTI
1899
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1900
                if (substream->pstr->substream_count > 1)
1901
                        res |= DSP_CAP_MULTI;
1902
#endif
1903
        /* DSP_CAP_REALTIME is set all times: */
1904
        /* all ALSA drivers can return actual pointer in ring buffer */
1905
#if defined(DSP_CAP_REALTIME) && 0
1906
        {
1907
                struct snd_pcm_runtime *runtime = substream->runtime;
1908
                if (runtime->info & (SNDRV_PCM_INFO_BLOCK_TRANSFER|SNDRV_PCM_INFO_BATCH))
1909
                        res &= ~DSP_CAP_REALTIME;
1910
        }
1911
#endif
1912
        return res;
1913
}
1914
 
1915
static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file)
1916
{
1917
        int result, idx;
1918
 
1919
        result = DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_DUPLEX | DSP_CAP_REALTIME;
1920
        for (idx = 0; idx < 2; idx++) {
1921
                struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
1922
                result = snd_pcm_oss_get_caps1(substream, result);
1923
        }
1924
        result |= 0x0001;       /* revision - same as SB AWE 64 */
1925
        return result;
1926
}
1927
 
1928
static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr)
1929
{
1930
        struct snd_pcm_runtime *runtime = substream->runtime;
1931
        snd_pcm_uframes_t appl_ptr;
1932
        appl_ptr = hw_ptr + runtime->buffer_size;
1933
        appl_ptr %= runtime->boundary;
1934
        runtime->control->appl_ptr = appl_ptr;
1935
}
1936
 
1937
static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int trigger)
1938
{
1939
        struct snd_pcm_runtime *runtime;
1940
        struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
1941
        int err, cmd;
1942
 
1943
#ifdef OSS_DEBUG
1944
        printk("pcm_oss: trigger = 0x%x\n", trigger);
1945
#endif
1946
 
1947
        psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1948
        csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
1949
 
1950
        if (psubstream) {
1951
                if ((err = snd_pcm_oss_make_ready(psubstream)) < 0)
1952
                        return err;
1953
        }
1954
        if (csubstream) {
1955
                if ((err = snd_pcm_oss_make_ready(csubstream)) < 0)
1956
                        return err;
1957
        }
1958
        if (psubstream) {
1959
                runtime = psubstream->runtime;
1960
                if (trigger & PCM_ENABLE_OUTPUT) {
1961
                        if (runtime->oss.trigger)
1962
                                goto _skip1;
1963
                        if (atomic_read(&psubstream->mmap_count))
1964
                                snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
1965
                        runtime->oss.trigger = 1;
1966
                        runtime->start_threshold = 1;
1967
                        cmd = SNDRV_PCM_IOCTL_START;
1968
                } else {
1969
                        if (!runtime->oss.trigger)
1970
                                goto _skip1;
1971
                        runtime->oss.trigger = 0;
1972
                        runtime->start_threshold = runtime->boundary;
1973
                        cmd = SNDRV_PCM_IOCTL_DROP;
1974
                        runtime->oss.prepare = 1;
1975
                }
1976
                err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
1977
                if (err < 0)
1978
                        return err;
1979
        }
1980
 _skip1:
1981
        if (csubstream) {
1982
                runtime = csubstream->runtime;
1983
                if (trigger & PCM_ENABLE_INPUT) {
1984
                        if (runtime->oss.trigger)
1985
                                goto _skip2;
1986
                        runtime->oss.trigger = 1;
1987
                        runtime->start_threshold = 1;
1988
                        cmd = SNDRV_PCM_IOCTL_START;
1989
                } else {
1990
                        if (!runtime->oss.trigger)
1991
                                goto _skip2;
1992
                        runtime->oss.trigger = 0;
1993
                        runtime->start_threshold = runtime->boundary;
1994
                        cmd = SNDRV_PCM_IOCTL_DROP;
1995
                        runtime->oss.prepare = 1;
1996
                }
1997
                err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
1998
                if (err < 0)
1999
                        return err;
2000
        }
2001
 _skip2:
2002
        return 0;
2003
}
2004
 
2005
static int snd_pcm_oss_get_trigger(struct snd_pcm_oss_file *pcm_oss_file)
2006
{
2007
        struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
2008
        int result = 0;
2009
 
2010
        psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2011
        csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2012
        if (psubstream && psubstream->runtime && psubstream->runtime->oss.trigger)
2013
                result |= PCM_ENABLE_OUTPUT;
2014
        if (csubstream && csubstream->runtime && csubstream->runtime->oss.trigger)
2015
                result |= PCM_ENABLE_INPUT;
2016
        return result;
2017
}
2018
 
2019
static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file)
2020
{
2021
        struct snd_pcm_substream *substream;
2022
        struct snd_pcm_runtime *runtime;
2023
        snd_pcm_sframes_t delay;
2024
        int err;
2025
 
2026
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2027
        if (substream == NULL)
2028
                return -EINVAL;
2029
        if ((err = snd_pcm_oss_make_ready(substream)) < 0)
2030
                return err;
2031
        runtime = substream->runtime;
2032
        if (runtime->oss.params || runtime->oss.prepare)
2033
                return 0;
2034
        err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
2035
        if (err == -EPIPE)
2036
                delay = 0;       /* hack for broken OSS applications */
2037
        else if (err < 0)
2038
                return err;
2039
        return snd_pcm_oss_bytes(substream, delay);
2040
}
2041
 
2042
static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct count_info __user * _info)
2043
{
2044
        struct snd_pcm_substream *substream;
2045
        struct snd_pcm_runtime *runtime;
2046
        snd_pcm_sframes_t delay;
2047
        int fixup;
2048
        struct count_info info;
2049
        int err;
2050
 
2051
        if (_info == NULL)
2052
                return -EFAULT;
2053
        substream = pcm_oss_file->streams[stream];
2054
        if (substream == NULL)
2055
                return -EINVAL;
2056
        if ((err = snd_pcm_oss_make_ready(substream)) < 0)
2057
                return err;
2058
        runtime = substream->runtime;
2059
        if (runtime->oss.params || runtime->oss.prepare) {
2060
                memset(&info, 0, sizeof(info));
2061
                if (copy_to_user(_info, &info, sizeof(info)))
2062
                        return -EFAULT;
2063
                return 0;
2064
        }
2065
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2066
                err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
2067
                if (err == -EPIPE || err == -ESTRPIPE || (! err && delay < 0)) {
2068
                        err = 0;
2069
                        delay = 0;
2070
                        fixup = 0;
2071
                } else {
2072
                        fixup = runtime->oss.buffer_used;
2073
                }
2074
        } else {
2075
                err = snd_pcm_oss_capture_position_fixup(substream, &delay);
2076
                fixup = -runtime->oss.buffer_used;
2077
        }
2078
        if (err < 0)
2079
                return err;
2080
        info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
2081
        if (atomic_read(&substream->mmap_count)) {
2082
                snd_pcm_sframes_t n;
2083
                n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
2084
                if (n < 0)
2085
                        n += runtime->boundary;
2086
                info.blocks = n / runtime->period_size;
2087
                runtime->oss.prev_hw_ptr_interrupt = delay;
2088
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
2089
                        snd_pcm_oss_simulate_fill(substream, delay);
2090
                info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
2091
        } else {
2092
                delay = snd_pcm_oss_bytes(substream, delay);
2093
                if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2094
                        if (substream->oss.setup.buggyptr)
2095
                                info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes;
2096
                        else
2097
                                info.blocks = (delay + fixup) / runtime->oss.period_bytes;
2098
                        info.bytes = (runtime->oss.bytes - delay) & INT_MAX;
2099
                } else {
2100
                        delay += fixup;
2101
                        info.blocks = delay / runtime->oss.period_bytes;
2102
                        info.bytes = (runtime->oss.bytes + delay) & INT_MAX;
2103
                }
2104
        }
2105
        if (copy_to_user(_info, &info, sizeof(info)))
2106
                return -EFAULT;
2107
        return 0;
2108
}
2109
 
2110
static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct audio_buf_info __user *_info)
2111
{
2112
        struct snd_pcm_substream *substream;
2113
        struct snd_pcm_runtime *runtime;
2114
        snd_pcm_sframes_t avail;
2115
        int fixup;
2116
        struct audio_buf_info info;
2117
        int err;
2118
 
2119
        if (_info == NULL)
2120
                return -EFAULT;
2121
        substream = pcm_oss_file->streams[stream];
2122
        if (substream == NULL)
2123
                return -EINVAL;
2124
        runtime = substream->runtime;
2125
 
2126
        if (runtime->oss.params &&
2127
            (err = snd_pcm_oss_change_params(substream)) < 0)
2128
                return err;
2129
 
2130
        info.fragsize = runtime->oss.period_bytes;
2131
        info.fragstotal = runtime->periods;
2132
        if (runtime->oss.prepare) {
2133
                if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2134
                        info.bytes = runtime->oss.period_bytes * runtime->oss.periods;
2135
                        info.fragments = runtime->oss.periods;
2136
                } else {
2137
                        info.bytes = 0;
2138
                        info.fragments = 0;
2139
                }
2140
        } else {
2141
                if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
2142
                        err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &avail);
2143
                        if (err == -EPIPE || err == -ESTRPIPE || (! err && avail < 0)) {
2144
                                avail = runtime->buffer_size;
2145
                                err = 0;
2146
                                fixup = 0;
2147
                        } else {
2148
                                avail = runtime->buffer_size - avail;
2149
                                fixup = -runtime->oss.buffer_used;
2150
                        }
2151
                } else {
2152
                        err = snd_pcm_oss_capture_position_fixup(substream, &avail);
2153
                        fixup = runtime->oss.buffer_used;
2154
                }
2155
                if (err < 0)
2156
                        return err;
2157
                info.bytes = snd_pcm_oss_bytes(substream, avail) + fixup;
2158
                info.fragments = info.bytes / runtime->oss.period_bytes;
2159
        }
2160
 
2161
#ifdef OSS_DEBUG
2162
        printk("pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.fragments, info.fragstotal, info.fragsize);
2163
#endif
2164
        if (copy_to_user(_info, &info, sizeof(info)))
2165
                return -EFAULT;
2166
        return 0;
2167
}
2168
 
2169
static int snd_pcm_oss_get_mapbuf(struct snd_pcm_oss_file *pcm_oss_file, int stream, struct buffmem_desc __user * _info)
2170
{
2171
        // it won't be probably implemented
2172
        // snd_printd("TODO: snd_pcm_oss_get_mapbuf\n");
2173
        return -EINVAL;
2174
}
2175
 
2176
static const char *strip_task_path(const char *path)
2177
{
2178
        const char *ptr, *ptrl = NULL;
2179
        for (ptr = path; *ptr; ptr++) {
2180
                if (*ptr == '/')
2181
                        ptrl = ptr + 1;
2182
        }
2183
        return ptrl;
2184
}
2185
 
2186
static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream,
2187
                                      const char *task_name,
2188
                                      struct snd_pcm_oss_setup *rsetup)
2189
{
2190
        struct snd_pcm_oss_setup *setup;
2191
 
2192
        mutex_lock(&pcm->streams[stream].oss.setup_mutex);
2193
        do {
2194
                for (setup = pcm->streams[stream].oss.setup_list; setup;
2195
                     setup = setup->next) {
2196
                        if (!strcmp(setup->task_name, task_name))
2197
                                goto out;
2198
                }
2199
        } while ((task_name = strip_task_path(task_name)) != NULL);
2200
 out:
2201
        if (setup)
2202
                *rsetup = *setup;
2203
        mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
2204
}
2205
 
2206
static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
2207
{
2208
        struct snd_pcm_runtime *runtime;
2209
        runtime = substream->runtime;
2210
        vfree(runtime->oss.buffer);
2211
        runtime->oss.buffer = NULL;
2212
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
2213
        snd_pcm_oss_plugin_clear(substream);
2214
#endif
2215
        substream->oss.oss = 0;
2216
}
2217
 
2218
static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
2219
                                       struct snd_pcm_oss_setup *setup,
2220
                                       int minor)
2221
{
2222
        struct snd_pcm_runtime *runtime;
2223
 
2224
        substream->oss.oss = 1;
2225
        substream->oss.setup = *setup;
2226
        if (setup->nonblock)
2227
                substream->f_flags |= O_NONBLOCK;
2228
        else if (setup->block)
2229
                substream->f_flags &= ~O_NONBLOCK;
2230
        runtime = substream->runtime;
2231
        runtime->oss.params = 1;
2232
        runtime->oss.trigger = 1;
2233
        runtime->oss.rate = 8000;
2234
        mutex_init(&runtime->oss.params_lock);
2235
        switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
2236
        case SNDRV_MINOR_OSS_PCM_8:
2237
                runtime->oss.format = AFMT_U8;
2238
                break;
2239
        case SNDRV_MINOR_OSS_PCM_16:
2240
                runtime->oss.format = AFMT_S16_LE;
2241
                break;
2242
        default:
2243
                runtime->oss.format = AFMT_MU_LAW;
2244
        }
2245
        runtime->oss.channels = 1;
2246
        runtime->oss.fragshift = 0;
2247
        runtime->oss.maxfrags = 0;
2248
        runtime->oss.subdivision = 0;
2249
        substream->pcm_release = snd_pcm_oss_release_substream;
2250
}
2251
 
2252
static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
2253
{
2254
        int cidx;
2255
        snd_assert(pcm_oss_file != NULL, return -ENXIO);
2256
        for (cidx = 0; cidx < 2; ++cidx) {
2257
                struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx];
2258
                if (substream)
2259
                        snd_pcm_release_substream(substream);
2260
        }
2261
        kfree(pcm_oss_file);
2262
        return 0;
2263
}
2264
 
2265
static int snd_pcm_oss_open_file(struct file *file,
2266
                                 struct snd_pcm *pcm,
2267
                                 struct snd_pcm_oss_file **rpcm_oss_file,
2268
                                 int minor,
2269
                                 struct snd_pcm_oss_setup *setup)
2270
{
2271
        int idx, err;
2272
        struct snd_pcm_oss_file *pcm_oss_file;
2273
        struct snd_pcm_substream *substream;
2274
        unsigned int f_mode = file->f_mode;
2275
 
2276
        snd_assert(rpcm_oss_file != NULL, return -EINVAL);
2277
        *rpcm_oss_file = NULL;
2278
 
2279
        pcm_oss_file = kzalloc(sizeof(*pcm_oss_file), GFP_KERNEL);
2280
        if (pcm_oss_file == NULL)
2281
                return -ENOMEM;
2282
 
2283
        if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) &&
2284
            (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
2285
                f_mode = FMODE_WRITE;
2286
 
2287
        file->f_flags &= ~O_APPEND;
2288
        for (idx = 0; idx < 2; idx++) {
2289
                if (setup[idx].disable)
2290
                        continue;
2291
                if (! pcm->streams[idx].substream_count)
2292
                        continue; /* no matching substream */
2293
                if (idx == SNDRV_PCM_STREAM_PLAYBACK) {
2294
                        if (! (f_mode & FMODE_WRITE))
2295
                                continue;
2296
                } else {
2297
                        if (! (f_mode & FMODE_READ))
2298
                                continue;
2299
                }
2300
                err = snd_pcm_open_substream(pcm, idx, file, &substream);
2301
                if (err < 0) {
2302
                        snd_pcm_oss_release_file(pcm_oss_file);
2303
                        return err;
2304
                }
2305
 
2306
                pcm_oss_file->streams[idx] = substream;
2307
                substream->file = pcm_oss_file;
2308
                snd_pcm_oss_init_substream(substream, &setup[idx], minor);
2309
        }
2310
 
2311
        if (!pcm_oss_file->streams[0] && !pcm_oss_file->streams[1]) {
2312
                snd_pcm_oss_release_file(pcm_oss_file);
2313
                return -EINVAL;
2314
        }
2315
 
2316
        file->private_data = pcm_oss_file;
2317
        *rpcm_oss_file = pcm_oss_file;
2318
        return 0;
2319
}
2320
 
2321
 
2322
static int snd_task_name(struct task_struct *task, char *name, size_t size)
2323
{
2324
        unsigned int idx;
2325
 
2326
        snd_assert(task != NULL && name != NULL && size >= 2, return -EINVAL);
2327
        for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++)
2328
                name[idx] = task->comm[idx];
2329
        name[idx] = '\0';
2330
        return 0;
2331
}
2332
 
2333
static int snd_pcm_oss_open(struct inode *inode, struct file *file)
2334
{
2335
        int err;
2336
        char task_name[32];
2337
        struct snd_pcm *pcm;
2338
        struct snd_pcm_oss_file *pcm_oss_file;
2339
        struct snd_pcm_oss_setup setup[2];
2340
        int nonblock;
2341
        wait_queue_t wait;
2342
 
2343
        pcm = snd_lookup_oss_minor_data(iminor(inode),
2344
                                        SNDRV_OSS_DEVICE_TYPE_PCM);
2345
        if (pcm == NULL) {
2346
                err = -ENODEV;
2347
                goto __error1;
2348
        }
2349
        err = snd_card_file_add(pcm->card, file);
2350
        if (err < 0)
2351
                goto __error1;
2352
        if (!try_module_get(pcm->card->module)) {
2353
                err = -EFAULT;
2354
                goto __error2;
2355
        }
2356
        if (snd_task_name(current, task_name, sizeof(task_name)) < 0) {
2357
                err = -EFAULT;
2358
                goto __error;
2359
        }
2360
        memset(setup, 0, sizeof(setup));
2361
        if (file->f_mode & FMODE_WRITE)
2362
                snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK,
2363
                                           task_name, &setup[0]);
2364
        if (file->f_mode & FMODE_READ)
2365
                snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE,
2366
                                           task_name, &setup[1]);
2367
 
2368
        nonblock = !!(file->f_flags & O_NONBLOCK);
2369
        if (!nonblock)
2370
                nonblock = nonblock_open;
2371
 
2372
        init_waitqueue_entry(&wait, current);
2373
        add_wait_queue(&pcm->open_wait, &wait);
2374
        mutex_lock(&pcm->open_mutex);
2375
        while (1) {
2376
                err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
2377
                                            iminor(inode), setup);
2378
                if (err >= 0)
2379
                        break;
2380
                if (err == -EAGAIN) {
2381
                        if (nonblock) {
2382
                                err = -EBUSY;
2383
                                break;
2384
                        }
2385
                } else
2386
                        break;
2387
                set_current_state(TASK_INTERRUPTIBLE);
2388
                mutex_unlock(&pcm->open_mutex);
2389
                schedule();
2390
                mutex_lock(&pcm->open_mutex);
2391
                if (signal_pending(current)) {
2392
                        err = -ERESTARTSYS;
2393
                        break;
2394
                }
2395
        }
2396
        remove_wait_queue(&pcm->open_wait, &wait);
2397
        mutex_unlock(&pcm->open_mutex);
2398
        if (err < 0)
2399
                goto __error;
2400
        return err;
2401
 
2402
      __error:
2403
        module_put(pcm->card->module);
2404
      __error2:
2405
        snd_card_file_remove(pcm->card, file);
2406
      __error1:
2407
        return err;
2408
}
2409
 
2410
static int snd_pcm_oss_release(struct inode *inode, struct file *file)
2411
{
2412
        struct snd_pcm *pcm;
2413
        struct snd_pcm_substream *substream;
2414
        struct snd_pcm_oss_file *pcm_oss_file;
2415
 
2416
        pcm_oss_file = file->private_data;
2417
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2418
        if (substream == NULL)
2419
                substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2420
        snd_assert(substream != NULL, return -ENXIO);
2421
        pcm = substream->pcm;
2422
        if (!pcm->card->shutdown)
2423
                snd_pcm_oss_sync(pcm_oss_file);
2424
        mutex_lock(&pcm->open_mutex);
2425
        snd_pcm_oss_release_file(pcm_oss_file);
2426
        mutex_unlock(&pcm->open_mutex);
2427
        wake_up(&pcm->open_wait);
2428
        module_put(pcm->card->module);
2429
        snd_card_file_remove(pcm->card, file);
2430
        return 0;
2431
}
2432
 
2433
static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2434
{
2435
        struct snd_pcm_oss_file *pcm_oss_file;
2436
        int __user *p = (int __user *)arg;
2437
        int res;
2438
 
2439
        pcm_oss_file = file->private_data;
2440
        if (cmd == OSS_GETVERSION)
2441
                return put_user(SNDRV_OSS_VERSION, p);
2442
        if (cmd == OSS_ALSAEMULVER)
2443
                return put_user(1, p);
2444
#if defined(CONFIG_SND_MIXER_OSS) || (defined(MODULE) && defined(CONFIG_SND_MIXER_OSS_MODULE))
2445
        if (((cmd >> 8) & 0xff) == 'M') {       /* mixer ioctl - for OSS compatibility */
2446
                struct snd_pcm_substream *substream;
2447
                int idx;
2448
                for (idx = 0; idx < 2; ++idx) {
2449
                        substream = pcm_oss_file->streams[idx];
2450
                        if (substream != NULL)
2451
                                break;
2452
                }
2453
                snd_assert(substream != NULL, return -ENXIO);
2454
                return snd_mixer_oss_ioctl_card(substream->pcm->card, cmd, arg);
2455
        }
2456
#endif
2457
        if (((cmd >> 8) & 0xff) != 'P')
2458
                return -EINVAL;
2459
#ifdef OSS_DEBUG
2460
        printk("pcm_oss: ioctl = 0x%x\n", cmd);
2461
#endif
2462
        switch (cmd) {
2463
        case SNDCTL_DSP_RESET:
2464
                return snd_pcm_oss_reset(pcm_oss_file);
2465
        case SNDCTL_DSP_SYNC:
2466
                return snd_pcm_oss_sync(pcm_oss_file);
2467
        case SNDCTL_DSP_SPEED:
2468
                if (get_user(res, p))
2469
                        return -EFAULT;
2470
                if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0)
2471
                        return res;
2472
                return put_user(res, p);
2473
        case SOUND_PCM_READ_RATE:
2474
                res = snd_pcm_oss_get_rate(pcm_oss_file);
2475
                if (res < 0)
2476
                        return res;
2477
                return put_user(res, p);
2478
        case SNDCTL_DSP_STEREO:
2479
                if (get_user(res, p))
2480
                        return -EFAULT;
2481
                res = res > 0 ? 2 : 1;
2482
                if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0)
2483
                        return res;
2484
                return put_user(--res, p);
2485
        case SNDCTL_DSP_GETBLKSIZE:
2486
                res = snd_pcm_oss_get_block_size(pcm_oss_file);
2487
                if (res < 0)
2488
                        return res;
2489
                return put_user(res, p);
2490
        case SNDCTL_DSP_SETFMT:
2491
                if (get_user(res, p))
2492
                        return -EFAULT;
2493
                res = snd_pcm_oss_set_format(pcm_oss_file, res);
2494
                if (res < 0)
2495
                        return res;
2496
                return put_user(res, p);
2497
        case SOUND_PCM_READ_BITS:
2498
                res = snd_pcm_oss_get_format(pcm_oss_file);
2499
                if (res < 0)
2500
                        return res;
2501
                return put_user(res, p);
2502
        case SNDCTL_DSP_CHANNELS:
2503
                if (get_user(res, p))
2504
                        return -EFAULT;
2505
                res = snd_pcm_oss_set_channels(pcm_oss_file, res);
2506
                if (res < 0)
2507
                        return res;
2508
                return put_user(res, p);
2509
        case SOUND_PCM_READ_CHANNELS:
2510
                res = snd_pcm_oss_get_channels(pcm_oss_file);
2511
                if (res < 0)
2512
                        return res;
2513
                return put_user(res, p);
2514
        case SOUND_PCM_WRITE_FILTER:
2515
        case SOUND_PCM_READ_FILTER:
2516
                return -EIO;
2517
        case SNDCTL_DSP_POST:
2518
                return snd_pcm_oss_post(pcm_oss_file);
2519
        case SNDCTL_DSP_SUBDIVIDE:
2520
                if (get_user(res, p))
2521
                        return -EFAULT;
2522
                res = snd_pcm_oss_set_subdivide(pcm_oss_file, res);
2523
                if (res < 0)
2524
                        return res;
2525
                return put_user(res, p);
2526
        case SNDCTL_DSP_SETFRAGMENT:
2527
                if (get_user(res, p))
2528
                        return -EFAULT;
2529
                return snd_pcm_oss_set_fragment(pcm_oss_file, res);
2530
        case SNDCTL_DSP_GETFMTS:
2531
                res = snd_pcm_oss_get_formats(pcm_oss_file);
2532
                if (res < 0)
2533
                        return res;
2534
                return put_user(res, p);
2535
        case SNDCTL_DSP_GETOSPACE:
2536
        case SNDCTL_DSP_GETISPACE:
2537
                return snd_pcm_oss_get_space(pcm_oss_file,
2538
                        cmd == SNDCTL_DSP_GETISPACE ?
2539
                                SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2540
                        (struct audio_buf_info __user *) arg);
2541
        case SNDCTL_DSP_NONBLOCK:
2542
                return snd_pcm_oss_nonblock(file);
2543
        case SNDCTL_DSP_GETCAPS:
2544
                res = snd_pcm_oss_get_caps(pcm_oss_file);
2545
                if (res < 0)
2546
                        return res;
2547
                return put_user(res, p);
2548
        case SNDCTL_DSP_GETTRIGGER:
2549
                res = snd_pcm_oss_get_trigger(pcm_oss_file);
2550
                if (res < 0)
2551
                        return res;
2552
                return put_user(res, p);
2553
        case SNDCTL_DSP_SETTRIGGER:
2554
                if (get_user(res, p))
2555
                        return -EFAULT;
2556
                return snd_pcm_oss_set_trigger(pcm_oss_file, res);
2557
        case SNDCTL_DSP_GETIPTR:
2558
        case SNDCTL_DSP_GETOPTR:
2559
                return snd_pcm_oss_get_ptr(pcm_oss_file,
2560
                        cmd == SNDCTL_DSP_GETIPTR ?
2561
                                SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2562
                        (struct count_info __user *) arg);
2563
        case SNDCTL_DSP_MAPINBUF:
2564
        case SNDCTL_DSP_MAPOUTBUF:
2565
                return snd_pcm_oss_get_mapbuf(pcm_oss_file,
2566
                        cmd == SNDCTL_DSP_MAPINBUF ?
2567
                                SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2568
                        (struct buffmem_desc __user *) arg);
2569
        case SNDCTL_DSP_SETSYNCRO:
2570
                /* stop DMA now.. */
2571
                return 0;
2572
        case SNDCTL_DSP_SETDUPLEX:
2573
                if (snd_pcm_oss_get_caps(pcm_oss_file) & DSP_CAP_DUPLEX)
2574
                        return 0;
2575
                return -EIO;
2576
        case SNDCTL_DSP_GETODELAY:
2577
                res = snd_pcm_oss_get_odelay(pcm_oss_file);
2578
                if (res < 0) {
2579
                        /* it's for sure, some broken apps don't check for error codes */
2580
                        put_user(0, p);
2581
                        return res;
2582
                }
2583
                return put_user(res, p);
2584
        case SNDCTL_DSP_PROFILE:
2585
                return 0;        /* silently ignore */
2586
        default:
2587
                snd_printd("pcm_oss: unknown command = 0x%x\n", cmd);
2588
        }
2589
        return -EINVAL;
2590
}
2591
 
2592
#ifdef CONFIG_COMPAT
2593
/* all compatible */
2594
#define snd_pcm_oss_ioctl_compat        snd_pcm_oss_ioctl
2595
#else
2596
#define snd_pcm_oss_ioctl_compat        NULL
2597
#endif
2598
 
2599
static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
2600
{
2601
        struct snd_pcm_oss_file *pcm_oss_file;
2602
        struct snd_pcm_substream *substream;
2603
 
2604
        pcm_oss_file = file->private_data;
2605
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2606
        if (substream == NULL)
2607
                return -ENXIO;
2608
        substream->f_flags = file->f_flags & O_NONBLOCK;
2609
#ifndef OSS_DEBUG
2610
        return snd_pcm_oss_read1(substream, buf, count);
2611
#else
2612
        {
2613
                ssize_t res = snd_pcm_oss_read1(substream, buf, count);
2614
                printk("pcm_oss: read %li bytes (returned %li bytes)\n", (long)count, (long)res);
2615
                return res;
2616
        }
2617
#endif
2618
}
2619
 
2620
static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
2621
{
2622
        struct snd_pcm_oss_file *pcm_oss_file;
2623
        struct snd_pcm_substream *substream;
2624
        long result;
2625
 
2626
        pcm_oss_file = file->private_data;
2627
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2628
        if (substream == NULL)
2629
                return -ENXIO;
2630
        substream->f_flags = file->f_flags & O_NONBLOCK;
2631
        result = snd_pcm_oss_write1(substream, buf, count);
2632
#ifdef OSS_DEBUG
2633
        printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
2634
#endif
2635
        return result;
2636
}
2637
 
2638
static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
2639
{
2640
        struct snd_pcm_runtime *runtime = substream->runtime;
2641
        if (atomic_read(&substream->mmap_count))
2642
                return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
2643
        else
2644
                return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
2645
}
2646
 
2647
static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
2648
{
2649
        struct snd_pcm_runtime *runtime = substream->runtime;
2650
        if (atomic_read(&substream->mmap_count))
2651
                return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
2652
        else
2653
                return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
2654
}
2655
 
2656
static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
2657
{
2658
        struct snd_pcm_oss_file *pcm_oss_file;
2659
        unsigned int mask;
2660
        struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
2661
 
2662
        pcm_oss_file = file->private_data;
2663
 
2664
        psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2665
        csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2666
 
2667
        mask = 0;
2668
        if (psubstream != NULL) {
2669
                struct snd_pcm_runtime *runtime = psubstream->runtime;
2670
                poll_wait(file, &runtime->sleep, wait);
2671
                snd_pcm_stream_lock_irq(psubstream);
2672
                if (runtime->status->state != SNDRV_PCM_STATE_DRAINING &&
2673
                    (runtime->status->state != SNDRV_PCM_STATE_RUNNING ||
2674
                     snd_pcm_oss_playback_ready(psubstream)))
2675
                        mask |= POLLOUT | POLLWRNORM;
2676
                snd_pcm_stream_unlock_irq(psubstream);
2677
        }
2678
        if (csubstream != NULL) {
2679
                struct snd_pcm_runtime *runtime = csubstream->runtime;
2680
                snd_pcm_state_t ostate;
2681
                poll_wait(file, &runtime->sleep, wait);
2682
                snd_pcm_stream_lock_irq(csubstream);
2683
                if ((ostate = runtime->status->state) != SNDRV_PCM_STATE_RUNNING ||
2684
                    snd_pcm_oss_capture_ready(csubstream))
2685
                        mask |= POLLIN | POLLRDNORM;
2686
                snd_pcm_stream_unlock_irq(csubstream);
2687
                if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
2688
                        struct snd_pcm_oss_file ofile;
2689
                        memset(&ofile, 0, sizeof(ofile));
2690
                        ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2691
                        runtime->oss.trigger = 0;
2692
                        snd_pcm_oss_set_trigger(&ofile, PCM_ENABLE_INPUT);
2693
                }
2694
        }
2695
 
2696
        return mask;
2697
}
2698
 
2699
static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
2700
{
2701
        struct snd_pcm_oss_file *pcm_oss_file;
2702
        struct snd_pcm_substream *substream = NULL;
2703
        struct snd_pcm_runtime *runtime;
2704
        int err;
2705
 
2706
#ifdef OSS_DEBUG
2707
        printk("pcm_oss: mmap begin\n");
2708
#endif
2709
        pcm_oss_file = file->private_data;
2710
        switch ((area->vm_flags & (VM_READ | VM_WRITE))) {
2711
        case VM_READ | VM_WRITE:
2712
                substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2713
                if (substream)
2714
                        break;
2715
                /* Fall through */
2716
        case VM_READ:
2717
                substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2718
                break;
2719
        case VM_WRITE:
2720
                substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2721
                break;
2722
        default:
2723
                return -EINVAL;
2724
        }
2725
        /* set VM_READ access as well to fix memset() routines that do
2726
           reads before writes (to improve performance) */
2727
        area->vm_flags |= VM_READ;
2728
        if (substream == NULL)
2729
                return -ENXIO;
2730
        runtime = substream->runtime;
2731
        if (!(runtime->info & SNDRV_PCM_INFO_MMAP_VALID))
2732
                return -EIO;
2733
        if (runtime->info & SNDRV_PCM_INFO_INTERLEAVED)
2734
                runtime->access = SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;
2735
        else
2736
                return -EIO;
2737
 
2738
        if (runtime->oss.params) {
2739
                if ((err = snd_pcm_oss_change_params(substream)) < 0)
2740
                        return err;
2741
        }
2742
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
2743
        if (runtime->oss.plugin_first != NULL)
2744
                return -EIO;
2745
#endif
2746
 
2747
        if (area->vm_pgoff != 0)
2748
                return -EINVAL;
2749
 
2750
        err = snd_pcm_mmap_data(substream, file, area);
2751
        if (err < 0)
2752
                return err;
2753
        runtime->oss.mmap_bytes = area->vm_end - area->vm_start;
2754
        runtime->silence_threshold = 0;
2755
        runtime->silence_size = 0;
2756
#ifdef OSS_DEBUG
2757
        printk("pcm_oss: mmap ok, bytes = 0x%x\n", runtime->oss.mmap_bytes);
2758
#endif
2759
        /* In mmap mode we never stop */
2760
        runtime->stop_threshold = runtime->boundary;
2761
 
2762
        return 0;
2763
}
2764
 
2765
#ifdef CONFIG_SND_VERBOSE_PROCFS
2766
/*
2767
 *  /proc interface
2768
 */
2769
 
2770
static void snd_pcm_oss_proc_read(struct snd_info_entry *entry,
2771
                                  struct snd_info_buffer *buffer)
2772
{
2773
        struct snd_pcm_str *pstr = entry->private_data;
2774
        struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
2775
        mutex_lock(&pstr->oss.setup_mutex);
2776
        while (setup) {
2777
                snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
2778
                            setup->task_name,
2779
                            setup->periods,
2780
                            setup->period_size,
2781
                            setup->disable ? " disable" : "",
2782
                            setup->direct ? " direct" : "",
2783
                            setup->block ? " block" : "",
2784
                            setup->nonblock ? " non-block" : "",
2785
                            setup->partialfrag ? " partial-frag" : "",
2786
                            setup->nosilence ? " no-silence" : "");
2787
                setup = setup->next;
2788
        }
2789
        mutex_unlock(&pstr->oss.setup_mutex);
2790
}
2791
 
2792
static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
2793
{
2794
        struct snd_pcm_oss_setup *setup, *setupn;
2795
 
2796
        for (setup = pstr->oss.setup_list, pstr->oss.setup_list = NULL;
2797
             setup; setup = setupn) {
2798
                setupn = setup->next;
2799
                kfree(setup->task_name);
2800
                kfree(setup);
2801
        }
2802
        pstr->oss.setup_list = NULL;
2803
}
2804
 
2805
static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
2806
                                   struct snd_info_buffer *buffer)
2807
{
2808
        struct snd_pcm_str *pstr = entry->private_data;
2809
        char line[128], str[32], task_name[32], *ptr;
2810
        int idx1;
2811
        struct snd_pcm_oss_setup *setup, *setup1, template;
2812
 
2813
        while (!snd_info_get_line(buffer, line, sizeof(line))) {
2814
                mutex_lock(&pstr->oss.setup_mutex);
2815
                memset(&template, 0, sizeof(template));
2816
                ptr = snd_info_get_str(task_name, line, sizeof(task_name));
2817
                if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
2818
                        snd_pcm_oss_proc_free_setup_list(pstr);
2819
                        mutex_unlock(&pstr->oss.setup_mutex);
2820
                        continue;
2821
                }
2822
                for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
2823
                        if (!strcmp(setup->task_name, task_name)) {
2824
                                template = *setup;
2825
                                break;
2826
                        }
2827
                }
2828
                ptr = snd_info_get_str(str, ptr, sizeof(str));
2829
                template.periods = simple_strtoul(str, NULL, 10);
2830
                ptr = snd_info_get_str(str, ptr, sizeof(str));
2831
                template.period_size = simple_strtoul(str, NULL, 10);
2832
                for (idx1 = 31; idx1 >= 0; idx1--)
2833
                        if (template.period_size & (1 << idx1))
2834
                                break;
2835
                for (idx1--; idx1 >= 0; idx1--)
2836
                        template.period_size &= ~(1 << idx1);
2837
                do {
2838
                        ptr = snd_info_get_str(str, ptr, sizeof(str));
2839
                        if (!strcmp(str, "disable")) {
2840
                                template.disable = 1;
2841
                        } else if (!strcmp(str, "direct")) {
2842
                                template.direct = 1;
2843
                        } else if (!strcmp(str, "block")) {
2844
                                template.block = 1;
2845
                        } else if (!strcmp(str, "non-block")) {
2846
                                template.nonblock = 1;
2847
                        } else if (!strcmp(str, "partial-frag")) {
2848
                                template.partialfrag = 1;
2849
                        } else if (!strcmp(str, "no-silence")) {
2850
                                template.nosilence = 1;
2851
                        } else if (!strcmp(str, "buggy-ptr")) {
2852
                                template.buggyptr = 1;
2853
                        }
2854
                } while (*str);
2855
                if (setup == NULL) {
2856
                        setup = kmalloc(sizeof(*setup), GFP_KERNEL);
2857
                        if (! setup) {
2858
                                buffer->error = -ENOMEM;
2859
                                mutex_lock(&pstr->oss.setup_mutex);
2860
                                return;
2861
                        }
2862
                        if (pstr->oss.setup_list == NULL)
2863
                                pstr->oss.setup_list = setup;
2864
                        else {
2865
                                for (setup1 = pstr->oss.setup_list;
2866
                                     setup1->next; setup1 = setup1->next);
2867
                                setup1->next = setup;
2868
                        }
2869
                        template.task_name = kstrdup(task_name, GFP_KERNEL);
2870
                        if (! template.task_name) {
2871
                                kfree(setup);
2872
                                buffer->error = -ENOMEM;
2873
                                mutex_lock(&pstr->oss.setup_mutex);
2874
                                return;
2875
                        }
2876
                }
2877
                *setup = template;
2878
                mutex_unlock(&pstr->oss.setup_mutex);
2879
        }
2880
}
2881
 
2882
static void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
2883
{
2884
        int stream;
2885
        for (stream = 0; stream < 2; ++stream) {
2886
                struct snd_info_entry *entry;
2887
                struct snd_pcm_str *pstr = &pcm->streams[stream];
2888
                if (pstr->substream_count == 0)
2889
                        continue;
2890
                if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) {
2891
                        entry->content = SNDRV_INFO_CONTENT_TEXT;
2892
                        entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
2893
                        entry->c.text.read = snd_pcm_oss_proc_read;
2894
                        entry->c.text.write = snd_pcm_oss_proc_write;
2895
                        entry->private_data = pstr;
2896
                        if (snd_info_register(entry) < 0) {
2897
                                snd_info_free_entry(entry);
2898
                                entry = NULL;
2899
                        }
2900
                }
2901
                pstr->oss.proc_entry = entry;
2902
        }
2903
}
2904
 
2905
static void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
2906
{
2907
        int stream;
2908
        for (stream = 0; stream < 2; ++stream) {
2909
                struct snd_pcm_str *pstr = &pcm->streams[stream];
2910
                snd_info_free_entry(pstr->oss.proc_entry);
2911
                pstr->oss.proc_entry = NULL;
2912
                snd_pcm_oss_proc_free_setup_list(pstr);
2913
        }
2914
}
2915
#else /* !CONFIG_SND_VERBOSE_PROCFS */
2916
#define snd_pcm_oss_proc_init(pcm)
2917
#define snd_pcm_oss_proc_done(pcm)
2918
#endif /* CONFIG_SND_VERBOSE_PROCFS */
2919
 
2920
/*
2921
 *  ENTRY functions
2922
 */
2923
 
2924
static const struct file_operations snd_pcm_oss_f_reg =
2925
{
2926
        .owner =        THIS_MODULE,
2927
        .read =         snd_pcm_oss_read,
2928
        .write =        snd_pcm_oss_write,
2929
        .open =         snd_pcm_oss_open,
2930
        .release =      snd_pcm_oss_release,
2931
        .poll =         snd_pcm_oss_poll,
2932
        .unlocked_ioctl =       snd_pcm_oss_ioctl,
2933
        .compat_ioctl = snd_pcm_oss_ioctl_compat,
2934
        .mmap =         snd_pcm_oss_mmap,
2935
};
2936
 
2937
static void register_oss_dsp(struct snd_pcm *pcm, int index)
2938
{
2939
        char name[128];
2940
        sprintf(name, "dsp%i%i", pcm->card->number, pcm->device);
2941
        if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
2942
                                    pcm->card, index, &snd_pcm_oss_f_reg,
2943
                                    pcm, name) < 0) {
2944
                snd_printk(KERN_ERR "unable to register OSS PCM device %i:%i\n",
2945
                           pcm->card->number, pcm->device);
2946
        }
2947
}
2948
 
2949
static int snd_pcm_oss_register_minor(struct snd_pcm *pcm)
2950
{
2951
        pcm->oss.reg = 0;
2952
        if (dsp_map[pcm->card->number] == (int)pcm->device) {
2953
                char name[128];
2954
                int duplex;
2955
                register_oss_dsp(pcm, 0);
2956
                duplex = (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count > 0 &&
2957
                              pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count &&
2958
                              !(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX));
2959
                sprintf(name, "%s%s", pcm->name, duplex ? " (DUPLEX)" : "");
2960
#ifdef SNDRV_OSS_INFO_DEV_AUDIO
2961
                snd_oss_info_register(SNDRV_OSS_INFO_DEV_AUDIO,
2962
                                      pcm->card->number,
2963
                                      name);
2964
#endif
2965
                pcm->oss.reg++;
2966
                pcm->oss.reg_mask |= 1;
2967
        }
2968
        if (adsp_map[pcm->card->number] == (int)pcm->device) {
2969
                register_oss_dsp(pcm, 1);
2970
                pcm->oss.reg++;
2971
                pcm->oss.reg_mask |= 2;
2972
        }
2973
 
2974
        if (pcm->oss.reg)
2975
                snd_pcm_oss_proc_init(pcm);
2976
 
2977
        return 0;
2978
}
2979
 
2980
static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm)
2981
{
2982
        if (pcm->oss.reg) {
2983
                if (pcm->oss.reg_mask & 1) {
2984
                        pcm->oss.reg_mask &= ~1;
2985
                        snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
2986
                                                  pcm->card, 0);
2987
                }
2988
                if (pcm->oss.reg_mask & 2) {
2989
                        pcm->oss.reg_mask &= ~2;
2990
                        snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
2991
                                                  pcm->card, 1);
2992
                }
2993
                if (dsp_map[pcm->card->number] == (int)pcm->device) {
2994
#ifdef SNDRV_OSS_INFO_DEV_AUDIO
2995
                        snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
2996
#endif
2997
                }
2998
                pcm->oss.reg = 0;
2999
        }
3000
        return 0;
3001
}
3002
 
3003
static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
3004
{
3005
        snd_pcm_oss_disconnect_minor(pcm);
3006
        snd_pcm_oss_proc_done(pcm);
3007
        return 0;
3008
}
3009
 
3010
static struct snd_pcm_notify snd_pcm_oss_notify =
3011
{
3012
        .n_register =   snd_pcm_oss_register_minor,
3013
        .n_disconnect = snd_pcm_oss_disconnect_minor,
3014
        .n_unregister = snd_pcm_oss_unregister_minor,
3015
};
3016
 
3017
static int __init alsa_pcm_oss_init(void)
3018
{
3019
        int i;
3020
        int err;
3021
 
3022
        /* check device map table */
3023
        for (i = 0; i < SNDRV_CARDS; i++) {
3024
                if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) {
3025
                        snd_printk(KERN_ERR "invalid dsp_map[%d] = %d\n",
3026
                                   i, dsp_map[i]);
3027
                        dsp_map[i] = 0;
3028
                }
3029
                if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_PCM_DEVICES) {
3030
                        snd_printk(KERN_ERR "invalid adsp_map[%d] = %d\n",
3031
                                   i, adsp_map[i]);
3032
                        adsp_map[i] = 1;
3033
                }
3034
        }
3035
        if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0)
3036
                return err;
3037
        return 0;
3038
}
3039
 
3040
static void __exit alsa_pcm_oss_exit(void)
3041
{
3042
        snd_pcm_notify(&snd_pcm_oss_notify, 1);
3043
}
3044
 
3045
module_init(alsa_pcm_oss_init)
3046
module_exit(alsa_pcm_oss_exit)

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.