1 /*- 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/queue.h> 29 30 #include <dev/sound/pcm/sound.h> 31 32 SND_DECLARE_FILE("$FreeBSD$"); 33 34 #define OLDPCM_IOCTL 35 36 static d_open_t dsp_open; 37 static d_close_t dsp_close; 38 static d_read_t dsp_read; 39 static d_write_t dsp_write; 40 static d_ioctl_t dsp_ioctl; 41 static d_poll_t dsp_poll; 42 static d_mmap_t dsp_mmap; 43 44 struct cdevsw dsp_cdevsw = { 45 .d_version = D_VERSION, 46 .d_flags = D_NEEDGIANT, 47 .d_open = dsp_open, 48 .d_close = dsp_close, 49 .d_read = dsp_read, 50 .d_write = dsp_write, 51 .d_ioctl = dsp_ioctl, 52 .d_poll = dsp_poll, 53 .d_mmap = dsp_mmap, 54 .d_name = "dsp", 55 }; 56 57 #ifdef USING_DEVFS 58 static eventhandler_tag dsp_ehtag; 59 #endif 60 61 static int dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group); 62 static int dsp_oss_syncstart(int sg_id); 63 static int dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy); 64 #ifdef OSSV4_EXPERIMENT 65 static int dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled); 66 static int dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map); 67 static int dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map); 68 static int dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label); 69 static int dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label); 70 static int dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song); 71 static int dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song); 72 static int dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name); 73 #endif 74 75 static struct snddev_info * 76 dsp_get_info(struct cdev *dev) 77 { 78 struct snddev_info *d; 79 int unit; 80 81 unit = PCMUNIT(dev); 82 if (unit >= devclass_get_maxunit(pcm_devclass)) 83 return NULL; 84 d = devclass_get_softc(pcm_devclass, unit); 85 86 return d; 87 } 88 89 static u_int32_t 90 dsp_get_flags(struct cdev *dev) 91 { 92 device_t bdev; 93 int unit; 94 95 unit = PCMUNIT(dev); 96 if (unit >= devclass_get_maxunit(pcm_devclass)) 97 return 0xffffffff; 98 bdev = devclass_get_device(pcm_devclass, unit); 99 100 return pcm_getflags(bdev); 101 } 102 103 static void 104 dsp_set_flags(struct cdev *dev, u_int32_t flags) 105 { 106 device_t bdev; 107 int unit; 108 109 unit = PCMUNIT(dev); 110 if (unit >= devclass_get_maxunit(pcm_devclass)) 111 return; 112 bdev = devclass_get_device(pcm_devclass, unit); 113 114 pcm_setflags(bdev, flags); 115 } 116 117 /* 118 * return the channels associated with an open device instance. 119 * set the priority if the device is simplex and one direction (only) is 120 * specified. 121 * lock channels specified. 122 */ 123 static int 124 getchns(struct cdev *dev, struct pcm_channel **rdch, struct pcm_channel **wrch, u_int32_t prio) 125 { 126 struct snddev_info *d; 127 u_int32_t flags; 128 129 flags = dsp_get_flags(dev); 130 d = dsp_get_info(dev); 131 pcm_inprog(d, 1); 132 pcm_lock(d); 133 KASSERT((flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \ 134 ("getchns: read and write both prioritised")); 135 136 if ((flags & SD_F_PRIO_SET) == 0 && (prio != (SD_F_PRIO_RD | SD_F_PRIO_WR))) { 137 flags |= prio & (SD_F_PRIO_RD | SD_F_PRIO_WR); 138 dsp_set_flags(dev, flags); 139 } 140 141 *rdch = dev->si_drv1; 142 *wrch = dev->si_drv2; 143 if ((flags & SD_F_SIMPLEX) && (flags & SD_F_PRIO_SET)) { 144 if (prio) { 145 if (*rdch && flags & SD_F_PRIO_WR) { 146 dev->si_drv1 = NULL; 147 *rdch = pcm_getfakechan(d); 148 } else if (*wrch && flags & SD_F_PRIO_RD) { 149 dev->si_drv2 = NULL; 150 *wrch = pcm_getfakechan(d); 151 } 152 } 153 154 pcm_getfakechan(d)->flags |= CHN_F_BUSY; 155 } 156 pcm_unlock(d); 157 158 if (*rdch && *rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD)) 159 CHN_LOCK(*rdch); 160 if (*wrch && *wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR)) 161 CHN_LOCK(*wrch); 162 163 return 0; 164 } 165 166 /* unlock specified channels */ 167 static void 168 relchns(struct cdev *dev, struct pcm_channel *rdch, struct pcm_channel *wrch, u_int32_t prio) 169 { 170 struct snddev_info *d; 171 172 d = dsp_get_info(dev); 173 if (wrch && wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR)) 174 CHN_UNLOCK(wrch); 175 if (rdch && rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD)) 176 CHN_UNLOCK(rdch); 177 pcm_inprog(d, -1); 178 } 179 180 static int 181 dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 182 { 183 struct pcm_channel *rdch, *wrch; 184 struct snddev_info *d; 185 u_int32_t fmt; 186 int devtype; 187 int error; 188 int chnum; 189 190 if (i_dev == NULL || td == NULL) 191 return ENODEV; 192 193 if ((flags & (FREAD | FWRITE)) == 0) 194 return EINVAL; 195 196 d = dsp_get_info(i_dev); 197 devtype = PCMDEV(i_dev); 198 chnum = -1; 199 200 /* decide default format */ 201 switch (devtype) { 202 case SND_DEV_DSP16: 203 fmt = AFMT_S16_LE; 204 break; 205 206 case SND_DEV_DSP: 207 fmt = AFMT_U8; 208 break; 209 210 case SND_DEV_AUDIO: 211 fmt = AFMT_MU_LAW; 212 break; 213 214 case SND_DEV_NORESET: 215 fmt = 0; 216 break; 217 218 case SND_DEV_DSPREC: 219 fmt = AFMT_U8; 220 if (flags & FWRITE) 221 return EINVAL; 222 chnum = PCMCHAN(i_dev); 223 break; 224 225 default: 226 panic("impossible devtype %d", devtype); 227 } 228 229 /* lock snddev so nobody else can monkey with it */ 230 pcm_lock(d); 231 232 rdch = i_dev->si_drv1; 233 wrch = i_dev->si_drv2; 234 235 if (rdch || wrch || ((dsp_get_flags(i_dev) & SD_F_SIMPLEX) && 236 (flags & (FREAD | FWRITE)) == (FREAD | FWRITE))) { 237 /* simplex or not, better safe than sorry. */ 238 pcm_unlock(d); 239 return EBUSY; 240 } 241 242 /* 243 * if we get here, the open request is valid- either: 244 * * we were previously not open 245 * * we were open for play xor record and the opener wants 246 * the non-open direction 247 */ 248 if (flags & FREAD) { 249 /* open for read */ 250 pcm_unlock(d); 251 error = pcm_chnalloc(d, &rdch, PCMDIR_REC, td->td_proc->p_pid, chnum); 252 if (error != 0 && error != EBUSY && chnum != -1 && (flags & FWRITE)) 253 error = pcm_chnalloc(d, &rdch, PCMDIR_REC, td->td_proc->p_pid, -1); 254 255 if (error == 0 && (chn_reset(rdch, fmt) || 256 (fmt && chn_setspeed(rdch, DSP_DEFAULT_SPEED)))) 257 error = ENODEV; 258 259 if (error != 0) { 260 if (rdch) 261 pcm_chnrelease(rdch); 262 return error; 263 } 264 265 if (flags & O_NONBLOCK) 266 rdch->flags |= CHN_F_NBIO; 267 pcm_chnref(rdch, 1); 268 CHN_UNLOCK(rdch); 269 pcm_lock(d); 270 } 271 272 if (flags & FWRITE) { 273 /* open for write */ 274 pcm_unlock(d); 275 error = pcm_chnalloc(d, &wrch, PCMDIR_PLAY, td->td_proc->p_pid, chnum); 276 if (error != 0 && error != EBUSY && chnum != -1 && (flags & FREAD)) 277 error = pcm_chnalloc(d, &wrch, PCMDIR_PLAY, td->td_proc->p_pid, -1); 278 279 if (error == 0 && (chn_reset(wrch, fmt) || 280 (fmt && chn_setspeed(wrch, DSP_DEFAULT_SPEED)))) 281 error = ENODEV; 282 283 if (error != 0) { 284 if (wrch) 285 pcm_chnrelease(wrch); 286 if (rdch) { 287 /* 288 * Lock, deref and release previously created record channel 289 */ 290 CHN_LOCK(rdch); 291 pcm_chnref(rdch, -1); 292 pcm_chnrelease(rdch); 293 } 294 295 return error; 296 } 297 298 if (flags & O_NONBLOCK) 299 wrch->flags |= CHN_F_NBIO; 300 pcm_chnref(wrch, 1); 301 CHN_UNLOCK(wrch); 302 pcm_lock(d); 303 } 304 305 i_dev->si_drv1 = rdch; 306 i_dev->si_drv2 = wrch; 307 308 pcm_unlock(d); 309 return 0; 310 } 311 312 static int 313 dsp_close(struct cdev *i_dev, int flags, int mode, struct thread *td) 314 { 315 struct pcm_channel *rdch, *wrch; 316 struct snddev_info *d; 317 int refs, sg_ids[2]; 318 319 d = dsp_get_info(i_dev); 320 pcm_lock(d); 321 rdch = i_dev->si_drv1; 322 wrch = i_dev->si_drv2; 323 pcm_unlock(d); 324 325 /* 326 * Free_unr() may sleep, so store released syncgroup IDs until after 327 * all locks are released. 328 */ 329 sg_ids[0] = sg_ids[1] = 0; 330 331 if (rdch || wrch) { 332 refs = 0; 333 if (rdch) { 334 /* 335 * The channel itself need not be locked because: 336 * a) Adding a channel to a syncgroup happens only in dsp_ioctl(), 337 * which cannot run concurrently to dsp_close(). 338 * b) The syncmember pointer (sm) is protected by the global 339 * syncgroup list lock. 340 * c) A channel can't just disappear, invalidating pointers, 341 * unless it's closed/dereferenced first. 342 */ 343 PCM_SG_LOCK(); 344 sg_ids[0] = chn_syncdestroy(rdch); 345 PCM_SG_UNLOCK(); 346 347 CHN_LOCK(rdch); 348 refs += pcm_chnref(rdch, -1); 349 chn_abort(rdch); /* won't sleep */ 350 rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD); 351 chn_reset(rdch, 0); 352 pcm_chnrelease(rdch); 353 } 354 if (wrch) { 355 /* 356 * Please see block above. 357 */ 358 PCM_SG_LOCK(); 359 sg_ids[1] = chn_syncdestroy(wrch); 360 PCM_SG_UNLOCK(); 361 362 CHN_LOCK(wrch); 363 refs += pcm_chnref(wrch, -1); 364 /* 365 * XXX: Maybe the right behaviour is to abort on non_block. 366 * It seems that mplayer flushes the audio queue by quickly 367 * closing and re-opening. In FBSD, there's a long pause 368 * while the audio queue flushes that I presume isn't there in 369 * linux. 370 */ 371 chn_flush(wrch); /* may sleep */ 372 wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD); 373 chn_reset(wrch, 0); 374 pcm_chnrelease(wrch); 375 } 376 377 pcm_lock(d); 378 if (rdch) 379 i_dev->si_drv1 = NULL; 380 if (wrch) 381 i_dev->si_drv2 = NULL; 382 /* 383 * If there are no more references, release the channels. 384 */ 385 if (refs == 0 && i_dev->si_drv1 == NULL && 386 i_dev->si_drv2 == NULL) { 387 if (pcm_getfakechan(d)) 388 pcm_getfakechan(d)->flags = 0; 389 /* What is this?!? */ 390 dsp_set_flags(i_dev, dsp_get_flags(i_dev) & ~SD_F_TRANSIENT); 391 } 392 pcm_unlock(d); 393 } 394 395 396 if (sg_ids[0]) 397 free_unr(pcmsg_unrhdr, sg_ids[0]); 398 if (sg_ids[1]) 399 free_unr(pcmsg_unrhdr, sg_ids[1]); 400 401 return 0; 402 } 403 404 static int 405 dsp_read(struct cdev *i_dev, struct uio *buf, int flag) 406 { 407 struct pcm_channel *rdch, *wrch; 408 int ret; 409 410 getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD); 411 412 KASSERT(rdch, ("dsp_read: nonexistant channel")); 413 KASSERT(rdch->flags & CHN_F_BUSY, ("dsp_read: nonbusy channel")); 414 415 if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) { 416 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD); 417 return EINVAL; 418 } 419 if (!(rdch->flags & CHN_F_RUNNING)) 420 rdch->flags |= CHN_F_RUNNING; 421 ret = chn_read(rdch, buf); 422 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD); 423 424 return ret; 425 } 426 427 static int 428 dsp_write(struct cdev *i_dev, struct uio *buf, int flag) 429 { 430 struct pcm_channel *rdch, *wrch; 431 int ret; 432 433 getchns(i_dev, &rdch, &wrch, SD_F_PRIO_WR); 434 435 KASSERT(wrch, ("dsp_write: nonexistant channel")); 436 KASSERT(wrch->flags & CHN_F_BUSY, ("dsp_write: nonbusy channel")); 437 438 if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) { 439 relchns(i_dev, rdch, wrch, SD_F_PRIO_WR); 440 return EINVAL; 441 } 442 if (!(wrch->flags & CHN_F_RUNNING)) 443 wrch->flags |= CHN_F_RUNNING; 444 445 /* 446 * Chn_write() must give up channel lock in order to copy bytes from 447 * userland, so up the "in progress" counter to make sure someone 448 * else doesn't come along and muss up the buffer. 449 */ 450 ++wrch->inprog; 451 ret = chn_write(wrch, buf); 452 --wrch->inprog; 453 cv_signal(&wrch->cv); 454 455 relchns(i_dev, rdch, wrch, SD_F_PRIO_WR); 456 457 return ret; 458 } 459 460 static int 461 dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) 462 { 463 struct pcm_channel *chn, *rdch, *wrch; 464 struct snddev_info *d; 465 int kill; 466 int ret = 0, *arg_i = (int *)arg, tmp; 467 int xcmd; 468 469 xcmd = 0; 470 471 /* 472 * this is an evil hack to allow broken apps to perform mixer ioctls 473 * on dsp devices. 474 */ 475 476 d = dsp_get_info(i_dev); 477 if (IOCGROUP(cmd) == 'M') { 478 /* 479 * This is at least, a bug to bug compatible with OSS. 480 */ 481 if (d->mixer_dev != NULL) 482 return mixer_ioctl(d->mixer_dev, cmd, arg, -1, td); 483 else 484 return EBADF; 485 } 486 487 /* 488 * Certain ioctls may be made on any type of device (audio, mixer, 489 * and MIDI). Handle those special cases here. 490 */ 491 if (IOCGROUP(cmd) == 'X') { 492 switch(cmd) { 493 case SNDCTL_SYSINFO: 494 sound_oss_sysinfo((oss_sysinfo *)arg); 495 break; 496 case SNDCTL_AUDIOINFO: 497 ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg); 498 break; 499 case SNDCTL_MIXERINFO: 500 ret = mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg); 501 break; 502 default: 503 ret = EINVAL; 504 } 505 506 return ret; 507 } 508 509 getchns(i_dev, &rdch, &wrch, 0); 510 511 kill = 0; 512 if (wrch && (wrch->flags & CHN_F_DEAD)) 513 kill |= 1; 514 if (rdch && (rdch->flags & CHN_F_DEAD)) 515 kill |= 2; 516 if (kill == 3) { 517 relchns(i_dev, rdch, wrch, 0); 518 return EINVAL; 519 } 520 if (kill & 1) 521 wrch = NULL; 522 if (kill & 2) 523 rdch = NULL; 524 525 switch(cmd) { 526 #ifdef OLDPCM_IOCTL 527 /* 528 * we start with the new ioctl interface. 529 */ 530 case AIONWRITE: /* how many bytes can write ? */ 531 if (wrch) { 532 CHN_LOCK(wrch); 533 /* 534 if (wrch && wrch->bufhard.dl) 535 while (chn_wrfeed(wrch) == 0); 536 */ 537 *arg_i = sndbuf_getfree(wrch->bufsoft); 538 CHN_UNLOCK(wrch); 539 } else { 540 *arg_i = 0; 541 ret = EINVAL; 542 } 543 break; 544 545 case AIOSSIZE: /* set the current blocksize */ 546 { 547 struct snd_size *p = (struct snd_size *)arg; 548 549 p->play_size = 0; 550 p->rec_size = 0; 551 if (wrch) { 552 CHN_LOCK(wrch); 553 chn_setblocksize(wrch, 2, p->play_size); 554 p->play_size = sndbuf_getblksz(wrch->bufsoft); 555 CHN_UNLOCK(wrch); 556 } 557 if (rdch) { 558 CHN_LOCK(rdch); 559 chn_setblocksize(rdch, 2, p->rec_size); 560 p->rec_size = sndbuf_getblksz(rdch->bufsoft); 561 CHN_UNLOCK(rdch); 562 } 563 } 564 break; 565 case AIOGSIZE: /* get the current blocksize */ 566 { 567 struct snd_size *p = (struct snd_size *)arg; 568 569 if (wrch) { 570 CHN_LOCK(wrch); 571 p->play_size = sndbuf_getblksz(wrch->bufsoft); 572 CHN_UNLOCK(wrch); 573 } 574 if (rdch) { 575 CHN_LOCK(rdch); 576 p->rec_size = sndbuf_getblksz(rdch->bufsoft); 577 CHN_UNLOCK(rdch); 578 } 579 } 580 break; 581 582 case AIOSFMT: 583 case AIOGFMT: 584 { 585 snd_chan_param *p = (snd_chan_param *)arg; 586 587 if (cmd == AIOSFMT && 588 ((p->play_format != 0 && p->play_rate == 0) || 589 (p->rec_format != 0 && p->rec_rate == 0))) { 590 ret = EINVAL; 591 break; 592 } 593 if (wrch) { 594 CHN_LOCK(wrch); 595 if (cmd == AIOSFMT && p->play_format != 0) { 596 chn_setformat(wrch, p->play_format); 597 chn_setspeed(wrch, p->play_rate); 598 } 599 p->play_rate = wrch->speed; 600 p->play_format = wrch->format; 601 CHN_UNLOCK(wrch); 602 } else { 603 p->play_rate = 0; 604 p->play_format = 0; 605 } 606 if (rdch) { 607 CHN_LOCK(rdch); 608 if (cmd == AIOSFMT && p->rec_format != 0) { 609 chn_setformat(rdch, p->rec_format); 610 chn_setspeed(rdch, p->rec_rate); 611 } 612 p->rec_rate = rdch->speed; 613 p->rec_format = rdch->format; 614 CHN_UNLOCK(rdch); 615 } else { 616 p->rec_rate = 0; 617 p->rec_format = 0; 618 } 619 } 620 break; 621 622 case AIOGCAP: /* get capabilities */ 623 { 624 snd_capabilities *p = (snd_capabilities *)arg; 625 struct pcmchan_caps *pcaps = NULL, *rcaps = NULL; 626 struct cdev *pdev; 627 628 if (rdch) { 629 CHN_LOCK(rdch); 630 rcaps = chn_getcaps(rdch); 631 } 632 if (wrch) { 633 CHN_LOCK(wrch); 634 pcaps = chn_getcaps(wrch); 635 } 636 p->rate_min = max(rcaps? rcaps->minspeed : 0, 637 pcaps? pcaps->minspeed : 0); 638 p->rate_max = min(rcaps? rcaps->maxspeed : 1000000, 639 pcaps? pcaps->maxspeed : 1000000); 640 p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000, 641 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000); 642 /* XXX bad on sb16 */ 643 p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) & 644 (wrch? chn_getformats(wrch) : 0xffffffff); 645 if (rdch && wrch) 646 p->formats |= (dsp_get_flags(i_dev) & SD_F_SIMPLEX)? 0 : AFMT_FULLDUPLEX; 647 pdev = d->mixer_dev; 648 p->mixers = 1; /* default: one mixer */ 649 p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0; 650 p->left = p->right = 100; 651 if (rdch) 652 CHN_UNLOCK(rdch); 653 if (wrch) 654 CHN_UNLOCK(wrch); 655 } 656 break; 657 658 case AIOSTOP: 659 if (*arg_i == AIOSYNC_PLAY && wrch) { 660 CHN_LOCK(wrch); 661 *arg_i = chn_abort(wrch); 662 CHN_UNLOCK(wrch); 663 } else if (*arg_i == AIOSYNC_CAPTURE && rdch) { 664 CHN_LOCK(rdch); 665 *arg_i = chn_abort(rdch); 666 CHN_UNLOCK(rdch); 667 } else { 668 printf("AIOSTOP: bad channel 0x%x\n", *arg_i); 669 *arg_i = 0; 670 } 671 break; 672 673 case AIOSYNC: 674 printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n", 675 ((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos); 676 break; 677 #endif 678 /* 679 * here follow the standard ioctls (filio.h etc.) 680 */ 681 case FIONREAD: /* get # bytes to read */ 682 if (rdch) { 683 CHN_LOCK(rdch); 684 /* if (rdch && rdch->bufhard.dl) 685 while (chn_rdfeed(rdch) == 0); 686 */ 687 *arg_i = sndbuf_getready(rdch->bufsoft); 688 CHN_UNLOCK(rdch); 689 } else { 690 *arg_i = 0; 691 ret = EINVAL; 692 } 693 break; 694 695 case FIOASYNC: /*set/clear async i/o */ 696 DEB( printf("FIOASYNC\n") ; ) 697 break; 698 699 case SNDCTL_DSP_NONBLOCK: /* set non-blocking i/o */ 700 case FIONBIO: /* set/clear non-blocking i/o */ 701 if (rdch) { 702 CHN_LOCK(rdch); 703 if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i) 704 rdch->flags |= CHN_F_NBIO; 705 else 706 rdch->flags &= ~CHN_F_NBIO; 707 CHN_UNLOCK(rdch); 708 } 709 if (wrch) { 710 CHN_LOCK(wrch); 711 if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i) 712 wrch->flags |= CHN_F_NBIO; 713 else 714 wrch->flags &= ~CHN_F_NBIO; 715 CHN_UNLOCK(wrch); 716 } 717 break; 718 719 /* 720 * Finally, here is the linux-compatible ioctl interface 721 */ 722 #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int) 723 case THE_REAL_SNDCTL_DSP_GETBLKSIZE: 724 case SNDCTL_DSP_GETBLKSIZE: 725 chn = wrch ? wrch : rdch; 726 if (chn) { 727 CHN_LOCK(chn); 728 *arg_i = sndbuf_getblksz(chn->bufsoft); 729 CHN_UNLOCK(chn); 730 } else { 731 *arg_i = 0; 732 ret = EINVAL; 733 } 734 break ; 735 736 case SNDCTL_DSP_SETBLKSIZE: 737 RANGE(*arg_i, 16, 65536); 738 if (wrch) { 739 CHN_LOCK(wrch); 740 chn_setblocksize(wrch, 2, *arg_i); 741 CHN_UNLOCK(wrch); 742 } 743 if (rdch) { 744 CHN_LOCK(rdch); 745 chn_setblocksize(rdch, 2, *arg_i); 746 CHN_UNLOCK(rdch); 747 } 748 break; 749 750 case SNDCTL_DSP_RESET: 751 DEB(printf("dsp reset\n")); 752 if (wrch) { 753 CHN_LOCK(wrch); 754 chn_abort(wrch); 755 chn_resetbuf(wrch); 756 CHN_UNLOCK(wrch); 757 } 758 if (rdch) { 759 CHN_LOCK(rdch); 760 chn_abort(rdch); 761 chn_resetbuf(rdch); 762 CHN_UNLOCK(rdch); 763 } 764 break; 765 766 case SNDCTL_DSP_SYNC: 767 DEB(printf("dsp sync\n")); 768 /* chn_sync may sleep */ 769 if (wrch) { 770 CHN_LOCK(wrch); 771 chn_sync(wrch, sndbuf_getsize(wrch->bufsoft) - 4); 772 CHN_UNLOCK(wrch); 773 } 774 break; 775 776 case SNDCTL_DSP_SPEED: 777 /* chn_setspeed may sleep */ 778 tmp = 0; 779 if (wrch) { 780 CHN_LOCK(wrch); 781 ret = chn_setspeed(wrch, *arg_i); 782 tmp = wrch->speed; 783 CHN_UNLOCK(wrch); 784 } 785 if (rdch && ret == 0) { 786 CHN_LOCK(rdch); 787 ret = chn_setspeed(rdch, *arg_i); 788 if (tmp == 0) 789 tmp = rdch->speed; 790 CHN_UNLOCK(rdch); 791 } 792 *arg_i = tmp; 793 break; 794 795 case SOUND_PCM_READ_RATE: 796 chn = wrch ? wrch : rdch; 797 if (chn) { 798 CHN_LOCK(chn); 799 *arg_i = chn->speed; 800 CHN_UNLOCK(chn); 801 } else { 802 *arg_i = 0; 803 ret = EINVAL; 804 } 805 break; 806 807 case SNDCTL_DSP_STEREO: 808 tmp = -1; 809 *arg_i = (*arg_i)? AFMT_STEREO : 0; 810 if (wrch) { 811 CHN_LOCK(wrch); 812 ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i); 813 tmp = (wrch->format & AFMT_STEREO)? 1 : 0; 814 CHN_UNLOCK(wrch); 815 } 816 if (rdch && ret == 0) { 817 CHN_LOCK(rdch); 818 ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i); 819 if (tmp == -1) 820 tmp = (rdch->format & AFMT_STEREO)? 1 : 0; 821 CHN_UNLOCK(rdch); 822 } 823 *arg_i = tmp; 824 break; 825 826 case SOUND_PCM_WRITE_CHANNELS: 827 /* case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */ 828 if (*arg_i != 0) { 829 tmp = 0; 830 *arg_i = (*arg_i != 1)? AFMT_STEREO : 0; 831 if (wrch) { 832 CHN_LOCK(wrch); 833 ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i); 834 tmp = (wrch->format & AFMT_STEREO)? 2 : 1; 835 CHN_UNLOCK(wrch); 836 } 837 if (rdch && ret == 0) { 838 CHN_LOCK(rdch); 839 ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i); 840 if (tmp == 0) 841 tmp = (rdch->format & AFMT_STEREO)? 2 : 1; 842 CHN_UNLOCK(rdch); 843 } 844 *arg_i = tmp; 845 } else { 846 chn = wrch ? wrch : rdch; 847 CHN_LOCK(chn); 848 *arg_i = (chn->format & AFMT_STEREO) ? 2 : 1; 849 CHN_UNLOCK(chn); 850 } 851 break; 852 853 case SOUND_PCM_READ_CHANNELS: 854 chn = wrch ? wrch : rdch; 855 if (chn) { 856 CHN_LOCK(chn); 857 *arg_i = (chn->format & AFMT_STEREO) ? 2 : 1; 858 CHN_UNLOCK(chn); 859 } else { 860 *arg_i = 0; 861 ret = EINVAL; 862 } 863 break; 864 865 case SNDCTL_DSP_GETFMTS: /* returns a mask of supported fmts */ 866 chn = wrch ? wrch : rdch; 867 if (chn) { 868 CHN_LOCK(chn); 869 *arg_i = chn_getformats(chn); 870 CHN_UNLOCK(chn); 871 } else { 872 *arg_i = 0; 873 ret = EINVAL; 874 } 875 break ; 876 877 case SNDCTL_DSP_SETFMT: /* sets _one_ format */ 878 if ((*arg_i != AFMT_QUERY)) { 879 tmp = 0; 880 if (wrch) { 881 CHN_LOCK(wrch); 882 ret = chn_setformat(wrch, (*arg_i) | (wrch->format & AFMT_STEREO)); 883 tmp = wrch->format & ~AFMT_STEREO; 884 CHN_UNLOCK(wrch); 885 } 886 if (rdch && ret == 0) { 887 CHN_LOCK(rdch); 888 ret = chn_setformat(rdch, (*arg_i) | (rdch->format & AFMT_STEREO)); 889 if (tmp == 0) 890 tmp = rdch->format & ~AFMT_STEREO; 891 CHN_UNLOCK(rdch); 892 } 893 *arg_i = tmp; 894 } else { 895 chn = wrch ? wrch : rdch; 896 CHN_LOCK(chn); 897 *arg_i = chn->format & ~AFMT_STEREO; 898 CHN_UNLOCK(chn); 899 } 900 break; 901 902 case SNDCTL_DSP_SETFRAGMENT: 903 DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg)); 904 { 905 u_int32_t fragln = (*arg_i) & 0x0000ffff; 906 u_int32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16; 907 u_int32_t fragsz; 908 u_int32_t r_maxfrags, r_fragsz; 909 910 RANGE(fragln, 4, 16); 911 fragsz = 1 << fragln; 912 913 if (maxfrags == 0) 914 maxfrags = CHN_2NDBUFMAXSIZE / fragsz; 915 if (maxfrags < 2) 916 maxfrags = 2; 917 if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE) 918 maxfrags = CHN_2NDBUFMAXSIZE / fragsz; 919 920 DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz)); 921 if (rdch) { 922 CHN_LOCK(rdch); 923 ret = chn_setblocksize(rdch, maxfrags, fragsz); 924 r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft); 925 r_fragsz = sndbuf_getblksz(rdch->bufsoft); 926 CHN_UNLOCK(rdch); 927 } else { 928 r_maxfrags = maxfrags; 929 r_fragsz = fragsz; 930 } 931 if (wrch && ret == 0) { 932 CHN_LOCK(wrch); 933 ret = chn_setblocksize(wrch, maxfrags, fragsz); 934 maxfrags = sndbuf_getblkcnt(wrch->bufsoft); 935 fragsz = sndbuf_getblksz(wrch->bufsoft); 936 CHN_UNLOCK(wrch); 937 } else { /* use whatever came from the read channel */ 938 maxfrags = r_maxfrags; 939 fragsz = r_fragsz; 940 } 941 942 fragln = 0; 943 while (fragsz > 1) { 944 fragln++; 945 fragsz >>= 1; 946 } 947 *arg_i = (maxfrags << 16) | fragln; 948 } 949 break; 950 951 case SNDCTL_DSP_GETISPACE: 952 /* return the size of data available in the input queue */ 953 { 954 audio_buf_info *a = (audio_buf_info *)arg; 955 if (rdch) { 956 struct snd_dbuf *bs = rdch->bufsoft; 957 958 CHN_LOCK(rdch); 959 a->bytes = sndbuf_getready(bs); 960 a->fragments = a->bytes / sndbuf_getblksz(bs); 961 a->fragstotal = sndbuf_getblkcnt(bs); 962 a->fragsize = sndbuf_getblksz(bs); 963 CHN_UNLOCK(rdch); 964 } 965 } 966 break; 967 968 case SNDCTL_DSP_GETOSPACE: 969 /* return space available in the output queue */ 970 { 971 audio_buf_info *a = (audio_buf_info *)arg; 972 if (wrch) { 973 struct snd_dbuf *bs = wrch->bufsoft; 974 975 CHN_LOCK(wrch); 976 /* XXX abusive DMA update: chn_wrupdate(wrch); */ 977 a->bytes = sndbuf_getfree(bs); 978 a->fragments = a->bytes / sndbuf_getblksz(bs); 979 a->fragstotal = sndbuf_getblkcnt(bs); 980 a->fragsize = sndbuf_getblksz(bs); 981 CHN_UNLOCK(wrch); 982 } 983 } 984 break; 985 986 case SNDCTL_DSP_GETIPTR: 987 { 988 count_info *a = (count_info *)arg; 989 if (rdch) { 990 struct snd_dbuf *bs = rdch->bufsoft; 991 992 CHN_LOCK(rdch); 993 /* XXX abusive DMA update: chn_rdupdate(rdch); */ 994 a->bytes = sndbuf_gettotal(bs); 995 a->blocks = sndbuf_getblocks(bs) - rdch->blocks; 996 a->ptr = sndbuf_getreadyptr(bs); 997 rdch->blocks = sndbuf_getblocks(bs); 998 CHN_UNLOCK(rdch); 999 } else 1000 ret = EINVAL; 1001 } 1002 break; 1003 1004 case SNDCTL_DSP_GETOPTR: 1005 { 1006 count_info *a = (count_info *)arg; 1007 if (wrch) { 1008 struct snd_dbuf *bs = wrch->bufsoft; 1009 1010 CHN_LOCK(wrch); 1011 /* XXX abusive DMA update: chn_wrupdate(wrch); */ 1012 a->bytes = sndbuf_gettotal(bs); 1013 a->blocks = sndbuf_getblocks(bs) - wrch->blocks; 1014 a->ptr = sndbuf_getreadyptr(bs); 1015 wrch->blocks = sndbuf_getblocks(bs); 1016 CHN_UNLOCK(wrch); 1017 } else 1018 ret = EINVAL; 1019 } 1020 break; 1021 1022 case SNDCTL_DSP_GETCAPS: 1023 *arg_i = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER; 1024 if (rdch && wrch && !(dsp_get_flags(i_dev) & SD_F_SIMPLEX)) 1025 *arg_i |= DSP_CAP_DUPLEX; 1026 break; 1027 1028 case SOUND_PCM_READ_BITS: 1029 chn = wrch ? wrch : rdch; 1030 if (chn) { 1031 CHN_LOCK(chn); 1032 if (chn->format & AFMT_8BIT) 1033 *arg_i = 8; 1034 else if (chn->format & AFMT_16BIT) 1035 *arg_i = 16; 1036 else if (chn->format & AFMT_24BIT) 1037 *arg_i = 24; 1038 else if (chn->format & AFMT_32BIT) 1039 *arg_i = 32; 1040 else 1041 ret = EINVAL; 1042 CHN_UNLOCK(chn); 1043 } else { 1044 *arg_i = 0; 1045 ret = EINVAL; 1046 } 1047 break; 1048 1049 case SNDCTL_DSP_SETTRIGGER: 1050 if (rdch) { 1051 CHN_LOCK(rdch); 1052 rdch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER); 1053 if (*arg_i & PCM_ENABLE_INPUT) 1054 chn_start(rdch, 1); 1055 else 1056 rdch->flags |= CHN_F_NOTRIGGER; 1057 CHN_UNLOCK(rdch); 1058 } 1059 if (wrch) { 1060 CHN_LOCK(wrch); 1061 wrch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER); 1062 if (*arg_i & PCM_ENABLE_OUTPUT) 1063 chn_start(wrch, 1); 1064 else 1065 wrch->flags |= CHN_F_NOTRIGGER; 1066 CHN_UNLOCK(wrch); 1067 } 1068 break; 1069 1070 case SNDCTL_DSP_GETTRIGGER: 1071 *arg_i = 0; 1072 if (wrch) { 1073 CHN_LOCK(wrch); 1074 if (wrch->flags & CHN_F_TRIGGERED) 1075 *arg_i |= PCM_ENABLE_OUTPUT; 1076 CHN_UNLOCK(wrch); 1077 } 1078 if (rdch) { 1079 CHN_LOCK(rdch); 1080 if (rdch->flags & CHN_F_TRIGGERED) 1081 *arg_i |= PCM_ENABLE_INPUT; 1082 CHN_UNLOCK(rdch); 1083 } 1084 break; 1085 1086 case SNDCTL_DSP_GETODELAY: 1087 if (wrch) { 1088 struct snd_dbuf *b = wrch->bufhard; 1089 struct snd_dbuf *bs = wrch->bufsoft; 1090 1091 CHN_LOCK(wrch); 1092 /* XXX abusive DMA update: chn_wrupdate(wrch); */ 1093 *arg_i = sndbuf_getready(b) + sndbuf_getready(bs); 1094 CHN_UNLOCK(wrch); 1095 } else 1096 ret = EINVAL; 1097 break; 1098 1099 case SNDCTL_DSP_POST: 1100 if (wrch) { 1101 CHN_LOCK(wrch); 1102 wrch->flags &= ~CHN_F_NOTRIGGER; 1103 chn_start(wrch, 1); 1104 CHN_UNLOCK(wrch); 1105 } 1106 break; 1107 1108 case SNDCTL_DSP_SETDUPLEX: 1109 /* 1110 * switch to full-duplex mode if card is in half-duplex 1111 * mode and is able to work in full-duplex mode 1112 */ 1113 if (rdch && wrch && (dsp_get_flags(i_dev) & SD_F_SIMPLEX)) 1114 dsp_set_flags(i_dev, dsp_get_flags(i_dev)^SD_F_SIMPLEX); 1115 break; 1116 1117 /* 1118 * The following four ioctls are simple wrappers around mixer_ioctl 1119 * with no further processing. xcmd is short for "translated 1120 * command". 1121 */ 1122 case SNDCTL_DSP_GETRECVOL: 1123 if (xcmd == 0) 1124 xcmd = SOUND_MIXER_READ_RECLEV; 1125 /* FALLTHROUGH */ 1126 case SNDCTL_DSP_SETRECVOL: 1127 if (xcmd == 0) 1128 xcmd = SOUND_MIXER_WRITE_RECLEV; 1129 /* FALLTHROUGH */ 1130 case SNDCTL_DSP_GETPLAYVOL: 1131 if (xcmd == 0) 1132 xcmd = SOUND_MIXER_READ_PCM; 1133 /* FALLTHROUGH */ 1134 case SNDCTL_DSP_SETPLAYVOL: 1135 if (xcmd == 0) 1136 xcmd = SOUND_MIXER_WRITE_PCM; 1137 1138 if (d->mixer_dev != NULL) 1139 ret = mixer_ioctl(d->mixer_dev, xcmd, arg, -1, td); 1140 else 1141 ret = ENOTSUP; 1142 break; 1143 1144 case SNDCTL_DSP_GET_RECSRC_NAMES: 1145 case SNDCTL_DSP_GET_RECSRC: 1146 case SNDCTL_DSP_SET_RECSRC: 1147 if (d->mixer_dev != NULL) 1148 ret = mixer_ioctl(d->mixer_dev, cmd, arg, -1, td); 1149 else 1150 ret = ENOTSUP; 1151 break; 1152 1153 /* 1154 * The following 3 ioctls aren't very useful at the moment. For 1155 * now, only a single channel is associated with a cdev (/dev/dspN 1156 * instance), so there's only a single output routing to use (i.e., 1157 * the wrch bound to this cdev). 1158 */ 1159 case SNDCTL_DSP_GET_PLAYTGT_NAMES: 1160 { 1161 oss_mixer_enuminfo *ei; 1162 ei = (oss_mixer_enuminfo *)arg; 1163 ei->dev = 0; 1164 ei->ctrl = 0; 1165 ei->version = 0; /* static for now */ 1166 ei->strindex[0] = 0; 1167 1168 if (wrch != NULL) { 1169 ei->nvalues = 1; 1170 strlcpy(ei->strings, wrch->name, 1171 sizeof(ei->strings)); 1172 } else { 1173 ei->nvalues = 0; 1174 ei->strings[0] = '\0'; 1175 } 1176 } 1177 break; 1178 case SNDCTL_DSP_GET_PLAYTGT: 1179 case SNDCTL_DSP_SET_PLAYTGT: /* yes, they are the same for now */ 1180 /* 1181 * Re: SET_PLAYTGT 1182 * OSSv4: "The value that was accepted by the device will 1183 * be returned back in the variable pointed by the 1184 * argument." 1185 */ 1186 if (wrch != NULL) 1187 *arg_i = 0; 1188 else 1189 ret = EINVAL; 1190 break; 1191 1192 case SNDCTL_DSP_SILENCE: 1193 /* 1194 * Flush the software (pre-feed) buffer, but try to minimize playback 1195 * interruption. (I.e., record unplayed samples with intent to 1196 * restore by SNDCTL_DSP_SKIP.) Intended for application "pause" 1197 * functionality. 1198 */ 1199 if (wrch == NULL) 1200 ret = EINVAL; 1201 else { 1202 struct snd_dbuf *bs; 1203 CHN_LOCK(wrch); 1204 while (wrch->inprog != 0) 1205 cv_wait(&wrch->cv, wrch->lock); 1206 bs = wrch->bufsoft; 1207 if ((bs->shadbuf != NULL) && (sndbuf_getready(bs) > 0)) { 1208 bs->sl = sndbuf_getready(bs); 1209 sndbuf_dispose(bs, bs->shadbuf, sndbuf_getready(bs)); 1210 sndbuf_fillsilence(bs); 1211 chn_start(wrch, 0); 1212 } 1213 CHN_UNLOCK(wrch); 1214 } 1215 break; 1216 1217 case SNDCTL_DSP_SKIP: 1218 /* 1219 * OSSv4 docs: "This ioctl call discards all unplayed samples in the 1220 * playback buffer by moving the current write position immediately 1221 * before the point where the device is currently reading the samples." 1222 */ 1223 if (wrch == NULL) 1224 ret = EINVAL; 1225 else { 1226 struct snd_dbuf *bs; 1227 CHN_LOCK(wrch); 1228 while (wrch->inprog != 0) 1229 cv_wait(&wrch->cv, wrch->lock); 1230 bs = wrch->bufsoft; 1231 if ((bs->shadbuf != NULL) && (bs->sl > 0)) { 1232 sndbuf_softreset(bs); 1233 sndbuf_acquire(bs, bs->shadbuf, bs->sl); 1234 bs->sl = 0; 1235 chn_start(wrch, 0); 1236 } 1237 CHN_UNLOCK(wrch); 1238 } 1239 break; 1240 1241 case SNDCTL_DSP_CURRENT_OPTR: 1242 case SNDCTL_DSP_CURRENT_IPTR: 1243 /** 1244 * @note Changing formats resets the buffer counters, which differs 1245 * from the 4Front drivers. However, I don't expect this to be 1246 * much of a problem. 1247 * 1248 * @note In a test where @c CURRENT_OPTR is called immediately after write 1249 * returns, this driver is about 32K samples behind whereas 1250 * 4Front's is about 8K samples behind. Should determine source 1251 * of discrepancy, even if only out of curiosity. 1252 * 1253 * @todo Actually test SNDCTL_DSP_CURRENT_IPTR. 1254 */ 1255 chn = (cmd == SNDCTL_DSP_CURRENT_OPTR) ? wrch : rdch; 1256 if (chn == NULL) 1257 ret = EINVAL; 1258 else { 1259 struct snd_dbuf *bs; 1260 /* int tmp; */ 1261 1262 oss_count_t *oc = (oss_count_t *)arg; 1263 1264 CHN_LOCK(chn); 1265 bs = chn->bufsoft; 1266 #if 0 1267 tmp = (sndbuf_getsize(b) + chn_getptr(chn) - sndbuf_gethwptr(b)) % sndbuf_getsize(b); 1268 oc->samples = (sndbuf_gettotal(b) + tmp) / sndbuf_getbps(b); 1269 oc->fifo_samples = (sndbuf_getready(b) - tmp) / sndbuf_getbps(b); 1270 #else 1271 oc->samples = sndbuf_gettotal(bs) / sndbuf_getbps(bs); 1272 oc->fifo_samples = sndbuf_getready(bs) / sndbuf_getbps(bs); 1273 #endif 1274 CHN_UNLOCK(chn); 1275 } 1276 break; 1277 1278 case SNDCTL_DSP_HALT_OUTPUT: 1279 case SNDCTL_DSP_HALT_INPUT: 1280 chn = (cmd == SNDCTL_DSP_HALT_OUTPUT) ? wrch : rdch; 1281 if (chn == NULL) 1282 ret = EINVAL; 1283 else { 1284 CHN_LOCK(chn); 1285 chn_abort(chn); 1286 CHN_UNLOCK(chn); 1287 } 1288 break; 1289 1290 case SNDCTL_DSP_LOW_WATER: 1291 /* 1292 * Set the number of bytes required to attract attention by 1293 * select/poll. 1294 */ 1295 if (wrch != NULL) { 1296 CHN_LOCK(wrch); 1297 wrch->lw = (*arg_i > 1) ? *arg_i : 1; 1298 CHN_UNLOCK(wrch); 1299 } 1300 if (rdch != NULL) { 1301 CHN_LOCK(rdch); 1302 rdch->lw = (*arg_i > 1) ? *arg_i : 1; 1303 CHN_UNLOCK(rdch); 1304 } 1305 break; 1306 1307 case SNDCTL_DSP_GETERROR: 1308 /* 1309 * OSSv4 docs: "All errors and counters will automatically be 1310 * cleared to zeroes after the call so each call will return only 1311 * the errors that occurred after the previous invocation. ... The 1312 * play_underruns and rec_overrun fields are the only usefull fields 1313 * returned by OSS 4.0." 1314 */ 1315 { 1316 audio_errinfo *ei = (audio_errinfo *)arg; 1317 1318 bzero((void *)ei, sizeof(*ei)); 1319 1320 if (wrch != NULL) { 1321 CHN_LOCK(wrch); 1322 ei->play_underruns = wrch->xruns; 1323 wrch->xruns = 0; 1324 CHN_UNLOCK(wrch); 1325 } 1326 if (rdch != NULL) { 1327 CHN_LOCK(rdch); 1328 ei->rec_overruns = rdch->xruns; 1329 rdch->xruns = 0; 1330 CHN_UNLOCK(rdch); 1331 } 1332 } 1333 break; 1334 1335 case SNDCTL_DSP_SYNCGROUP: 1336 ret = dsp_oss_syncgroup(wrch, rdch, (oss_syncgroup *)arg); 1337 break; 1338 1339 case SNDCTL_DSP_SYNCSTART: 1340 ret = dsp_oss_syncstart(*arg_i); 1341 break; 1342 1343 case SNDCTL_DSP_POLICY: 1344 ret = dsp_oss_policy(wrch, rdch, *arg_i); 1345 break; 1346 1347 #ifdef OSSV4_EXPERIMENT 1348 /* 1349 * XXX The following ioctls are not yet supported and just return 1350 * EINVAL. 1351 */ 1352 case SNDCTL_DSP_GETOPEAKS: 1353 case SNDCTL_DSP_GETIPEAKS: 1354 chn = (cmd == SNDCTL_DSP_GETOPEAKS) ? wrch : rdch; 1355 if (chn == NULL) 1356 ret = EINVAL; 1357 else { 1358 oss_peaks_t *op = (oss_peaks_t *)arg; 1359 int lpeak, rpeak; 1360 1361 CHN_LOCK(chn); 1362 ret = chn_getpeaks(chn, &lpeak, &rpeak); 1363 if (ret == -1) 1364 ret = EINVAL; 1365 else { 1366 (*op)[0] = lpeak; 1367 (*op)[1] = rpeak; 1368 } 1369 CHN_UNLOCK(chn); 1370 } 1371 break; 1372 1373 case SNDCTL_DSP_COOKEDMODE: 1374 ret = dsp_oss_cookedmode(wrch, rdch, *arg_i); 1375 break; 1376 case SNDCTL_DSP_GET_CHNORDER: 1377 ret = dsp_oss_getchnorder(wrch, rdch, (unsigned long long *)arg); 1378 break; 1379 case SNDCTL_DSP_SET_CHNORDER: 1380 ret = dsp_oss_setchnorder(wrch, rdch, (unsigned long long *)arg); 1381 break; 1382 case SNDCTL_GETLABEL: 1383 ret = dsp_oss_getlabel(wrch, rdch, (oss_label_t *)arg); 1384 break; 1385 case SNDCTL_SETLABEL: 1386 ret = dsp_oss_setlabel(wrch, rdch, (oss_label_t *)arg); 1387 break; 1388 case SNDCTL_GETSONG: 1389 ret = dsp_oss_getsong(wrch, rdch, (oss_longname_t *)arg); 1390 break; 1391 case SNDCTL_SETSONG: 1392 ret = dsp_oss_setsong(wrch, rdch, (oss_longname_t *)arg); 1393 break; 1394 case SNDCTL_SETNAME: 1395 ret = dsp_oss_setname(wrch, rdch, (oss_longname_t *)arg); 1396 break; 1397 #if 0 1398 /** 1399 * @note The SNDCTL_CARDINFO ioctl was omitted per 4Front developer 1400 * documentation. "The usability of this call is very limited. It's 1401 * provided only for completeness of the API. OSS API doesn't have 1402 * any concept of card. Any information returned by this ioctl calld 1403 * is reserved exclusively for the utility programs included in the 1404 * OSS package. Applications should not try to use for this 1405 * information in any ways." 1406 */ 1407 case SNDCTL_CARDINFO: 1408 ret = EINVAL; 1409 break; 1410 /** 1411 * @note The S/PDIF interface ioctls, @c SNDCTL_DSP_READCTL and 1412 * @c SNDCTL_DSP_WRITECTL have been omitted at the suggestion of 1413 * 4Front Technologies. 1414 */ 1415 case SNDCTL_DSP_READCTL: 1416 case SNDCTL_DSP_WRITECTL: 1417 ret = EINVAL; 1418 break; 1419 #endif /* !0 (explicitly omitted ioctls) */ 1420 1421 #endif /* !OSSV4_EXPERIMENT */ 1422 case SNDCTL_DSP_MAPINBUF: 1423 case SNDCTL_DSP_MAPOUTBUF: 1424 case SNDCTL_DSP_SETSYNCRO: 1425 /* undocumented */ 1426 1427 case SNDCTL_DSP_SUBDIVIDE: 1428 case SOUND_PCM_WRITE_FILTER: 1429 case SOUND_PCM_READ_FILTER: 1430 /* dunno what these do, don't sound important */ 1431 1432 default: 1433 DEB(printf("default ioctl fn 0x%08lx fail\n", cmd)); 1434 ret = EINVAL; 1435 break; 1436 } 1437 relchns(i_dev, rdch, wrch, 0); 1438 return ret; 1439 } 1440 1441 static int 1442 dsp_poll(struct cdev *i_dev, int events, struct thread *td) 1443 { 1444 struct pcm_channel *wrch = NULL, *rdch = NULL; 1445 int ret, e; 1446 1447 ret = 0; 1448 getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1449 1450 if (wrch) { 1451 e = (events & (POLLOUT | POLLWRNORM)); 1452 if (e) 1453 ret |= chn_poll(wrch, e, td); 1454 } 1455 if (rdch) { 1456 e = (events & (POLLIN | POLLRDNORM)); 1457 if (e) 1458 ret |= chn_poll(rdch, e, td); 1459 } 1460 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1461 1462 return ret; 1463 } 1464 1465 static int 1466 dsp_mmap(struct cdev *i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 1467 { 1468 struct pcm_channel *wrch = NULL, *rdch = NULL, *c; 1469 1470 if (nprot & PROT_EXEC) 1471 return -1; 1472 1473 getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1474 #if 0 1475 /* 1476 * XXX the linux api uses the nprot to select read/write buffer 1477 * our vm system doesn't allow this, so force write buffer 1478 */ 1479 1480 if (wrch && (nprot & PROT_WRITE)) { 1481 c = wrch; 1482 } else if (rdch && (nprot & PROT_READ)) { 1483 c = rdch; 1484 } else { 1485 return -1; 1486 } 1487 #else 1488 c = wrch; 1489 #endif 1490 1491 if (c == NULL) { 1492 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1493 return -1; 1494 } 1495 1496 if (offset >= sndbuf_getsize(c->bufsoft)) { 1497 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1498 return -1; 1499 } 1500 1501 if (!(c->flags & CHN_F_MAPPED)) 1502 c->flags |= CHN_F_MAPPED; 1503 1504 *paddr = vtophys(sndbuf_getbufofs(c->bufsoft, offset)); 1505 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1506 1507 return 0; 1508 } 1509 1510 #ifdef USING_DEVFS 1511 1512 /* 1513 * Clone logic is this: 1514 * x E X = {dsp, dspW, audio} 1515 * x -> x${sysctl("hw.snd.unit")} 1516 * xN-> 1517 * for i N = 1 to channels of device N 1518 * if xN.i isn't busy, return its dev_t 1519 */ 1520 static void 1521 dsp_clone(void *arg, struct ucred *cred, char *name, int namelen, 1522 struct cdev **dev) 1523 { 1524 struct cdev *pdev; 1525 struct snddev_info *pcm_dev; 1526 struct snddev_channel *pcm_chan; 1527 int i, unit, devtype; 1528 static int devtypes[3] = {SND_DEV_DSP, SND_DEV_DSP16, SND_DEV_AUDIO}; 1529 static char *devnames[3] = {"dsp", "dspW", "audio"}; 1530 1531 if (*dev != NULL) 1532 return; 1533 if (pcm_devclass == NULL) 1534 return; 1535 1536 devtype = 0; 1537 unit = -1; 1538 for (i = 0; (i < 3) && (unit == -1); i++) { 1539 devtype = devtypes[i]; 1540 if (strcmp(name, devnames[i]) == 0) { 1541 unit = snd_unit; 1542 } else { 1543 if (dev_stdclone(name, NULL, devnames[i], &unit) != 1) 1544 unit = -1; 1545 } 1546 } 1547 if (unit == -1 || unit >= devclass_get_maxunit(pcm_devclass)) 1548 return; 1549 1550 pcm_dev = devclass_get_softc(pcm_devclass, unit); 1551 1552 if (pcm_dev == NULL) 1553 return; 1554 1555 SLIST_FOREACH(pcm_chan, &pcm_dev->channels, link) { 1556 1557 switch(devtype) { 1558 case SND_DEV_DSP: 1559 pdev = pcm_chan->dsp_devt; 1560 break; 1561 case SND_DEV_DSP16: 1562 pdev = pcm_chan->dspW_devt; 1563 break; 1564 case SND_DEV_AUDIO: 1565 pdev = pcm_chan->audio_devt; 1566 break; 1567 default: 1568 panic("Unknown devtype %d", devtype); 1569 } 1570 1571 if ((pdev != NULL) && (pdev->si_drv1 == NULL) && (pdev->si_drv2 == NULL)) { 1572 *dev = pdev; 1573 dev_ref(*dev); 1574 return; 1575 } 1576 } 1577 } 1578 1579 static void 1580 dsp_sysinit(void *p) 1581 { 1582 dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000); 1583 } 1584 1585 static void 1586 dsp_sysuninit(void *p) 1587 { 1588 if (dsp_ehtag != NULL) 1589 EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag); 1590 } 1591 1592 SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL); 1593 SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL); 1594 #endif 1595 1596 /** 1597 * @brief Handler for SNDCTL_AUDIOINFO. 1598 * 1599 * Gathers information about the audio device specified in ai->dev. If 1600 * ai->dev == -1, then this function gathers information about the current 1601 * device. If the call comes in on a non-audio device and ai->dev == -1, 1602 * return EINVAL. 1603 * 1604 * This routine is supposed to go practically straight to the hardware, 1605 * getting capabilities directly from the sound card driver, side-stepping 1606 * the intermediate channel interface. 1607 * 1608 * Note, however, that the usefulness of this command is significantly 1609 * decreased when requesting info about any device other than the one serving 1610 * the request. While each snddev_channel refers to a specific device node, 1611 * the converse is *not* true. Currently, when a sound device node is opened, 1612 * the sound subsystem scans for an available audio channel (or channels, if 1613 * opened in read+write) and then assigns them to the si_drv[12] private 1614 * data fields. As a result, any information returned linking a channel to 1615 * a specific character device isn't necessarily accurate. 1616 * 1617 * @note 1618 * Calling threads must not hold any snddev_info or pcm_channel locks. 1619 * 1620 * @param dev device on which the ioctl was issued 1621 * @param ai ioctl request data container 1622 * 1623 * @retval 0 success 1624 * @retval EINVAL ai->dev specifies an invalid device 1625 * 1626 * @todo Verify correctness of Doxygen tags. ;) 1627 */ 1628 int 1629 dsp_oss_audioinfo(struct cdev *i_dev, oss_audioinfo *ai) 1630 { 1631 struct snddev_channel *sce; 1632 struct pcmchan_caps *caps; 1633 struct pcm_channel *ch; 1634 struct snddev_info *d; 1635 struct cdev *t_cdev; 1636 uint32_t fmts; 1637 int i, nchan, ret, *rates, minch, maxch; 1638 1639 /* 1640 * If probing the device that received the ioctl, make sure it's a 1641 * DSP device. (Users may use this ioctl with /dev/mixer and 1642 * /dev/midi.) 1643 */ 1644 if ((ai->dev == -1) && (i_dev->si_devsw != &dsp_cdevsw)) 1645 return EINVAL; 1646 1647 ch = NULL; 1648 t_cdev = NULL; 1649 nchan = 0; 1650 ret = 0; 1651 1652 /* 1653 * Search for the requested audio device (channel). Start by 1654 * iterating over pcm devices. 1655 */ 1656 for (i = 0; i < devclass_get_maxunit(pcm_devclass); i++) { 1657 d = devclass_get_softc(pcm_devclass, i); 1658 if (d == NULL) 1659 continue; 1660 1661 /* See the note in function docblock */ 1662 mtx_assert(d->lock, MA_NOTOWNED); 1663 pcm_inprog(d, 1); 1664 pcm_lock(d); 1665 1666 SLIST_FOREACH(sce, &d->channels, link) { 1667 ch = sce->channel; 1668 mtx_assert(ch->lock, MA_NOTOWNED); 1669 CHN_LOCK(ch); 1670 if (ai->dev == -1) { 1671 if ((ch == i_dev->si_drv1) || /* record ch */ 1672 (ch == i_dev->si_drv2)) { /* playback ch */ 1673 t_cdev = i_dev; 1674 goto dspfound; 1675 } 1676 } else if (ai->dev == nchan) { 1677 t_cdev = sce->dsp_devt; 1678 goto dspfound; 1679 } 1680 CHN_UNLOCK(ch); 1681 ++nchan; 1682 } 1683 1684 pcm_unlock(d); 1685 pcm_inprog(d, -1); 1686 } 1687 1688 /* Exhausted the search -- nothing is locked, so return. */ 1689 return EINVAL; 1690 1691 dspfound: 1692 /* Should've found the device, but something isn't right */ 1693 if (t_cdev == NULL) { 1694 ret = EINVAL; 1695 goto out; 1696 } 1697 1698 /* 1699 * At this point, the following synchronization stuff has happened: 1700 * - a specific PCM device is locked and its "in progress 1701 * operations" counter has been incremented, so be sure to unlock 1702 * and decrement when exiting; 1703 * - a specific audio channel has been locked, so be sure to unlock 1704 * when exiting; 1705 */ 1706 1707 caps = chn_getcaps(ch); 1708 1709 /* 1710 * With all handles collected, zero out the user's container and 1711 * begin filling in its fields. 1712 */ 1713 bzero((void *)ai, sizeof(oss_audioinfo)); 1714 1715 ai->dev = nchan; 1716 strlcpy(ai->name, ch->name, sizeof(ai->name)); 1717 1718 if ((ch->flags & CHN_F_BUSY) == 0) 1719 ai->busy = 0; 1720 else 1721 ai->busy = (ch->direction == PCMDIR_PLAY) ? OPEN_WRITE : OPEN_READ; 1722 1723 /** 1724 * @note 1725 * @c cmd - OSSv4 docs: "Only supported under Linux at this moment." 1726 * Cop-out, I know, but I'll save running around in the process 1727 * table for later. Is there a risk of leaking information? 1728 */ 1729 ai->pid = ch->pid; 1730 1731 /* 1732 * These flags stolen from SNDCTL_DSP_GETCAPS handler. Note, however, 1733 * that a single channel operates in only one direction, so 1734 * DSP_CAP_DUPLEX is out. 1735 */ 1736 /** 1737 * @todo @c SNDCTL_AUDIOINFO::caps - Make drivers keep these in 1738 * pcmchan::caps? 1739 */ 1740 ai->caps = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER; 1741 1742 /* 1743 * Collect formats supported @b natively by the device. Also 1744 * determine min/max channels. (I.e., mono, stereo, or both?) 1745 * 1746 * If any channel is stereo, maxch = 2; 1747 * if all channels are stereo, minch = 2, too; 1748 * if any channel is mono, minch = 1; 1749 * and if all channels are mono, maxch = 1. 1750 */ 1751 minch = 0; 1752 maxch = 0; 1753 fmts = 0; 1754 for (i = 0; caps->fmtlist[i]; i++) { 1755 fmts |= caps->fmtlist[i]; 1756 if (caps->fmtlist[i] & AFMT_STEREO) { 1757 minch = (minch == 0) ? 2 : minch; 1758 maxch = 2; 1759 } else { 1760 minch = 1; 1761 maxch = (maxch == 0) ? 1 : maxch; 1762 } 1763 } 1764 1765 if (ch->direction == PCMDIR_PLAY) 1766 ai->oformats = fmts; 1767 else 1768 ai->iformats = fmts; 1769 1770 /** 1771 * @note 1772 * @c magic - OSSv4 docs: "Reserved for internal use by OSS." 1773 * 1774 * @par 1775 * @c card_number - OSSv4 docs: "Number of the sound card where this 1776 * device belongs or -1 if this information is not available. 1777 * Applications should normally not use this field for any 1778 * purpose." 1779 */ 1780 ai->card_number = -1; 1781 /** 1782 * @todo @c song_name - depends first on SNDCTL_[GS]ETSONG 1783 * @todo @c label - depends on SNDCTL_[GS]ETLABEL 1784 * @todo @c port_number - routing information? 1785 */ 1786 ai->port_number = -1; 1787 ai->mixer_dev = (d->mixer_dev != NULL) ? PCMUNIT(d->mixer_dev) : -1; 1788 /** 1789 * @note 1790 * @c real_device - OSSv4 docs: "Obsolete." 1791 */ 1792 ai->real_device = -1; 1793 strlcpy(ai->devnode, t_cdev->si_name, sizeof(ai->devnode)); 1794 ai->enabled = device_is_attached(d->dev) ? 1 : 0; 1795 /** 1796 * @note 1797 * @c flags - OSSv4 docs: "Reserved for future use." 1798 * 1799 * @note 1800 * @c binding - OSSv4 docs: "Reserved for future use." 1801 * 1802 * @todo @c handle - haven't decided how to generate this yet; bus, 1803 * vendor, device IDs? 1804 */ 1805 ai->min_rate = caps->minspeed; 1806 ai->max_rate = caps->maxspeed; 1807 1808 ai->min_channels = minch; 1809 ai->max_channels = maxch; 1810 1811 ai->nrates = chn_getrates(ch, &rates); 1812 if (ai->nrates > OSS_MAX_SAMPLE_RATES) 1813 ai->nrates = OSS_MAX_SAMPLE_RATES; 1814 1815 for (i = 0; i < ai->nrates; i++) 1816 ai->rates[i] = rates[i]; 1817 1818 out: 1819 CHN_UNLOCK(ch); 1820 pcm_unlock(d); 1821 pcm_inprog(d, -1); 1822 1823 return ret; 1824 } 1825 1826 /** 1827 * @brief Assigns a PCM channel to a sync group. 1828 * 1829 * Sync groups are used to enable audio operations on multiple devices 1830 * simultaneously. They may be used with any number of devices and may 1831 * span across applications. Devices are added to groups with 1832 * the SNDCTL_DSP_SYNCGROUP ioctl, and operations are triggered with the 1833 * SNDCTL_DSP_SYNCSTART ioctl. 1834 * 1835 * If the @c id field of the @c group parameter is set to zero, then a new 1836 * sync group is created. Otherwise, wrch and rdch (if set) are added to 1837 * the group specified. 1838 * 1839 * @todo As far as memory allocation, should we assume that things are 1840 * okay and allocate with M_WAITOK before acquiring channel locks, 1841 * freeing later if not? 1842 * 1843 * @param wrch output channel associated w/ device (if any) 1844 * @param rdch input channel associated w/ device (if any) 1845 * @param group Sync group parameters 1846 * 1847 * @retval 0 success 1848 * @retval non-zero error to be propagated upstream 1849 */ 1850 static int 1851 dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group) 1852 { 1853 struct pcmchan_syncmember *smrd, *smwr; 1854 struct pcmchan_syncgroup *sg; 1855 int ret, sg_ids[3]; 1856 1857 smrd = NULL; 1858 smwr = NULL; 1859 sg = NULL; 1860 ret = 0; 1861 1862 /* 1863 * Free_unr() may sleep, so store released syncgroup IDs until after 1864 * all locks are released. 1865 */ 1866 sg_ids[0] = sg_ids[1] = sg_ids[2] = 0; 1867 1868 PCM_SG_LOCK(); 1869 1870 /* 1871 * - Insert channel(s) into group's member list. 1872 * - Set CHN_F_NOTRIGGER on channel(s). 1873 * - Stop channel(s). 1874 */ 1875 1876 /* 1877 * If device's channels are already mapped to a group, unmap them. 1878 */ 1879 if (wrch) { 1880 CHN_LOCK(wrch); 1881 sg_ids[0] = chn_syncdestroy(wrch); 1882 } 1883 1884 if (rdch) { 1885 CHN_LOCK(rdch); 1886 sg_ids[1] = chn_syncdestroy(rdch); 1887 } 1888 1889 /* 1890 * Verify that mode matches character device properites. 1891 * - Bail if PCM_ENABLE_OUTPUT && wrch == NULL. 1892 * - Bail if PCM_ENABLE_INPUT && rdch == NULL. 1893 */ 1894 if (((wrch == NULL) && (group->mode & PCM_ENABLE_OUTPUT)) || 1895 ((rdch == NULL) && (group->mode & PCM_ENABLE_INPUT))) { 1896 ret = EINVAL; 1897 goto out; 1898 } 1899 1900 /* 1901 * An id of zero indicates the user wants to create a new 1902 * syncgroup. 1903 */ 1904 if (group->id == 0) { 1905 sg = (struct pcmchan_syncgroup *)malloc(sizeof(*sg), M_DEVBUF, M_NOWAIT); 1906 if (sg != NULL) { 1907 SLIST_INIT(&sg->members); 1908 sg->id = alloc_unr(pcmsg_unrhdr); 1909 1910 group->id = sg->id; 1911 SLIST_INSERT_HEAD(&snd_pcm_syncgroups, sg, link); 1912 } else 1913 ret = ENOMEM; 1914 } else { 1915 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) { 1916 if (sg->id == group->id) 1917 break; 1918 } 1919 if (sg == NULL) 1920 ret = EINVAL; 1921 } 1922 1923 /* Couldn't create or find a syncgroup. Fail. */ 1924 if (sg == NULL) 1925 goto out; 1926 1927 /* 1928 * Allocate a syncmember, assign it and a channel together, and 1929 * insert into syncgroup. 1930 */ 1931 if (group->mode & PCM_ENABLE_INPUT) { 1932 smrd = (struct pcmchan_syncmember *)malloc(sizeof(*smrd), M_DEVBUF, M_NOWAIT); 1933 if (smrd == NULL) { 1934 ret = ENOMEM; 1935 goto out; 1936 } 1937 1938 SLIST_INSERT_HEAD(&sg->members, smrd, link); 1939 smrd->parent = sg; 1940 smrd->ch = rdch; 1941 1942 chn_abort(rdch); 1943 rdch->flags |= CHN_F_NOTRIGGER; 1944 rdch->sm = smrd; 1945 } 1946 1947 if (group->mode & PCM_ENABLE_OUTPUT) { 1948 smwr = (struct pcmchan_syncmember *)malloc(sizeof(*smwr), M_DEVBUF, M_NOWAIT); 1949 if (smwr == NULL) { 1950 ret = ENOMEM; 1951 goto out; 1952 } 1953 1954 SLIST_INSERT_HEAD(&sg->members, smwr, link); 1955 smwr->parent = sg; 1956 smwr->ch = wrch; 1957 1958 chn_abort(wrch); 1959 wrch->flags |= CHN_F_NOTRIGGER; 1960 wrch->sm = smwr; 1961 } 1962 1963 1964 out: 1965 if (ret != 0) { 1966 if (smrd != NULL) 1967 free(smrd, M_DEVBUF); 1968 if ((sg != NULL) && SLIST_EMPTY(&sg->members)) { 1969 sg_ids[2] = sg->id; 1970 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link); 1971 free(sg, M_DEVBUF); 1972 } 1973 1974 if (wrch) 1975 wrch->sm = NULL; 1976 if (rdch) 1977 rdch->sm = NULL; 1978 } 1979 1980 if (wrch) 1981 CHN_UNLOCK(wrch); 1982 if (rdch) 1983 CHN_UNLOCK(rdch); 1984 1985 PCM_SG_UNLOCK(); 1986 1987 if (sg_ids[0]) 1988 free_unr(pcmsg_unrhdr, sg_ids[0]); 1989 if (sg_ids[1]) 1990 free_unr(pcmsg_unrhdr, sg_ids[1]); 1991 if (sg_ids[2]) 1992 free_unr(pcmsg_unrhdr, sg_ids[2]); 1993 1994 return ret; 1995 } 1996 1997 /** 1998 * @brief Launch a sync group into action 1999 * 2000 * Sync groups are established via SNDCTL_DSP_SYNCGROUP. This function 2001 * iterates over all members, triggering them along the way. 2002 * 2003 * @note Caller must not hold any channel locks. 2004 * 2005 * @param sg_id sync group identifier 2006 * 2007 * @retval 0 success 2008 * @retval non-zero error worthy of propagating upstream to user 2009 */ 2010 static int 2011 dsp_oss_syncstart(int sg_id) 2012 { 2013 struct pcmchan_syncmember *sm, *sm_tmp; 2014 struct pcmchan_syncgroup *sg; 2015 struct pcm_channel *c; 2016 int ret, needlocks; 2017 2018 /* Get the synclists lock */ 2019 PCM_SG_LOCK(); 2020 2021 do { 2022 ret = 0; 2023 needlocks = 0; 2024 2025 /* Search for syncgroup by ID */ 2026 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) { 2027 if (sg->id == sg_id) 2028 break; 2029 } 2030 2031 /* Return EINVAL if not found */ 2032 if (sg == NULL) { 2033 ret = EINVAL; 2034 break; 2035 } 2036 2037 /* Any removals resulting in an empty group should've handled this */ 2038 KASSERT(!SLIST_EMPTY(&sg->members), ("found empty syncgroup")); 2039 2040 /* 2041 * Attempt to lock all member channels - if any are already 2042 * locked, unlock those acquired, sleep for a bit, and try 2043 * again. 2044 */ 2045 SLIST_FOREACH(sm, &sg->members, link) { 2046 if (CHN_TRYLOCK(sm->ch) == 0) { 2047 int timo = hz * 5/1000; 2048 if (timo < 1) 2049 timo = 1; 2050 2051 /* Release all locked channels so far, retry */ 2052 SLIST_FOREACH(sm_tmp, &sg->members, link) { 2053 /* sm is the member already locked */ 2054 if (sm == sm_tmp) 2055 break; 2056 CHN_UNLOCK(sm_tmp->ch); 2057 } 2058 2059 /** @todo Is PRIBIO correct/ */ 2060 ret = msleep(sm, &snd_pcm_syncgroups_mtx, PRIBIO | PCATCH, "pcmsgrp", timo); 2061 if (ret == EINTR || ret == ERESTART) 2062 break; 2063 2064 needlocks = 1; 2065 ret = 0; /* Assumes ret == EWOULDBLOCK... */ 2066 } 2067 } 2068 } while (needlocks && ret == 0); 2069 2070 /* Proceed only if no errors encountered. */ 2071 if (ret == 0) { 2072 /* Launch channels */ 2073 while((sm = SLIST_FIRST(&sg->members)) != NULL) { 2074 SLIST_REMOVE_HEAD(&sg->members, link); 2075 2076 c = sm->ch; 2077 c->sm = NULL; 2078 chn_start(c, 1); 2079 c->flags &= ~CHN_F_NOTRIGGER; 2080 CHN_UNLOCK(c); 2081 2082 free(sm, M_DEVBUF); 2083 } 2084 2085 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link); 2086 free(sg, M_DEVBUF); 2087 } 2088 2089 PCM_SG_UNLOCK(); 2090 2091 /* 2092 * Free_unr() may sleep, so be sure to give up the syncgroup lock 2093 * first. 2094 */ 2095 if (ret == 0) 2096 free_unr(pcmsg_unrhdr, sg_id); 2097 2098 return ret; 2099 } 2100 2101 /** 2102 * @brief Handler for SNDCTL_DSP_POLICY 2103 * 2104 * The SNDCTL_DSP_POLICY ioctl is a simpler interface to control fragment 2105 * size and count like with SNDCTL_DSP_SETFRAGMENT. Instead of the user 2106 * specifying those two parameters, s/he simply selects a number from 0..10 2107 * which corresponds to a buffer size. Smaller numbers request smaller 2108 * buffers with lower latencies (at greater overhead from more frequent 2109 * interrupts), while greater numbers behave in the opposite manner. 2110 * 2111 * The 4Front spec states that a value of 5 should be the default. However, 2112 * this implementation deviates slightly by using a linear scale without 2113 * consulting drivers. I.e., even though drivers may have different default 2114 * buffer sizes, a policy argument of 5 will have the same result across 2115 * all drivers. 2116 * 2117 * See http://manuals.opensound.com/developer/SNDCTL_DSP_POLICY.html for 2118 * more information. 2119 * 2120 * @todo When SNDCTL_DSP_COOKEDMODE is supported, it'll be necessary to 2121 * work with hardware drivers directly. 2122 * 2123 * @note PCM channel arguments must not be locked by caller. 2124 * 2125 * @param wrch Pointer to opened playback channel (optional; may be NULL) 2126 * @param rdch " recording channel (optional; may be NULL) 2127 * @param policy Integer from [0:10] 2128 * 2129 * @retval 0 constant (for now) 2130 */ 2131 static int 2132 dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy) 2133 { 2134 int fragln, fragsz, maxfrags, ret; 2135 2136 /* Default: success */ 2137 ret = 0; 2138 2139 /* Scale policy [0..10] to fragment size [2^4..2^16]. */ 2140 fragln = policy; 2141 RANGE(fragln, 0, 10); 2142 fragln += 4; 2143 fragsz = 1 << fragln; 2144 2145 maxfrags = CHN_2NDBUFMAXSIZE / fragsz; 2146 2147 if (rdch) { 2148 CHN_LOCK(rdch); 2149 ret = chn_setblocksize(rdch, maxfrags, fragsz); 2150 CHN_UNLOCK(rdch); 2151 } 2152 2153 if (wrch && ret == 0) { 2154 CHN_LOCK(wrch); 2155 ret = chn_setblocksize(wrch, maxfrags, fragsz); 2156 CHN_UNLOCK(wrch); 2157 } 2158 2159 return ret; 2160 } 2161 2162 #ifdef OSSV4_EXPERIMENT 2163 /** 2164 * @brief Enable or disable "cooked" mode 2165 * 2166 * This is a handler for @c SNDCTL_DSP_COOKEDMODE. When in cooked mode, which 2167 * is the default, the sound system handles rate and format conversions 2168 * automatically (ex: user writing 11025Hz/8 bit/unsigned but card only 2169 * operates with 44100Hz/16bit/signed samples). 2170 * 2171 * Disabling cooked mode is intended for applications wanting to mmap() 2172 * a sound card's buffer space directly, bypassing the FreeBSD 2-stage 2173 * feeder architecture, presumably to gain as much control over audio 2174 * hardware as possible. 2175 * 2176 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_COOKEDMODE.html 2177 * for more details. 2178 * 2179 * @note Currently, this function is just a stub that always returns EINVAL. 2180 * 2181 * @todo Figure out how to and actually implement this. 2182 * 2183 * @param wrch playback channel (optional; may be NULL) 2184 * @param rdch recording channel (optional; may be NULL) 2185 * @param enabled 0 = raw mode, 1 = cooked mode 2186 * 2187 * @retval EINVAL Operation not yet supported. 2188 */ 2189 static int 2190 dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled) 2191 { 2192 return EINVAL; 2193 } 2194 2195 /** 2196 * @brief Retrieve channel interleaving order 2197 * 2198 * This is the handler for @c SNDCTL_DSP_GET_CHNORDER. 2199 * 2200 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_GET_CHNORDER.html 2201 * for more details. 2202 * 2203 * @note As the ioctl definition is still under construction, FreeBSD 2204 * does not currently support SNDCTL_DSP_GET_CHNORDER. 2205 * 2206 * @param wrch playback channel (optional; may be NULL) 2207 * @param rdch recording channel (optional; may be NULL) 2208 * @param map channel map (result will be stored there) 2209 * 2210 * @retval EINVAL Operation not yet supported. 2211 */ 2212 static int 2213 dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map) 2214 { 2215 return EINVAL; 2216 } 2217 2218 /** 2219 * @brief Specify channel interleaving order 2220 * 2221 * This is the handler for @c SNDCTL_DSP_SET_CHNORDER. 2222 * 2223 * @note As the ioctl definition is still under construction, FreeBSD 2224 * does not currently support @c SNDCTL_DSP_SET_CHNORDER. 2225 * 2226 * @param wrch playback channel (optional; may be NULL) 2227 * @param rdch recording channel (optional; may be NULL) 2228 * @param map channel map 2229 * 2230 * @retval EINVAL Operation not yet supported. 2231 */ 2232 static int 2233 dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map) 2234 { 2235 return EINVAL; 2236 } 2237 2238 /** 2239 * @brief Retrieve an audio device's label 2240 * 2241 * This is a handler for the @c SNDCTL_GETLABEL ioctl. 2242 * 2243 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html 2244 * for more details. 2245 * 2246 * From Hannu@4Front: "For example ossxmix (just like some HW mixer 2247 * consoles) can show variable "labels" for certain controls. By default 2248 * the application name (say quake) is shown as the label but 2249 * applications may change the labels themselves." 2250 * 2251 * @note As the ioctl definition is still under construction, FreeBSD 2252 * does not currently support @c SNDCTL_GETLABEL. 2253 * 2254 * @param wrch playback channel (optional; may be NULL) 2255 * @param rdch recording channel (optional; may be NULL) 2256 * @param label label gets copied here 2257 * 2258 * @retval EINVAL Operation not yet supported. 2259 */ 2260 static int 2261 dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label) 2262 { 2263 return EINVAL; 2264 } 2265 2266 /** 2267 * @brief Specify an audio device's label 2268 * 2269 * This is a handler for the @c SNDCTL_SETLABEL ioctl. Please see the 2270 * comments for @c dsp_oss_getlabel immediately above. 2271 * 2272 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html 2273 * for more details. 2274 * 2275 * @note As the ioctl definition is still under construction, FreeBSD 2276 * does not currently support SNDCTL_SETLABEL. 2277 * 2278 * @param wrch playback channel (optional; may be NULL) 2279 * @param rdch recording channel (optional; may be NULL) 2280 * @param label label gets copied from here 2281 * 2282 * @retval EINVAL Operation not yet supported. 2283 */ 2284 static int 2285 dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label) 2286 { 2287 return EINVAL; 2288 } 2289 2290 /** 2291 * @brief Retrieve name of currently played song 2292 * 2293 * This is a handler for the @c SNDCTL_GETSONG ioctl. Audio players could 2294 * tell the system the name of the currently playing song, which would be 2295 * visible in @c /dev/sndstat. 2296 * 2297 * See @c http://manuals.opensound.com/developer/SNDCTL_GETSONG.html 2298 * for more details. 2299 * 2300 * @note As the ioctl definition is still under construction, FreeBSD 2301 * does not currently support SNDCTL_GETSONG. 2302 * 2303 * @param wrch playback channel (optional; may be NULL) 2304 * @param rdch recording channel (optional; may be NULL) 2305 * @param song song name gets copied here 2306 * 2307 * @retval EINVAL Operation not yet supported. 2308 */ 2309 static int 2310 dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song) 2311 { 2312 return EINVAL; 2313 } 2314 2315 /** 2316 * @brief Retrieve name of currently played song 2317 * 2318 * This is a handler for the @c SNDCTL_SETSONG ioctl. Audio players could 2319 * tell the system the name of the currently playing song, which would be 2320 * visible in @c /dev/sndstat. 2321 * 2322 * See @c http://manuals.opensound.com/developer/SNDCTL_SETSONG.html 2323 * for more details. 2324 * 2325 * @note As the ioctl definition is still under construction, FreeBSD 2326 * does not currently support SNDCTL_SETSONG. 2327 * 2328 * @param wrch playback channel (optional; may be NULL) 2329 * @param rdch recording channel (optional; may be NULL) 2330 * @param song song name gets copied from here 2331 * 2332 * @retval EINVAL Operation not yet supported. 2333 */ 2334 static int 2335 dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song) 2336 { 2337 return EINVAL; 2338 } 2339 2340 /** 2341 * @brief Rename a device 2342 * 2343 * This is a handler for the @c SNDCTL_SETNAME ioctl. 2344 * 2345 * See @c http://manuals.opensound.com/developer/SNDCTL_SETNAME.html for 2346 * more details. 2347 * 2348 * From Hannu@4Front: "This call is used to change the device name 2349 * reported in /dev/sndstat and ossinfo. So instead of using some generic 2350 * 'OSS loopback audio (MIDI) driver' the device may be given a meaningfull 2351 * name depending on the current context (for example 'OSS virtual wave table 2352 * synth' or 'VoIP link to London')." 2353 * 2354 * @note As the ioctl definition is still under construction, FreeBSD 2355 * does not currently support SNDCTL_SETNAME. 2356 * 2357 * @param wrch playback channel (optional; may be NULL) 2358 * @param rdch recording channel (optional; may be NULL) 2359 * @param name new device name gets copied from here 2360 * 2361 * @retval EINVAL Operation not yet supported. 2362 */ 2363 static int 2364 dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name) 2365 { 2366 return EINVAL; 2367 } 2368 #endif /* !OSSV4_EXPERIMENT */ 2369