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