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