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