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