Statistics
| Branch: | Revision:

root / audio / ossaudio.c @ 78d9356d

History | View | Annotate | Download (22.8 kB)

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

    
45
typedef 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

    
56
typedef struct OSSVoiceIn {
57
    HWVoiceIn hw;
58
    void *pcm_buf;
59
    int fd;
60
    int nfrags;
61
    int fragsize;
62
} OSSVoiceIn;
63

    
64
static 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

    
84
struct oss_params {
85
    int freq;
86
    audfmt_e fmt;
87
    int nchannels;
88
    int nfrags;
89
    int fragsize;
90
};
91

    
92
static 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

    
103
static 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

    
121
static 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

    
133
static void oss_helper_poll_out (void *opaque)
134
{
135
    (void) opaque;
136
    audio_run ("oss_poll_out");
137
}
138

    
139
static void oss_helper_poll_in (void *opaque)
140
{
141
    (void) opaque;
142
    audio_run ("oss_poll_in");
143
}
144

    
145
static 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

    
152
static 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

    
159
static int oss_write (SWVoiceOut *sw, void *buf, int len)
160
{
161
    return audio_pcm_sw_write (sw, buf, len);
162
}
163

    
164
static 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

    
188
static 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
230
static 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
static int oss_open (int in, struct oss_params *req,
244
                     struct oss_params *obt, int *pfd)
245
{
246
    int fd;
247
#ifdef USE_DSP_POLICY
248
    int version;
249
#endif
250
    int oflags = conf.exclusive ? O_EXCL : 0;
251
    audio_buf_info abinfo;
252
    int fmt, freq, nchannels;
253
    const char *dspname = in ? conf.devpath_in : conf.devpath_out;
254
    const char *typ = in ? "ADC" : "DAC";
255

    
256
    /* Kludge needed to have working mmap on Linux */
257
    oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
258

    
259
    fd = open (dspname, oflags | O_NONBLOCK);
260
    if (-1 == fd) {
261
        oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
262
        return -1;
263
    }
264

    
265
    freq = req->freq;
266
    nchannels = req->nchannels;
267
    fmt = req->fmt;
268

    
269
    if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
270
        oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
271
        goto err;
272
    }
273

    
274
    if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
275
        oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
276
                     req->nchannels);
277
        goto err;
278
    }
279

    
280
    if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
281
        oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
282
        goto err;
283
    }
284

    
285
    if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
286
        oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
287
        goto err;
288
    }
289

    
290
#ifdef USE_DSP_POLICY
291
    if (ioctl (fd, OSS_GETVERSION, &version)) {
292
        oss_logerr2 (errno, typ, "Failed to get OSS version\n");
293
        version = 0;
294
    }
295

    
296
    if (conf.debug) {
297
        dolog ("OSS version = %#x\n", version);
298
    }
299

    
300
    if (conf.policy >= 0 && version >= 0x040000)
301
    {
302
        int policy = conf.policy;
303
        if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
304
            oss_logerr2 (errno, typ, "Failed to set timing policy to %d\n",
305
                         conf.policy);
306
            goto err;
307
        }
308
    }
309
    else
310
#endif
311
    {
312
        int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
313
        if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
314
            oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
315
                         req->nfrags, req->fragsize);
316
            goto err;
317
        }
318
    }
319

    
320
    if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
321
        oss_logerr2 (errno, typ, "Failed to get buffer length\n");
322
        goto err;
323
    }
324

    
325
    if (!abinfo.fragstotal || !abinfo.fragsize) {
326
        AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
327
                 abinfo.fragstotal, abinfo.fragsize, typ);
328
        goto err;
329
    }
330

    
331
    obt->fmt = fmt;
332
    obt->nchannels = nchannels;
333
    obt->freq = freq;
334
    obt->nfrags = abinfo.fragstotal;
335
    obt->fragsize = abinfo.fragsize;
336
    *pfd = fd;
337

    
338
#ifdef DEBUG_MISMATCHES
339
    if ((req->fmt != obt->fmt) ||
340
        (req->nchannels != obt->nchannels) ||
341
        (req->freq != obt->freq) ||
342
        (req->fragsize != obt->fragsize) ||
343
        (req->nfrags != obt->nfrags)) {
344
        dolog ("Audio parameters mismatch\n");
345
        oss_dump_info (req, obt);
346
    }
347
#endif
348

    
349
#ifdef DEBUG
350
    oss_dump_info (req, obt);
351
#endif
352
    return 0;
353

    
354
 err:
355
    oss_anal_close (&fd);
356
    return -1;
357
}
358

    
359
static void oss_write_pending (OSSVoiceOut *oss)
360
{
361
    HWVoiceOut *hw = &oss->hw;
362

    
363
    if (oss->mmapped) {
364
        return;
365
    }
366

    
367
    while (oss->pending) {
368
        int samples_written;
369
        ssize_t bytes_written;
370
        int samples_till_end = hw->samples - oss->wpos;
371
        int samples_to_write = audio_MIN (oss->pending, samples_till_end);
372
        int bytes_to_write = samples_to_write << hw->info.shift;
373
        void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
374

    
375
        bytes_written = write (oss->fd, pcm, bytes_to_write);
376
        if (bytes_written < 0) {
377
            if (errno != EAGAIN) {
378
                oss_logerr (errno, "failed to write %d bytes\n",
379
                            bytes_to_write);
380
            }
381
            break;
382
        }
383

    
384
        if (bytes_written & hw->info.align) {
385
            dolog ("misaligned write asked for %d, but got %zd\n",
386
                   bytes_to_write, bytes_written);
387
            return;
388
        }
389

    
390
        samples_written = bytes_written >> hw->info.shift;
391
        oss->pending -= samples_written;
392
        oss->wpos = (oss->wpos + samples_written) % hw->samples;
393
        if (bytes_written - bytes_to_write) {
394
            break;
395
        }
396
    }
397
}
398

    
399
static int oss_run_out (HWVoiceOut *hw, int live)
400
{
401
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
402
    int err, decr;
403
    struct audio_buf_info abinfo;
404
    struct count_info cntinfo;
405
    int bufsize;
406

    
407
    bufsize = hw->samples << hw->info.shift;
408

    
409
    if (oss->mmapped) {
410
        int bytes, pos;
411

    
412
        err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
413
        if (err < 0) {
414
            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
415
            return 0;
416
        }
417

    
418
        pos = hw->rpos << hw->info.shift;
419
        bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
420
        decr = audio_MIN (bytes >> hw->info.shift, live);
421
    }
422
    else {
423
        err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
424
        if (err < 0) {
425
            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
426
            return 0;
427
        }
428

    
429
        if (abinfo.bytes > bufsize) {
430
            if (conf.debug) {
431
                dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
432
                       "please report your OS/audio hw to av1474@comtv.ru\n",
433
                       abinfo.bytes, bufsize);
434
            }
435
            abinfo.bytes = bufsize;
436
        }
437

    
438
        if (abinfo.bytes < 0) {
439
            if (conf.debug) {
440
                dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
441
                       abinfo.bytes, bufsize);
442
            }
443
            return 0;
444
        }
445

    
446
        decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
447
        if (!decr) {
448
            return 0;
449
        }
450
    }
451

    
452
    decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending);
453
    oss->pending += decr;
454
    oss_write_pending (oss);
455

    
456
    return decr;
457
}
458

    
459
static void oss_fini_out (HWVoiceOut *hw)
460
{
461
    int err;
462
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
463

    
464
    ldebug ("oss_fini\n");
465
    oss_anal_close (&oss->fd);
466

    
467
    if (oss->pcm_buf) {
468
        if (oss->mmapped) {
469
            err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
470
            if (err) {
471
                oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
472
                            oss->pcm_buf, hw->samples << hw->info.shift);
473
            }
474
        }
475
        else {
476
            qemu_free (oss->pcm_buf);
477
        }
478
        oss->pcm_buf = NULL;
479
    }
480
}
481

    
482
static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
483
{
484
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
485
    struct oss_params req, obt;
486
    int endianness;
487
    int err;
488
    int fd;
489
    audfmt_e effective_fmt;
490
    struct audsettings obt_as;
491

    
492
    oss->fd = -1;
493

    
494
    req.fmt = aud_to_ossfmt (as->fmt);
495
    req.freq = as->freq;
496
    req.nchannels = as->nchannels;
497
    req.fragsize = conf.fragsize;
498
    req.nfrags = conf.nfrags;
499

    
500
    if (oss_open (0, &req, &obt, &fd)) {
501
        return -1;
502
    }
503

    
504
    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
505
    if (err) {
506
        oss_anal_close (&fd);
507
        return -1;
508
    }
509

    
510
    obt_as.freq = obt.freq;
511
    obt_as.nchannels = obt.nchannels;
512
    obt_as.fmt = effective_fmt;
513
    obt_as.endianness = endianness;
514

    
515
    audio_pcm_init_info (&hw->info, &obt_as);
516
    oss->nfrags = obt.nfrags;
517
    oss->fragsize = obt.fragsize;
518

    
519
    if (obt.nfrags * obt.fragsize & hw->info.align) {
520
        dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
521
               obt.nfrags * obt.fragsize, hw->info.align + 1);
522
    }
523

    
524
    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
525

    
526
    oss->mmapped = 0;
527
    if (conf.try_mmap) {
528
        oss->pcm_buf = mmap (
529
            NULL,
530
            hw->samples << hw->info.shift,
531
            PROT_READ | PROT_WRITE,
532
            MAP_SHARED,
533
            fd,
534
            0
535
            );
536
        if (oss->pcm_buf == MAP_FAILED) {
537
            oss_logerr (errno, "Failed to map %d bytes of DAC\n",
538
                        hw->samples << hw->info.shift);
539
        }
540
        else {
541
            int err;
542
            int trig = 0;
543
            if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
544
                oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
545
            }
546
            else {
547
                trig = PCM_ENABLE_OUTPUT;
548
                if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
549
                    oss_logerr (
550
                        errno,
551
                        "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
552
                        );
553
                }
554
                else {
555
                    oss->mmapped = 1;
556
                }
557
            }
558

    
559
            if (!oss->mmapped) {
560
                err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
561
                if (err) {
562
                    oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
563
                                oss->pcm_buf, hw->samples << hw->info.shift);
564
                }
565
            }
566
        }
567
    }
568

    
569
    if (!oss->mmapped) {
570
        oss->pcm_buf = audio_calloc (
571
            AUDIO_FUNC,
572
            hw->samples,
573
            1 << hw->info.shift
574
            );
575
        if (!oss->pcm_buf) {
576
            dolog (
577
                "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
578
                hw->samples,
579
                1 << hw->info.shift
580
                );
581
            oss_anal_close (&fd);
582
            return -1;
583
        }
584
    }
585

    
586
    oss->fd = fd;
587
    return 0;
588
}
589

    
590
static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
591
{
592
    int trig;
593
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
594

    
595
    switch (cmd) {
596
    case VOICE_ENABLE:
597
        {
598
            va_list ap;
599
            int poll_mode;
600

    
601
            va_start (ap, cmd);
602
            poll_mode = va_arg (ap, int);
603
            va_end (ap);
604

    
605
            ldebug ("enabling voice\n");
606
            if (poll_mode && oss_poll_out (hw)) {
607
                poll_mode = 0;
608
            }
609
            hw->poll_mode = poll_mode;
610

    
611
            if (!oss->mmapped) {
612
                return 0;
613
            }
614

    
615
            audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
616
            trig = PCM_ENABLE_OUTPUT;
617
            if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
618
                oss_logerr (
619
                    errno,
620
                    "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
621
                    );
622
                return -1;
623
            }
624
        }
625
        break;
626

    
627
    case VOICE_DISABLE:
628
        if (hw->poll_mode) {
629
            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
630
            hw->poll_mode = 0;
631
        }
632

    
633
        if (!oss->mmapped) {
634
            return 0;
635
        }
636

    
637
        ldebug ("disabling voice\n");
638
        trig = 0;
639
        if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
640
            oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
641
            return -1;
642
        }
643
        break;
644
    }
645
    return 0;
646
}
647

    
648
static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
649
{
650
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
651
    struct oss_params req, obt;
652
    int endianness;
653
    int err;
654
    int fd;
655
    audfmt_e effective_fmt;
656
    struct audsettings obt_as;
657

    
658
    oss->fd = -1;
659

    
660
    req.fmt = aud_to_ossfmt (as->fmt);
661
    req.freq = as->freq;
662
    req.nchannels = as->nchannels;
663
    req.fragsize = conf.fragsize;
664
    req.nfrags = conf.nfrags;
665
    if (oss_open (1, &req, &obt, &fd)) {
666
        return -1;
667
    }
668

    
669
    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
670
    if (err) {
671
        oss_anal_close (&fd);
672
        return -1;
673
    }
674

    
675
    obt_as.freq = obt.freq;
676
    obt_as.nchannels = obt.nchannels;
677
    obt_as.fmt = effective_fmt;
678
    obt_as.endianness = endianness;
679

    
680
    audio_pcm_init_info (&hw->info, &obt_as);
681
    oss->nfrags = obt.nfrags;
682
    oss->fragsize = obt.fragsize;
683

    
684
    if (obt.nfrags * obt.fragsize & hw->info.align) {
685
        dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
686
               obt.nfrags * obt.fragsize, hw->info.align + 1);
687
    }
688

    
689
    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
690
    oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
691
    if (!oss->pcm_buf) {
692
        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
693
               hw->samples, 1 << hw->info.shift);
694
        oss_anal_close (&fd);
695
        return -1;
696
    }
697

    
698
    oss->fd = fd;
699
    return 0;
700
}
701

    
702
static void oss_fini_in (HWVoiceIn *hw)
703
{
704
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
705

    
706
    oss_anal_close (&oss->fd);
707

    
708
    if (oss->pcm_buf) {
709
        qemu_free (oss->pcm_buf);
710
        oss->pcm_buf = NULL;
711
    }
712
}
713

    
714
static int oss_run_in (HWVoiceIn *hw)
715
{
716
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
717
    int hwshift = hw->info.shift;
718
    int i;
719
    int live = audio_pcm_hw_get_live_in (hw);
720
    int dead = hw->samples - live;
721
    size_t read_samples = 0;
722
    struct {
723
        int add;
724
        int len;
725
    } bufs[2] = {
726
        { .add = hw->wpos, .len = 0 },
727
        { .add = 0,        .len = 0 }
728
    };
729

    
730
    if (!dead) {
731
        return 0;
732
    }
733

    
734
    if (hw->wpos + dead > hw->samples) {
735
        bufs[0].len = (hw->samples - hw->wpos) << hwshift;
736
        bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
737
    }
738
    else {
739
        bufs[0].len = dead << hwshift;
740
    }
741

    
742
    for (i = 0; i < 2; ++i) {
743
        ssize_t nread;
744

    
745
        if (bufs[i].len) {
746
            void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
747
            nread = read (oss->fd, p, bufs[i].len);
748

    
749
            if (nread > 0) {
750
                if (nread & hw->info.align) {
751
                    dolog ("warning: Misaligned read %zd (requested %d), "
752
                           "alignment %d\n", nread, bufs[i].add << hwshift,
753
                           hw->info.align + 1);
754
                }
755
                read_samples += nread >> hwshift;
756
                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
757
                          &nominal_volume);
758
            }
759

    
760
            if (bufs[i].len - nread) {
761
                if (nread == -1) {
762
                    switch (errno) {
763
                    case EINTR:
764
                    case EAGAIN:
765
                        break;
766
                    default:
767
                        oss_logerr (
768
                            errno,
769
                            "Failed to read %d bytes of audio (to %p)\n",
770
                            bufs[i].len, p
771
                            );
772
                        break;
773
                    }
774
                }
775
                break;
776
            }
777
        }
778
    }
779

    
780
    hw->wpos = (hw->wpos + read_samples) % hw->samples;
781
    return read_samples;
782
}
783

    
784
static int oss_read (SWVoiceIn *sw, void *buf, int size)
785
{
786
    return audio_pcm_sw_read (sw, buf, size);
787
}
788

    
789
static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
790
{
791
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
792

    
793
    switch (cmd) {
794
    case VOICE_ENABLE:
795
        {
796
            va_list ap;
797
            int poll_mode;
798

    
799
            va_start (ap, cmd);
800
            poll_mode = va_arg (ap, int);
801
            va_end (ap);
802

    
803
            if (poll_mode && oss_poll_in (hw)) {
804
                poll_mode = 0;
805
            }
806
            hw->poll_mode = poll_mode;
807
        }
808
        break;
809

    
810
    case VOICE_DISABLE:
811
        if (hw->poll_mode) {
812
            hw->poll_mode = 0;
813
            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
814
        }
815
        break;
816
    }
817
    return 0;
818
}
819

    
820
static void *oss_audio_init (void)
821
{
822
    return &conf;
823
}
824

    
825
static void oss_audio_fini (void *opaque)
826
{
827
    (void) opaque;
828
}
829

    
830
static struct audio_option oss_options[] = {
831
    {
832
        .name  = "FRAGSIZE",
833
        .tag   = AUD_OPT_INT,
834
        .valp  = &conf.fragsize,
835
        .descr = "Fragment size in bytes"
836
    },
837
    {
838
        .name  = "NFRAGS",
839
        .tag   = AUD_OPT_INT,
840
        .valp  = &conf.nfrags,
841
        .descr = "Number of fragments"
842
    },
843
    {
844
        .name  = "MMAP",
845
        .tag   = AUD_OPT_BOOL,
846
        .valp  = &conf.try_mmap,
847
        .descr = "Try using memory mapped access"
848
    },
849
    {
850
        .name  = "DAC_DEV",
851
        .tag   = AUD_OPT_STR,
852
        .valp  = &conf.devpath_out,
853
        .descr = "Path to DAC device"
854
    },
855
    {
856
        .name  = "ADC_DEV",
857
        .tag   = AUD_OPT_STR,
858
        .valp  = &conf.devpath_in,
859
        .descr = "Path to ADC device"
860
    },
861
    {
862
        .name  = "EXCLUSIVE",
863
        .tag   = AUD_OPT_BOOL,
864
        .valp  = &conf.exclusive,
865
        .descr = "Open device in exclusive mode (vmix wont work)"
866
    },
867
#ifdef USE_DSP_POLICY
868
    {
869
        .name  = "POLICY",
870
        .tag   = AUD_OPT_INT,
871
        .valp  = &conf.policy,
872
        .descr = "Set the timing policy of the device, -1 to use fragment mode",
873
    },
874
#endif
875
    {
876
        .name  = "DEBUG",
877
        .tag   = AUD_OPT_BOOL,
878
        .valp  = &conf.debug,
879
        .descr = "Turn on some debugging messages"
880
    },
881
    { /* End of list */ }
882
};
883

    
884
static struct audio_pcm_ops oss_pcm_ops = {
885
    .init_out = oss_init_out,
886
    .fini_out = oss_fini_out,
887
    .run_out  = oss_run_out,
888
    .write    = oss_write,
889
    .ctl_out  = oss_ctl_out,
890

    
891
    .init_in  = oss_init_in,
892
    .fini_in  = oss_fini_in,
893
    .run_in   = oss_run_in,
894
    .read     = oss_read,
895
    .ctl_in   = oss_ctl_in
896
};
897

    
898
struct audio_driver oss_audio_driver = {
899
    .name           = "oss",
900
    .descr          = "OSS http://www.opensound.com",
901
    .options        = oss_options,
902
    .init           = oss_audio_init,
903
    .fini           = oss_audio_fini,
904
    .pcm_ops        = &oss_pcm_ops,
905
    .can_be_default = 1,
906
    .max_voices_out = INT_MAX,
907
    .max_voices_in  = INT_MAX,
908
    .voice_size_out = sizeof (OSSVoiceOut),
909
    .voice_size_in  = sizeof (OSSVoiceIn)
910
};