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