qemu/audio/ossaudio.c
<<
>>
Prefs
   1/*
   2 * QEMU OSS audio driver
   3 *
   4 * Copyright (c) 2003-2005 Vassili Karpov (malc)
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24#include <stdlib.h>
  25#include <sys/mman.h>
  26#include <sys/types.h>
  27#include <sys/ioctl.h>
  28#ifdef __OpenBSD__
  29#include <soundcard.h>
  30#else
  31#include <sys/soundcard.h>
  32#endif
  33#include "qemu-common.h"
  34#include "qemu/main-loop.h"
  35#include "qemu/host-utils.h"
  36#include "audio.h"
  37
  38#define AUDIO_CAP "oss"
  39#include "audio_int.h"
  40
  41#if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
  42#define USE_DSP_POLICY
  43#endif
  44
  45typedef struct OSSVoiceOut {
  46    HWVoiceOut hw;
  47    void *pcm_buf;
  48    int fd;
  49    int wpos;
  50    int nfrags;
  51    int fragsize;
  52    int mmapped;
  53    int pending;
  54} OSSVoiceOut;
  55
  56typedef struct OSSVoiceIn {
  57    HWVoiceIn hw;
  58    void *pcm_buf;
  59    int fd;
  60    int nfrags;
  61    int fragsize;
  62} OSSVoiceIn;
  63
  64static struct {
  65    int try_mmap;
  66    int nfrags;
  67    int fragsize;
  68    const char *devpath_out;
  69    const char *devpath_in;
  70    int debug;
  71    int exclusive;
  72    int policy;
  73} conf = {
  74    .try_mmap = 0,
  75    .nfrags = 4,
  76    .fragsize = 4096,
  77    .devpath_out = "/dev/dsp",
  78    .devpath_in = "/dev/dsp",
  79    .debug = 0,
  80    .exclusive = 0,
  81    .policy = 5
  82};
  83
  84struct oss_params {
  85    int freq;
  86    audfmt_e fmt;
  87    int nchannels;
  88    int nfrags;
  89    int fragsize;
  90};
  91
  92static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
  93{
  94    va_list ap;
  95
  96    va_start (ap, fmt);
  97    AUD_vlog (AUDIO_CAP, fmt, ap);
  98    va_end (ap);
  99
 100    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
 101}
 102
 103static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
 104    int err,
 105    const char *typ,
 106    const char *fmt,
 107    ...
 108    )
 109{
 110    va_list ap;
 111
 112    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
 113
 114    va_start (ap, fmt);
 115    AUD_vlog (AUDIO_CAP, fmt, ap);
 116    va_end (ap);
 117
 118    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
 119}
 120
 121static void oss_anal_close (int *fdp)
 122{
 123    int err;
 124
 125    qemu_set_fd_handler (*fdp, NULL, NULL, NULL);
 126    err = close (*fdp);
 127    if (err) {
 128        oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
 129    }
 130    *fdp = -1;
 131}
 132
 133static void oss_helper_poll_out (void *opaque)
 134{
 135    (void) opaque;
 136    audio_run ("oss_poll_out");
 137}
 138
 139static void oss_helper_poll_in (void *opaque)
 140{
 141    (void) opaque;
 142    audio_run ("oss_poll_in");
 143}
 144
 145static int oss_poll_out (HWVoiceOut *hw)
 146{
 147    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 148
 149    return qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
 150}
 151
 152static int oss_poll_in (HWVoiceIn *hw)
 153{
 154    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 155
 156    return qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
 157}
 158
 159static int oss_write (SWVoiceOut *sw, void *buf, int len)
 160{
 161    return audio_pcm_sw_write (sw, buf, len);
 162}
 163
 164static int aud_to_ossfmt (audfmt_e fmt, int endianness)
 165{
 166    switch (fmt) {
 167    case AUD_FMT_S8:
 168        return AFMT_S8;
 169
 170    case AUD_FMT_U8:
 171        return AFMT_U8;
 172
 173    case AUD_FMT_S16:
 174        if (endianness) {
 175            return AFMT_S16_BE;
 176        }
 177        else {
 178            return AFMT_S16_LE;
 179        }
 180
 181    case AUD_FMT_U16:
 182        if (endianness) {
 183            return AFMT_U16_BE;
 184        }
 185        else {
 186            return AFMT_U16_LE;
 187        }
 188
 189    default:
 190        dolog ("Internal logic error: Bad audio format %d\n", fmt);
 191#ifdef DEBUG_AUDIO
 192        abort ();
 193#endif
 194        return AFMT_U8;
 195    }
 196}
 197
 198static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
 199{
 200    switch (ossfmt) {
 201    case AFMT_S8:
 202        *endianness = 0;
 203        *fmt = AUD_FMT_S8;
 204        break;
 205
 206    case AFMT_U8:
 207        *endianness = 0;
 208        *fmt = AUD_FMT_U8;
 209        break;
 210
 211    case AFMT_S16_LE:
 212        *endianness = 0;
 213        *fmt = AUD_FMT_S16;
 214        break;
 215
 216    case AFMT_U16_LE:
 217        *endianness = 0;
 218        *fmt = AUD_FMT_U16;
 219        break;
 220
 221    case AFMT_S16_BE:
 222        *endianness = 1;
 223        *fmt = AUD_FMT_S16;
 224        break;
 225
 226    case AFMT_U16_BE:
 227        *endianness = 1;
 228        *fmt = AUD_FMT_U16;
 229        break;
 230
 231    default:
 232        dolog ("Unrecognized audio format %d\n", ossfmt);
 233        return -1;
 234    }
 235
 236    return 0;
 237}
 238
 239#if defined DEBUG_MISMATCHES || defined DEBUG
 240static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
 241{
 242    dolog ("parameter | requested value | obtained value\n");
 243    dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
 244    dolog ("channels  |      %10d |     %10d\n",
 245           req->nchannels, obt->nchannels);
 246    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
 247    dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
 248    dolog ("fragsize  |      %10d |     %10d\n",
 249           req->fragsize, obt->fragsize);
 250}
 251#endif
 252
 253#ifdef USE_DSP_POLICY
 254static int oss_get_version (int fd, int *version, const char *typ)
 255{
 256    if (ioctl (fd, OSS_GETVERSION, &version)) {
 257#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 258        /*
 259         * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
 260         * since 7.x, but currently only on the mixer device (or in
 261         * the Linuxolator), and in the native version that part of
 262         * the code is in fact never reached so the ioctl fails anyway.
 263         * Until this is fixed, just check the errno and if its what
 264         * FreeBSD's sound drivers return atm assume they are new enough.
 265         */
 266        if (errno == EINVAL) {
 267            *version = 0x040000;
 268            return 0;
 269        }
 270#endif
 271        oss_logerr2 (errno, typ, "Failed to get OSS version\n");
 272        return -1;
 273    }
 274    return 0;
 275}
 276#endif
 277
 278static int oss_open (int in, struct oss_params *req,
 279                     struct oss_params *obt, int *pfd)
 280{
 281    int fd;
 282    int oflags = conf.exclusive ? O_EXCL : 0;
 283    audio_buf_info abinfo;
 284    int fmt, freq, nchannels;
 285    int setfragment = 1;
 286    const char *dspname = in ? conf.devpath_in : conf.devpath_out;
 287    const char *typ = in ? "ADC" : "DAC";
 288
 289    /* Kludge needed to have working mmap on Linux */
 290    oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
 291
 292    fd = open (dspname, oflags | O_NONBLOCK);
 293    if (-1 == fd) {
 294        oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
 295        return -1;
 296    }
 297
 298    freq = req->freq;
 299    nchannels = req->nchannels;
 300    fmt = req->fmt;
 301
 302    if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
 303        oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
 304        goto err;
 305    }
 306
 307    if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
 308        oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
 309                     req->nchannels);
 310        goto err;
 311    }
 312
 313    if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
 314        oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
 315        goto err;
 316    }
 317
 318    if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
 319        oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
 320        goto err;
 321    }
 322
 323#ifdef USE_DSP_POLICY
 324    if (conf.policy >= 0) {
 325        int version;
 326
 327        if (!oss_get_version (fd, &version, typ)) {
 328            if (conf.debug) {
 329                dolog ("OSS version = %#x\n", version);
 330            }
 331
 332            if (version >= 0x040000) {
 333                int policy = conf.policy;
 334                if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
 335                    oss_logerr2 (errno, typ,
 336                                 "Failed to set timing policy to %d\n",
 337                                 conf.policy);
 338                    goto err;
 339                }
 340                setfragment = 0;
 341            }
 342        }
 343    }
 344#endif
 345
 346    if (setfragment) {
 347        int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
 348        if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
 349            oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
 350                         req->nfrags, req->fragsize);
 351            goto err;
 352        }
 353    }
 354
 355    if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
 356        oss_logerr2 (errno, typ, "Failed to get buffer length\n");
 357        goto err;
 358    }
 359
 360    if (!abinfo.fragstotal || !abinfo.fragsize) {
 361        AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
 362                 abinfo.fragstotal, abinfo.fragsize, typ);
 363        goto err;
 364    }
 365
 366    obt->fmt = fmt;
 367    obt->nchannels = nchannels;
 368    obt->freq = freq;
 369    obt->nfrags = abinfo.fragstotal;
 370    obt->fragsize = abinfo.fragsize;
 371    *pfd = fd;
 372
 373#ifdef DEBUG_MISMATCHES
 374    if ((req->fmt != obt->fmt) ||
 375        (req->nchannels != obt->nchannels) ||
 376        (req->freq != obt->freq) ||
 377        (req->fragsize != obt->fragsize) ||
 378        (req->nfrags != obt->nfrags)) {
 379        dolog ("Audio parameters mismatch\n");
 380        oss_dump_info (req, obt);
 381    }
 382#endif
 383
 384#ifdef DEBUG
 385    oss_dump_info (req, obt);
 386#endif
 387    return 0;
 388
 389 err:
 390    oss_anal_close (&fd);
 391    return -1;
 392}
 393
 394static void oss_write_pending (OSSVoiceOut *oss)
 395{
 396    HWVoiceOut *hw = &oss->hw;
 397
 398    if (oss->mmapped) {
 399        return;
 400    }
 401
 402    while (oss->pending) {
 403        int samples_written;
 404        ssize_t bytes_written;
 405        int samples_till_end = hw->samples - oss->wpos;
 406        int samples_to_write = audio_MIN (oss->pending, samples_till_end);
 407        int bytes_to_write = samples_to_write << hw->info.shift;
 408        void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
 409
 410        bytes_written = write (oss->fd, pcm, bytes_to_write);
 411        if (bytes_written < 0) {
 412            if (errno != EAGAIN) {
 413                oss_logerr (errno, "failed to write %d bytes\n",
 414                            bytes_to_write);
 415            }
 416            break;
 417        }
 418
 419        if (bytes_written & hw->info.align) {
 420            dolog ("misaligned write asked for %d, but got %zd\n",
 421                   bytes_to_write, bytes_written);
 422            return;
 423        }
 424
 425        samples_written = bytes_written >> hw->info.shift;
 426        oss->pending -= samples_written;
 427        oss->wpos = (oss->wpos + samples_written) % hw->samples;
 428        if (bytes_written - bytes_to_write) {
 429            break;
 430        }
 431    }
 432}
 433
 434static int oss_run_out (HWVoiceOut *hw, int live)
 435{
 436    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 437    int err, decr;
 438    struct audio_buf_info abinfo;
 439    struct count_info cntinfo;
 440    int bufsize;
 441
 442    bufsize = hw->samples << hw->info.shift;
 443
 444    if (oss->mmapped) {
 445        int bytes, pos;
 446
 447        err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
 448        if (err < 0) {
 449            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
 450            return 0;
 451        }
 452
 453        pos = hw->rpos << hw->info.shift;
 454        bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
 455        decr = audio_MIN (bytes >> hw->info.shift, live);
 456    }
 457    else {
 458        err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
 459        if (err < 0) {
 460            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
 461            return 0;
 462        }
 463
 464        if (abinfo.bytes > bufsize) {
 465            if (conf.debug) {
 466                dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
 467                       "please report your OS/audio hw to av1474@comtv.ru\n",
 468                       abinfo.bytes, bufsize);
 469            }
 470            abinfo.bytes = bufsize;
 471        }
 472
 473        if (abinfo.bytes < 0) {
 474            if (conf.debug) {
 475                dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
 476                       abinfo.bytes, bufsize);
 477            }
 478            return 0;
 479        }
 480
 481        decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
 482        if (!decr) {
 483            return 0;
 484        }
 485    }
 486
 487    decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending);
 488    oss->pending += decr;
 489    oss_write_pending (oss);
 490
 491    return decr;
 492}
 493
 494static void oss_fini_out (HWVoiceOut *hw)
 495{
 496    int err;
 497    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 498
 499    ldebug ("oss_fini\n");
 500    oss_anal_close (&oss->fd);
 501
 502    if (oss->pcm_buf) {
 503        if (oss->mmapped) {
 504            err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
 505            if (err) {
 506                oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
 507                            oss->pcm_buf, hw->samples << hw->info.shift);
 508            }
 509        }
 510        else {
 511            g_free (oss->pcm_buf);
 512        }
 513        oss->pcm_buf = NULL;
 514    }
 515}
 516
 517static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
 518{
 519    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 520    struct oss_params req, obt;
 521    int endianness;
 522    int err;
 523    int fd;
 524    audfmt_e effective_fmt;
 525    struct audsettings obt_as;
 526
 527    oss->fd = -1;
 528
 529    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
 530    req.freq = as->freq;
 531    req.nchannels = as->nchannels;
 532    req.fragsize = conf.fragsize;
 533    req.nfrags = conf.nfrags;
 534
 535    if (oss_open (0, &req, &obt, &fd)) {
 536        return -1;
 537    }
 538
 539    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
 540    if (err) {
 541        oss_anal_close (&fd);
 542        return -1;
 543    }
 544
 545    obt_as.freq = obt.freq;
 546    obt_as.nchannels = obt.nchannels;
 547    obt_as.fmt = effective_fmt;
 548    obt_as.endianness = endianness;
 549
 550    audio_pcm_init_info (&hw->info, &obt_as);
 551    oss->nfrags = obt.nfrags;
 552    oss->fragsize = obt.fragsize;
 553
 554    if (obt.nfrags * obt.fragsize & hw->info.align) {
 555        dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
 556               obt.nfrags * obt.fragsize, hw->info.align + 1);
 557    }
 558
 559    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
 560
 561    oss->mmapped = 0;
 562    if (conf.try_mmap) {
 563        oss->pcm_buf = mmap (
 564            NULL,
 565            hw->samples << hw->info.shift,
 566            PROT_READ | PROT_WRITE,
 567            MAP_SHARED,
 568            fd,
 569            0
 570            );
 571        if (oss->pcm_buf == MAP_FAILED) {
 572            oss_logerr (errno, "Failed to map %d bytes of DAC\n",
 573                        hw->samples << hw->info.shift);
 574        }
 575        else {
 576            int err;
 577            int trig = 0;
 578            if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 579                oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
 580            }
 581            else {
 582                trig = PCM_ENABLE_OUTPUT;
 583                if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 584                    oss_logerr (
 585                        errno,
 586                        "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
 587                        );
 588                }
 589                else {
 590                    oss->mmapped = 1;
 591                }
 592            }
 593
 594            if (!oss->mmapped) {
 595                err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
 596                if (err) {
 597                    oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
 598                                oss->pcm_buf, hw->samples << hw->info.shift);
 599                }
 600            }
 601        }
 602    }
 603
 604    if (!oss->mmapped) {
 605        oss->pcm_buf = audio_calloc (
 606            AUDIO_FUNC,
 607            hw->samples,
 608            1 << hw->info.shift
 609            );
 610        if (!oss->pcm_buf) {
 611            dolog (
 612                "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
 613                hw->samples,
 614                1 << hw->info.shift
 615                );
 616            oss_anal_close (&fd);
 617            return -1;
 618        }
 619    }
 620
 621    oss->fd = fd;
 622    return 0;
 623}
 624
 625static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
 626{
 627    int trig;
 628    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 629
 630    switch (cmd) {
 631    case VOICE_ENABLE:
 632        {
 633            va_list ap;
 634            int poll_mode;
 635
 636            va_start (ap, cmd);
 637            poll_mode = va_arg (ap, int);
 638            va_end (ap);
 639
 640            ldebug ("enabling voice\n");
 641            if (poll_mode && oss_poll_out (hw)) {
 642                poll_mode = 0;
 643            }
 644            hw->poll_mode = poll_mode;
 645
 646            if (!oss->mmapped) {
 647                return 0;
 648            }
 649
 650            audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
 651            trig = PCM_ENABLE_OUTPUT;
 652            if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 653                oss_logerr (
 654                    errno,
 655                    "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
 656                    );
 657                return -1;
 658            }
 659        }
 660        break;
 661
 662    case VOICE_DISABLE:
 663        if (hw->poll_mode) {
 664            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
 665            hw->poll_mode = 0;
 666        }
 667
 668        if (!oss->mmapped) {
 669            return 0;
 670        }
 671
 672        ldebug ("disabling voice\n");
 673        trig = 0;
 674        if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 675            oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
 676            return -1;
 677        }
 678        break;
 679    }
 680    return 0;
 681}
 682
 683static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
 684{
 685    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 686    struct oss_params req, obt;
 687    int endianness;
 688    int err;
 689    int fd;
 690    audfmt_e effective_fmt;
 691    struct audsettings obt_as;
 692
 693    oss->fd = -1;
 694
 695    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
 696    req.freq = as->freq;
 697    req.nchannels = as->nchannels;
 698    req.fragsize = conf.fragsize;
 699    req.nfrags = conf.nfrags;
 700    if (oss_open (1, &req, &obt, &fd)) {
 701        return -1;
 702    }
 703
 704    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
 705    if (err) {
 706        oss_anal_close (&fd);
 707        return -1;
 708    }
 709
 710    obt_as.freq = obt.freq;
 711    obt_as.nchannels = obt.nchannels;
 712    obt_as.fmt = effective_fmt;
 713    obt_as.endianness = endianness;
 714
 715    audio_pcm_init_info (&hw->info, &obt_as);
 716    oss->nfrags = obt.nfrags;
 717    oss->fragsize = obt.fragsize;
 718
 719    if (obt.nfrags * obt.fragsize & hw->info.align) {
 720        dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
 721               obt.nfrags * obt.fragsize, hw->info.align + 1);
 722    }
 723
 724    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
 725    oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
 726    if (!oss->pcm_buf) {
 727        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
 728               hw->samples, 1 << hw->info.shift);
 729        oss_anal_close (&fd);
 730        return -1;
 731    }
 732
 733    oss->fd = fd;
 734    return 0;
 735}
 736
 737static void oss_fini_in (HWVoiceIn *hw)
 738{
 739    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 740
 741    oss_anal_close (&oss->fd);
 742
 743    if (oss->pcm_buf) {
 744        g_free (oss->pcm_buf);
 745        oss->pcm_buf = NULL;
 746    }
 747}
 748
 749static int oss_run_in (HWVoiceIn *hw)
 750{
 751    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 752    int hwshift = hw->info.shift;
 753    int i;
 754    int live = audio_pcm_hw_get_live_in (hw);
 755    int dead = hw->samples - live;
 756    size_t read_samples = 0;
 757    struct {
 758        int add;
 759        int len;
 760    } bufs[2] = {
 761        { .add = hw->wpos, .len = 0 },
 762        { .add = 0,        .len = 0 }
 763    };
 764
 765    if (!dead) {
 766        return 0;
 767    }
 768
 769    if (hw->wpos + dead > hw->samples) {
 770        bufs[0].len = (hw->samples - hw->wpos) << hwshift;
 771        bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
 772    }
 773    else {
 774        bufs[0].len = dead << hwshift;
 775    }
 776
 777    for (i = 0; i < 2; ++i) {
 778        ssize_t nread;
 779
 780        if (bufs[i].len) {
 781            void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
 782            nread = read (oss->fd, p, bufs[i].len);
 783
 784            if (nread > 0) {
 785                if (nread & hw->info.align) {
 786                    dolog ("warning: Misaligned read %zd (requested %d), "
 787                           "alignment %d\n", nread, bufs[i].add << hwshift,
 788                           hw->info.align + 1);
 789                }
 790                read_samples += nread >> hwshift;
 791                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift);
 792            }
 793
 794            if (bufs[i].len - nread) {
 795                if (nread == -1) {
 796                    switch (errno) {
 797                    case EINTR:
 798                    case EAGAIN:
 799                        break;
 800                    default:
 801                        oss_logerr (
 802                            errno,
 803                            "Failed to read %d bytes of audio (to %p)\n",
 804                            bufs[i].len, p
 805                            );
 806                        break;
 807                    }
 808                }
 809                break;
 810            }
 811        }
 812    }
 813
 814    hw->wpos = (hw->wpos + read_samples) % hw->samples;
 815    return read_samples;
 816}
 817
 818static int oss_read (SWVoiceIn *sw, void *buf, int size)
 819{
 820    return audio_pcm_sw_read (sw, buf, size);
 821}
 822
 823static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
 824{
 825    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 826
 827    switch (cmd) {
 828    case VOICE_ENABLE:
 829        {
 830            va_list ap;
 831            int poll_mode;
 832
 833            va_start (ap, cmd);
 834            poll_mode = va_arg (ap, int);
 835            va_end (ap);
 836
 837            if (poll_mode && oss_poll_in (hw)) {
 838                poll_mode = 0;
 839            }
 840            hw->poll_mode = poll_mode;
 841        }
 842        break;
 843
 844    case VOICE_DISABLE:
 845        if (hw->poll_mode) {
 846            hw->poll_mode = 0;
 847            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
 848        }
 849        break;
 850    }
 851    return 0;
 852}
 853
 854static void *oss_audio_init (void)
 855{
 856    return &conf;
 857}
 858
 859static void oss_audio_fini (void *opaque)
 860{
 861    (void) opaque;
 862}
 863
 864static struct audio_option oss_options[] = {
 865    {
 866        .name  = "FRAGSIZE",
 867        .tag   = AUD_OPT_INT,
 868        .valp  = &conf.fragsize,
 869        .descr = "Fragment size in bytes"
 870    },
 871    {
 872        .name  = "NFRAGS",
 873        .tag   = AUD_OPT_INT,
 874        .valp  = &conf.nfrags,
 875        .descr = "Number of fragments"
 876    },
 877    {
 878        .name  = "MMAP",
 879        .tag   = AUD_OPT_BOOL,
 880        .valp  = &conf.try_mmap,
 881        .descr = "Try using memory mapped access"
 882    },
 883    {
 884        .name  = "DAC_DEV",
 885        .tag   = AUD_OPT_STR,
 886        .valp  = &conf.devpath_out,
 887        .descr = "Path to DAC device"
 888    },
 889    {
 890        .name  = "ADC_DEV",
 891        .tag   = AUD_OPT_STR,
 892        .valp  = &conf.devpath_in,
 893        .descr = "Path to ADC device"
 894    },
 895    {
 896        .name  = "EXCLUSIVE",
 897        .tag   = AUD_OPT_BOOL,
 898        .valp  = &conf.exclusive,
 899        .descr = "Open device in exclusive mode (vmix wont work)"
 900    },
 901#ifdef USE_DSP_POLICY
 902    {
 903        .name  = "POLICY",
 904        .tag   = AUD_OPT_INT,
 905        .valp  = &conf.policy,
 906        .descr = "Set the timing policy of the device, -1 to use fragment mode",
 907    },
 908#endif
 909    {
 910        .name  = "DEBUG",
 911        .tag   = AUD_OPT_BOOL,
 912        .valp  = &conf.debug,
 913        .descr = "Turn on some debugging messages"
 914    },
 915    { /* End of list */ }
 916};
 917
 918static struct audio_pcm_ops oss_pcm_ops = {
 919    .init_out = oss_init_out,
 920    .fini_out = oss_fini_out,
 921    .run_out  = oss_run_out,
 922    .write    = oss_write,
 923    .ctl_out  = oss_ctl_out,
 924
 925    .init_in  = oss_init_in,
 926    .fini_in  = oss_fini_in,
 927    .run_in   = oss_run_in,
 928    .read     = oss_read,
 929    .ctl_in   = oss_ctl_in
 930};
 931
 932struct audio_driver oss_audio_driver = {
 933    .name           = "oss",
 934    .descr          = "OSS http://www.opensound.com",
 935    .options        = oss_options,
 936    .init           = oss_audio_init,
 937    .fini           = oss_audio_fini,
 938    .pcm_ops        = &oss_pcm_ops,
 939    .can_be_default = 1,
 940    .max_voices_out = INT_MAX,
 941    .max_voices_in  = INT_MAX,
 942    .voice_size_out = sizeof (OSSVoiceOut),
 943    .voice_size_in  = sizeof (OSSVoiceIn)
 944};
 945