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