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