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 "host-utils.h"
  35#include "qemu-char.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)
 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        return AFMT_S16_LE;
 175
 176    case AUD_FMT_U16:
 177        return AFMT_U16_LE;
 178
 179    default:
 180        dolog ("Internal logic error: Bad audio format %d\n", fmt);
 181#ifdef DEBUG_AUDIO
 182        abort ();
 183#endif
 184        return AFMT_U8;
 185    }
 186}
 187
 188static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
 189{
 190    switch (ossfmt) {
 191    case AFMT_S8:
 192        *endianness = 0;
 193        *fmt = AUD_FMT_S8;
 194        break;
 195
 196    case AFMT_U8:
 197        *endianness = 0;
 198        *fmt = AUD_FMT_U8;
 199        break;
 200
 201    case AFMT_S16_LE:
 202        *endianness = 0;
 203        *fmt = AUD_FMT_S16;
 204        break;
 205
 206    case AFMT_U16_LE:
 207        *endianness = 0;
 208        *fmt = AUD_FMT_U16;
 209        break;
 210
 211    case AFMT_S16_BE:
 212        *endianness = 1;
 213        *fmt = AUD_FMT_S16;
 214        break;
 215
 216    case AFMT_U16_BE:
 217        *endianness = 1;
 218        *fmt = AUD_FMT_U16;
 219        break;
 220
 221    default:
 222        dolog ("Unrecognized audio format %d\n", ossfmt);
 223        return -1;
 224    }
 225
 226    return 0;
 227}
 228
 229#if defined DEBUG_MISMATCHES || defined DEBUG
 230static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
 231{
 232    dolog ("parameter | requested value | obtained value\n");
 233    dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
 234    dolog ("channels  |      %10d |     %10d\n",
 235           req->nchannels, obt->nchannels);
 236    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
 237    dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
 238    dolog ("fragsize  |      %10d |     %10d\n",
 239           req->fragsize, obt->fragsize);
 240}
 241#endif
 242
 243#ifdef USE_DSP_POLICY
 244static int oss_get_version (int fd, int *version, const char *typ)
 245{
 246    if (ioctl (fd, OSS_GETVERSION, &version)) {
 247#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 248        /*
 249         * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
 250         * since 7.x, but currently only on the mixer device (or in
 251         * the Linuxolator), and in the native version that part of
 252         * the code is in fact never reached so the ioctl fails anyway.
 253         * Until this is fixed, just check the errno and if its what
 254         * FreeBSD's sound drivers return atm assume they are new enough.
 255         */
 256        if (errno == EINVAL) {
 257            *version = 0x040000;
 258            return 0;
 259        }
 260#endif
 261        oss_logerr2 (errno, typ, "Failed to get OSS version\n");
 262        return -1;
 263    }
 264    return 0;
 265}
 266#endif
 267
 268static int oss_open (int in, struct oss_params *req,
 269                     struct oss_params *obt, int *pfd)
 270{
 271    int fd;
 272    int oflags = conf.exclusive ? O_EXCL : 0;
 273    audio_buf_info abinfo;
 274    int fmt, freq, nchannels;
 275    int setfragment = 1;
 276    const char *dspname = in ? conf.devpath_in : conf.devpath_out;
 277    const char *typ = in ? "ADC" : "DAC";
 278
 279    /* Kludge needed to have working mmap on Linux */
 280    oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
 281
 282    fd = open (dspname, oflags | O_NONBLOCK);
 283    if (-1 == fd) {
 284        oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
 285        return -1;
 286    }
 287
 288    freq = req->freq;
 289    nchannels = req->nchannels;
 290    fmt = req->fmt;
 291
 292    if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
 293        oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
 294        goto err;
 295    }
 296
 297    if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
 298        oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
 299                     req->nchannels);
 300        goto err;
 301    }
 302
 303    if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
 304        oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
 305        goto err;
 306    }
 307
 308    if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
 309        oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
 310        goto err;
 311    }
 312
 313#ifdef USE_DSP_POLICY
 314    if (conf.policy >= 0) {
 315        int version;
 316
 317        if (!oss_get_version (fd, &version, typ)) {
 318            if (conf.debug) {
 319                dolog ("OSS version = %#x\n", version);
 320            }
 321
 322            if (version >= 0x040000) {
 323                int policy = conf.policy;
 324                if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
 325                    oss_logerr2 (errno, typ,
 326                                 "Failed to set timing policy to %d\n",
 327                                 conf.policy);
 328                    goto err;
 329                }
 330                setfragment = 0;
 331            }
 332        }
 333    }
 334#endif
 335
 336    if (setfragment) {
 337        int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
 338        if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
 339            oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
 340                         req->nfrags, req->fragsize);
 341            goto err;
 342        }
 343    }
 344
 345    if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
 346        oss_logerr2 (errno, typ, "Failed to get buffer length\n");
 347        goto err;
 348    }
 349
 350    if (!abinfo.fragstotal || !abinfo.fragsize) {
 351        AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
 352                 abinfo.fragstotal, abinfo.fragsize, typ);
 353        goto err;
 354    }
 355
 356    obt->fmt = fmt;
 357    obt->nchannels = nchannels;
 358    obt->freq = freq;
 359    obt->nfrags = abinfo.fragstotal;
 360    obt->fragsize = abinfo.fragsize;
 361    *pfd = fd;
 362
 363#ifdef DEBUG_MISMATCHES
 364    if ((req->fmt != obt->fmt) ||
 365        (req->nchannels != obt->nchannels) ||
 366        (req->freq != obt->freq) ||
 367        (req->fragsize != obt->fragsize) ||
 368        (req->nfrags != obt->nfrags)) {
 369        dolog ("Audio parameters mismatch\n");
 370        oss_dump_info (req, obt);
 371    }
 372#endif
 373
 374#ifdef DEBUG
 375    oss_dump_info (req, obt);
 376#endif
 377    return 0;
 378
 379 err:
 380    oss_anal_close (&fd);
 381    return -1;
 382}
 383
 384static void oss_write_pending (OSSVoiceOut *oss)
 385{
 386    HWVoiceOut *hw = &oss->hw;
 387
 388    if (oss->mmapped) {
 389        return;
 390    }
 391
 392    while (oss->pending) {
 393        int samples_written;
 394        ssize_t bytes_written;
 395        int samples_till_end = hw->samples - oss->wpos;
 396        int samples_to_write = audio_MIN (oss->pending, samples_till_end);
 397        int bytes_to_write = samples_to_write << hw->info.shift;
 398        void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
 399
 400        bytes_written = write (oss->fd, pcm, bytes_to_write);
 401        if (bytes_written < 0) {
 402            if (errno != EAGAIN) {
 403                oss_logerr (errno, "failed to write %d bytes\n",
 404                            bytes_to_write);
 405            }
 406            break;
 407        }
 408
 409        if (bytes_written & hw->info.align) {
 410            dolog ("misaligned write asked for %d, but got %zd\n",
 411                   bytes_to_write, bytes_written);
 412            return;
 413        }
 414
 415        samples_written = bytes_written >> hw->info.shift;
 416        oss->pending -= samples_written;
 417        oss->wpos = (oss->wpos + samples_written) % hw->samples;
 418        if (bytes_written - bytes_to_write) {
 419            break;
 420        }
 421    }
 422}
 423
 424static int oss_run_out (HWVoiceOut *hw, int live)
 425{
 426    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 427    int err, decr;
 428    struct audio_buf_info abinfo;
 429    struct count_info cntinfo;
 430    int bufsize;
 431
 432    bufsize = hw->samples << hw->info.shift;
 433
 434    if (oss->mmapped) {
 435        int bytes, pos;
 436
 437        err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
 438        if (err < 0) {
 439            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
 440            return 0;
 441        }
 442
 443        pos = hw->rpos << hw->info.shift;
 444        bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
 445        decr = audio_MIN (bytes >> hw->info.shift, live);
 446    }
 447    else {
 448        err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
 449        if (err < 0) {
 450            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
 451            return 0;
 452        }
 453
 454        if (abinfo.bytes > bufsize) {
 455            if (conf.debug) {
 456                dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
 457                       "please report your OS/audio hw to av1474@comtv.ru\n",
 458                       abinfo.bytes, bufsize);
 459            }
 460            abinfo.bytes = bufsize;
 461        }
 462
 463        if (abinfo.bytes < 0) {
 464            if (conf.debug) {
 465                dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
 466                       abinfo.bytes, bufsize);
 467            }
 468            return 0;
 469        }
 470
 471        decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
 472        if (!decr) {
 473            return 0;
 474        }
 475    }
 476
 477    decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending);
 478    oss->pending += decr;
 479    oss_write_pending (oss);
 480
 481    return decr;
 482}
 483
 484static void oss_fini_out (HWVoiceOut *hw)
 485{
 486    int err;
 487    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 488
 489    ldebug ("oss_fini\n");
 490    oss_anal_close (&oss->fd);
 491
 492    if (oss->pcm_buf) {
 493        if (oss->mmapped) {
 494            err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
 495            if (err) {
 496                oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
 497                            oss->pcm_buf, hw->samples << hw->info.shift);
 498            }
 499        }
 500        else {
 501            qemu_free (oss->pcm_buf);
 502        }
 503        oss->pcm_buf = NULL;
 504    }
 505}
 506
 507static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
 508{
 509    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 510    struct oss_params req, obt;
 511    int endianness;
 512    int err;
 513    int fd;
 514    audfmt_e effective_fmt;
 515    struct audsettings obt_as;
 516
 517    oss->fd = -1;
 518
 519    req.fmt = aud_to_ossfmt (as->fmt);
 520    req.freq = as->freq;
 521    req.nchannels = as->nchannels;
 522    req.fragsize = conf.fragsize;
 523    req.nfrags = conf.nfrags;
 524
 525    if (oss_open (0, &req, &obt, &fd)) {
 526        return -1;
 527    }
 528
 529    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
 530    if (err) {
 531        oss_anal_close (&fd);
 532        return -1;
 533    }
 534
 535    obt_as.freq = obt.freq;
 536    obt_as.nchannels = obt.nchannels;
 537    obt_as.fmt = effective_fmt;
 538    obt_as.endianness = endianness;
 539
 540    audio_pcm_init_info (&hw->info, &obt_as);
 541    oss->nfrags = obt.nfrags;
 542    oss->fragsize = obt.fragsize;
 543
 544    if (obt.nfrags * obt.fragsize & hw->info.align) {
 545        dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
 546               obt.nfrags * obt.fragsize, hw->info.align + 1);
 547    }
 548
 549    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
 550
 551    oss->mmapped = 0;
 552    if (conf.try_mmap) {
 553        oss->pcm_buf = mmap (
 554            NULL,
 555            hw->samples << hw->info.shift,
 556            PROT_READ | PROT_WRITE,
 557            MAP_SHARED,
 558            fd,
 559            0
 560            );
 561        if (oss->pcm_buf == MAP_FAILED) {
 562            oss_logerr (errno, "Failed to map %d bytes of DAC\n",
 563                        hw->samples << hw->info.shift);
 564        }
 565        else {
 566            int err;
 567            int trig = 0;
 568            if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 569                oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
 570            }
 571            else {
 572                trig = PCM_ENABLE_OUTPUT;
 573                if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 574                    oss_logerr (
 575                        errno,
 576                        "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
 577                        );
 578                }
 579                else {
 580                    oss->mmapped = 1;
 581                }
 582            }
 583
 584            if (!oss->mmapped) {
 585                err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
 586                if (err) {
 587                    oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
 588                                oss->pcm_buf, hw->samples << hw->info.shift);
 589                }
 590            }
 591        }
 592    }
 593
 594    if (!oss->mmapped) {
 595        oss->pcm_buf = audio_calloc (
 596            AUDIO_FUNC,
 597            hw->samples,
 598            1 << hw->info.shift
 599            );
 600        if (!oss->pcm_buf) {
 601            dolog (
 602                "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
 603                hw->samples,
 604                1 << hw->info.shift
 605                );
 606            oss_anal_close (&fd);
 607            return -1;
 608        }
 609    }
 610
 611    oss->fd = fd;
 612    return 0;
 613}
 614
 615static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
 616{
 617    int trig;
 618    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 619
 620    switch (cmd) {
 621    case VOICE_ENABLE:
 622        {
 623            va_list ap;
 624            int poll_mode;
 625
 626            va_start (ap, cmd);
 627            poll_mode = va_arg (ap, int);
 628            va_end (ap);
 629
 630            ldebug ("enabling voice\n");
 631            if (poll_mode && oss_poll_out (hw)) {
 632                poll_mode = 0;
 633            }
 634            hw->poll_mode = poll_mode;
 635
 636            if (!oss->mmapped) {
 637                return 0;
 638            }
 639
 640            audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
 641            trig = PCM_ENABLE_OUTPUT;
 642            if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 643                oss_logerr (
 644                    errno,
 645                    "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
 646                    );
 647                return -1;
 648            }
 649        }
 650        break;
 651
 652    case VOICE_DISABLE:
 653        if (hw->poll_mode) {
 654            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
 655            hw->poll_mode = 0;
 656        }
 657
 658        if (!oss->mmapped) {
 659            return 0;
 660        }
 661
 662        ldebug ("disabling voice\n");
 663        trig = 0;
 664        if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 665            oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
 666            return -1;
 667        }
 668        break;
 669    }
 670    return 0;
 671}
 672
 673static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
 674{
 675    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 676    struct oss_params req, obt;
 677    int endianness;
 678    int err;
 679    int fd;
 680    audfmt_e effective_fmt;
 681    struct audsettings obt_as;
 682
 683    oss->fd = -1;
 684
 685    req.fmt = aud_to_ossfmt (as->fmt);
 686    req.freq = as->freq;
 687    req.nchannels = as->nchannels;
 688    req.fragsize = conf.fragsize;
 689    req.nfrags = conf.nfrags;
 690    if (oss_open (1, &req, &obt, &fd)) {
 691        return -1;
 692    }
 693
 694    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
 695    if (err) {
 696        oss_anal_close (&fd);
 697        return -1;
 698    }
 699
 700    obt_as.freq = obt.freq;
 701    obt_as.nchannels = obt.nchannels;
 702    obt_as.fmt = effective_fmt;
 703    obt_as.endianness = endianness;
 704
 705    audio_pcm_init_info (&hw->info, &obt_as);
 706    oss->nfrags = obt.nfrags;
 707    oss->fragsize = obt.fragsize;
 708
 709    if (obt.nfrags * obt.fragsize & hw->info.align) {
 710        dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
 711               obt.nfrags * obt.fragsize, hw->info.align + 1);
 712    }
 713
 714    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
 715    oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
 716    if (!oss->pcm_buf) {
 717        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
 718               hw->samples, 1 << hw->info.shift);
 719        oss_anal_close (&fd);
 720        return -1;
 721    }
 722
 723    oss->fd = fd;
 724    return 0;
 725}
 726
 727static void oss_fini_in (HWVoiceIn *hw)
 728{
 729    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 730
 731    oss_anal_close (&oss->fd);
 732
 733    if (oss->pcm_buf) {
 734        qemu_free (oss->pcm_buf);
 735        oss->pcm_buf = NULL;
 736    }
 737}
 738
 739static int oss_run_in (HWVoiceIn *hw)
 740{
 741    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 742    int hwshift = hw->info.shift;
 743    int i;
 744    int live = audio_pcm_hw_get_live_in (hw);
 745    int dead = hw->samples - live;
 746    size_t read_samples = 0;
 747    struct {
 748        int add;
 749        int len;
 750    } bufs[2] = {
 751        { .add = hw->wpos, .len = 0 },
 752        { .add = 0,        .len = 0 }
 753    };
 754
 755    if (!dead) {
 756        return 0;
 757    }
 758
 759    if (hw->wpos + dead > hw->samples) {
 760        bufs[0].len = (hw->samples - hw->wpos) << hwshift;
 761        bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
 762    }
 763    else {
 764        bufs[0].len = dead << hwshift;
 765    }
 766
 767    for (i = 0; i < 2; ++i) {
 768        ssize_t nread;
 769
 770        if (bufs[i].len) {
 771            void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
 772            nread = read (oss->fd, p, bufs[i].len);
 773
 774            if (nread > 0) {
 775                if (nread & hw->info.align) {
 776                    dolog ("warning: Misaligned read %zd (requested %d), "
 777                           "alignment %d\n", nread, bufs[i].add << hwshift,
 778                           hw->info.align + 1);
 779                }
 780                read_samples += nread >> hwshift;
 781                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
 782                          &nominal_volume);
 783            }
 784
 785            if (bufs[i].len - nread) {
 786                if (nread == -1) {
 787                    switch (errno) {
 788                    case EINTR:
 789                    case EAGAIN:
 790                        break;
 791                    default:
 792                        oss_logerr (
 793                            errno,
 794                            "Failed to read %d bytes of audio (to %p)\n",
 795                            bufs[i].len, p
 796                            );
 797                        break;
 798                    }
 799                }
 800                break;
 801            }
 802        }
 803    }
 804
 805    hw->wpos = (hw->wpos + read_samples) % hw->samples;
 806    return read_samples;
 807}
 808
 809static int oss_read (SWVoiceIn *sw, void *buf, int size)
 810{
 811    return audio_pcm_sw_read (sw, buf, size);
 812}
 813
 814static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
 815{
 816    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 817
 818    switch (cmd) {
 819    case VOICE_ENABLE:
 820        {
 821            va_list ap;
 822            int poll_mode;
 823
 824            va_start (ap, cmd);
 825            poll_mode = va_arg (ap, int);
 826            va_end (ap);
 827
 828            if (poll_mode && oss_poll_in (hw)) {
 829                poll_mode = 0;
 830            }
 831            hw->poll_mode = poll_mode;
 832        }
 833        break;
 834
 835    case VOICE_DISABLE:
 836        if (hw->poll_mode) {
 837            hw->poll_mode = 0;
 838            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
 839        }
 840        break;
 841    }
 842    return 0;
 843}
 844
 845static void *oss_audio_init (void)
 846{
 847    return &conf;
 848}
 849
 850static void oss_audio_fini (void *opaque)
 851{
 852    (void) opaque;
 853}
 854
 855static struct audio_option oss_options[] = {
 856    {
 857        .name  = "FRAGSIZE",
 858        .tag   = AUD_OPT_INT,
 859        .valp  = &conf.fragsize,
 860        .descr = "Fragment size in bytes"
 861    },
 862    {
 863        .name  = "NFRAGS",
 864        .tag   = AUD_OPT_INT,
 865        .valp  = &conf.nfrags,
 866        .descr = "Number of fragments"
 867    },
 868    {
 869        .name  = "MMAP",
 870        .tag   = AUD_OPT_BOOL,
 871        .valp  = &conf.try_mmap,
 872        .descr = "Try using memory mapped access"
 873    },
 874    {
 875        .name  = "DAC_DEV",
 876        .tag   = AUD_OPT_STR,
 877        .valp  = &conf.devpath_out,
 878        .descr = "Path to DAC device"
 879    },
 880    {
 881        .name  = "ADC_DEV",
 882        .tag   = AUD_OPT_STR,
 883        .valp  = &conf.devpath_in,
 884        .descr = "Path to ADC device"
 885    },
 886    {
 887        .name  = "EXCLUSIVE",
 888        .tag   = AUD_OPT_BOOL,
 889        .valp  = &conf.exclusive,
 890        .descr = "Open device in exclusive mode (vmix wont work)"
 891    },
 892#ifdef USE_DSP_POLICY
 893    {
 894        .name  = "POLICY",
 895        .tag   = AUD_OPT_INT,
 896        .valp  = &conf.policy,
 897        .descr = "Set the timing policy of the device, -1 to use fragment mode",
 898    },
 899#endif
 900    {
 901        .name  = "DEBUG",
 902        .tag   = AUD_OPT_BOOL,
 903        .valp  = &conf.debug,
 904        .descr = "Turn on some debugging messages"
 905    },
 906    { /* End of list */ }
 907};
 908
 909static struct audio_pcm_ops oss_pcm_ops = {
 910    .init_out = oss_init_out,
 911    .fini_out = oss_fini_out,
 912    .run_out  = oss_run_out,
 913    .write    = oss_write,
 914    .ctl_out  = oss_ctl_out,
 915
 916    .init_in  = oss_init_in,
 917    .fini_in  = oss_fini_in,
 918    .run_in   = oss_run_in,
 919    .read     = oss_read,
 920    .ctl_in   = oss_ctl_in
 921};
 922
 923struct audio_driver oss_audio_driver = {
 924    .name           = "oss",
 925    .descr          = "OSS http://www.opensound.com",
 926    .options        = oss_options,
 927    .init           = oss_audio_init,
 928    .fini           = oss_audio_fini,
 929    .pcm_ops        = &oss_pcm_ops,
 930    .can_be_default = 1,
 931    .max_voices_out = INT_MAX,
 932    .max_voices_in  = INT_MAX,
 933    .voice_size_out = sizeof (OSSVoiceOut),
 934    .voice_size_in  = sizeof (OSSVoiceIn)
 935};
 936