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