aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/oss
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2006-04-28 09:13:40 -0400
committerJaroslav Kysela <perex@suse.cz>2006-06-22 15:33:05 -0400
commite88e8ae639a4908b903d9406c54e99a729b01a28 (patch)
treeff49ba0d2370c3259b055986ebca6487994cf6e2 /sound/core/oss
parente5e8a1d4618595ea406336da3cdbd0c6eb6f260d (diff)
[ALSA] Move OSS-specific hw_params helper to snd-pcm-oss module
Move EXPORT_SYMBOL()s to places adjacent to functions/variables. Also move OSS-specific hw_params helper functions to pcm_oss.c. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/oss')
-rw-r--r--sound/core/oss/pcm_oss.c481
1 files changed, 481 insertions, 0 deletions
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index ac990bf0b48..0d2e232afe6 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -78,6 +78,487 @@ static inline void snd_leave_user(mm_segment_t fs)
78 set_fs(fs); 78 set_fs(fs);
79} 79}
80 80
81/*
82 * helper functions to process hw_params
83 */
84static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin)
85{
86 int changed = 0;
87 if (i->min < min) {
88 i->min = min;
89 i->openmin = openmin;
90 changed = 1;
91 } else if (i->min == min && !i->openmin && openmin) {
92 i->openmin = 1;
93 changed = 1;
94 }
95 if (i->integer) {
96 if (i->openmin) {
97 i->min++;
98 i->openmin = 0;
99 }
100 }
101 if (snd_interval_checkempty(i)) {
102 snd_interval_none(i);
103 return -EINVAL;
104 }
105 return changed;
106}
107
108static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax)
109{
110 int changed = 0;
111 if (i->max > max) {
112 i->max = max;
113 i->openmax = openmax;
114 changed = 1;
115 } else if (i->max == max && !i->openmax && openmax) {
116 i->openmax = 1;
117 changed = 1;
118 }
119 if (i->integer) {
120 if (i->openmax) {
121 i->max--;
122 i->openmax = 0;
123 }
124 }
125 if (snd_interval_checkempty(i)) {
126 snd_interval_none(i);
127 return -EINVAL;
128 }
129 return changed;
130}
131
132static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
133{
134 struct snd_interval t;
135 t.empty = 0;
136 t.min = t.max = val;
137 t.openmin = t.openmax = 0;
138 t.integer = 1;
139 return snd_interval_refine(i, &t);
140}
141
142/**
143 * snd_pcm_hw_param_value_min
144 * @params: the hw_params instance
145 * @var: parameter to retrieve
146 * @dir: pointer to the direction (-1,0,1) or NULL
147 *
148 * Return the minimum value for field PAR.
149 */
150static unsigned int
151snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
152 snd_pcm_hw_param_t var, int *dir)
153{
154 if (hw_is_mask(var)) {
155 if (dir)
156 *dir = 0;
157 return snd_mask_min(hw_param_mask_c(params, var));
158 }
159 if (hw_is_interval(var)) {
160 const struct snd_interval *i = hw_param_interval_c(params, var);
161 if (dir)
162 *dir = i->openmin;
163 return snd_interval_min(i);
164 }
165 return -EINVAL;
166}
167
168/**
169 * snd_pcm_hw_param_value_max
170 * @params: the hw_params instance
171 * @var: parameter to retrieve
172 * @dir: pointer to the direction (-1,0,1) or NULL
173 *
174 * Return the maximum value for field PAR.
175 */
176static unsigned int
177snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
178 snd_pcm_hw_param_t var, int *dir)
179{
180 if (hw_is_mask(var)) {
181 if (dir)
182 *dir = 0;
183 return snd_mask_max(hw_param_mask_c(params, var));
184 }
185 if (hw_is_interval(var)) {
186 const struct snd_interval *i = hw_param_interval_c(params, var);
187 if (dir)
188 *dir = - (int) i->openmax;
189 return snd_interval_max(i);
190 }
191 return -EINVAL;
192}
193
194static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params,
195 snd_pcm_hw_param_t var,
196 const struct snd_mask *val)
197{
198 int changed;
199 changed = snd_mask_refine(hw_param_mask(params, var), val);
200 if (changed) {
201 params->cmask |= 1 << var;
202 params->rmask |= 1 << var;
203 }
204 return changed;
205}
206
207static int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm,
208 struct snd_pcm_hw_params *params,
209 snd_pcm_hw_param_t var,
210 const struct snd_mask *val)
211{
212 int changed = _snd_pcm_hw_param_mask(params, var, val);
213 if (changed < 0)
214 return changed;
215 if (params->rmask) {
216 int err = snd_pcm_hw_refine(pcm, params);
217 if (err < 0)
218 return err;
219 }
220 return 0;
221}
222
223static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
224 snd_pcm_hw_param_t var, unsigned int val,
225 int dir)
226{
227 int changed;
228 int open = 0;
229 if (dir) {
230 if (dir > 0) {
231 open = 1;
232 } else if (dir < 0) {
233 if (val > 0) {
234 open = 1;
235 val--;
236 }
237 }
238 }
239 if (hw_is_mask(var))
240 changed = snd_mask_refine_min(hw_param_mask(params, var),
241 val + !!open);
242 else if (hw_is_interval(var))
243 changed = snd_interval_refine_min(hw_param_interval(params, var),
244 val, open);
245 else
246 return -EINVAL;
247 if (changed) {
248 params->cmask |= 1 << var;
249 params->rmask |= 1 << var;
250 }
251 return changed;
252}
253
254/**
255 * snd_pcm_hw_param_min
256 * @pcm: PCM instance
257 * @params: the hw_params instance
258 * @var: parameter to retrieve
259 * @val: minimal value
260 * @dir: pointer to the direction (-1,0,1) or NULL
261 *
262 * Inside configuration space defined by PARAMS remove from PAR all
263 * values < VAL. Reduce configuration space accordingly.
264 * Return new minimum or -EINVAL if the configuration space is empty
265 */
266static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm,
267 struct snd_pcm_hw_params *params,
268 snd_pcm_hw_param_t var, unsigned int val,
269 int *dir)
270{
271 int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
272 if (changed < 0)
273 return changed;
274 if (params->rmask) {
275 int err = snd_pcm_hw_refine(pcm, params);
276 if (err < 0)
277 return err;
278 }
279 return snd_pcm_hw_param_value_min(params, var, dir);
280}
281
282static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
283 snd_pcm_hw_param_t var, unsigned int val,
284 int dir)
285{
286 int changed;
287 int open = 0;
288 if (dir) {
289 if (dir < 0) {
290 open = 1;
291 } else if (dir > 0) {
292 open = 1;
293 val++;
294 }
295 }
296 if (hw_is_mask(var)) {
297 if (val == 0 && open) {
298 snd_mask_none(hw_param_mask(params, var));
299 changed = -EINVAL;
300 } else
301 changed = snd_mask_refine_max(hw_param_mask(params, var),
302 val - !!open);
303 } else if (hw_is_interval(var))
304 changed = snd_interval_refine_max(hw_param_interval(params, var),
305 val, open);
306 else
307 return -EINVAL;
308 if (changed) {
309 params->cmask |= 1 << var;
310 params->rmask |= 1 << var;
311 }
312 return changed;
313}
314
315/**
316 * snd_pcm_hw_param_max
317 * @pcm: PCM instance
318 * @params: the hw_params instance
319 * @var: parameter to retrieve
320 * @val: maximal value
321 * @dir: pointer to the direction (-1,0,1) or NULL
322 *
323 * Inside configuration space defined by PARAMS remove from PAR all
324 * values >= VAL + 1. Reduce configuration space accordingly.
325 * Return new maximum or -EINVAL if the configuration space is empty
326 */
327static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm,
328 struct snd_pcm_hw_params *params,
329 snd_pcm_hw_param_t var, unsigned int val,
330 int *dir)
331{
332 int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
333 if (changed < 0)
334 return changed;
335 if (params->rmask) {
336 int err = snd_pcm_hw_refine(pcm, params);
337 if (err < 0)
338 return err;
339 }
340 return snd_pcm_hw_param_value_max(params, var, dir);
341}
342
343static int boundary_sub(int a, int adir,
344 int b, int bdir,
345 int *c, int *cdir)
346{
347 adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
348 bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
349 *c = a - b;
350 *cdir = adir - bdir;
351 if (*cdir == -2) {
352 (*c)--;
353 } else if (*cdir == 2) {
354 (*c)++;
355 }
356 return 0;
357}
358
359static int boundary_lt(unsigned int a, int adir,
360 unsigned int b, int bdir)
361{
362 if (adir < 0) {
363 a--;
364 adir = 1;
365 } else if (adir > 0)
366 adir = 1;
367 if (bdir < 0) {
368 b--;
369 bdir = 1;
370 } else if (bdir > 0)
371 bdir = 1;
372 return a < b || (a == b && adir < bdir);
373}
374
375/* Return 1 if min is nearer to best than max */
376static int boundary_nearer(int min, int mindir,
377 int best, int bestdir,
378 int max, int maxdir)
379{
380 int dmin, dmindir;
381 int dmax, dmaxdir;
382 boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
383 boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
384 return boundary_lt(dmin, dmindir, dmax, dmaxdir);
385}
386
387/**
388 * snd_pcm_hw_param_near
389 * @pcm: PCM instance
390 * @params: the hw_params instance
391 * @var: parameter to retrieve
392 * @best: value to set
393 * @dir: pointer to the direction (-1,0,1) or NULL
394 *
395 * Inside configuration space defined by PARAMS set PAR to the available value
396 * nearest to VAL. Reduce configuration space accordingly.
397 * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
398 * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
399 * Return the value found.
400 */
401static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
402 struct snd_pcm_hw_params *params,
403 snd_pcm_hw_param_t var, unsigned int best,
404 int *dir)
405{
406 struct snd_pcm_hw_params *save = NULL;
407 int v;
408 unsigned int saved_min;
409 int last = 0;
410 int min, max;
411 int mindir, maxdir;
412 int valdir = dir ? *dir : 0;
413 /* FIXME */
414 if (best > INT_MAX)
415 best = INT_MAX;
416 min = max = best;
417 mindir = maxdir = valdir;
418 if (maxdir > 0)
419 maxdir = 0;
420 else if (maxdir == 0)
421 maxdir = -1;
422 else {
423 maxdir = 1;
424 max--;
425 }
426 save = kmalloc(sizeof(*save), GFP_KERNEL);
427 if (save == NULL)
428 return -ENOMEM;
429 *save = *params;
430 saved_min = min;
431 min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
432 if (min >= 0) {
433 struct snd_pcm_hw_params *params1;
434 if (max < 0)
435 goto _end;
436 if ((unsigned int)min == saved_min && mindir == valdir)
437 goto _end;
438 params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
439 if (params1 == NULL) {
440 kfree(save);
441 return -ENOMEM;
442 }
443 *params1 = *save;
444 max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
445 if (max < 0) {
446 kfree(params1);
447 goto _end;
448 }
449 if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
450 *params = *params1;
451 last = 1;
452 }
453 kfree(params1);
454 } else {
455 *params = *save;
456 max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
457 snd_assert(max >= 0, return -EINVAL);
458 last = 1;
459 }
460 _end:
461 kfree(save);
462 if (last)
463 v = snd_pcm_hw_param_last(pcm, params, var, dir);
464 else
465 v = snd_pcm_hw_param_first(pcm, params, var, dir);
466 snd_assert(v >= 0, return -EINVAL);
467 return v;
468}
469
470static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
471 snd_pcm_hw_param_t var, unsigned int val,
472 int dir)
473{
474 int changed;
475 if (hw_is_mask(var)) {
476 struct snd_mask *m = hw_param_mask(params, var);
477 if (val == 0 && dir < 0) {
478 changed = -EINVAL;
479 snd_mask_none(m);
480 } else {
481 if (dir > 0)
482 val++;
483 else if (dir < 0)
484 val--;
485 changed = snd_mask_refine_set(hw_param_mask(params, var), val);
486 }
487 } else if (hw_is_interval(var)) {
488 struct snd_interval *i = hw_param_interval(params, var);
489 if (val == 0 && dir < 0) {
490 changed = -EINVAL;
491 snd_interval_none(i);
492 } else if (dir == 0)
493 changed = snd_interval_refine_set(i, val);
494 else {
495 struct snd_interval t;
496 t.openmin = 1;
497 t.openmax = 1;
498 t.empty = 0;
499 t.integer = 0;
500 if (dir < 0) {
501 t.min = val - 1;
502 t.max = val;
503 } else {
504 t.min = val;
505 t.max = val+1;
506 }
507 changed = snd_interval_refine(i, &t);
508 }
509 } else
510 return -EINVAL;
511 if (changed) {
512 params->cmask |= 1 << var;
513 params->rmask |= 1 << var;
514 }
515 return changed;
516}
517
518/**
519 * snd_pcm_hw_param_set
520 * @pcm: PCM instance
521 * @params: the hw_params instance
522 * @var: parameter to retrieve
523 * @val: value to set
524 * @dir: pointer to the direction (-1,0,1) or NULL
525 *
526 * Inside configuration space defined by PARAMS remove from PAR all
527 * values != VAL. Reduce configuration space accordingly.
528 * Return VAL or -EINVAL if the configuration space is empty
529 */
530static int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,
531 struct snd_pcm_hw_params *params,
532 snd_pcm_hw_param_t var, unsigned int val,
533 int dir)
534{
535 int changed = _snd_pcm_hw_param_set(params, var, val, dir);
536 if (changed < 0)
537 return changed;
538 if (params->rmask) {
539 int err = snd_pcm_hw_refine(pcm, params);
540 if (err < 0)
541 return err;
542 }
543 return snd_pcm_hw_param_value(params, var, NULL);
544}
545
546static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
547 snd_pcm_hw_param_t var)
548{
549 int changed;
550 changed = snd_interval_setinteger(hw_param_interval(params, var));
551 if (changed) {
552 params->cmask |= 1 << var;
553 params->rmask |= 1 << var;
554 }
555 return changed;
556}
557
558/*
559 * plugin
560 */
561
81#ifdef CONFIG_SND_PCM_OSS_PLUGINS 562#ifdef CONFIG_SND_PCM_OSS_PLUGINS
82static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream) 563static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream)
83{ 564{