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