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