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