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