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 "qapi/error.h" 32 #include "audio.h" 33 #include "trace.h" 34 35 #define AUDIO_CAP "oss" 36 #include "audio_int.h" 37 38 #if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY 39 #define USE_DSP_POLICY 40 #endif 41 42 typedef struct OSSVoiceOut { 43 HWVoiceOut hw; 44 int fd; 45 int nfrags; 46 int fragsize; 47 int mmapped; 48 Audiodev *dev; 49 } OSSVoiceOut; 50 51 typedef struct OSSVoiceIn { 52 HWVoiceIn hw; 53 int fd; 54 int nfrags; 55 int fragsize; 56 Audiodev *dev; 57 } OSSVoiceIn; 58 59 struct oss_params { 60 int freq; 61 int fmt; 62 int nchannels; 63 int nfrags; 64 int fragsize; 65 }; 66 67 static void G_GNUC_PRINTF (2, 3) oss_logerr (int err, const char *fmt, ...) 68 { 69 va_list ap; 70 71 va_start (ap, fmt); 72 AUD_vlog (AUDIO_CAP, fmt, ap); 73 va_end (ap); 74 75 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); 76 } 77 78 static void G_GNUC_PRINTF (3, 4) oss_logerr2 ( 79 int err, 80 const char *typ, 81 const char *fmt, 82 ... 83 ) 84 { 85 va_list ap; 86 87 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); 88 89 va_start (ap, fmt); 90 AUD_vlog (AUDIO_CAP, fmt, ap); 91 va_end (ap); 92 93 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); 94 } 95 96 static void oss_anal_close (int *fdp) 97 { 98 int err; 99 100 qemu_set_fd_handler (*fdp, NULL, NULL, NULL); 101 err = close (*fdp); 102 if (err) { 103 oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp); 104 } 105 *fdp = -1; 106 } 107 108 static void oss_helper_poll_out (void *opaque) 109 { 110 AudioState *s = opaque; 111 audio_run(s, "oss_poll_out"); 112 } 113 114 static void oss_helper_poll_in (void *opaque) 115 { 116 AudioState *s = opaque; 117 audio_run(s, "oss_poll_in"); 118 } 119 120 static void oss_poll_out (HWVoiceOut *hw) 121 { 122 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 123 124 qemu_set_fd_handler(oss->fd, NULL, oss_helper_poll_out, hw->s); 125 } 126 127 static void oss_poll_in (HWVoiceIn *hw) 128 { 129 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 130 131 qemu_set_fd_handler(oss->fd, oss_helper_poll_in, NULL, hw->s); 132 } 133 134 static int aud_to_ossfmt (AudioFormat fmt, int endianness) 135 { 136 switch (fmt) { 137 case AUDIO_FORMAT_S8: 138 return AFMT_S8; 139 140 case AUDIO_FORMAT_U8: 141 return AFMT_U8; 142 143 case AUDIO_FORMAT_S16: 144 if (endianness) { 145 return AFMT_S16_BE; 146 } else { 147 return AFMT_S16_LE; 148 } 149 150 case AUDIO_FORMAT_U16: 151 if (endianness) { 152 return AFMT_U16_BE; 153 } else { 154 return AFMT_U16_LE; 155 } 156 157 default: 158 dolog ("Internal logic error: Bad audio format %d\n", fmt); 159 #ifdef DEBUG_AUDIO 160 abort (); 161 #endif 162 return AFMT_U8; 163 } 164 } 165 166 static int oss_to_audfmt (int ossfmt, AudioFormat *fmt, int *endianness) 167 { 168 switch (ossfmt) { 169 case AFMT_S8: 170 *endianness = 0; 171 *fmt = AUDIO_FORMAT_S8; 172 break; 173 174 case AFMT_U8: 175 *endianness = 0; 176 *fmt = AUDIO_FORMAT_U8; 177 break; 178 179 case AFMT_S16_LE: 180 *endianness = 0; 181 *fmt = AUDIO_FORMAT_S16; 182 break; 183 184 case AFMT_U16_LE: 185 *endianness = 0; 186 *fmt = AUDIO_FORMAT_U16; 187 break; 188 189 case AFMT_S16_BE: 190 *endianness = 1; 191 *fmt = AUDIO_FORMAT_S16; 192 break; 193 194 case AFMT_U16_BE: 195 *endianness = 1; 196 *fmt = AUDIO_FORMAT_U16; 197 break; 198 199 default: 200 dolog ("Unrecognized audio format %d\n", ossfmt); 201 return -1; 202 } 203 204 return 0; 205 } 206 207 #if defined DEBUG_MISMATCHES || defined DEBUG 208 static void oss_dump_info (struct oss_params *req, struct oss_params *obt) 209 { 210 dolog ("parameter | requested value | obtained value\n"); 211 dolog ("format | %10d | %10d\n", req->fmt, obt->fmt); 212 dolog ("channels | %10d | %10d\n", 213 req->nchannels, obt->nchannels); 214 dolog ("frequency | %10d | %10d\n", req->freq, obt->freq); 215 dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags); 216 dolog ("fragsize | %10d | %10d\n", 217 req->fragsize, obt->fragsize); 218 } 219 #endif 220 221 #ifdef USE_DSP_POLICY 222 static int oss_get_version (int fd, int *version, const char *typ) 223 { 224 if (ioctl (fd, OSS_GETVERSION, &version)) { 225 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 226 /* 227 * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION 228 * since 7.x, but currently only on the mixer device (or in 229 * the Linuxolator), and in the native version that part of 230 * the code is in fact never reached so the ioctl fails anyway. 231 * Until this is fixed, just check the errno and if its what 232 * FreeBSD's sound drivers return atm assume they are new enough. 233 */ 234 if (errno == EINVAL) { 235 *version = 0x040000; 236 return 0; 237 } 238 #endif 239 oss_logerr2 (errno, typ, "Failed to get OSS version\n"); 240 return -1; 241 } 242 return 0; 243 } 244 #endif 245 246 static int oss_open(int in, struct oss_params *req, audsettings *as, 247 struct oss_params *obt, int *pfd, Audiodev *dev) 248 { 249 AudiodevOssOptions *oopts = &dev->u.oss; 250 AudiodevOssPerDirectionOptions *opdo = in ? oopts->in : oopts->out; 251 int fd; 252 int oflags = (oopts->has_exclusive && oopts->exclusive) ? O_EXCL : 0; 253 audio_buf_info abinfo; 254 int fmt, freq, nchannels; 255 int setfragment = 1; 256 const char *dspname = opdo->dev ?: "/dev/dsp"; 257 const char *typ = in ? "ADC" : "DAC"; 258 #ifdef USE_DSP_POLICY 259 int policy = oopts->has_dsp_policy ? oopts->dsp_policy : 5; 260 #endif 261 262 /* Kludge needed to have working mmap on Linux */ 263 oflags |= (oopts->has_try_mmap && oopts->try_mmap) ? 264 O_RDWR : (in ? O_RDONLY : O_WRONLY); 265 266 fd = open (dspname, oflags | O_NONBLOCK); 267 if (-1 == fd) { 268 oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname); 269 return -1; 270 } 271 272 freq = req->freq; 273 nchannels = req->nchannels; 274 fmt = req->fmt; 275 req->nfrags = opdo->has_buffer_count ? opdo->buffer_count : 4; 276 req->fragsize = audio_buffer_bytes( 277 qapi_AudiodevOssPerDirectionOptions_base(opdo), as, 23220); 278 279 if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) { 280 oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt); 281 goto err; 282 } 283 284 if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) { 285 oss_logerr2 (errno, typ, "Failed to set number of channels %d\n", 286 req->nchannels); 287 goto err; 288 } 289 290 if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) { 291 oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq); 292 goto err; 293 } 294 295 if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) { 296 oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n"); 297 goto err; 298 } 299 300 #ifdef USE_DSP_POLICY 301 if (policy >= 0) { 302 int version; 303 304 if (!oss_get_version (fd, &version, typ)) { 305 trace_oss_version(version); 306 307 if (version >= 0x040000) { 308 int policy2 = policy; 309 if (ioctl(fd, SNDCTL_DSP_POLICY, &policy2)) { 310 oss_logerr2 (errno, typ, 311 "Failed to set timing policy to %d\n", 312 policy); 313 goto err; 314 } 315 setfragment = 0; 316 } 317 } 318 } 319 #endif 320 321 if (setfragment) { 322 int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize); 323 if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) { 324 oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n", 325 req->nfrags, req->fragsize); 326 goto err; 327 } 328 } 329 330 if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) { 331 oss_logerr2 (errno, typ, "Failed to get buffer length\n"); 332 goto err; 333 } 334 335 if (!abinfo.fragstotal || !abinfo.fragsize) { 336 AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n", 337 abinfo.fragstotal, abinfo.fragsize, typ); 338 goto err; 339 } 340 341 obt->fmt = fmt; 342 obt->nchannels = nchannels; 343 obt->freq = freq; 344 obt->nfrags = abinfo.fragstotal; 345 obt->fragsize = abinfo.fragsize; 346 *pfd = fd; 347 348 #ifdef DEBUG_MISMATCHES 349 if ((req->fmt != obt->fmt) || 350 (req->nchannels != obt->nchannels) || 351 (req->freq != obt->freq) || 352 (req->fragsize != obt->fragsize) || 353 (req->nfrags != obt->nfrags)) { 354 dolog ("Audio parameters mismatch\n"); 355 oss_dump_info (req, obt); 356 } 357 #endif 358 359 #ifdef DEBUG 360 oss_dump_info (req, obt); 361 #endif 362 return 0; 363 364 err: 365 oss_anal_close (&fd); 366 return -1; 367 } 368 369 static size_t oss_get_available_bytes(OSSVoiceOut *oss) 370 { 371 int err; 372 struct count_info cntinfo; 373 assert(oss->mmapped); 374 375 err = ioctl(oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo); 376 if (err < 0) { 377 oss_logerr(errno, "SNDCTL_DSP_GETOPTR failed\n"); 378 return 0; 379 } 380 381 return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul); 382 } 383 384 static void oss_run_buffer_out(HWVoiceOut *hw) 385 { 386 OSSVoiceOut *oss = (OSSVoiceOut *)hw; 387 388 if (!oss->mmapped) { 389 audio_generic_run_buffer_out(hw); 390 } 391 } 392 393 static size_t oss_buffer_get_free(HWVoiceOut *hw) 394 { 395 OSSVoiceOut *oss = (OSSVoiceOut *)hw; 396 397 if (oss->mmapped) { 398 return oss_get_available_bytes(oss); 399 } else { 400 return audio_generic_buffer_get_free(hw); 401 } 402 } 403 404 static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size) 405 { 406 OSSVoiceOut *oss = (OSSVoiceOut *)hw; 407 408 if (oss->mmapped) { 409 *size = hw->size_emul - hw->pos_emul; 410 return hw->buf_emul + hw->pos_emul; 411 } else { 412 return audio_generic_get_buffer_out(hw, size); 413 } 414 } 415 416 static size_t oss_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size) 417 { 418 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 419 if (oss->mmapped) { 420 assert(buf == hw->buf_emul + hw->pos_emul && size < hw->size_emul); 421 422 hw->pos_emul = (hw->pos_emul + size) % hw->size_emul; 423 return size; 424 } else { 425 return audio_generic_put_buffer_out(hw, buf, size); 426 } 427 } 428 429 static size_t oss_write(HWVoiceOut *hw, void *buf, size_t len) 430 { 431 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 432 size_t pos; 433 434 if (oss->mmapped) { 435 size_t total_len; 436 len = MIN(len, oss_get_available_bytes(oss)); 437 438 total_len = len; 439 while (len) { 440 size_t to_copy = MIN(len, hw->size_emul - hw->pos_emul); 441 memcpy(hw->buf_emul + hw->pos_emul, buf, to_copy); 442 443 hw->pos_emul = (hw->pos_emul + to_copy) % hw->size_emul; 444 buf += to_copy; 445 len -= to_copy; 446 } 447 return total_len; 448 } 449 450 pos = 0; 451 while (len) { 452 ssize_t bytes_written; 453 void *pcm = advance(buf, pos); 454 455 bytes_written = write(oss->fd, pcm, len); 456 if (bytes_written < 0) { 457 if (errno != EAGAIN) { 458 oss_logerr(errno, "failed to write %zu bytes\n", 459 len); 460 } 461 return pos; 462 } 463 464 pos += bytes_written; 465 if (bytes_written < len) { 466 break; 467 } 468 len -= bytes_written; 469 } 470 return pos; 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->mmapped && hw->buf_emul) { 482 err = munmap(hw->buf_emul, hw->size_emul); 483 if (err) { 484 oss_logerr(errno, "Failed to unmap buffer %p, size %zu\n", 485 hw->buf_emul, hw->size_emul); 486 } 487 hw->buf_emul = 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.bytes_per_frame) { 530 dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n", 531 obt.nfrags * obt.fragsize, hw->info.bytes_per_frame); 532 } 533 534 hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame; 535 536 oss->mmapped = 0; 537 if (oopts->has_try_mmap && oopts->try_mmap) { 538 hw->size_emul = hw->samples * hw->info.bytes_per_frame; 539 hw->buf_emul = mmap( 540 NULL, 541 hw->size_emul, 542 PROT_READ | PROT_WRITE, 543 MAP_SHARED, 544 fd, 545 0 546 ); 547 if (hw->buf_emul == MAP_FAILED) { 548 oss_logerr(errno, "Failed to map %zu bytes of DAC\n", 549 hw->size_emul); 550 hw->buf_emul = NULL; 551 } else { 552 int err; 553 int trig = 0; 554 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 555 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 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 } else { 564 oss->mmapped = 1; 565 } 566 } 567 568 if (!oss->mmapped) { 569 err = munmap(hw->buf_emul, hw->size_emul); 570 if (err) { 571 oss_logerr(errno, "Failed to unmap buffer %p size %zu\n", 572 hw->buf_emul, hw->size_emul); 573 } 574 hw->buf_emul = NULL; 575 } 576 } 577 } 578 579 oss->fd = fd; 580 oss->dev = dev; 581 return 0; 582 } 583 584 static void oss_enable_out(HWVoiceOut *hw, bool enable) 585 { 586 int trig; 587 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 588 AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out; 589 590 if (enable) { 591 hw->poll_mode = opdo->try_poll; 592 593 ldebug("enabling voice\n"); 594 if (hw->poll_mode) { 595 oss_poll_out(hw); 596 } 597 598 if (!oss->mmapped) { 599 return; 600 } 601 602 audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->samples); 603 trig = PCM_ENABLE_OUTPUT; 604 if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 605 oss_logerr(errno, 606 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"); 607 return; 608 } 609 } else { 610 if (hw->poll_mode) { 611 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 612 hw->poll_mode = 0; 613 } 614 615 if (!oss->mmapped) { 616 return; 617 } 618 619 ldebug ("disabling voice\n"); 620 trig = 0; 621 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 622 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 623 return; 624 } 625 } 626 } 627 628 static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) 629 { 630 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 631 struct oss_params req, obt; 632 int endianness; 633 int err; 634 int fd; 635 AudioFormat effective_fmt; 636 struct audsettings obt_as; 637 Audiodev *dev = drv_opaque; 638 639 oss->fd = -1; 640 641 req.fmt = aud_to_ossfmt (as->fmt, as->endianness); 642 req.freq = as->freq; 643 req.nchannels = as->nchannels; 644 if (oss_open(1, &req, as, &obt, &fd, dev)) { 645 return -1; 646 } 647 648 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); 649 if (err) { 650 oss_anal_close (&fd); 651 return -1; 652 } 653 654 obt_as.freq = obt.freq; 655 obt_as.nchannels = obt.nchannels; 656 obt_as.fmt = effective_fmt; 657 obt_as.endianness = endianness; 658 659 audio_pcm_init_info (&hw->info, &obt_as); 660 oss->nfrags = obt.nfrags; 661 oss->fragsize = obt.fragsize; 662 663 if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) { 664 dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", 665 obt.nfrags * obt.fragsize, hw->info.bytes_per_frame); 666 } 667 668 hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame; 669 670 oss->fd = fd; 671 oss->dev = dev; 672 return 0; 673 } 674 675 static void oss_fini_in (HWVoiceIn *hw) 676 { 677 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 678 679 oss_anal_close (&oss->fd); 680 } 681 682 static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len) 683 { 684 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 685 size_t pos = 0; 686 687 while (len) { 688 ssize_t nread; 689 690 void *dst = advance(buf, pos); 691 nread = read(oss->fd, dst, len); 692 693 if (nread == -1) { 694 switch (errno) { 695 case EINTR: 696 case EAGAIN: 697 break; 698 default: 699 oss_logerr(errno, "Failed to read %zu bytes of audio (to %p)\n", 700 len, dst); 701 break; 702 } 703 break; 704 } 705 706 pos += nread; 707 len -= nread; 708 } 709 710 return pos; 711 } 712 713 static void oss_enable_in(HWVoiceIn *hw, bool enable) 714 { 715 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 716 AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out; 717 718 if (enable) { 719 hw->poll_mode = opdo->try_poll; 720 721 if (hw->poll_mode) { 722 oss_poll_in(hw); 723 } 724 } else { 725 if (hw->poll_mode) { 726 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 727 hw->poll_mode = 0; 728 } 729 } 730 } 731 732 static void oss_init_per_direction(AudiodevOssPerDirectionOptions *opdo) 733 { 734 if (!opdo->has_try_poll) { 735 opdo->try_poll = true; 736 opdo->has_try_poll = true; 737 } 738 } 739 740 static void *oss_audio_init(Audiodev *dev, Error **errp) 741 { 742 AudiodevOssOptions *oopts; 743 assert(dev->driver == AUDIODEV_DRIVER_OSS); 744 745 oopts = &dev->u.oss; 746 oss_init_per_direction(oopts->in); 747 oss_init_per_direction(oopts->out); 748 749 if (access(oopts->in->dev ?: "/dev/dsp", R_OK | W_OK) < 0) { 750 error_setg_errno(errp, errno, "%s not accessible", oopts->in->dev ?: "/dev/dsp"); 751 return NULL; 752 } 753 if (access(oopts->out->dev ?: "/dev/dsp", R_OK | W_OK) < 0) { 754 error_setg_errno(errp, errno, "%s not accessible", oopts->out->dev ?: "/dev/dsp"); 755 return NULL; 756 } 757 return dev; 758 } 759 760 static void oss_audio_fini (void *opaque) 761 { 762 } 763 764 static struct audio_pcm_ops oss_pcm_ops = { 765 .init_out = oss_init_out, 766 .fini_out = oss_fini_out, 767 .write = oss_write, 768 .buffer_get_free = oss_buffer_get_free, 769 .run_buffer_out = oss_run_buffer_out, 770 .get_buffer_out = oss_get_buffer_out, 771 .put_buffer_out = oss_put_buffer_out, 772 .enable_out = oss_enable_out, 773 774 .init_in = oss_init_in, 775 .fini_in = oss_fini_in, 776 .read = oss_read, 777 .run_buffer_in = audio_generic_run_buffer_in, 778 .enable_in = oss_enable_in 779 }; 780 781 static struct audio_driver oss_audio_driver = { 782 .name = "oss", 783 .descr = "OSS http://www.opensound.com", 784 .init = oss_audio_init, 785 .fini = oss_audio_fini, 786 .pcm_ops = &oss_pcm_ops, 787 .max_voices_out = INT_MAX, 788 .max_voices_in = INT_MAX, 789 .voice_size_out = sizeof (OSSVoiceOut), 790 .voice_size_in = sizeof (OSSVoiceIn) 791 }; 792 793 static void register_audio_oss(void) 794 { 795 audio_driver_register(&oss_audio_driver); 796 } 797 type_init(register_audio_oss); 798