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 (void) opaque; 114 audio_run ("oss_poll_out"); 115 } 116 117 static void oss_helper_poll_in (void *opaque) 118 { 119 (void) opaque; 120 audio_run ("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, NULL); 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, NULL); 135 } 136 137 static int oss_write (SWVoiceOut *sw, void *buf, int len) 138 { 139 return audio_pcm_sw_write (sw, buf, len); 140 } 141 142 static int aud_to_ossfmt (AudioFormat fmt, int endianness) 143 { 144 switch (fmt) { 145 case AUDIO_FORMAT_S8: 146 return AFMT_S8; 147 148 case AUDIO_FORMAT_U8: 149 return AFMT_U8; 150 151 case AUDIO_FORMAT_S16: 152 if (endianness) { 153 return AFMT_S16_BE; 154 } 155 else { 156 return AFMT_S16_LE; 157 } 158 159 case AUDIO_FORMAT_U16: 160 if (endianness) { 161 return AFMT_U16_BE; 162 } 163 else { 164 return AFMT_U16_LE; 165 } 166 167 default: 168 dolog ("Internal logic error: Bad audio format %d\n", fmt); 169 #ifdef DEBUG_AUDIO 170 abort (); 171 #endif 172 return AFMT_U8; 173 } 174 } 175 176 static int oss_to_audfmt (int ossfmt, AudioFormat *fmt, int *endianness) 177 { 178 switch (ossfmt) { 179 case AFMT_S8: 180 *endianness = 0; 181 *fmt = AUDIO_FORMAT_S8; 182 break; 183 184 case AFMT_U8: 185 *endianness = 0; 186 *fmt = AUDIO_FORMAT_U8; 187 break; 188 189 case AFMT_S16_LE: 190 *endianness = 0; 191 *fmt = AUDIO_FORMAT_S16; 192 break; 193 194 case AFMT_U16_LE: 195 *endianness = 0; 196 *fmt = AUDIO_FORMAT_U16; 197 break; 198 199 case AFMT_S16_BE: 200 *endianness = 1; 201 *fmt = AUDIO_FORMAT_S16; 202 break; 203 204 case AFMT_U16_BE: 205 *endianness = 1; 206 *fmt = AUDIO_FORMAT_U16; 207 break; 208 209 default: 210 dolog ("Unrecognized audio format %d\n", ossfmt); 211 return -1; 212 } 213 214 return 0; 215 } 216 217 #if defined DEBUG_MISMATCHES || defined DEBUG 218 static void oss_dump_info (struct oss_params *req, struct oss_params *obt) 219 { 220 dolog ("parameter | requested value | obtained value\n"); 221 dolog ("format | %10d | %10d\n", req->fmt, obt->fmt); 222 dolog ("channels | %10d | %10d\n", 223 req->nchannels, obt->nchannels); 224 dolog ("frequency | %10d | %10d\n", req->freq, obt->freq); 225 dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags); 226 dolog ("fragsize | %10d | %10d\n", 227 req->fragsize, obt->fragsize); 228 } 229 #endif 230 231 #ifdef USE_DSP_POLICY 232 static int oss_get_version (int fd, int *version, const char *typ) 233 { 234 if (ioctl (fd, OSS_GETVERSION, &version)) { 235 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 236 /* 237 * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION 238 * since 7.x, but currently only on the mixer device (or in 239 * the Linuxolator), and in the native version that part of 240 * the code is in fact never reached so the ioctl fails anyway. 241 * Until this is fixed, just check the errno and if its what 242 * FreeBSD's sound drivers return atm assume they are new enough. 243 */ 244 if (errno == EINVAL) { 245 *version = 0x040000; 246 return 0; 247 } 248 #endif 249 oss_logerr2 (errno, typ, "Failed to get OSS version\n"); 250 return -1; 251 } 252 return 0; 253 } 254 #endif 255 256 static int oss_open(int in, struct oss_params *req, audsettings *as, 257 struct oss_params *obt, int *pfd, Audiodev *dev) 258 { 259 AudiodevOssOptions *oopts = &dev->u.oss; 260 AudiodevOssPerDirectionOptions *opdo = in ? oopts->in : oopts->out; 261 int fd; 262 int oflags = (oopts->has_exclusive && oopts->exclusive) ? O_EXCL : 0; 263 audio_buf_info abinfo; 264 int fmt, freq, nchannels; 265 int setfragment = 1; 266 const char *dspname = opdo->has_dev ? opdo->dev : "/dev/dsp"; 267 const char *typ = in ? "ADC" : "DAC"; 268 #ifdef USE_DSP_POLICY 269 int policy = oopts->has_dsp_policy ? oopts->dsp_policy : 5; 270 #endif 271 272 /* Kludge needed to have working mmap on Linux */ 273 oflags |= (oopts->has_try_mmap && oopts->try_mmap) ? 274 O_RDWR : (in ? O_RDONLY : O_WRONLY); 275 276 fd = open (dspname, oflags | O_NONBLOCK); 277 if (-1 == fd) { 278 oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname); 279 return -1; 280 } 281 282 freq = req->freq; 283 nchannels = req->nchannels; 284 fmt = req->fmt; 285 req->nfrags = opdo->has_buffer_count ? opdo->buffer_count : 4; 286 req->fragsize = audio_buffer_bytes( 287 qapi_AudiodevOssPerDirectionOptions_base(opdo), as, 23220); 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 (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 policy2 = policy; 319 if (ioctl(fd, SNDCTL_DSP_POLICY, &policy2)) { 320 oss_logerr2 (errno, typ, 321 "Failed to set timing policy to %d\n", 322 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 AudioFormat effective_fmt; 504 struct audsettings obt_as; 505 Audiodev *dev = drv_opaque; 506 AudiodevOssOptions *oopts = &dev->u.oss; 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 514 if (oss_open(0, &req, as, &obt, &fd, dev)) { 515 return -1; 516 } 517 518 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); 519 if (err) { 520 oss_anal_close (&fd); 521 return -1; 522 } 523 524 obt_as.freq = obt.freq; 525 obt_as.nchannels = obt.nchannels; 526 obt_as.fmt = effective_fmt; 527 obt_as.endianness = endianness; 528 529 audio_pcm_init_info (&hw->info, &obt_as); 530 oss->nfrags = obt.nfrags; 531 oss->fragsize = obt.fragsize; 532 533 if (obt.nfrags * obt.fragsize & hw->info.align) { 534 dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n", 535 obt.nfrags * obt.fragsize, hw->info.align + 1); 536 } 537 538 hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; 539 540 oss->mmapped = 0; 541 if (oopts->has_try_mmap && oopts->try_mmap) { 542 oss->pcm_buf = mmap ( 543 NULL, 544 hw->samples << hw->info.shift, 545 PROT_READ | PROT_WRITE, 546 MAP_SHARED, 547 fd, 548 0 549 ); 550 if (oss->pcm_buf == MAP_FAILED) { 551 oss_logerr (errno, "Failed to map %d bytes of DAC\n", 552 hw->samples << hw->info.shift); 553 } 554 else { 555 int err; 556 int trig = 0; 557 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 558 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 559 } 560 else { 561 trig = PCM_ENABLE_OUTPUT; 562 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 563 oss_logerr ( 564 errno, 565 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" 566 ); 567 } 568 else { 569 oss->mmapped = 1; 570 } 571 } 572 573 if (!oss->mmapped) { 574 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); 575 if (err) { 576 oss_logerr (errno, "Failed to unmap buffer %p size %d\n", 577 oss->pcm_buf, hw->samples << hw->info.shift); 578 } 579 } 580 } 581 } 582 583 if (!oss->mmapped) { 584 oss->pcm_buf = audio_calloc(__func__, 585 hw->samples, 586 1 << hw->info.shift); 587 if (!oss->pcm_buf) { 588 dolog ( 589 "Could not allocate DAC buffer (%d samples, each %d bytes)\n", 590 hw->samples, 591 1 << hw->info.shift 592 ); 593 oss_anal_close (&fd); 594 return -1; 595 } 596 } 597 598 oss->fd = fd; 599 oss->dev = dev; 600 return 0; 601 } 602 603 static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...) 604 { 605 int trig; 606 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 607 AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out; 608 609 switch (cmd) { 610 case VOICE_ENABLE: 611 { 612 bool poll_mode = opdo->try_poll; 613 614 ldebug ("enabling voice\n"); 615 if (poll_mode) { 616 oss_poll_out (hw); 617 poll_mode = 0; 618 } 619 hw->poll_mode = poll_mode; 620 621 if (!oss->mmapped) { 622 return 0; 623 } 624 625 audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples); 626 trig = PCM_ENABLE_OUTPUT; 627 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 628 oss_logerr ( 629 errno, 630 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" 631 ); 632 return -1; 633 } 634 } 635 break; 636 637 case VOICE_DISABLE: 638 if (hw->poll_mode) { 639 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 640 hw->poll_mode = 0; 641 } 642 643 if (!oss->mmapped) { 644 return 0; 645 } 646 647 ldebug ("disabling voice\n"); 648 trig = 0; 649 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 650 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 651 return -1; 652 } 653 break; 654 } 655 return 0; 656 } 657 658 static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) 659 { 660 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 661 struct oss_params req, obt; 662 int endianness; 663 int err; 664 int fd; 665 AudioFormat effective_fmt; 666 struct audsettings obt_as; 667 Audiodev *dev = drv_opaque; 668 669 oss->fd = -1; 670 671 req.fmt = aud_to_ossfmt (as->fmt, as->endianness); 672 req.freq = as->freq; 673 req.nchannels = as->nchannels; 674 if (oss_open(1, &req, as, &obt, &fd, dev)) { 675 return -1; 676 } 677 678 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); 679 if (err) { 680 oss_anal_close (&fd); 681 return -1; 682 } 683 684 obt_as.freq = obt.freq; 685 obt_as.nchannels = obt.nchannels; 686 obt_as.fmt = effective_fmt; 687 obt_as.endianness = endianness; 688 689 audio_pcm_init_info (&hw->info, &obt_as); 690 oss->nfrags = obt.nfrags; 691 oss->fragsize = obt.fragsize; 692 693 if (obt.nfrags * obt.fragsize & hw->info.align) { 694 dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", 695 obt.nfrags * obt.fragsize, hw->info.align + 1); 696 } 697 698 hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; 699 oss->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); 700 if (!oss->pcm_buf) { 701 dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n", 702 hw->samples, 1 << hw->info.shift); 703 oss_anal_close (&fd); 704 return -1; 705 } 706 707 oss->fd = fd; 708 oss->dev = dev; 709 return 0; 710 } 711 712 static void oss_fini_in (HWVoiceIn *hw) 713 { 714 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 715 716 oss_anal_close (&oss->fd); 717 718 g_free(oss->pcm_buf); 719 oss->pcm_buf = NULL; 720 } 721 722 static int oss_run_in (HWVoiceIn *hw) 723 { 724 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 725 int hwshift = hw->info.shift; 726 int i; 727 int live = audio_pcm_hw_get_live_in (hw); 728 int dead = hw->samples - live; 729 size_t read_samples = 0; 730 struct { 731 int add; 732 int len; 733 } bufs[2] = { 734 { .add = hw->wpos, .len = 0 }, 735 { .add = 0, .len = 0 } 736 }; 737 738 if (!dead) { 739 return 0; 740 } 741 742 if (hw->wpos + dead > hw->samples) { 743 bufs[0].len = (hw->samples - hw->wpos) << hwshift; 744 bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift; 745 } 746 else { 747 bufs[0].len = dead << hwshift; 748 } 749 750 for (i = 0; i < 2; ++i) { 751 ssize_t nread; 752 753 if (bufs[i].len) { 754 void *p = advance (oss->pcm_buf, bufs[i].add << hwshift); 755 nread = read (oss->fd, p, bufs[i].len); 756 757 if (nread > 0) { 758 if (nread & hw->info.align) { 759 dolog ("warning: Misaligned read %zd (requested %d), " 760 "alignment %d\n", nread, bufs[i].add << hwshift, 761 hw->info.align + 1); 762 } 763 read_samples += nread >> hwshift; 764 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift); 765 } 766 767 if (bufs[i].len - nread) { 768 if (nread == -1) { 769 switch (errno) { 770 case EINTR: 771 case EAGAIN: 772 break; 773 default: 774 oss_logerr ( 775 errno, 776 "Failed to read %d bytes of audio (to %p)\n", 777 bufs[i].len, p 778 ); 779 break; 780 } 781 } 782 break; 783 } 784 } 785 } 786 787 hw->wpos = (hw->wpos + read_samples) % hw->samples; 788 return read_samples; 789 } 790 791 static int oss_read (SWVoiceIn *sw, void *buf, int size) 792 { 793 return audio_pcm_sw_read (sw, buf, size); 794 } 795 796 static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...) 797 { 798 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 799 AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out; 800 801 switch (cmd) { 802 case VOICE_ENABLE: 803 { 804 bool poll_mode = opdo->try_poll; 805 806 if (poll_mode) { 807 oss_poll_in (hw); 808 poll_mode = 0; 809 } 810 hw->poll_mode = poll_mode; 811 } 812 break; 813 814 case VOICE_DISABLE: 815 if (hw->poll_mode) { 816 hw->poll_mode = 0; 817 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 818 } 819 break; 820 } 821 return 0; 822 } 823 824 static void oss_init_per_direction(AudiodevOssPerDirectionOptions *opdo) 825 { 826 if (!opdo->has_try_poll) { 827 opdo->try_poll = true; 828 opdo->has_try_poll = true; 829 } 830 } 831 832 static void *oss_audio_init(Audiodev *dev) 833 { 834 AudiodevOssOptions *oopts; 835 assert(dev->driver == AUDIODEV_DRIVER_OSS); 836 837 oopts = &dev->u.oss; 838 oss_init_per_direction(oopts->in); 839 oss_init_per_direction(oopts->out); 840 841 if (access(oopts->in->has_dev ? oopts->in->dev : "/dev/dsp", 842 R_OK | W_OK) < 0 || 843 access(oopts->out->has_dev ? oopts->out->dev : "/dev/dsp", 844 R_OK | W_OK) < 0) { 845 return NULL; 846 } 847 return dev; 848 } 849 850 static void oss_audio_fini (void *opaque) 851 { 852 } 853 854 static struct audio_pcm_ops oss_pcm_ops = { 855 .init_out = oss_init_out, 856 .fini_out = oss_fini_out, 857 .run_out = oss_run_out, 858 .write = oss_write, 859 .ctl_out = oss_ctl_out, 860 861 .init_in = oss_init_in, 862 .fini_in = oss_fini_in, 863 .run_in = oss_run_in, 864 .read = oss_read, 865 .ctl_in = oss_ctl_in 866 }; 867 868 static struct audio_driver oss_audio_driver = { 869 .name = "oss", 870 .descr = "OSS http://www.opensound.com", 871 .init = oss_audio_init, 872 .fini = oss_audio_fini, 873 .pcm_ops = &oss_pcm_ops, 874 .can_be_default = 1, 875 .max_voices_out = INT_MAX, 876 .max_voices_in = INT_MAX, 877 .voice_size_out = sizeof (OSSVoiceOut), 878 .voice_size_in = sizeof (OSSVoiceIn) 879 }; 880 881 static void register_audio_oss(void) 882 { 883 audio_driver_register(&oss_audio_driver); 884 } 885 type_init(register_audio_oss); 886