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