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 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, 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 && oss_poll_out (hw)) { 638 poll_mode = 0; 639 } 640 hw->poll_mode = poll_mode; 641 642 if (!oss->mmapped) { 643 return 0; 644 } 645 646 audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples); 647 trig = PCM_ENABLE_OUTPUT; 648 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 649 oss_logerr ( 650 errno, 651 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" 652 ); 653 return -1; 654 } 655 } 656 break; 657 658 case VOICE_DISABLE: 659 if (hw->poll_mode) { 660 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 661 hw->poll_mode = 0; 662 } 663 664 if (!oss->mmapped) { 665 return 0; 666 } 667 668 ldebug ("disabling voice\n"); 669 trig = 0; 670 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 671 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 672 return -1; 673 } 674 break; 675 } 676 return 0; 677 } 678 679 static int oss_init_in (HWVoiceIn *hw, struct audsettings *as) 680 { 681 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 682 struct oss_params req, obt; 683 int endianness; 684 int err; 685 int fd; 686 audfmt_e effective_fmt; 687 struct audsettings obt_as; 688 689 oss->fd = -1; 690 691 req.fmt = aud_to_ossfmt (as->fmt, as->endianness); 692 req.freq = as->freq; 693 req.nchannels = as->nchannels; 694 req.fragsize = conf.fragsize; 695 req.nfrags = conf.nfrags; 696 if (oss_open (1, &req, &obt, &fd)) { 697 return -1; 698 } 699 700 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); 701 if (err) { 702 oss_anal_close (&fd); 703 return -1; 704 } 705 706 obt_as.freq = obt.freq; 707 obt_as.nchannels = obt.nchannels; 708 obt_as.fmt = effective_fmt; 709 obt_as.endianness = endianness; 710 711 audio_pcm_init_info (&hw->info, &obt_as); 712 oss->nfrags = obt.nfrags; 713 oss->fragsize = obt.fragsize; 714 715 if (obt.nfrags * obt.fragsize & hw->info.align) { 716 dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", 717 obt.nfrags * obt.fragsize, hw->info.align + 1); 718 } 719 720 hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; 721 oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); 722 if (!oss->pcm_buf) { 723 dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n", 724 hw->samples, 1 << hw->info.shift); 725 oss_anal_close (&fd); 726 return -1; 727 } 728 729 oss->fd = fd; 730 return 0; 731 } 732 733 static void oss_fini_in (HWVoiceIn *hw) 734 { 735 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 736 737 oss_anal_close (&oss->fd); 738 739 g_free(oss->pcm_buf); 740 oss->pcm_buf = NULL; 741 } 742 743 static int oss_run_in (HWVoiceIn *hw) 744 { 745 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 746 int hwshift = hw->info.shift; 747 int i; 748 int live = audio_pcm_hw_get_live_in (hw); 749 int dead = hw->samples - live; 750 size_t read_samples = 0; 751 struct { 752 int add; 753 int len; 754 } bufs[2] = { 755 { .add = hw->wpos, .len = 0 }, 756 { .add = 0, .len = 0 } 757 }; 758 759 if (!dead) { 760 return 0; 761 } 762 763 if (hw->wpos + dead > hw->samples) { 764 bufs[0].len = (hw->samples - hw->wpos) << hwshift; 765 bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift; 766 } 767 else { 768 bufs[0].len = dead << hwshift; 769 } 770 771 for (i = 0; i < 2; ++i) { 772 ssize_t nread; 773 774 if (bufs[i].len) { 775 void *p = advance (oss->pcm_buf, bufs[i].add << hwshift); 776 nread = read (oss->fd, p, bufs[i].len); 777 778 if (nread > 0) { 779 if (nread & hw->info.align) { 780 dolog ("warning: Misaligned read %zd (requested %d), " 781 "alignment %d\n", nread, bufs[i].add << hwshift, 782 hw->info.align + 1); 783 } 784 read_samples += nread >> hwshift; 785 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift); 786 } 787 788 if (bufs[i].len - nread) { 789 if (nread == -1) { 790 switch (errno) { 791 case EINTR: 792 case EAGAIN: 793 break; 794 default: 795 oss_logerr ( 796 errno, 797 "Failed to read %d bytes of audio (to %p)\n", 798 bufs[i].len, p 799 ); 800 break; 801 } 802 } 803 break; 804 } 805 } 806 } 807 808 hw->wpos = (hw->wpos + read_samples) % hw->samples; 809 return read_samples; 810 } 811 812 static int oss_read (SWVoiceIn *sw, void *buf, int size) 813 { 814 return audio_pcm_sw_read (sw, buf, size); 815 } 816 817 static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...) 818 { 819 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 820 821 switch (cmd) { 822 case VOICE_ENABLE: 823 { 824 va_list ap; 825 int poll_mode; 826 827 va_start (ap, cmd); 828 poll_mode = va_arg (ap, int); 829 va_end (ap); 830 831 if (poll_mode && oss_poll_in (hw)) { 832 poll_mode = 0; 833 } 834 hw->poll_mode = poll_mode; 835 } 836 break; 837 838 case VOICE_DISABLE: 839 if (hw->poll_mode) { 840 hw->poll_mode = 0; 841 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 842 } 843 break; 844 } 845 return 0; 846 } 847 848 static void *oss_audio_init (void) 849 { 850 if (access(conf.devpath_in, R_OK | W_OK) < 0 || 851 access(conf.devpath_out, R_OK | W_OK) < 0) { 852 return NULL; 853 } 854 return &conf; 855 } 856 857 static void oss_audio_fini (void *opaque) 858 { 859 (void) opaque; 860 } 861 862 static struct audio_option oss_options[] = { 863 { 864 .name = "FRAGSIZE", 865 .tag = AUD_OPT_INT, 866 .valp = &conf.fragsize, 867 .descr = "Fragment size in bytes" 868 }, 869 { 870 .name = "NFRAGS", 871 .tag = AUD_OPT_INT, 872 .valp = &conf.nfrags, 873 .descr = "Number of fragments" 874 }, 875 { 876 .name = "MMAP", 877 .tag = AUD_OPT_BOOL, 878 .valp = &conf.try_mmap, 879 .descr = "Try using memory mapped access" 880 }, 881 { 882 .name = "DAC_DEV", 883 .tag = AUD_OPT_STR, 884 .valp = &conf.devpath_out, 885 .descr = "Path to DAC device" 886 }, 887 { 888 .name = "ADC_DEV", 889 .tag = AUD_OPT_STR, 890 .valp = &conf.devpath_in, 891 .descr = "Path to ADC device" 892 }, 893 { 894 .name = "EXCLUSIVE", 895 .tag = AUD_OPT_BOOL, 896 .valp = &conf.exclusive, 897 .descr = "Open device in exclusive mode (vmix wont work)" 898 }, 899 #ifdef USE_DSP_POLICY 900 { 901 .name = "POLICY", 902 .tag = AUD_OPT_INT, 903 .valp = &conf.policy, 904 .descr = "Set the timing policy of the device, -1 to use fragment mode", 905 }, 906 #endif 907 { 908 .name = "DEBUG", 909 .tag = AUD_OPT_BOOL, 910 .valp = &conf.debug, 911 .descr = "Turn on some debugging messages" 912 }, 913 { /* End of list */ } 914 }; 915 916 static struct audio_pcm_ops oss_pcm_ops = { 917 .init_out = oss_init_out, 918 .fini_out = oss_fini_out, 919 .run_out = oss_run_out, 920 .write = oss_write, 921 .ctl_out = oss_ctl_out, 922 923 .init_in = oss_init_in, 924 .fini_in = oss_fini_in, 925 .run_in = oss_run_in, 926 .read = oss_read, 927 .ctl_in = oss_ctl_in 928 }; 929 930 struct audio_driver oss_audio_driver = { 931 .name = "oss", 932 .descr = "OSS http://www.opensound.com", 933 .options = oss_options, 934 .init = oss_audio_init, 935 .fini = oss_audio_fini, 936 .pcm_ops = &oss_pcm_ops, 937 .can_be_default = 1, 938 .max_voices_out = INT_MAX, 939 .max_voices_in = INT_MAX, 940 .voice_size_out = sizeof (OSSVoiceOut), 941 .voice_size_in = sizeof (OSSVoiceIn) 942 }; 943