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