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