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