xref: /openbmc/qemu/audio/ossaudio.c (revision 17a319b175a57ee6fde4dabcaa2e11d47c39301e)
185571bc7Sbellard /*
21d14ffa9Sbellard  * QEMU OSS audio driver
385571bc7Sbellard  *
41d14ffa9Sbellard  * Copyright (c) 2003-2005 Vassili Karpov (malc)
585571bc7Sbellard  *
685571bc7Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
785571bc7Sbellard  * of this software and associated documentation files (the "Software"), to deal
885571bc7Sbellard  * in the Software without restriction, including without limitation the rights
985571bc7Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1085571bc7Sbellard  * copies of the Software, and to permit persons to whom the Software is
1185571bc7Sbellard  * furnished to do so, subject to the following conditions:
1285571bc7Sbellard  *
1385571bc7Sbellard  * The above copyright notice and this permission notice shall be included in
1485571bc7Sbellard  * all copies or substantial portions of the Software.
1585571bc7Sbellard  *
1685571bc7Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1785571bc7Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1885571bc7Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1985571bc7Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2085571bc7Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2185571bc7Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2285571bc7Sbellard  * THE SOFTWARE.
2385571bc7Sbellard  */
240b8fa32fSMarkus Armbruster 
256086a565SPeter Maydell #include "qemu/osdep.h"
2685571bc7Sbellard #include <sys/ioctl.h>
2785571bc7Sbellard #include <sys/soundcard.h>
281de7afc9SPaolo Bonzini #include "qemu/main-loop.h"
290b8fa32fSMarkus Armbruster #include "qemu/module.h"
301de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
31*f6061733SPaolo Bonzini #include "qapi/error.h"
3287ecb68bSpbrook #include "audio.h"
33d95d7d80SKővágó, Zoltán #include "trace.h"
3485571bc7Sbellard 
351d14ffa9Sbellard #define AUDIO_CAP "oss"
361d14ffa9Sbellard #include "audio_int.h"
37fb065187Sbellard 
3878d9356dSmalc #if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
3978d9356dSmalc #define USE_DSP_POLICY
4078d9356dSmalc #endif
4178d9356dSmalc 
421d14ffa9Sbellard typedef struct OSSVoiceOut {
431d14ffa9Sbellard     HWVoiceOut hw;
44fb065187Sbellard     int fd;
45fb065187Sbellard     int nfrags;
46fb065187Sbellard     int fragsize;
47fb065187Sbellard     int mmapped;
48baf6c7f4SKővágó, Zoltán     Audiodev *dev;
491d14ffa9Sbellard } OSSVoiceOut;
50fb065187Sbellard 
511d14ffa9Sbellard typedef struct OSSVoiceIn {
521d14ffa9Sbellard     HWVoiceIn hw;
531d14ffa9Sbellard     int fd;
541d14ffa9Sbellard     int nfrags;
551d14ffa9Sbellard     int fragsize;
56baf6c7f4SKővágó, Zoltán     Audiodev *dev;
571d14ffa9Sbellard } OSSVoiceIn;
5885571bc7Sbellard 
5985571bc7Sbellard struct oss_params {
6085571bc7Sbellard     int freq;
61baf6c7f4SKővágó, Zoltán     int fmt;
6285571bc7Sbellard     int nchannels;
6385571bc7Sbellard     int nfrags;
6485571bc7Sbellard     int fragsize;
6585571bc7Sbellard };
6685571bc7Sbellard 
oss_logerr(int err,const char * fmt,...)679edc6313SMarc-André Lureau static void G_GNUC_PRINTF (2, 3) oss_logerr (int err, const char *fmt, ...)
6885571bc7Sbellard {
691d14ffa9Sbellard     va_list ap;
701d14ffa9Sbellard 
711d14ffa9Sbellard     va_start (ap, fmt);
72571ec3d6Sbellard     AUD_vlog (AUDIO_CAP, fmt, ap);
731d14ffa9Sbellard     va_end (ap);
74571ec3d6Sbellard 
75571ec3d6Sbellard     AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
7685571bc7Sbellard }
7785571bc7Sbellard 
oss_logerr2(int err,const char * typ,const char * fmt,...)789edc6313SMarc-André Lureau static void G_GNUC_PRINTF (3, 4) oss_logerr2 (
791d14ffa9Sbellard     int err,
801d14ffa9Sbellard     const char *typ,
811d14ffa9Sbellard     const char *fmt,
821d14ffa9Sbellard     ...
831d14ffa9Sbellard     )
841d14ffa9Sbellard {
851d14ffa9Sbellard     va_list ap;
861d14ffa9Sbellard 
87c0fe3827Sbellard     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
881d14ffa9Sbellard 
891d14ffa9Sbellard     va_start (ap, fmt);
901d14ffa9Sbellard     AUD_vlog (AUDIO_CAP, fmt, ap);
911d14ffa9Sbellard     va_end (ap);
921d14ffa9Sbellard 
931d14ffa9Sbellard     AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
941d14ffa9Sbellard }
951d14ffa9Sbellard 
oss_anal_close(int * fdp)961d14ffa9Sbellard static void oss_anal_close (int *fdp)
971d14ffa9Sbellard {
986ebfda13Smalc     int err;
996ebfda13Smalc 
1006ebfda13Smalc     qemu_set_fd_handler (*fdp, NULL, NULL, NULL);
1016ebfda13Smalc     err = close (*fdp);
1021d14ffa9Sbellard     if (err) {
1031d14ffa9Sbellard         oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
1041d14ffa9Sbellard     }
1051d14ffa9Sbellard     *fdp = -1;
1061d14ffa9Sbellard }
1071d14ffa9Sbellard 
oss_helper_poll_out(void * opaque)108dd8a5649Smalc static void oss_helper_poll_out (void *opaque)
109dd8a5649Smalc {
11018e2c177SKővágó, Zoltán     AudioState *s = opaque;
11118e2c177SKővágó, Zoltán     audio_run(s, "oss_poll_out");
112dd8a5649Smalc }
113dd8a5649Smalc 
oss_helper_poll_in(void * opaque)114dd8a5649Smalc static void oss_helper_poll_in (void *opaque)
115dd8a5649Smalc {
11618e2c177SKővágó, Zoltán     AudioState *s = opaque;
11718e2c177SKővágó, Zoltán     audio_run(s, "oss_poll_in");
118dd8a5649Smalc }
119dd8a5649Smalc 
oss_poll_out(HWVoiceOut * hw)120b027a538SFam Zheng static void oss_poll_out (HWVoiceOut *hw)
121dd8a5649Smalc {
122dd8a5649Smalc     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
123dd8a5649Smalc 
12418e2c177SKővágó, Zoltán     qemu_set_fd_handler(oss->fd, NULL, oss_helper_poll_out, hw->s);
125dd8a5649Smalc }
126dd8a5649Smalc 
oss_poll_in(HWVoiceIn * hw)127b027a538SFam Zheng static void oss_poll_in (HWVoiceIn *hw)
128dd8a5649Smalc {
129dd8a5649Smalc     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
130dd8a5649Smalc 
13118e2c177SKővágó, Zoltán     qemu_set_fd_handler(oss->fd, oss_helper_poll_in, NULL, hw->s);
132dd8a5649Smalc }
133dd8a5649Smalc 
aud_to_ossfmt(AudioFormat fmt,int endianness)13485bc5852SKővágó, Zoltán static int aud_to_ossfmt (AudioFormat fmt, int endianness)
13585571bc7Sbellard {
13685571bc7Sbellard     switch (fmt) {
13785bc5852SKővágó, Zoltán     case AUDIO_FORMAT_S8:
1381d14ffa9Sbellard         return AFMT_S8;
1391d14ffa9Sbellard 
14085bc5852SKővágó, Zoltán     case AUDIO_FORMAT_U8:
1411d14ffa9Sbellard         return AFMT_U8;
1421d14ffa9Sbellard 
14385bc5852SKővágó, Zoltán     case AUDIO_FORMAT_S16:
144b6c9c940SMichael Walle         if (endianness) {
145b6c9c940SMichael Walle             return AFMT_S16_BE;
1466c6886bdSZhang Han         } else {
1471d14ffa9Sbellard             return AFMT_S16_LE;
148b6c9c940SMichael Walle         }
1491d14ffa9Sbellard 
15085bc5852SKővágó, Zoltán     case AUDIO_FORMAT_U16:
151b6c9c940SMichael Walle         if (endianness) {
152b6c9c940SMichael Walle             return AFMT_U16_BE;
1536c6886bdSZhang Han         } else {
1541d14ffa9Sbellard             return AFMT_U16_LE;
155b6c9c940SMichael Walle         }
1561d14ffa9Sbellard 
15785571bc7Sbellard     default:
1581d14ffa9Sbellard         dolog ("Internal logic error: Bad audio format %d\n", fmt);
1591d14ffa9Sbellard #ifdef DEBUG_AUDIO
1601d14ffa9Sbellard         abort ();
1611d14ffa9Sbellard #endif
1621d14ffa9Sbellard         return AFMT_U8;
16385571bc7Sbellard     }
16485571bc7Sbellard }
16585571bc7Sbellard 
oss_to_audfmt(int ossfmt,AudioFormat * fmt,int * endianness)16685bc5852SKővágó, Zoltán static int oss_to_audfmt (int ossfmt, AudioFormat *fmt, int *endianness)
16785571bc7Sbellard {
1681d14ffa9Sbellard     switch (ossfmt) {
1691d14ffa9Sbellard     case AFMT_S8:
1701d14ffa9Sbellard         *endianness = 0;
17185bc5852SKővágó, Zoltán         *fmt = AUDIO_FORMAT_S8;
1721d14ffa9Sbellard         break;
1731d14ffa9Sbellard 
1741d14ffa9Sbellard     case AFMT_U8:
1751d14ffa9Sbellard         *endianness = 0;
17685bc5852SKővágó, Zoltán         *fmt = AUDIO_FORMAT_U8;
1771d14ffa9Sbellard         break;
1781d14ffa9Sbellard 
1791d14ffa9Sbellard     case AFMT_S16_LE:
1801d14ffa9Sbellard         *endianness = 0;
18185bc5852SKővágó, Zoltán         *fmt = AUDIO_FORMAT_S16;
1821d14ffa9Sbellard         break;
1831d14ffa9Sbellard 
1841d14ffa9Sbellard     case AFMT_U16_LE:
1851d14ffa9Sbellard         *endianness = 0;
18685bc5852SKővágó, Zoltán         *fmt = AUDIO_FORMAT_U16;
1871d14ffa9Sbellard         break;
1881d14ffa9Sbellard 
1891d14ffa9Sbellard     case AFMT_S16_BE:
1901d14ffa9Sbellard         *endianness = 1;
19185bc5852SKővágó, Zoltán         *fmt = AUDIO_FORMAT_S16;
1921d14ffa9Sbellard         break;
1931d14ffa9Sbellard 
1941d14ffa9Sbellard     case AFMT_U16_BE:
1951d14ffa9Sbellard         *endianness = 1;
19685bc5852SKővágó, Zoltán         *fmt = AUDIO_FORMAT_U16;
1971d14ffa9Sbellard         break;
1981d14ffa9Sbellard 
19985571bc7Sbellard     default:
2001d14ffa9Sbellard         dolog ("Unrecognized audio format %d\n", ossfmt);
2011d14ffa9Sbellard         return -1;
20285571bc7Sbellard     }
20385571bc7Sbellard 
2041d14ffa9Sbellard     return 0;
2051d14ffa9Sbellard }
2061d14ffa9Sbellard 
207c0fe3827Sbellard #if defined DEBUG_MISMATCHES || defined DEBUG
oss_dump_info(struct oss_params * req,struct oss_params * obt)2081d14ffa9Sbellard static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
20985571bc7Sbellard {
21085571bc7Sbellard     dolog ("parameter | requested value | obtained value\n");
21185571bc7Sbellard     dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
2121d14ffa9Sbellard     dolog ("channels  |      %10d |     %10d\n",
2131d14ffa9Sbellard            req->nchannels, obt->nchannels);
21485571bc7Sbellard     dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
21585571bc7Sbellard     dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
2161d14ffa9Sbellard     dolog ("fragsize  |      %10d |     %10d\n",
2171d14ffa9Sbellard            req->fragsize, obt->fragsize);
21885571bc7Sbellard }
21985571bc7Sbellard #endif
22085571bc7Sbellard 
22172ff25e4SJuergen Lock #ifdef USE_DSP_POLICY
oss_get_version(int fd,int * version,const char * typ)22272ff25e4SJuergen Lock static int oss_get_version (int fd, int *version, const char *typ)
22372ff25e4SJuergen Lock {
22472ff25e4SJuergen Lock     if (ioctl (fd, OSS_GETVERSION, &version)) {
22572ff25e4SJuergen Lock #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
22672ff25e4SJuergen Lock         /*
22772ff25e4SJuergen Lock          * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
22872ff25e4SJuergen Lock          * since 7.x, but currently only on the mixer device (or in
22972ff25e4SJuergen Lock          * the Linuxolator), and in the native version that part of
23072ff25e4SJuergen Lock          * the code is in fact never reached so the ioctl fails anyway.
23172ff25e4SJuergen Lock          * Until this is fixed, just check the errno and if its what
23272ff25e4SJuergen Lock          * FreeBSD's sound drivers return atm assume they are new enough.
23372ff25e4SJuergen Lock          */
23472ff25e4SJuergen Lock         if (errno == EINVAL) {
23572ff25e4SJuergen Lock             *version = 0x040000;
23672ff25e4SJuergen Lock             return 0;
23772ff25e4SJuergen Lock         }
23872ff25e4SJuergen Lock #endif
23972ff25e4SJuergen Lock         oss_logerr2 (errno, typ, "Failed to get OSS version\n");
24072ff25e4SJuergen Lock         return -1;
24172ff25e4SJuergen Lock     }
24272ff25e4SJuergen Lock     return 0;
24372ff25e4SJuergen Lock }
24472ff25e4SJuergen Lock #endif
24572ff25e4SJuergen Lock 
oss_open(int in,struct oss_params * req,audsettings * as,struct oss_params * obt,int * pfd,Audiodev * dev)246baf6c7f4SKővágó, Zoltán static int oss_open(int in, struct oss_params *req, audsettings *as,
247baf6c7f4SKővágó, Zoltán                     struct oss_params *obt, int *pfd, Audiodev *dev)
24885571bc7Sbellard {
249baf6c7f4SKővágó, Zoltán     AudiodevOssOptions *oopts = &dev->u.oss;
250baf6c7f4SKővágó, Zoltán     AudiodevOssPerDirectionOptions *opdo = in ? oopts->in : oopts->out;
25185571bc7Sbellard     int fd;
252baf6c7f4SKővágó, Zoltán     int oflags = (oopts->has_exclusive && oopts->exclusive) ? O_EXCL : 0;
25385571bc7Sbellard     audio_buf_info abinfo;
25485571bc7Sbellard     int fmt, freq, nchannels;
2553d709fe7Smalc     int setfragment = 1;
256ceb19c8fSMarkus Armbruster     const char *dspname = opdo->dev ?: "/dev/dsp";
2571d14ffa9Sbellard     const char *typ = in ? "ADC" : "DAC";
258baf6c7f4SKővágó, Zoltán #ifdef USE_DSP_POLICY
259baf6c7f4SKővágó, Zoltán     int policy = oopts->has_dsp_policy ? oopts->dsp_policy : 5;
260baf6c7f4SKővágó, Zoltán #endif
26185571bc7Sbellard 
2622182349dSmalc     /* Kludge needed to have working mmap on Linux */
263baf6c7f4SKővágó, Zoltán     oflags |= (oopts->has_try_mmap && oopts->try_mmap) ?
264baf6c7f4SKővágó, Zoltán         O_RDWR : (in ? O_RDONLY : O_WRONLY);
2650b3652bcSmalc 
2662182349dSmalc     fd = open (dspname, oflags | O_NONBLOCK);
26785571bc7Sbellard     if (-1 == fd) {
2681d14ffa9Sbellard         oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
26985571bc7Sbellard         return -1;
27085571bc7Sbellard     }
27185571bc7Sbellard 
27285571bc7Sbellard     freq = req->freq;
27385571bc7Sbellard     nchannels = req->nchannels;
27485571bc7Sbellard     fmt = req->fmt;
275baf6c7f4SKővágó, Zoltán     req->nfrags = opdo->has_buffer_count ? opdo->buffer_count : 4;
276baf6c7f4SKővágó, Zoltán     req->fragsize = audio_buffer_bytes(
277baf6c7f4SKővágó, Zoltán         qapi_AudiodevOssPerDirectionOptions_base(opdo), as, 23220);
27885571bc7Sbellard 
27985571bc7Sbellard     if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
2801d14ffa9Sbellard         oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
28185571bc7Sbellard         goto err;
28285571bc7Sbellard     }
28385571bc7Sbellard 
28485571bc7Sbellard     if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
2851d14ffa9Sbellard         oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
2861d14ffa9Sbellard                      req->nchannels);
28785571bc7Sbellard         goto err;
28885571bc7Sbellard     }
28985571bc7Sbellard 
29085571bc7Sbellard     if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
2911d14ffa9Sbellard         oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
29285571bc7Sbellard         goto err;
29385571bc7Sbellard     }
29485571bc7Sbellard 
295902e2b51Smalc     if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
2961d14ffa9Sbellard         oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
29785571bc7Sbellard         goto err;
29885571bc7Sbellard     }
29985571bc7Sbellard 
30078d9356dSmalc #ifdef USE_DSP_POLICY
301baf6c7f4SKővágó, Zoltán     if (policy >= 0) {
3026d246526Smalc         int version;
3036d246526Smalc 
30472ff25e4SJuergen Lock         if (!oss_get_version (fd, &version, typ)) {
305d95d7d80SKővágó, Zoltán             trace_oss_version(version);
3060b3652bcSmalc 
3076d246526Smalc             if (version >= 0x040000) {
308baf6c7f4SKővágó, Zoltán                 int policy2 = policy;
309baf6c7f4SKővágó, Zoltán                 if (ioctl(fd, SNDCTL_DSP_POLICY, &policy2)) {
3103d709fe7Smalc                     oss_logerr2 (errno, typ,
3113d709fe7Smalc                                  "Failed to set timing policy to %d\n",
312baf6c7f4SKővágó, Zoltán                                  policy);
3130b3652bcSmalc                     goto err;
3140b3652bcSmalc                 }
3153d709fe7Smalc                 setfragment = 0;
3160b3652bcSmalc             }
3176d246526Smalc         }
3183d709fe7Smalc     }
3190b3652bcSmalc #endif
3203d709fe7Smalc 
3213d709fe7Smalc     if (setfragment) {
3220b3652bcSmalc         int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
32385571bc7Sbellard         if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
3241d14ffa9Sbellard             oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
3251d14ffa9Sbellard                          req->nfrags, req->fragsize);
32685571bc7Sbellard             goto err;
32785571bc7Sbellard         }
3280b3652bcSmalc     }
32985571bc7Sbellard 
3301d14ffa9Sbellard     if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
3311d14ffa9Sbellard         oss_logerr2 (errno, typ, "Failed to get buffer length\n");
33285571bc7Sbellard         goto err;
33385571bc7Sbellard     }
33485571bc7Sbellard 
33529ddf27bSmalc     if (!abinfo.fragstotal || !abinfo.fragsize) {
33629ddf27bSmalc         AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
33729ddf27bSmalc                  abinfo.fragstotal, abinfo.fragsize, typ);
33829ddf27bSmalc         goto err;
33929ddf27bSmalc     }
34029ddf27bSmalc 
34185571bc7Sbellard     obt->fmt = fmt;
34285571bc7Sbellard     obt->nchannels = nchannels;
34385571bc7Sbellard     obt->freq = freq;
34485571bc7Sbellard     obt->nfrags = abinfo.fragstotal;
34585571bc7Sbellard     obt->fragsize = abinfo.fragsize;
34685571bc7Sbellard     *pfd = fd;
34785571bc7Sbellard 
348c0fe3827Sbellard #ifdef DEBUG_MISMATCHES
34985571bc7Sbellard     if ((req->fmt != obt->fmt) ||
35085571bc7Sbellard         (req->nchannels != obt->nchannels) ||
35185571bc7Sbellard         (req->freq != obt->freq) ||
35285571bc7Sbellard         (req->fragsize != obt->fragsize) ||
35385571bc7Sbellard         (req->nfrags != obt->nfrags)) {
35485571bc7Sbellard         dolog ("Audio parameters mismatch\n");
3551d14ffa9Sbellard         oss_dump_info (req, obt);
35685571bc7Sbellard     }
357c0fe3827Sbellard #endif
35885571bc7Sbellard 
3591d14ffa9Sbellard #ifdef DEBUG
3601d14ffa9Sbellard     oss_dump_info (req, obt);
36185571bc7Sbellard #endif
36285571bc7Sbellard     return 0;
36385571bc7Sbellard 
36485571bc7Sbellard  err:
3651d14ffa9Sbellard     oss_anal_close (&fd);
36685571bc7Sbellard     return -1;
36785571bc7Sbellard }
36885571bc7Sbellard 
oss_get_available_bytes(OSSVoiceOut * oss)3693ba4066dSKővágó, Zoltán static size_t oss_get_available_bytes(OSSVoiceOut *oss)
3709d168976Smalc {
3717520462bSKővágó, Zoltán     int err;
37285571bc7Sbellard     struct count_info cntinfo;
3733ba4066dSKővágó, Zoltán     assert(oss->mmapped);
37485571bc7Sbellard 
37585571bc7Sbellard     err = ioctl(oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
37685571bc7Sbellard     if (err < 0) {
3771d14ffa9Sbellard         oss_logerr(errno, "SNDCTL_DSP_GETOPTR failed\n");
3781d14ffa9Sbellard         return 0;
37985571bc7Sbellard     }
38085571bc7Sbellard 
3813ba4066dSKővágó, Zoltán     return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul);
38285571bc7Sbellard }
38385571bc7Sbellard 
oss_run_buffer_out(HWVoiceOut * hw)384fdc8c5f4SVolker Rümelin static void oss_run_buffer_out(HWVoiceOut *hw)
385fdc8c5f4SVolker Rümelin {
386fdc8c5f4SVolker Rümelin     OSSVoiceOut *oss = (OSSVoiceOut *)hw;
387fdc8c5f4SVolker Rümelin 
388fdc8c5f4SVolker Rümelin     if (!oss->mmapped) {
389fdc8c5f4SVolker Rümelin         audio_generic_run_buffer_out(hw);
390fdc8c5f4SVolker Rümelin     }
391fdc8c5f4SVolker Rümelin }
392fdc8c5f4SVolker Rümelin 
oss_buffer_get_free(HWVoiceOut * hw)3939833438eSVolker Rümelin static size_t oss_buffer_get_free(HWVoiceOut *hw)
3949833438eSVolker Rümelin {
3959833438eSVolker Rümelin     OSSVoiceOut *oss = (OSSVoiceOut *)hw;
3969833438eSVolker Rümelin 
3979833438eSVolker Rümelin     if (oss->mmapped) {
398385211e8SVolker Rümelin         return oss_get_available_bytes(oss);
3999833438eSVolker Rümelin     } else {
4009833438eSVolker Rümelin         return audio_generic_buffer_get_free(hw);
4019833438eSVolker Rümelin     }
4029833438eSVolker Rümelin }
4039833438eSVolker Rümelin 
oss_get_buffer_out(HWVoiceOut * hw,size_t * size)4043ba4066dSKővágó, Zoltán static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
4053ba4066dSKővágó, Zoltán {
4063ba4066dSKővágó, Zoltán     OSSVoiceOut *oss = (OSSVoiceOut *)hw;
407385211e8SVolker Rümelin 
4083ba4066dSKővágó, Zoltán     if (oss->mmapped) {
409385211e8SVolker Rümelin         *size = hw->size_emul - hw->pos_emul;
4103ba4066dSKővágó, Zoltán         return hw->buf_emul + hw->pos_emul;
4113ba4066dSKővágó, Zoltán     } else {
4123ba4066dSKővágó, Zoltán         return audio_generic_get_buffer_out(hw, size);
4131d14ffa9Sbellard     }
41485571bc7Sbellard }
41585571bc7Sbellard 
oss_put_buffer_out(HWVoiceOut * hw,void * buf,size_t size)4163ba4066dSKővágó, Zoltán static size_t oss_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
4173ba4066dSKővágó, Zoltán {
4183ba4066dSKővágó, Zoltán     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
4193ba4066dSKővágó, Zoltán     if (oss->mmapped) {
4203ba4066dSKővágó, Zoltán         assert(buf == hw->buf_emul + hw->pos_emul && size < hw->size_emul);
42185571bc7Sbellard 
4223ba4066dSKővágó, Zoltán         hw->pos_emul = (hw->pos_emul + size) % hw->size_emul;
4233ba4066dSKővágó, Zoltán         return size;
4243ba4066dSKővágó, Zoltán     } else {
4253ba4066dSKővágó, Zoltán         return audio_generic_put_buffer_out(hw, buf, size);
4263ba4066dSKővágó, Zoltán     }
4273ba4066dSKővágó, Zoltán }
4283ba4066dSKővágó, Zoltán 
oss_write(HWVoiceOut * hw,void * buf,size_t len)4293ba4066dSKővágó, Zoltán static size_t oss_write(HWVoiceOut *hw, void *buf, size_t len)
4303ba4066dSKővágó, Zoltán {
4313ba4066dSKővágó, Zoltán     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
4323ba4066dSKővágó, Zoltán     size_t pos;
4333ba4066dSKővágó, Zoltán 
4343ba4066dSKővágó, Zoltán     if (oss->mmapped) {
4353ba4066dSKővágó, Zoltán         size_t total_len;
4363ba4066dSKővágó, Zoltán         len = MIN(len, oss_get_available_bytes(oss));
4373ba4066dSKővágó, Zoltán 
4383ba4066dSKővágó, Zoltán         total_len = len;
4393ba4066dSKővágó, Zoltán         while (len) {
4403ba4066dSKővágó, Zoltán             size_t to_copy = MIN(len, hw->size_emul - hw->pos_emul);
4413ba4066dSKővágó, Zoltán             memcpy(hw->buf_emul + hw->pos_emul, buf, to_copy);
4423ba4066dSKővágó, Zoltán 
4437a4ede00SGerd Hoffmann             hw->pos_emul = (hw->pos_emul + to_copy) % hw->size_emul;
4443ba4066dSKővágó, Zoltán             buf += to_copy;
4453ba4066dSKővágó, Zoltán             len -= to_copy;
4463ba4066dSKővágó, Zoltán         }
4473ba4066dSKővágó, Zoltán         return total_len;
4483ba4066dSKővágó, Zoltán     }
4493ba4066dSKővágó, Zoltán 
4503ba4066dSKővágó, Zoltán     pos = 0;
4513ba4066dSKővágó, Zoltán     while (len) {
4523ba4066dSKővágó, Zoltán         ssize_t bytes_written;
4533ba4066dSKővágó, Zoltán         void *pcm = advance(buf, pos);
4543ba4066dSKővágó, Zoltán 
4553ba4066dSKővágó, Zoltán         bytes_written = write(oss->fd, pcm, len);
4563ba4066dSKővágó, Zoltán         if (bytes_written < 0) {
4573ba4066dSKővágó, Zoltán             if (errno != EAGAIN) {
4583ba4066dSKővágó, Zoltán                 oss_logerr(errno, "failed to write %zu bytes\n",
4593ba4066dSKővágó, Zoltán                            len);
4603ba4066dSKővágó, Zoltán             }
4613ba4066dSKővágó, Zoltán             return pos;
4623ba4066dSKővágó, Zoltán         }
4633ba4066dSKővágó, Zoltán 
4643ba4066dSKővágó, Zoltán         pos += bytes_written;
4653ba4066dSKővágó, Zoltán         if (bytes_written < len) {
4663ba4066dSKővágó, Zoltán             break;
4673ba4066dSKővágó, Zoltán         }
4683ba4066dSKővágó, Zoltán         len -= bytes_written;
4693ba4066dSKővágó, Zoltán     }
4703ba4066dSKővágó, Zoltán     return pos;
47185571bc7Sbellard }
47285571bc7Sbellard 
oss_fini_out(HWVoiceOut * hw)4731d14ffa9Sbellard static void oss_fini_out (HWVoiceOut *hw)
47485571bc7Sbellard {
47585571bc7Sbellard     int err;
4761d14ffa9Sbellard     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
47785571bc7Sbellard 
4781d14ffa9Sbellard     ldebug ("oss_fini\n");
4791d14ffa9Sbellard     oss_anal_close (&oss->fd);
48085571bc7Sbellard 
4813ba4066dSKővágó, Zoltán     if (oss->mmapped && hw->buf_emul) {
4823ba4066dSKővágó, Zoltán         err = munmap(hw->buf_emul, hw->size_emul);
48385571bc7Sbellard         if (err) {
4847520462bSKővágó, Zoltán             oss_logerr(errno, "Failed to unmap buffer %p, size %zu\n",
4853ba4066dSKővágó, Zoltán                        hw->buf_emul, hw->size_emul);
48685571bc7Sbellard         }
4873ba4066dSKővágó, Zoltán         hw->buf_emul = NULL;
48885571bc7Sbellard     }
48985571bc7Sbellard }
49085571bc7Sbellard 
oss_init_out(HWVoiceOut * hw,struct audsettings * as,void * drv_opaque)4915706db1dSKővágó, Zoltán static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
4925706db1dSKővágó, Zoltán                         void *drv_opaque)
49385571bc7Sbellard {
4941d14ffa9Sbellard     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
49585571bc7Sbellard     struct oss_params req, obt;
4961d14ffa9Sbellard     int endianness;
4971d14ffa9Sbellard     int err;
4981d14ffa9Sbellard     int fd;
49985bc5852SKővágó, Zoltán     AudioFormat effective_fmt;
5001ea879e5Smalc     struct audsettings obt_as;
501baf6c7f4SKővágó, Zoltán     Audiodev *dev = drv_opaque;
502baf6c7f4SKővágó, Zoltán     AudiodevOssOptions *oopts = &dev->u.oss;
50385571bc7Sbellard 
504571ec3d6Sbellard     oss->fd = -1;
505571ec3d6Sbellard 
506b6c9c940SMichael Walle     req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
507c0fe3827Sbellard     req.freq = as->freq;
508c0fe3827Sbellard     req.nchannels = as->nchannels;
50985571bc7Sbellard 
510baf6c7f4SKővágó, Zoltán     if (oss_open(0, &req, as, &obt, &fd, dev)) {
51185571bc7Sbellard         return -1;
5121d14ffa9Sbellard     }
51385571bc7Sbellard 
5141d14ffa9Sbellard     err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
5151d14ffa9Sbellard     if (err) {
5161d14ffa9Sbellard         oss_anal_close (&fd);
5171d14ffa9Sbellard         return -1;
5181d14ffa9Sbellard     }
51985571bc7Sbellard 
520c0fe3827Sbellard     obt_as.freq = obt.freq;
521c0fe3827Sbellard     obt_as.nchannels = obt.nchannels;
522c0fe3827Sbellard     obt_as.fmt = effective_fmt;
523d929eba5Sbellard     obt_as.endianness = endianness;
524c0fe3827Sbellard 
525d929eba5Sbellard     audio_pcm_init_info (&hw->info, &obt_as);
52685571bc7Sbellard     oss->nfrags = obt.nfrags;
52785571bc7Sbellard     oss->fragsize = obt.fragsize;
528c0fe3827Sbellard 
5292b9cce8cSKővágó, Zoltán     if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) {
530c0fe3827Sbellard         dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
5312b9cce8cSKővágó, Zoltán                obt.nfrags * obt.fragsize, hw->info.bytes_per_frame);
532c0fe3827Sbellard     }
533c0fe3827Sbellard 
5342b9cce8cSKővágó, Zoltán     hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame;
53585571bc7Sbellard 
53685571bc7Sbellard     oss->mmapped = 0;
537baf6c7f4SKővágó, Zoltán     if (oopts->has_try_mmap && oopts->try_mmap) {
5382b9cce8cSKővágó, Zoltán         hw->size_emul = hw->samples * hw->info.bytes_per_frame;
5393ba4066dSKővágó, Zoltán         hw->buf_emul = mmap(
540660f11beSBlue Swirl             NULL,
5413ba4066dSKővágó, Zoltán             hw->size_emul,
542c0fe3827Sbellard             PROT_READ | PROT_WRITE,
543c0fe3827Sbellard             MAP_SHARED,
544c0fe3827Sbellard             fd,
545c0fe3827Sbellard             0
546c0fe3827Sbellard             );
5473ba4066dSKővágó, Zoltán         if (hw->buf_emul == MAP_FAILED) {
5487520462bSKővágó, Zoltán             oss_logerr(errno, "Failed to map %zu bytes of DAC\n",
5493ba4066dSKővágó, Zoltán                        hw->size_emul);
5503ba4066dSKővágó, Zoltán             hw->buf_emul = NULL;
5513ba4066dSKővágó, Zoltán         } else {
55285571bc7Sbellard             int trig = 0;
5531d14ffa9Sbellard             if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
5541d14ffa9Sbellard                 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
5556c6886bdSZhang Han             } else {
55685571bc7Sbellard                 trig = PCM_ENABLE_OUTPUT;
5571d14ffa9Sbellard                 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
5581d14ffa9Sbellard                     oss_logerr (
5591d14ffa9Sbellard                         errno,
5601d14ffa9Sbellard                         "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
5611d14ffa9Sbellard                         );
5626c6886bdSZhang Han                 } else {
56385571bc7Sbellard                     oss->mmapped = 1;
56444a095a7Sbellard                 }
56544a095a7Sbellard             }
56685571bc7Sbellard 
56744a095a7Sbellard             if (!oss->mmapped) {
5683ba4066dSKővágó, Zoltán                 err = munmap(hw->buf_emul, hw->size_emul);
56985571bc7Sbellard                 if (err) {
5707520462bSKővágó, Zoltán                     oss_logerr(errno, "Failed to unmap buffer %p size %zu\n",
5713ba4066dSKővágó, Zoltán                                hw->buf_emul, hw->size_emul);
57285571bc7Sbellard                 }
5733ba4066dSKővágó, Zoltán                 hw->buf_emul = NULL;
57485571bc7Sbellard             }
57585571bc7Sbellard         }
57644a095a7Sbellard     }
57785571bc7Sbellard 
5781d14ffa9Sbellard     oss->fd = fd;
579baf6c7f4SKővágó, Zoltán     oss->dev = dev;
58085571bc7Sbellard     return 0;
58185571bc7Sbellard }
58285571bc7Sbellard 
oss_enable_out(HWVoiceOut * hw,bool enable)583571a8c52SKővágó, Zoltán static void oss_enable_out(HWVoiceOut *hw, bool enable)
58485571bc7Sbellard {
58585571bc7Sbellard     int trig;
586301901b5Smalc     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
587baf6c7f4SKővágó, Zoltán     AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
588301901b5Smalc 
589571a8c52SKővágó, Zoltán     if (enable) {
590f03cd068SVolker Rümelin         hw->poll_mode = opdo->try_poll;
591dd8a5649Smalc 
592dd8a5649Smalc         ldebug("enabling voice\n");
593f03cd068SVolker Rümelin         if (hw->poll_mode) {
594b027a538SFam Zheng             oss_poll_out(hw);
595dd8a5649Smalc         }
596dd8a5649Smalc 
5971d14ffa9Sbellard         if (!oss->mmapped) {
598571a8c52SKővágó, Zoltán             return;
5991d14ffa9Sbellard         }
60085571bc7Sbellard 
6013e0c1bbaSVolker Rümelin         audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->samples);
60285571bc7Sbellard         trig = PCM_ENABLE_OUTPUT;
60385571bc7Sbellard         if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
604571a8c52SKővágó, Zoltán             oss_logerr(errno,
605571a8c52SKővágó, Zoltán                        "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n");
606571a8c52SKővágó, Zoltán             return;
60785571bc7Sbellard         }
608571a8c52SKővágó, Zoltán     } else {
609dd8a5649Smalc         if (hw->poll_mode) {
610dd8a5649Smalc             qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
611dd8a5649Smalc             hw->poll_mode = 0;
612dd8a5649Smalc         }
613dd8a5649Smalc 
614dd8a5649Smalc         if (!oss->mmapped) {
615571a8c52SKővágó, Zoltán             return;
616dd8a5649Smalc         }
617dd8a5649Smalc 
61885571bc7Sbellard         ldebug ("disabling voice\n");
61985571bc7Sbellard         trig = 0;
62085571bc7Sbellard         if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
6211d14ffa9Sbellard             oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
622571a8c52SKővágó, Zoltán             return;
62385571bc7Sbellard         }
62485571bc7Sbellard     }
62585571bc7Sbellard }
62685571bc7Sbellard 
oss_init_in(HWVoiceIn * hw,struct audsettings * as,void * drv_opaque)6275706db1dSKővágó, Zoltán static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
6281d14ffa9Sbellard {
6291d14ffa9Sbellard     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
6301d14ffa9Sbellard     struct oss_params req, obt;
6311d14ffa9Sbellard     int endianness;
6321d14ffa9Sbellard     int err;
6331d14ffa9Sbellard     int fd;
63485bc5852SKővágó, Zoltán     AudioFormat effective_fmt;
6351ea879e5Smalc     struct audsettings obt_as;
636baf6c7f4SKővágó, Zoltán     Audiodev *dev = drv_opaque;
6371d14ffa9Sbellard 
638571ec3d6Sbellard     oss->fd = -1;
639571ec3d6Sbellard 
640b6c9c940SMichael Walle     req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
641c0fe3827Sbellard     req.freq = as->freq;
642c0fe3827Sbellard     req.nchannels = as->nchannels;
643baf6c7f4SKővágó, Zoltán     if (oss_open(1, &req, as, &obt, &fd, dev)) {
6441d14ffa9Sbellard         return -1;
6451d14ffa9Sbellard     }
6461d14ffa9Sbellard 
6471d14ffa9Sbellard     err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
6481d14ffa9Sbellard     if (err) {
6491d14ffa9Sbellard         oss_anal_close (&fd);
6501d14ffa9Sbellard         return -1;
6511d14ffa9Sbellard     }
6521d14ffa9Sbellard 
653c0fe3827Sbellard     obt_as.freq = obt.freq;
654c0fe3827Sbellard     obt_as.nchannels = obt.nchannels;
655c0fe3827Sbellard     obt_as.fmt = effective_fmt;
656d929eba5Sbellard     obt_as.endianness = endianness;
657c0fe3827Sbellard 
658d929eba5Sbellard     audio_pcm_init_info (&hw->info, &obt_as);
6591d14ffa9Sbellard     oss->nfrags = obt.nfrags;
6601d14ffa9Sbellard     oss->fragsize = obt.fragsize;
661c0fe3827Sbellard 
6622b9cce8cSKővágó, Zoltán     if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) {
663c0fe3827Sbellard         dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
6642b9cce8cSKővágó, Zoltán                obt.nfrags * obt.fragsize, hw->info.bytes_per_frame);
665c0fe3827Sbellard     }
666c0fe3827Sbellard 
6672b9cce8cSKővágó, Zoltán     hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame;
6681d14ffa9Sbellard 
6691d14ffa9Sbellard     oss->fd = fd;
670baf6c7f4SKővágó, Zoltán     oss->dev = dev;
6711d14ffa9Sbellard     return 0;
6721d14ffa9Sbellard }
6731d14ffa9Sbellard 
oss_fini_in(HWVoiceIn * hw)6741d14ffa9Sbellard static void oss_fini_in (HWVoiceIn *hw)
6751d14ffa9Sbellard {
6761d14ffa9Sbellard     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
6771d14ffa9Sbellard 
6781d14ffa9Sbellard     oss_anal_close (&oss->fd);
6791d14ffa9Sbellard }
6801d14ffa9Sbellard 
oss_read(HWVoiceIn * hw,void * buf,size_t len)6813ba4066dSKővágó, Zoltán static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len)
6821d14ffa9Sbellard {
6831d14ffa9Sbellard     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
6843ba4066dSKővágó, Zoltán     size_t pos = 0;
6851d14ffa9Sbellard 
6863ba4066dSKővágó, Zoltán     while (len) {
6871d14ffa9Sbellard         ssize_t nread;
6881d14ffa9Sbellard 
6893ba4066dSKővágó, Zoltán         void *dst = advance(buf, pos);
6903ba4066dSKővágó, Zoltán         nread = read(oss->fd, dst, len);
6911d14ffa9Sbellard 
6921d14ffa9Sbellard         if (nread == -1) {
6931d14ffa9Sbellard             switch (errno) {
6941d14ffa9Sbellard             case EINTR:
6951d14ffa9Sbellard             case EAGAIN:
6961d14ffa9Sbellard                 break;
6971d14ffa9Sbellard             default:
6983ba4066dSKővágó, Zoltán                 oss_logerr(errno, "Failed to read %zu bytes of audio (to %p)\n",
6993ba4066dSKővágó, Zoltán                            len, dst);
7001d14ffa9Sbellard                 break;
7011d14ffa9Sbellard             }
7024f50d4a4SVolker Rümelin             break;
7031d14ffa9Sbellard         }
7041d14ffa9Sbellard 
7053ba4066dSKővágó, Zoltán         pos += nread;
7063ba4066dSKővágó, Zoltán         len -= nread;
7073ba4066dSKővágó, Zoltán     }
7083ba4066dSKővágó, Zoltán 
7093ba4066dSKővágó, Zoltán     return pos;
7101d14ffa9Sbellard }
7111d14ffa9Sbellard 
oss_enable_in(HWVoiceIn * hw,bool enable)712571a8c52SKővágó, Zoltán static void oss_enable_in(HWVoiceIn *hw, bool enable)
7131d14ffa9Sbellard {
714a628b869Smalc     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
715baf6c7f4SKővágó, Zoltán     AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
716a628b869Smalc 
717571a8c52SKővágó, Zoltán     if (enable) {
718f03cd068SVolker Rümelin         hw->poll_mode = opdo->try_poll;
719dd8a5649Smalc 
720f03cd068SVolker Rümelin         if (hw->poll_mode) {
721b027a538SFam Zheng             oss_poll_in(hw);
722dd8a5649Smalc         }
723571a8c52SKővágó, Zoltán     } else {
724dd8a5649Smalc         if (hw->poll_mode) {
725dd8a5649Smalc             qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
726f03cd068SVolker Rümelin             hw->poll_mode = 0;
727dd8a5649Smalc         }
728dd8a5649Smalc     }
7291d14ffa9Sbellard }
7301d14ffa9Sbellard 
oss_init_per_direction(AudiodevOssPerDirectionOptions * opdo)731baf6c7f4SKővágó, Zoltán static void oss_init_per_direction(AudiodevOssPerDirectionOptions *opdo)
732baf6c7f4SKővágó, Zoltán {
733baf6c7f4SKővágó, Zoltán     if (!opdo->has_try_poll) {
734baf6c7f4SKővágó, Zoltán         opdo->try_poll = true;
735baf6c7f4SKővágó, Zoltán         opdo->has_try_poll = true;
736baf6c7f4SKővágó, Zoltán     }
737baf6c7f4SKővágó, Zoltán }
7384045a85aSKővágó, Zoltán 
oss_audio_init(Audiodev * dev,Error ** errp)739*f6061733SPaolo Bonzini static void *oss_audio_init(Audiodev *dev, Error **errp)
74085571bc7Sbellard {
741baf6c7f4SKővágó, Zoltán     AudiodevOssOptions *oopts;
742baf6c7f4SKővágó, Zoltán     assert(dev->driver == AUDIODEV_DRIVER_OSS);
7434045a85aSKővágó, Zoltán 
744baf6c7f4SKővágó, Zoltán     oopts = &dev->u.oss;
745baf6c7f4SKővágó, Zoltán     oss_init_per_direction(oopts->in);
746baf6c7f4SKővágó, Zoltán     oss_init_per_direction(oopts->out);
747baf6c7f4SKővágó, Zoltán 
748*f6061733SPaolo Bonzini     if (access(oopts->in->dev ?: "/dev/dsp", R_OK | W_OK) < 0) {
749*f6061733SPaolo Bonzini         error_setg_errno(errp, errno, "%s not accessible", oopts->in->dev ?: "/dev/dsp");
750*f6061733SPaolo Bonzini         return NULL;
751*f6061733SPaolo Bonzini     }
752*f6061733SPaolo Bonzini     if (access(oopts->out->dev ?: "/dev/dsp", R_OK | W_OK) < 0) {
753*f6061733SPaolo Bonzini         error_setg_errno(errp, errno, "%s not accessible", oopts->out->dev ?: "/dev/dsp");
75473204cffSGerd Hoffmann         return NULL;
75573204cffSGerd Hoffmann     }
756baf6c7f4SKővágó, Zoltán     return dev;
75785571bc7Sbellard }
75885571bc7Sbellard 
oss_audio_fini(void * opaque)75985571bc7Sbellard static void oss_audio_fini (void *opaque)
76085571bc7Sbellard {
76185571bc7Sbellard }
76285571bc7Sbellard 
76335f4b58cSblueswir1 static struct audio_pcm_ops oss_pcm_ops = {
7641dd3e4d1SJuan Quintela     .init_out = oss_init_out,
7651dd3e4d1SJuan Quintela     .fini_out = oss_fini_out,
7663ba4066dSKővágó, Zoltán     .write    = oss_write,
7679833438eSVolker Rümelin     .buffer_get_free = oss_buffer_get_free,
768fdc8c5f4SVolker Rümelin     .run_buffer_out = oss_run_buffer_out,
7693ba4066dSKővágó, Zoltán     .get_buffer_out = oss_get_buffer_out,
7703ba4066dSKővágó, Zoltán     .put_buffer_out = oss_put_buffer_out,
771571a8c52SKővágó, Zoltán     .enable_out = oss_enable_out,
7721d14ffa9Sbellard 
7731dd3e4d1SJuan Quintela     .init_in  = oss_init_in,
7741dd3e4d1SJuan Quintela     .fini_in  = oss_fini_in,
7753ba4066dSKővágó, Zoltán     .read     = oss_read,
776a2893c83SVolker Rümelin     .run_buffer_in = audio_generic_run_buffer_in,
777571a8c52SKővágó, Zoltán     .enable_in = oss_enable_in
7781d14ffa9Sbellard };
7791d14ffa9Sbellard 
780d3893a39SGerd Hoffmann static struct audio_driver oss_audio_driver = {
781bee37f32SJuan Quintela     .name           = "oss",
782bee37f32SJuan Quintela     .descr          = "OSS http://www.opensound.com",
783bee37f32SJuan Quintela     .init           = oss_audio_init,
784bee37f32SJuan Quintela     .fini           = oss_audio_fini,
785bee37f32SJuan Quintela     .pcm_ops        = &oss_pcm_ops,
786bee37f32SJuan Quintela     .max_voices_out = INT_MAX,
787bee37f32SJuan Quintela     .max_voices_in  = INT_MAX,
788bee37f32SJuan Quintela     .voice_size_out = sizeof (OSSVoiceOut),
789bee37f32SJuan Quintela     .voice_size_in  = sizeof (OSSVoiceIn)
79085571bc7Sbellard };
791d3893a39SGerd Hoffmann 
register_audio_oss(void)792d3893a39SGerd Hoffmann static void register_audio_oss(void)
793d3893a39SGerd Hoffmann {
794d3893a39SGerd Hoffmann     audio_driver_register(&oss_audio_driver);
795d3893a39SGerd Hoffmann }
796d3893a39SGerd Hoffmann type_init(register_audio_oss);
797