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