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 trig = 0; 553 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 554 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 555 } else { 556 trig = PCM_ENABLE_OUTPUT; 557 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 558 oss_logerr ( 559 errno, 560 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" 561 ); 562 } else { 563 oss->mmapped = 1; 564 } 565 } 566 567 if (!oss->mmapped) { 568 err = munmap(hw->buf_emul, hw->size_emul); 569 if (err) { 570 oss_logerr(errno, "Failed to unmap buffer %p size %zu\n", 571 hw->buf_emul, hw->size_emul); 572 } 573 hw->buf_emul = NULL; 574 } 575 } 576 } 577 578 oss->fd = fd; 579 oss->dev = dev; 580 return 0; 581 } 582 583 static void oss_enable_out(HWVoiceOut *hw, bool enable) 584 { 585 int trig; 586 OSSVoiceOut *oss = (OSSVoiceOut *) hw; 587 AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out; 588 589 if (enable) { 590 hw->poll_mode = opdo->try_poll; 591 592 ldebug("enabling voice\n"); 593 if (hw->poll_mode) { 594 oss_poll_out(hw); 595 } 596 597 if (!oss->mmapped) { 598 return; 599 } 600 601 audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->samples); 602 trig = PCM_ENABLE_OUTPUT; 603 if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 604 oss_logerr(errno, 605 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"); 606 return; 607 } 608 } else { 609 if (hw->poll_mode) { 610 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 611 hw->poll_mode = 0; 612 } 613 614 if (!oss->mmapped) { 615 return; 616 } 617 618 ldebug ("disabling voice\n"); 619 trig = 0; 620 if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { 621 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); 622 return; 623 } 624 } 625 } 626 627 static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) 628 { 629 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 630 struct oss_params req, obt; 631 int endianness; 632 int err; 633 int fd; 634 AudioFormat effective_fmt; 635 struct audsettings obt_as; 636 Audiodev *dev = drv_opaque; 637 638 oss->fd = -1; 639 640 req.fmt = aud_to_ossfmt (as->fmt, as->endianness); 641 req.freq = as->freq; 642 req.nchannels = as->nchannels; 643 if (oss_open(1, &req, as, &obt, &fd, dev)) { 644 return -1; 645 } 646 647 err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); 648 if (err) { 649 oss_anal_close (&fd); 650 return -1; 651 } 652 653 obt_as.freq = obt.freq; 654 obt_as.nchannels = obt.nchannels; 655 obt_as.fmt = effective_fmt; 656 obt_as.endianness = endianness; 657 658 audio_pcm_init_info (&hw->info, &obt_as); 659 oss->nfrags = obt.nfrags; 660 oss->fragsize = obt.fragsize; 661 662 if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) { 663 dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", 664 obt.nfrags * obt.fragsize, hw->info.bytes_per_frame); 665 } 666 667 hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame; 668 669 oss->fd = fd; 670 oss->dev = dev; 671 return 0; 672 } 673 674 static void oss_fini_in (HWVoiceIn *hw) 675 { 676 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 677 678 oss_anal_close (&oss->fd); 679 } 680 681 static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len) 682 { 683 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 684 size_t pos = 0; 685 686 while (len) { 687 ssize_t nread; 688 689 void *dst = advance(buf, pos); 690 nread = read(oss->fd, dst, len); 691 692 if (nread == -1) { 693 switch (errno) { 694 case EINTR: 695 case EAGAIN: 696 break; 697 default: 698 oss_logerr(errno, "Failed to read %zu bytes of audio (to %p)\n", 699 len, dst); 700 break; 701 } 702 break; 703 } 704 705 pos += nread; 706 len -= nread; 707 } 708 709 return pos; 710 } 711 712 static void oss_enable_in(HWVoiceIn *hw, bool enable) 713 { 714 OSSVoiceIn *oss = (OSSVoiceIn *) hw; 715 AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out; 716 717 if (enable) { 718 hw->poll_mode = opdo->try_poll; 719 720 if (hw->poll_mode) { 721 oss_poll_in(hw); 722 } 723 } else { 724 if (hw->poll_mode) { 725 qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); 726 hw->poll_mode = 0; 727 } 728 } 729 } 730 731 static void oss_init_per_direction(AudiodevOssPerDirectionOptions *opdo) 732 { 733 if (!opdo->has_try_poll) { 734 opdo->try_poll = true; 735 opdo->has_try_poll = true; 736 } 737 } 738 739 static void *oss_audio_init(Audiodev *dev, Error **errp) 740 { 741 AudiodevOssOptions *oopts; 742 assert(dev->driver == AUDIODEV_DRIVER_OSS); 743 744 oopts = &dev->u.oss; 745 oss_init_per_direction(oopts->in); 746 oss_init_per_direction(oopts->out); 747 748 if (access(oopts->in->dev ?: "/dev/dsp", R_OK | W_OK) < 0) { 749 error_setg_errno(errp, errno, "%s not accessible", oopts->in->dev ?: "/dev/dsp"); 750 return NULL; 751 } 752 if (access(oopts->out->dev ?: "/dev/dsp", R_OK | W_OK) < 0) { 753 error_setg_errno(errp, errno, "%s not accessible", oopts->out->dev ?: "/dev/dsp"); 754 return NULL; 755 } 756 return dev; 757 } 758 759 static void oss_audio_fini (void *opaque) 760 { 761 } 762 763 static struct audio_pcm_ops oss_pcm_ops = { 764 .init_out = oss_init_out, 765 .fini_out = oss_fini_out, 766 .write = oss_write, 767 .buffer_get_free = oss_buffer_get_free, 768 .run_buffer_out = oss_run_buffer_out, 769 .get_buffer_out = oss_get_buffer_out, 770 .put_buffer_out = oss_put_buffer_out, 771 .enable_out = oss_enable_out, 772 773 .init_in = oss_init_in, 774 .fini_in = oss_fini_in, 775 .read = oss_read, 776 .run_buffer_in = audio_generic_run_buffer_in, 777 .enable_in = oss_enable_in 778 }; 779 780 static struct audio_driver oss_audio_driver = { 781 .name = "oss", 782 .descr = "OSS http://www.opensound.com", 783 .init = oss_audio_init, 784 .fini = oss_audio_fini, 785 .pcm_ops = &oss_pcm_ops, 786 .max_voices_out = INT_MAX, 787 .max_voices_in = INT_MAX, 788 .voice_size_out = sizeof (OSSVoiceOut), 789 .voice_size_in = sizeof (OSSVoiceIn) 790 }; 791 792 static void register_audio_oss(void) 793 { 794 audio_driver_register(&oss_audio_driver); 795 } 796 type_init(register_audio_oss); 797