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