rtoss - Blame information for rev 73

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