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