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