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