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(__func__,
 586                                    hw->samples,
 587                                    1 << hw->info.shift);
 588        if (!oss->pcm_buf) {
 589            dolog (
 590                "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
 591                hw->samples,
 592                1 << hw->info.shift
 593                );
 594            oss_anal_close (&fd);
 595            return -1;
 596        }
 597    }
 598
 599    oss->fd = fd;
 600    oss->conf = conf;
 601    return 0;
 602}
 603
 604static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
 605{
 606    int trig;
 607    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 608
 609    switch (cmd) {
 610    case VOICE_ENABLE:
 611        {
 612            va_list ap;
 613            int poll_mode;
 614
 615            va_start (ap, cmd);
 616            poll_mode = va_arg (ap, int);
 617            va_end (ap);
 618
 619            ldebug ("enabling voice\n");
 620            if (poll_mode) {
 621                oss_poll_out (hw);
 622                poll_mode = 0;
 623            }
 624            hw->poll_mode = poll_mode;
 625
 626            if (!oss->mmapped) {
 627                return 0;
 628            }
 629
 630            audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
 631            trig = PCM_ENABLE_OUTPUT;
 632            if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 633                oss_logerr (
 634                    errno,
 635                    "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
 636                    );
 637                return -1;
 638            }
 639        }
 640        break;
 641
 642    case VOICE_DISABLE:
 643        if (hw->poll_mode) {
 644            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
 645            hw->poll_mode = 0;
 646        }
 647
 648        if (!oss->mmapped) {
 649            return 0;
 650        }
 651
 652        ldebug ("disabling voice\n");
 653        trig = 0;
 654        if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 655            oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
 656            return -1;
 657        }
 658        break;
 659    }
 660    return 0;
 661}
 662
 663static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
 664{
 665    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 666    struct oss_params req, obt;
 667    int endianness;
 668    int err;
 669    int fd;
 670    audfmt_e effective_fmt;
 671    struct audsettings obt_as;
 672    OSSConf *conf = drv_opaque;
 673
 674    oss->fd = -1;
 675
 676    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
 677    req.freq = as->freq;
 678    req.nchannels = as->nchannels;
 679    req.fragsize = conf->fragsize;
 680    req.nfrags = conf->nfrags;
 681    if (oss_open (1, &req, &obt, &fd, conf)) {
 682        return -1;
 683    }
 684
 685    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
 686    if (err) {
 687        oss_anal_close (&fd);
 688        return -1;
 689    }
 690
 691    obt_as.freq = obt.freq;
 692    obt_as.nchannels = obt.nchannels;
 693    obt_as.fmt = effective_fmt;
 694    obt_as.endianness = endianness;
 695
 696    audio_pcm_init_info (&hw->info, &obt_as);
 697    oss->nfrags = obt.nfrags;
 698    oss->fragsize = obt.fragsize;
 699
 700    if (obt.nfrags * obt.fragsize & hw->info.align) {
 701        dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
 702               obt.nfrags * obt.fragsize, hw->info.align + 1);
 703    }
 704
 705    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
 706    oss->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
 707    if (!oss->pcm_buf) {
 708        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
 709               hw->samples, 1 << hw->info.shift);
 710        oss_anal_close (&fd);
 711        return -1;
 712    }
 713
 714    oss->fd = fd;
 715    oss->conf = conf;
 716    return 0;
 717}
 718
 719static void oss_fini_in (HWVoiceIn *hw)
 720{
 721    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 722
 723    oss_anal_close (&oss->fd);
 724
 725    g_free(oss->pcm_buf);
 726    oss->pcm_buf = NULL;
 727}
 728
 729static int oss_run_in (HWVoiceIn *hw)
 730{
 731    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 732    int hwshift = hw->info.shift;
 733    int i;
 734    int live = audio_pcm_hw_get_live_in (hw);
 735    int dead = hw->samples - live;
 736    size_t read_samples = 0;
 737    struct {
 738        int add;
 739        int len;
 740    } bufs[2] = {
 741        { .add = hw->wpos, .len = 0 },
 742        { .add = 0,        .len = 0 }
 743    };
 744
 745    if (!dead) {
 746        return 0;
 747    }
 748
 749    if (hw->wpos + dead > hw->samples) {
 750        bufs[0].len = (hw->samples - hw->wpos) << hwshift;
 751        bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
 752    }
 753    else {
 754        bufs[0].len = dead << hwshift;
 755    }
 756
 757    for (i = 0; i < 2; ++i) {
 758        ssize_t nread;
 759
 760        if (bufs[i].len) {
 761            void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
 762            nread = read (oss->fd, p, bufs[i].len);
 763
 764            if (nread > 0) {
 765                if (nread & hw->info.align) {
 766                    dolog ("warning: Misaligned read %zd (requested %d), "
 767                           "alignment %d\n", nread, bufs[i].add << hwshift,
 768                           hw->info.align + 1);
 769                }
 770                read_samples += nread >> hwshift;
 771                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift);
 772            }
 773
 774            if (bufs[i].len - nread) {
 775                if (nread == -1) {
 776                    switch (errno) {
 777                    case EINTR:
 778                    case EAGAIN:
 779                        break;
 780                    default:
 781                        oss_logerr (
 782                            errno,
 783                            "Failed to read %d bytes of audio (to %p)\n",
 784                            bufs[i].len, p
 785                            );
 786                        break;
 787                    }
 788                }
 789                break;
 790            }
 791        }
 792    }
 793
 794    hw->wpos = (hw->wpos + read_samples) % hw->samples;
 795    return read_samples;
 796}
 797
 798static int oss_read (SWVoiceIn *sw, void *buf, int size)
 799{
 800    return audio_pcm_sw_read (sw, buf, size);
 801}
 802
 803static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
 804{
 805    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 806
 807    switch (cmd) {
 808    case VOICE_ENABLE:
 809        {
 810            va_list ap;
 811            int poll_mode;
 812
 813            va_start (ap, cmd);
 814            poll_mode = va_arg (ap, int);
 815            va_end (ap);
 816
 817            if (poll_mode) {
 818                oss_poll_in (hw);
 819                poll_mode = 0;
 820            }
 821            hw->poll_mode = poll_mode;
 822        }
 823        break;
 824
 825    case VOICE_DISABLE:
 826        if (hw->poll_mode) {
 827            hw->poll_mode = 0;
 828            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
 829        }
 830        break;
 831    }
 832    return 0;
 833}
 834
 835static OSSConf glob_conf = {
 836    .try_mmap = 0,
 837    .nfrags = 4,
 838    .fragsize = 4096,
 839    .devpath_out = "/dev/dsp",
 840    .devpath_in = "/dev/dsp",
 841    .exclusive = 0,
 842    .policy = 5
 843};
 844
 845static void *oss_audio_init (void)
 846{
 847    OSSConf *conf = g_malloc(sizeof(OSSConf));
 848    *conf = glob_conf;
 849
 850    if (access(conf->devpath_in, R_OK | W_OK) < 0 ||
 851        access(conf->devpath_out, R_OK | W_OK) < 0) {
 852        g_free(conf);
 853        return NULL;
 854    }
 855    return conf;
 856}
 857
 858static void oss_audio_fini (void *opaque)
 859{
 860    g_free(opaque);
 861}
 862
 863static struct audio_option oss_options[] = {
 864    {
 865        .name  = "FRAGSIZE",
 866        .tag   = AUD_OPT_INT,
 867        .valp  = &glob_conf.fragsize,
 868        .descr = "Fragment size in bytes"
 869    },
 870    {
 871        .name  = "NFRAGS",
 872        .tag   = AUD_OPT_INT,
 873        .valp  = &glob_conf.nfrags,
 874        .descr = "Number of fragments"
 875    },
 876    {
 877        .name  = "MMAP",
 878        .tag   = AUD_OPT_BOOL,
 879        .valp  = &glob_conf.try_mmap,
 880        .descr = "Try using memory mapped access"
 881    },
 882    {
 883        .name  = "DAC_DEV",
 884        .tag   = AUD_OPT_STR,
 885        .valp  = &glob_conf.devpath_out,
 886        .descr = "Path to DAC device"
 887    },
 888    {
 889        .name  = "ADC_DEV",
 890        .tag   = AUD_OPT_STR,
 891        .valp  = &glob_conf.devpath_in,
 892        .descr = "Path to ADC device"
 893    },
 894    {
 895        .name  = "EXCLUSIVE",
 896        .tag   = AUD_OPT_BOOL,
 897        .valp  = &glob_conf.exclusive,
 898        .descr = "Open device in exclusive mode (vmix won't work)"
 899    },
 900#ifdef USE_DSP_POLICY
 901    {
 902        .name  = "POLICY",
 903        .tag   = AUD_OPT_INT,
 904        .valp  = &glob_conf.policy,
 905        .descr = "Set the timing policy of the device, -1 to use fragment mode",
 906    },
 907#endif
 908    { /* End of list */ }
 909};
 910
 911static struct audio_pcm_ops oss_pcm_ops = {
 912    .init_out = oss_init_out,
 913    .fini_out = oss_fini_out,
 914    .run_out  = oss_run_out,
 915    .write    = oss_write,
 916    .ctl_out  = oss_ctl_out,
 917
 918    .init_in  = oss_init_in,
 919    .fini_in  = oss_fini_in,
 920    .run_in   = oss_run_in,
 921    .read     = oss_read,
 922    .ctl_in   = oss_ctl_in
 923};
 924
 925static struct audio_driver oss_audio_driver = {
 926    .name           = "oss",
 927    .descr          = "OSS http://www.opensound.com",
 928    .options        = oss_options,
 929    .init           = oss_audio_init,
 930    .fini           = oss_audio_fini,
 931    .pcm_ops        = &oss_pcm_ops,
 932    .can_be_default = 1,
 933    .max_voices_out = INT_MAX,
 934    .max_voices_in  = INT_MAX,
 935    .voice_size_out = sizeof (OSSVoiceOut),
 936    .voice_size_in  = sizeof (OSSVoiceIn)
 937};
 938
 939static void register_audio_oss(void)
 940{
 941    audio_driver_register(&oss_audio_driver);
 942}
 943type_init(register_audio_oss);
 944