1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org> 5 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006 6 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org> 7 * All rights reserved. 8 * Copyright (c) 2024 The FreeBSD Foundation 9 * 10 * Portions of this software were developed by Christos Margiolis 11 * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #ifdef HAVE_KERNEL_OPTION_HEADERS 36 #include "opt_snd.h" 37 #endif 38 39 #include <dev/sound/pcm/sound.h> 40 #include <sys/ctype.h> 41 #include <sys/lock.h> 42 #include <sys/rwlock.h> 43 #include <sys/sysent.h> 44 45 #include <vm/vm.h> 46 #include <vm/vm_object.h> 47 #include <vm/vm_page.h> 48 #include <vm/vm_pager.h> 49 50 struct dsp_cdevpriv { 51 struct snddev_info *sc; 52 struct pcm_channel *rdch; 53 struct pcm_channel *wrch; 54 struct pcm_channel *volch; 55 int simplex; 56 }; 57 58 static int dsp_mmap_allow_prot_exec = 0; 59 SYSCTL_INT(_hw_snd, OID_AUTO, compat_linux_mmap, CTLFLAG_RWTUN, 60 &dsp_mmap_allow_prot_exec, 0, 61 "linux mmap compatibility (-1=force disable 0=auto 1=force enable)"); 62 63 static int dsp_basename_clone = 1; 64 SYSCTL_INT(_hw_snd, OID_AUTO, basename_clone, CTLFLAG_RWTUN, 65 &dsp_basename_clone, 0, 66 "DSP basename cloning (0: Disable; 1: Enabled)"); 67 68 #define DSP_REGISTERED(x) (PCM_REGISTERED(x) && (x)->dsp_dev != NULL) 69 70 #define OLDPCM_IOCTL 71 72 static d_open_t dsp_open; 73 static d_read_t dsp_read; 74 static d_write_t dsp_write; 75 static d_ioctl_t dsp_ioctl; 76 static d_poll_t dsp_poll; 77 static d_mmap_t dsp_mmap; 78 static d_mmap_single_t dsp_mmap_single; 79 80 struct cdevsw dsp_cdevsw = { 81 .d_version = D_VERSION, 82 .d_open = dsp_open, 83 .d_read = dsp_read, 84 .d_write = dsp_write, 85 .d_ioctl = dsp_ioctl, 86 .d_poll = dsp_poll, 87 .d_mmap = dsp_mmap, 88 .d_mmap_single = dsp_mmap_single, 89 .d_name = "dsp", 90 }; 91 92 static eventhandler_tag dsp_ehtag = NULL; 93 94 static int dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group); 95 static int dsp_oss_syncstart(int sg_id); 96 static int dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy); 97 static int dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled); 98 static int dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map); 99 static int dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map); 100 static int dsp_oss_getchannelmask(struct pcm_channel *wrch, struct pcm_channel *rdch, int *mask); 101 #ifdef OSSV4_EXPERIMENT 102 static int dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label); 103 static int dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label); 104 static int dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song); 105 static int dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song); 106 static int dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name); 107 #endif 108 109 int 110 dsp_make_dev(device_t dev) 111 { 112 struct make_dev_args devargs; 113 struct snddev_info *sc; 114 int err, unit; 115 116 sc = device_get_softc(dev); 117 unit = device_get_unit(dev); 118 119 make_dev_args_init(&devargs); 120 devargs.mda_devsw = &dsp_cdevsw; 121 devargs.mda_uid = UID_ROOT; 122 devargs.mda_gid = GID_WHEEL; 123 devargs.mda_mode = 0666; 124 devargs.mda_si_drv1 = sc; 125 err = make_dev_s(&devargs, &sc->dsp_dev, "dsp%d", unit); 126 if (err != 0) { 127 device_printf(dev, "failed to create dsp%d: error %d", 128 unit, err); 129 return (ENXIO); 130 } 131 132 return (0); 133 } 134 135 void 136 dsp_destroy_dev(device_t dev) 137 { 138 struct snddev_info *d; 139 140 d = device_get_softc(dev); 141 destroy_dev_sched(d->dsp_dev); 142 } 143 144 static void 145 getchns(struct dsp_cdevpriv *priv, uint32_t prio) 146 { 147 struct snddev_info *d; 148 struct pcm_channel *ch; 149 uint32_t flags; 150 151 if (priv->simplex) { 152 d = priv->sc; 153 if (!PCM_REGISTERED(d)) 154 return; 155 PCM_LOCK(d); 156 PCM_WAIT(d); 157 PCM_ACQUIRE(d); 158 /* 159 * Note: order is important - 160 * pcm flags -> prio query flags -> wild guess 161 */ 162 ch = NULL; 163 flags = pcm_getflags(d->dev); 164 if (flags & SD_F_PRIO_WR) { 165 ch = priv->rdch; 166 } else if (flags & SD_F_PRIO_RD) { 167 ch = priv->wrch; 168 } else if (prio & SD_F_PRIO_WR) { 169 ch = priv->rdch; 170 flags |= SD_F_PRIO_WR; 171 } else if (prio & SD_F_PRIO_RD) { 172 ch = priv->wrch; 173 flags |= SD_F_PRIO_RD; 174 } else if (priv->wrch != NULL) { 175 ch = priv->rdch; 176 flags |= SD_F_PRIO_WR; 177 } else if (priv->rdch != NULL) { 178 ch = priv->wrch; 179 flags |= SD_F_PRIO_RD; 180 } 181 pcm_setflags(d->dev, flags); 182 if (ch != NULL) { 183 CHN_LOCK(ch); 184 chn_ref(ch, -1); 185 chn_release(ch); 186 } 187 PCM_RELEASE(d); 188 PCM_UNLOCK(d); 189 } 190 191 if (priv->rdch != NULL && (prio & SD_F_PRIO_RD)) 192 CHN_LOCK(priv->rdch); 193 if (priv->wrch != NULL && (prio & SD_F_PRIO_WR)) 194 CHN_LOCK(priv->wrch); 195 } 196 197 static void 198 relchns(struct dsp_cdevpriv *priv, uint32_t prio) 199 { 200 if (priv->rdch != NULL && (prio & SD_F_PRIO_RD)) 201 CHN_UNLOCK(priv->rdch); 202 if (priv->wrch != NULL && (prio & SD_F_PRIO_WR)) 203 CHN_UNLOCK(priv->wrch); 204 } 205 206 #define DSP_F_VALID(x) ((x) & (FREAD | FWRITE)) 207 #define DSP_F_DUPLEX(x) (((x) & (FREAD | FWRITE)) == (FREAD | FWRITE)) 208 #define DSP_F_SIMPLEX(x) (!DSP_F_DUPLEX(x)) 209 #define DSP_F_READ(x) ((x) & FREAD) 210 #define DSP_F_WRITE(x) ((x) & FWRITE) 211 212 static const struct { 213 int type; 214 char *name; 215 char *sep; 216 char *alias; 217 } dsp_cdevs[] = { 218 { SND_DEV_DSP, "dsp", ".", NULL }, 219 { SND_DEV_DSPHW_PLAY, "dsp", ".p", NULL }, 220 { SND_DEV_DSPHW_VPLAY, "dsp", ".vp", NULL }, 221 { SND_DEV_DSPHW_REC, "dsp", ".r", NULL }, 222 { SND_DEV_DSPHW_VREC, "dsp", ".vr", NULL }, 223 /* Low priority, OSSv4 aliases. */ 224 { SND_DEV_DSP, "dsp_ac3", ".", "dsp" }, 225 { SND_DEV_DSP, "dsp_mmap", ".", "dsp" }, 226 { SND_DEV_DSP, "dsp_multich", ".", "dsp" }, 227 { SND_DEV_DSP, "dsp_spdifout", ".", "dsp" }, 228 { SND_DEV_DSP, "dsp_spdifin", ".", "dsp" }, 229 }; 230 231 static void 232 dsp_close(void *data) 233 { 234 struct dsp_cdevpriv *priv = data; 235 struct pcm_channel *rdch, *wrch, *volch; 236 struct snddev_info *d; 237 int sg_ids, rdref, wdref; 238 239 if (priv == NULL) 240 return; 241 242 d = priv->sc; 243 /* At this point pcm_unregister() will destroy all channels anyway. */ 244 if (PCM_DETACHING(d)) 245 goto skip; 246 247 PCM_GIANT_ENTER(d); 248 249 PCM_LOCK(d); 250 PCM_WAIT(d); 251 PCM_ACQUIRE(d); 252 253 rdch = priv->rdch; 254 wrch = priv->wrch; 255 volch = priv->volch; 256 257 rdref = -1; 258 wdref = -1; 259 260 if (volch != NULL) { 261 if (volch == rdch) 262 rdref--; 263 else if (volch == wrch) 264 wdref--; 265 else { 266 CHN_LOCK(volch); 267 chn_ref(volch, -1); 268 CHN_UNLOCK(volch); 269 } 270 } 271 272 if (rdch != NULL) 273 CHN_REMOVE(d, rdch, channels.pcm.opened); 274 if (wrch != NULL) 275 CHN_REMOVE(d, wrch, channels.pcm.opened); 276 277 if (rdch != NULL || wrch != NULL) { 278 PCM_UNLOCK(d); 279 if (rdch != NULL) { 280 /* 281 * The channel itself need not be locked because: 282 * a) Adding a channel to a syncgroup happens only 283 * in dsp_ioctl(), which cannot run concurrently 284 * to dsp_close(). 285 * b) The syncmember pointer (sm) is protected by 286 * the global syncgroup list lock. 287 * c) A channel can't just disappear, invalidating 288 * pointers, unless it's closed/dereferenced 289 * first. 290 */ 291 PCM_SG_LOCK(); 292 sg_ids = chn_syncdestroy(rdch); 293 PCM_SG_UNLOCK(); 294 if (sg_ids != 0) 295 free_unr(pcmsg_unrhdr, sg_ids); 296 297 CHN_LOCK(rdch); 298 chn_ref(rdch, rdref); 299 chn_abort(rdch); /* won't sleep */ 300 rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP | 301 CHN_F_DEAD | CHN_F_EXCLUSIVE); 302 chn_reset(rdch, 0, 0); 303 chn_release(rdch); 304 } 305 if (wrch != NULL) { 306 /* 307 * Please see block above. 308 */ 309 PCM_SG_LOCK(); 310 sg_ids = chn_syncdestroy(wrch); 311 PCM_SG_UNLOCK(); 312 if (sg_ids != 0) 313 free_unr(pcmsg_unrhdr, sg_ids); 314 315 CHN_LOCK(wrch); 316 chn_ref(wrch, wdref); 317 chn_flush(wrch); /* may sleep */ 318 wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP | 319 CHN_F_DEAD | CHN_F_EXCLUSIVE); 320 chn_reset(wrch, 0, 0); 321 chn_release(wrch); 322 } 323 PCM_LOCK(d); 324 } 325 326 PCM_RELEASE(d); 327 PCM_UNLOCK(d); 328 329 PCM_GIANT_LEAVE(d); 330 skip: 331 free(priv, M_DEVBUF); 332 priv = NULL; 333 } 334 335 #define DSP_FIXUP_ERROR() do { \ 336 prio = pcm_getflags(d->dev); \ 337 if (!DSP_F_VALID(flags)) \ 338 error = EINVAL; \ 339 if (!DSP_F_DUPLEX(flags) && \ 340 ((DSP_F_READ(flags) && d->reccount == 0) || \ 341 (DSP_F_WRITE(flags) && d->playcount == 0))) \ 342 error = ENOTSUP; \ 343 else if (!DSP_F_DUPLEX(flags) && (prio & SD_F_SIMPLEX) && \ 344 ((DSP_F_READ(flags) && (prio & SD_F_PRIO_WR)) || \ 345 (DSP_F_WRITE(flags) && (prio & SD_F_PRIO_RD)))) \ 346 error = EBUSY; \ 347 } while (0) 348 349 static int 350 dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 351 { 352 struct dsp_cdevpriv *priv; 353 struct pcm_channel *rdch, *wrch; 354 struct snddev_info *d; 355 uint32_t fmt, spd, prio; 356 int error, rderror, wrerror; 357 358 /* Kind of impossible.. */ 359 if (i_dev == NULL || td == NULL) 360 return (ENODEV); 361 362 d = i_dev->si_drv1; 363 if (PCM_DETACHING(d) || !PCM_REGISTERED(d)) 364 return (EBADF); 365 366 priv = malloc(sizeof(*priv), M_DEVBUF, M_WAITOK | M_ZERO); 367 priv->sc = d; 368 priv->rdch = NULL; 369 priv->wrch = NULL; 370 priv->volch = NULL; 371 priv->simplex = (pcm_getflags(d->dev) & SD_F_SIMPLEX) ? 1 : 0; 372 373 error = devfs_set_cdevpriv(priv, dsp_close); 374 if (error != 0) 375 return (error); 376 377 PCM_GIANT_ENTER(d); 378 379 /* Lock snddev so nobody else can monkey with it. */ 380 PCM_LOCK(d); 381 PCM_WAIT(d); 382 383 error = 0; 384 DSP_FIXUP_ERROR(); 385 if (error != 0) { 386 PCM_UNLOCK(d); 387 PCM_GIANT_EXIT(d); 388 return (error); 389 } 390 391 /* 392 * That is just enough. Acquire and unlock pcm lock so 393 * the other will just have to wait until we finish doing 394 * everything. 395 */ 396 PCM_ACQUIRE(d); 397 PCM_UNLOCK(d); 398 399 fmt = SND_FORMAT(AFMT_U8, 1, 0); 400 spd = DSP_DEFAULT_SPEED; 401 402 rdch = NULL; 403 wrch = NULL; 404 rderror = 0; 405 wrerror = 0; 406 407 if (DSP_F_READ(flags)) { 408 /* open for read */ 409 rderror = pcm_chnalloc(d, &rdch, PCMDIR_REC, 410 td->td_proc->p_pid, td->td_proc->p_comm); 411 412 if (rderror == 0 && chn_reset(rdch, fmt, spd) != 0) 413 rderror = ENXIO; 414 415 if (rderror != 0) { 416 if (rdch != NULL) 417 chn_release(rdch); 418 if (!DSP_F_DUPLEX(flags)) { 419 PCM_RELEASE_QUICK(d); 420 PCM_GIANT_EXIT(d); 421 return (rderror); 422 } 423 rdch = NULL; 424 } else { 425 if (flags & O_NONBLOCK) 426 rdch->flags |= CHN_F_NBIO; 427 if (flags & O_EXCL) 428 rdch->flags |= CHN_F_EXCLUSIVE; 429 chn_ref(rdch, 1); 430 chn_vpc_reset(rdch, SND_VOL_C_PCM, 0); 431 CHN_UNLOCK(rdch); 432 } 433 } 434 435 if (DSP_F_WRITE(flags)) { 436 /* open for write */ 437 wrerror = pcm_chnalloc(d, &wrch, PCMDIR_PLAY, 438 td->td_proc->p_pid, td->td_proc->p_comm); 439 440 if (wrerror == 0 && chn_reset(wrch, fmt, spd) != 0) 441 wrerror = ENXIO; 442 443 if (wrerror != 0) { 444 if (wrch != NULL) 445 chn_release(wrch); 446 if (!DSP_F_DUPLEX(flags)) { 447 if (rdch != NULL) { 448 /* 449 * Lock, deref and release previously 450 * created record channel 451 */ 452 CHN_LOCK(rdch); 453 chn_ref(rdch, -1); 454 chn_release(rdch); 455 } 456 PCM_RELEASE_QUICK(d); 457 PCM_GIANT_EXIT(d); 458 return (wrerror); 459 } 460 wrch = NULL; 461 } else { 462 if (flags & O_NONBLOCK) 463 wrch->flags |= CHN_F_NBIO; 464 if (flags & O_EXCL) 465 wrch->flags |= CHN_F_EXCLUSIVE; 466 chn_ref(wrch, 1); 467 chn_vpc_reset(wrch, SND_VOL_C_PCM, 0); 468 CHN_UNLOCK(wrch); 469 } 470 } 471 472 PCM_LOCK(d); 473 474 if (wrch == NULL && rdch == NULL) { 475 PCM_RELEASE(d); 476 PCM_UNLOCK(d); 477 PCM_GIANT_EXIT(d); 478 if (wrerror != 0) 479 return (wrerror); 480 if (rderror != 0) 481 return (rderror); 482 return (EINVAL); 483 } 484 if (rdch != NULL) 485 CHN_INSERT_HEAD(d, rdch, channels.pcm.opened); 486 if (wrch != NULL) 487 CHN_INSERT_HEAD(d, wrch, channels.pcm.opened); 488 priv->rdch = rdch; 489 priv->wrch = wrch; 490 491 PCM_RELEASE(d); 492 PCM_UNLOCK(d); 493 494 PCM_GIANT_LEAVE(d); 495 496 return (0); 497 } 498 499 static __inline int 500 dsp_io_ops(struct dsp_cdevpriv *priv, struct uio *buf) 501 { 502 struct snddev_info *d; 503 struct pcm_channel **ch; 504 int (*chn_io)(struct pcm_channel *, struct uio *); 505 int prio, ret; 506 pid_t runpid; 507 508 KASSERT(buf != NULL && 509 (buf->uio_rw == UIO_READ || buf->uio_rw == UIO_WRITE), 510 ("%s(): io train wreck!", __func__)); 511 512 d = priv->sc; 513 if (PCM_DETACHING(d) || !DSP_REGISTERED(d)) 514 return (EBADF); 515 516 PCM_GIANT_ENTER(d); 517 518 switch (buf->uio_rw) { 519 case UIO_READ: 520 prio = SD_F_PRIO_RD; 521 ch = &priv->rdch; 522 chn_io = chn_read; 523 break; 524 case UIO_WRITE: 525 prio = SD_F_PRIO_WR; 526 ch = &priv->wrch; 527 chn_io = chn_write; 528 break; 529 default: 530 panic("invalid/corrupted uio direction: %d", buf->uio_rw); 531 break; 532 } 533 534 runpid = buf->uio_td->td_proc->p_pid; 535 536 getchns(priv, prio); 537 538 if (*ch == NULL || !((*ch)->flags & CHN_F_BUSY)) { 539 if (priv->rdch != NULL || priv->wrch != NULL) 540 relchns(priv, prio); 541 PCM_GIANT_EXIT(d); 542 return (EBADF); 543 } 544 545 if (((*ch)->flags & (CHN_F_MMAP | CHN_F_DEAD)) || 546 (((*ch)->flags & CHN_F_RUNNING) && (*ch)->pid != runpid)) { 547 relchns(priv, prio); 548 PCM_GIANT_EXIT(d); 549 return (EINVAL); 550 } else if (!((*ch)->flags & CHN_F_RUNNING)) { 551 (*ch)->flags |= CHN_F_RUNNING; 552 (*ch)->pid = runpid; 553 } 554 555 /* 556 * chn_read/write must give up channel lock in order to copy bytes 557 * from/to userland, so up the "in progress" counter to make sure 558 * someone else doesn't come along and muss up the buffer. 559 */ 560 ++(*ch)->inprog; 561 ret = chn_io(*ch, buf); 562 --(*ch)->inprog; 563 564 CHN_BROADCAST(&(*ch)->cv); 565 566 relchns(priv, prio); 567 568 PCM_GIANT_LEAVE(d); 569 570 return (ret); 571 } 572 573 static int 574 dsp_read(struct cdev *i_dev, struct uio *buf, int flag) 575 { 576 struct dsp_cdevpriv *priv; 577 int err; 578 579 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0) 580 return (err); 581 return (dsp_io_ops(priv, buf)); 582 } 583 584 static int 585 dsp_write(struct cdev *i_dev, struct uio *buf, int flag) 586 { 587 struct dsp_cdevpriv *priv; 588 int err; 589 590 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0) 591 return (err); 592 return (dsp_io_ops(priv, buf)); 593 } 594 595 static int 596 dsp_ioctl_channel(struct dsp_cdevpriv *priv, struct pcm_channel *volch, 597 u_long cmd, caddr_t arg) 598 { 599 struct snddev_info *d; 600 struct pcm_channel *rdch, *wrch; 601 int j, left, right, center, mute; 602 603 d = priv->sc; 604 if (!PCM_REGISTERED(d) || !(pcm_getflags(d->dev) & SD_F_VPC)) 605 return (-1); 606 607 PCM_UNLOCKASSERT(d); 608 609 j = cmd & 0xff; 610 611 rdch = priv->rdch; 612 wrch = priv->wrch; 613 614 /* No specific channel, look into cache */ 615 if (volch == NULL) 616 volch = priv->volch; 617 618 /* Look harder */ 619 if (volch == NULL) { 620 if (j == SOUND_MIXER_RECLEV && rdch != NULL) 621 volch = rdch; 622 else if (j == SOUND_MIXER_PCM && wrch != NULL) 623 volch = wrch; 624 } 625 626 /* Final validation */ 627 if (volch == NULL) 628 return (EINVAL); 629 630 CHN_LOCK(volch); 631 if (!(volch->feederflags & (1 << FEEDER_VOLUME))) { 632 CHN_UNLOCK(volch); 633 return (EINVAL); 634 } 635 636 switch (cmd & ~0xff) { 637 case MIXER_WRITE(0): 638 switch (j) { 639 case SOUND_MIXER_MUTE: 640 if (volch->direction == PCMDIR_REC) { 641 chn_setmute_multi(volch, SND_VOL_C_PCM, (*(int *)arg & SOUND_MASK_RECLEV) != 0); 642 } else { 643 chn_setmute_multi(volch, SND_VOL_C_PCM, (*(int *)arg & SOUND_MASK_PCM) != 0); 644 } 645 break; 646 case SOUND_MIXER_PCM: 647 if (volch->direction != PCMDIR_PLAY) 648 break; 649 left = *(int *)arg & 0x7f; 650 right = ((*(int *)arg) >> 8) & 0x7f; 651 center = (left + right) >> 1; 652 chn_setvolume_multi(volch, SND_VOL_C_PCM, 653 left, right, center); 654 break; 655 case SOUND_MIXER_RECLEV: 656 if (volch->direction != PCMDIR_REC) 657 break; 658 left = *(int *)arg & 0x7f; 659 right = ((*(int *)arg) >> 8) & 0x7f; 660 center = (left + right) >> 1; 661 chn_setvolume_multi(volch, SND_VOL_C_PCM, 662 left, right, center); 663 break; 664 default: 665 /* ignore all other mixer writes */ 666 break; 667 } 668 break; 669 670 case MIXER_READ(0): 671 switch (j) { 672 case SOUND_MIXER_MUTE: 673 mute = CHN_GETMUTE(volch, SND_VOL_C_PCM, SND_CHN_T_FL) || 674 CHN_GETMUTE(volch, SND_VOL_C_PCM, SND_CHN_T_FR); 675 if (volch->direction == PCMDIR_REC) { 676 *(int *)arg = mute << SOUND_MIXER_RECLEV; 677 } else { 678 *(int *)arg = mute << SOUND_MIXER_PCM; 679 } 680 break; 681 case SOUND_MIXER_PCM: 682 if (volch->direction != PCMDIR_PLAY) 683 break; 684 *(int *)arg = CHN_GETVOLUME(volch, 685 SND_VOL_C_PCM, SND_CHN_T_FL); 686 *(int *)arg |= CHN_GETVOLUME(volch, 687 SND_VOL_C_PCM, SND_CHN_T_FR) << 8; 688 break; 689 case SOUND_MIXER_RECLEV: 690 if (volch->direction != PCMDIR_REC) 691 break; 692 *(int *)arg = CHN_GETVOLUME(volch, 693 SND_VOL_C_PCM, SND_CHN_T_FL); 694 *(int *)arg |= CHN_GETVOLUME(volch, 695 SND_VOL_C_PCM, SND_CHN_T_FR) << 8; 696 break; 697 case SOUND_MIXER_DEVMASK: 698 case SOUND_MIXER_CAPS: 699 case SOUND_MIXER_STEREODEVS: 700 if (volch->direction == PCMDIR_REC) 701 *(int *)arg = SOUND_MASK_RECLEV; 702 else 703 *(int *)arg = SOUND_MASK_PCM; 704 break; 705 default: 706 *(int *)arg = 0; 707 break; 708 } 709 break; 710 711 default: 712 break; 713 } 714 CHN_UNLOCK(volch); 715 return (0); 716 } 717 718 static int 719 dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, 720 struct thread *td) 721 { 722 struct dsp_cdevpriv *priv; 723 struct pcm_channel *chn, *rdch, *wrch; 724 struct snddev_info *d; 725 u_long xcmd; 726 int *arg_i, ret, tmp, err; 727 728 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0) 729 return (err); 730 731 d = priv->sc; 732 if (PCM_DETACHING(d) || !DSP_REGISTERED(d)) 733 return (EBADF); 734 735 PCM_GIANT_ENTER(d); 736 737 arg_i = (int *)arg; 738 ret = 0; 739 xcmd = 0; 740 chn = NULL; 741 742 if (IOCGROUP(cmd) == 'M') { 743 if (cmd == OSS_GETVERSION) { 744 *arg_i = SOUND_VERSION; 745 PCM_GIANT_EXIT(d); 746 return (0); 747 } 748 ret = dsp_ioctl_channel(priv, priv->volch, cmd, arg); 749 if (ret != -1) { 750 PCM_GIANT_EXIT(d); 751 return (ret); 752 } 753 754 if (d->mixer_dev != NULL) { 755 PCM_ACQUIRE_QUICK(d); 756 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td, 757 MIXER_CMD_DIRECT); 758 PCM_RELEASE_QUICK(d); 759 } else 760 ret = EBADF; 761 762 PCM_GIANT_EXIT(d); 763 764 return (ret); 765 } 766 767 /* 768 * Certain ioctls may be made on any type of device (audio, mixer, 769 * and MIDI). Handle those special cases here. 770 */ 771 if (IOCGROUP(cmd) == 'X') { 772 PCM_ACQUIRE_QUICK(d); 773 switch(cmd) { 774 case SNDCTL_SYSINFO: 775 sound_oss_sysinfo((oss_sysinfo *)arg); 776 break; 777 case SNDCTL_CARDINFO: 778 ret = sound_oss_card_info((oss_card_info *)arg); 779 break; 780 case SNDCTL_AUDIOINFO: 781 ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg, 782 false); 783 break; 784 case SNDCTL_AUDIOINFO_EX: 785 ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg, 786 true); 787 break; 788 case SNDCTL_ENGINEINFO: 789 ret = dsp_oss_engineinfo(i_dev, (oss_audioinfo *)arg); 790 break; 791 case SNDCTL_MIXERINFO: 792 ret = mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg); 793 break; 794 default: 795 ret = EINVAL; 796 } 797 PCM_RELEASE_QUICK(d); 798 PCM_GIANT_EXIT(d); 799 return (ret); 800 } 801 802 getchns(priv, 0); 803 rdch = priv->rdch; 804 wrch = priv->wrch; 805 806 if (wrch != NULL && (wrch->flags & CHN_F_DEAD)) 807 wrch = NULL; 808 if (rdch != NULL && (rdch->flags & CHN_F_DEAD)) 809 rdch = NULL; 810 811 if (wrch == NULL && rdch == NULL) { 812 PCM_GIANT_EXIT(d); 813 return (EINVAL); 814 } 815 816 switch(cmd) { 817 #ifdef OLDPCM_IOCTL 818 /* 819 * we start with the new ioctl interface. 820 */ 821 case AIONWRITE: /* how many bytes can write ? */ 822 if (wrch) { 823 CHN_LOCK(wrch); 824 /* 825 if (wrch && wrch->bufhard.dl) 826 while (chn_wrfeed(wrch) == 0); 827 */ 828 *arg_i = sndbuf_getfree(wrch->bufsoft); 829 CHN_UNLOCK(wrch); 830 } else { 831 *arg_i = 0; 832 ret = EINVAL; 833 } 834 break; 835 836 case AIOSSIZE: /* set the current blocksize */ 837 { 838 struct snd_size *p = (struct snd_size *)arg; 839 840 p->play_size = 0; 841 p->rec_size = 0; 842 PCM_ACQUIRE_QUICK(d); 843 if (wrch) { 844 CHN_LOCK(wrch); 845 chn_setblocksize(wrch, 2, p->play_size); 846 p->play_size = sndbuf_getblksz(wrch->bufsoft); 847 CHN_UNLOCK(wrch); 848 } 849 if (rdch) { 850 CHN_LOCK(rdch); 851 chn_setblocksize(rdch, 2, p->rec_size); 852 p->rec_size = sndbuf_getblksz(rdch->bufsoft); 853 CHN_UNLOCK(rdch); 854 } 855 PCM_RELEASE_QUICK(d); 856 } 857 break; 858 case AIOGSIZE: /* get the current blocksize */ 859 { 860 struct snd_size *p = (struct snd_size *)arg; 861 862 if (wrch) { 863 CHN_LOCK(wrch); 864 p->play_size = sndbuf_getblksz(wrch->bufsoft); 865 CHN_UNLOCK(wrch); 866 } 867 if (rdch) { 868 CHN_LOCK(rdch); 869 p->rec_size = sndbuf_getblksz(rdch->bufsoft); 870 CHN_UNLOCK(rdch); 871 } 872 } 873 break; 874 875 case AIOSFMT: 876 case AIOGFMT: 877 { 878 snd_chan_param *p = (snd_chan_param *)arg; 879 880 if (cmd == AIOSFMT && 881 ((p->play_format != 0 && p->play_rate == 0) || 882 (p->rec_format != 0 && p->rec_rate == 0))) { 883 ret = EINVAL; 884 break; 885 } 886 PCM_ACQUIRE_QUICK(d); 887 if (wrch) { 888 CHN_LOCK(wrch); 889 if (cmd == AIOSFMT && p->play_format != 0) { 890 chn_setformat(wrch, 891 SND_FORMAT(p->play_format, 892 AFMT_CHANNEL(wrch->format), 893 AFMT_EXTCHANNEL(wrch->format))); 894 chn_setspeed(wrch, p->play_rate); 895 } 896 p->play_rate = wrch->speed; 897 p->play_format = AFMT_ENCODING(wrch->format); 898 CHN_UNLOCK(wrch); 899 } else { 900 p->play_rate = 0; 901 p->play_format = 0; 902 } 903 if (rdch) { 904 CHN_LOCK(rdch); 905 if (cmd == AIOSFMT && p->rec_format != 0) { 906 chn_setformat(rdch, 907 SND_FORMAT(p->rec_format, 908 AFMT_CHANNEL(rdch->format), 909 AFMT_EXTCHANNEL(rdch->format))); 910 chn_setspeed(rdch, p->rec_rate); 911 } 912 p->rec_rate = rdch->speed; 913 p->rec_format = AFMT_ENCODING(rdch->format); 914 CHN_UNLOCK(rdch); 915 } else { 916 p->rec_rate = 0; 917 p->rec_format = 0; 918 } 919 PCM_RELEASE_QUICK(d); 920 } 921 break; 922 923 case AIOGCAP: /* get capabilities */ 924 { 925 snd_capabilities *p = (snd_capabilities *)arg; 926 struct pcmchan_caps *pcaps = NULL, *rcaps = NULL; 927 struct cdev *pdev; 928 929 PCM_LOCK(d); 930 if (rdch) { 931 CHN_LOCK(rdch); 932 rcaps = chn_getcaps(rdch); 933 } 934 if (wrch) { 935 CHN_LOCK(wrch); 936 pcaps = chn_getcaps(wrch); 937 } 938 p->rate_min = max(rcaps? rcaps->minspeed : 0, 939 pcaps? pcaps->minspeed : 0); 940 p->rate_max = min(rcaps? rcaps->maxspeed : 1000000, 941 pcaps? pcaps->maxspeed : 1000000); 942 p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000, 943 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000); 944 /* XXX bad on sb16 */ 945 p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) & 946 (wrch? chn_getformats(wrch) : 0xffffffff); 947 if (rdch && wrch) { 948 p->formats |= 949 (pcm_getflags(d->dev) & SD_F_SIMPLEX) ? 0 : 950 AFMT_FULLDUPLEX; 951 } 952 pdev = d->mixer_dev; 953 p->mixers = 1; /* default: one mixer */ 954 p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0; 955 p->left = p->right = 100; 956 if (wrch) 957 CHN_UNLOCK(wrch); 958 if (rdch) 959 CHN_UNLOCK(rdch); 960 PCM_UNLOCK(d); 961 } 962 break; 963 964 case AIOSTOP: 965 if (*arg_i == AIOSYNC_PLAY && wrch) { 966 CHN_LOCK(wrch); 967 *arg_i = chn_abort(wrch); 968 CHN_UNLOCK(wrch); 969 } else if (*arg_i == AIOSYNC_CAPTURE && rdch) { 970 CHN_LOCK(rdch); 971 *arg_i = chn_abort(rdch); 972 CHN_UNLOCK(rdch); 973 } else { 974 printf("AIOSTOP: bad channel 0x%x\n", *arg_i); 975 *arg_i = 0; 976 } 977 break; 978 979 case AIOSYNC: 980 printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n", 981 ((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos); 982 break; 983 #endif 984 /* 985 * here follow the standard ioctls (filio.h etc.) 986 */ 987 case FIONREAD: /* get # bytes to read */ 988 if (rdch) { 989 CHN_LOCK(rdch); 990 /* if (rdch && rdch->bufhard.dl) 991 while (chn_rdfeed(rdch) == 0); 992 */ 993 *arg_i = sndbuf_getready(rdch->bufsoft); 994 CHN_UNLOCK(rdch); 995 } else { 996 *arg_i = 0; 997 ret = EINVAL; 998 } 999 break; 1000 1001 case FIOASYNC: /*set/clear async i/o */ 1002 DEB( printf("FIOASYNC\n") ; ) 1003 break; 1004 1005 case SNDCTL_DSP_NONBLOCK: /* set non-blocking i/o */ 1006 case FIONBIO: /* set/clear non-blocking i/o */ 1007 if (rdch) { 1008 CHN_LOCK(rdch); 1009 if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i) 1010 rdch->flags |= CHN_F_NBIO; 1011 else 1012 rdch->flags &= ~CHN_F_NBIO; 1013 CHN_UNLOCK(rdch); 1014 } 1015 if (wrch) { 1016 CHN_LOCK(wrch); 1017 if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i) 1018 wrch->flags |= CHN_F_NBIO; 1019 else 1020 wrch->flags &= ~CHN_F_NBIO; 1021 CHN_UNLOCK(wrch); 1022 } 1023 break; 1024 1025 /* 1026 * Finally, here is the linux-compatible ioctl interface 1027 */ 1028 #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int) 1029 case THE_REAL_SNDCTL_DSP_GETBLKSIZE: 1030 case SNDCTL_DSP_GETBLKSIZE: 1031 chn = wrch ? wrch : rdch; 1032 if (chn) { 1033 CHN_LOCK(chn); 1034 *arg_i = sndbuf_getblksz(chn->bufsoft); 1035 CHN_UNLOCK(chn); 1036 } else { 1037 *arg_i = 0; 1038 ret = EINVAL; 1039 } 1040 break; 1041 1042 case SNDCTL_DSP_SETBLKSIZE: 1043 RANGE(*arg_i, 16, 65536); 1044 PCM_ACQUIRE_QUICK(d); 1045 if (wrch) { 1046 CHN_LOCK(wrch); 1047 chn_setblocksize(wrch, 2, *arg_i); 1048 CHN_UNLOCK(wrch); 1049 } 1050 if (rdch) { 1051 CHN_LOCK(rdch); 1052 chn_setblocksize(rdch, 2, *arg_i); 1053 CHN_UNLOCK(rdch); 1054 } 1055 PCM_RELEASE_QUICK(d); 1056 break; 1057 1058 case SNDCTL_DSP_RESET: 1059 DEB(printf("dsp reset\n")); 1060 if (wrch) { 1061 CHN_LOCK(wrch); 1062 chn_abort(wrch); 1063 chn_resetbuf(wrch); 1064 CHN_UNLOCK(wrch); 1065 } 1066 if (rdch) { 1067 CHN_LOCK(rdch); 1068 chn_abort(rdch); 1069 chn_resetbuf(rdch); 1070 CHN_UNLOCK(rdch); 1071 } 1072 break; 1073 1074 case SNDCTL_DSP_SYNC: 1075 DEB(printf("dsp sync\n")); 1076 /* chn_sync may sleep */ 1077 if (wrch) { 1078 CHN_LOCK(wrch); 1079 chn_sync(wrch, 0); 1080 CHN_UNLOCK(wrch); 1081 } 1082 break; 1083 1084 case SNDCTL_DSP_SPEED: 1085 /* chn_setspeed may sleep */ 1086 tmp = 0; 1087 PCM_ACQUIRE_QUICK(d); 1088 if (wrch) { 1089 CHN_LOCK(wrch); 1090 ret = chn_setspeed(wrch, *arg_i); 1091 tmp = wrch->speed; 1092 CHN_UNLOCK(wrch); 1093 } 1094 if (rdch && ret == 0) { 1095 CHN_LOCK(rdch); 1096 ret = chn_setspeed(rdch, *arg_i); 1097 if (tmp == 0) 1098 tmp = rdch->speed; 1099 CHN_UNLOCK(rdch); 1100 } 1101 PCM_RELEASE_QUICK(d); 1102 *arg_i = tmp; 1103 break; 1104 1105 case SOUND_PCM_READ_RATE: 1106 chn = wrch ? wrch : rdch; 1107 if (chn) { 1108 CHN_LOCK(chn); 1109 *arg_i = chn->speed; 1110 CHN_UNLOCK(chn); 1111 } else { 1112 *arg_i = 0; 1113 ret = EINVAL; 1114 } 1115 break; 1116 1117 case SNDCTL_DSP_STEREO: 1118 tmp = -1; 1119 *arg_i = (*arg_i)? 2 : 1; 1120 PCM_ACQUIRE_QUICK(d); 1121 if (wrch) { 1122 CHN_LOCK(wrch); 1123 ret = chn_setformat(wrch, 1124 SND_FORMAT(wrch->format, *arg_i, 0)); 1125 tmp = (AFMT_CHANNEL(wrch->format) > 1)? 1 : 0; 1126 CHN_UNLOCK(wrch); 1127 } 1128 if (rdch && ret == 0) { 1129 CHN_LOCK(rdch); 1130 ret = chn_setformat(rdch, 1131 SND_FORMAT(rdch->format, *arg_i, 0)); 1132 if (tmp == -1) 1133 tmp = (AFMT_CHANNEL(rdch->format) > 1)? 1 : 0; 1134 CHN_UNLOCK(rdch); 1135 } 1136 PCM_RELEASE_QUICK(d); 1137 *arg_i = tmp; 1138 break; 1139 1140 case SOUND_PCM_WRITE_CHANNELS: 1141 /* case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */ 1142 if (*arg_i < 0 || *arg_i > AFMT_CHANNEL_MAX) { 1143 *arg_i = 0; 1144 ret = EINVAL; 1145 break; 1146 } 1147 if (*arg_i != 0) { 1148 uint32_t ext = 0; 1149 1150 tmp = 0; 1151 /* 1152 * Map channel number to surround sound formats. 1153 * Devices that need bitperfect mode to operate 1154 * (e.g. more than SND_CHN_MAX channels) are not 1155 * subject to any mapping. 1156 */ 1157 if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT)) { 1158 struct pcmchan_matrix *m; 1159 1160 if (*arg_i > SND_CHN_MAX) 1161 *arg_i = SND_CHN_MAX; 1162 1163 m = feeder_matrix_default_channel_map(*arg_i); 1164 if (m != NULL) 1165 ext = m->ext; 1166 } 1167 1168 PCM_ACQUIRE_QUICK(d); 1169 if (wrch) { 1170 CHN_LOCK(wrch); 1171 ret = chn_setformat(wrch, 1172 SND_FORMAT(wrch->format, *arg_i, ext)); 1173 tmp = AFMT_CHANNEL(wrch->format); 1174 CHN_UNLOCK(wrch); 1175 } 1176 if (rdch && ret == 0) { 1177 CHN_LOCK(rdch); 1178 ret = chn_setformat(rdch, 1179 SND_FORMAT(rdch->format, *arg_i, ext)); 1180 if (tmp == 0) 1181 tmp = AFMT_CHANNEL(rdch->format); 1182 CHN_UNLOCK(rdch); 1183 } 1184 PCM_RELEASE_QUICK(d); 1185 *arg_i = tmp; 1186 } else { 1187 chn = wrch ? wrch : rdch; 1188 CHN_LOCK(chn); 1189 *arg_i = AFMT_CHANNEL(chn->format); 1190 CHN_UNLOCK(chn); 1191 } 1192 break; 1193 1194 case SOUND_PCM_READ_CHANNELS: 1195 chn = wrch ? wrch : rdch; 1196 if (chn) { 1197 CHN_LOCK(chn); 1198 *arg_i = AFMT_CHANNEL(chn->format); 1199 CHN_UNLOCK(chn); 1200 } else { 1201 *arg_i = 0; 1202 ret = EINVAL; 1203 } 1204 break; 1205 1206 case SNDCTL_DSP_GETFMTS: /* returns a mask of supported fmts */ 1207 chn = wrch ? wrch : rdch; 1208 if (chn) { 1209 CHN_LOCK(chn); 1210 *arg_i = chn_getformats(chn); 1211 CHN_UNLOCK(chn); 1212 } else { 1213 *arg_i = 0; 1214 ret = EINVAL; 1215 } 1216 break; 1217 1218 case SNDCTL_DSP_SETFMT: /* sets _one_ format */ 1219 if (*arg_i != AFMT_QUERY) { 1220 tmp = 0; 1221 PCM_ACQUIRE_QUICK(d); 1222 if (wrch) { 1223 CHN_LOCK(wrch); 1224 ret = chn_setformat(wrch, SND_FORMAT(*arg_i, 1225 AFMT_CHANNEL(wrch->format), 1226 AFMT_EXTCHANNEL(wrch->format))); 1227 tmp = wrch->format; 1228 CHN_UNLOCK(wrch); 1229 } 1230 if (rdch && ret == 0) { 1231 CHN_LOCK(rdch); 1232 ret = chn_setformat(rdch, SND_FORMAT(*arg_i, 1233 AFMT_CHANNEL(rdch->format), 1234 AFMT_EXTCHANNEL(rdch->format))); 1235 if (tmp == 0) 1236 tmp = rdch->format; 1237 CHN_UNLOCK(rdch); 1238 } 1239 PCM_RELEASE_QUICK(d); 1240 *arg_i = AFMT_ENCODING(tmp); 1241 } else { 1242 chn = wrch ? wrch : rdch; 1243 CHN_LOCK(chn); 1244 *arg_i = AFMT_ENCODING(chn->format); 1245 CHN_UNLOCK(chn); 1246 } 1247 break; 1248 1249 case SNDCTL_DSP_SETFRAGMENT: 1250 DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg)); 1251 { 1252 uint32_t fragln = (*arg_i) & 0x0000ffff; 1253 uint32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16; 1254 uint32_t fragsz; 1255 uint32_t r_maxfrags, r_fragsz; 1256 1257 RANGE(fragln, 4, 16); 1258 fragsz = 1 << fragln; 1259 1260 if (maxfrags == 0) 1261 maxfrags = CHN_2NDBUFMAXSIZE / fragsz; 1262 if (maxfrags < 2) 1263 maxfrags = 2; 1264 if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE) 1265 maxfrags = CHN_2NDBUFMAXSIZE / fragsz; 1266 1267 DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz)); 1268 PCM_ACQUIRE_QUICK(d); 1269 if (rdch) { 1270 CHN_LOCK(rdch); 1271 ret = chn_setblocksize(rdch, maxfrags, fragsz); 1272 r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft); 1273 r_fragsz = sndbuf_getblksz(rdch->bufsoft); 1274 CHN_UNLOCK(rdch); 1275 } else { 1276 r_maxfrags = maxfrags; 1277 r_fragsz = fragsz; 1278 } 1279 if (wrch && ret == 0) { 1280 CHN_LOCK(wrch); 1281 ret = chn_setblocksize(wrch, maxfrags, fragsz); 1282 maxfrags = sndbuf_getblkcnt(wrch->bufsoft); 1283 fragsz = sndbuf_getblksz(wrch->bufsoft); 1284 CHN_UNLOCK(wrch); 1285 } else { /* use whatever came from the read channel */ 1286 maxfrags = r_maxfrags; 1287 fragsz = r_fragsz; 1288 } 1289 PCM_RELEASE_QUICK(d); 1290 1291 fragln = 0; 1292 while (fragsz > 1) { 1293 fragln++; 1294 fragsz >>= 1; 1295 } 1296 *arg_i = (maxfrags << 16) | fragln; 1297 } 1298 break; 1299 1300 case SNDCTL_DSP_GETISPACE: 1301 /* return the size of data available in the input queue */ 1302 { 1303 audio_buf_info *a = (audio_buf_info *)arg; 1304 if (rdch) { 1305 struct snd_dbuf *bs = rdch->bufsoft; 1306 1307 CHN_LOCK(rdch); 1308 a->bytes = sndbuf_getready(bs); 1309 a->fragments = a->bytes / sndbuf_getblksz(bs); 1310 a->fragstotal = sndbuf_getblkcnt(bs); 1311 a->fragsize = sndbuf_getblksz(bs); 1312 CHN_UNLOCK(rdch); 1313 } else 1314 ret = EINVAL; 1315 } 1316 break; 1317 1318 case SNDCTL_DSP_GETOSPACE: 1319 /* return space available in the output queue */ 1320 { 1321 audio_buf_info *a = (audio_buf_info *)arg; 1322 if (wrch) { 1323 struct snd_dbuf *bs = wrch->bufsoft; 1324 1325 CHN_LOCK(wrch); 1326 /* XXX abusive DMA update: chn_wrupdate(wrch); */ 1327 a->bytes = sndbuf_getfree(bs); 1328 a->fragments = a->bytes / sndbuf_getblksz(bs); 1329 a->fragstotal = sndbuf_getblkcnt(bs); 1330 a->fragsize = sndbuf_getblksz(bs); 1331 CHN_UNLOCK(wrch); 1332 } else 1333 ret = EINVAL; 1334 } 1335 break; 1336 1337 case SNDCTL_DSP_GETIPTR: 1338 { 1339 count_info *a = (count_info *)arg; 1340 if (rdch) { 1341 struct snd_dbuf *bs = rdch->bufsoft; 1342 1343 CHN_LOCK(rdch); 1344 /* XXX abusive DMA update: chn_rdupdate(rdch); */ 1345 a->bytes = sndbuf_gettotal(bs); 1346 a->blocks = sndbuf_getblocks(bs) - rdch->blocks; 1347 a->ptr = sndbuf_getfreeptr(bs); 1348 rdch->blocks = sndbuf_getblocks(bs); 1349 CHN_UNLOCK(rdch); 1350 } else 1351 ret = EINVAL; 1352 } 1353 break; 1354 1355 case SNDCTL_DSP_GETOPTR: 1356 { 1357 count_info *a = (count_info *)arg; 1358 if (wrch) { 1359 struct snd_dbuf *bs = wrch->bufsoft; 1360 1361 CHN_LOCK(wrch); 1362 /* XXX abusive DMA update: chn_wrupdate(wrch); */ 1363 a->bytes = sndbuf_gettotal(bs); 1364 a->blocks = sndbuf_getblocks(bs) - wrch->blocks; 1365 a->ptr = sndbuf_getreadyptr(bs); 1366 wrch->blocks = sndbuf_getblocks(bs); 1367 CHN_UNLOCK(wrch); 1368 } else 1369 ret = EINVAL; 1370 } 1371 break; 1372 1373 case SNDCTL_DSP_GETCAPS: 1374 PCM_LOCK(d); 1375 *arg_i = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER; 1376 if (rdch && wrch && !(pcm_getflags(d->dev) & SD_F_SIMPLEX)) 1377 *arg_i |= PCM_CAP_DUPLEX; 1378 if (rdch && (rdch->flags & CHN_F_VIRTUAL) != 0) 1379 *arg_i |= PCM_CAP_VIRTUAL; 1380 if (wrch && (wrch->flags & CHN_F_VIRTUAL) != 0) 1381 *arg_i |= PCM_CAP_VIRTUAL; 1382 PCM_UNLOCK(d); 1383 break; 1384 1385 case SOUND_PCM_READ_BITS: 1386 chn = wrch ? wrch : rdch; 1387 if (chn) { 1388 CHN_LOCK(chn); 1389 if (chn->format & AFMT_8BIT) 1390 *arg_i = 8; 1391 else if (chn->format & AFMT_16BIT) 1392 *arg_i = 16; 1393 else if (chn->format & AFMT_24BIT) 1394 *arg_i = 24; 1395 else if (chn->format & AFMT_32BIT) 1396 *arg_i = 32; 1397 else 1398 ret = EINVAL; 1399 CHN_UNLOCK(chn); 1400 } else { 1401 *arg_i = 0; 1402 ret = EINVAL; 1403 } 1404 break; 1405 1406 case SNDCTL_DSP_SETTRIGGER: 1407 if (rdch) { 1408 CHN_LOCK(rdch); 1409 rdch->flags &= ~CHN_F_NOTRIGGER; 1410 if (*arg_i & PCM_ENABLE_INPUT) 1411 chn_start(rdch, 1); 1412 else { 1413 chn_abort(rdch); 1414 chn_resetbuf(rdch); 1415 rdch->flags |= CHN_F_NOTRIGGER; 1416 } 1417 CHN_UNLOCK(rdch); 1418 } 1419 if (wrch) { 1420 CHN_LOCK(wrch); 1421 wrch->flags &= ~CHN_F_NOTRIGGER; 1422 if (*arg_i & PCM_ENABLE_OUTPUT) 1423 chn_start(wrch, 1); 1424 else { 1425 chn_abort(wrch); 1426 chn_resetbuf(wrch); 1427 wrch->flags |= CHN_F_NOTRIGGER; 1428 } 1429 CHN_UNLOCK(wrch); 1430 } 1431 break; 1432 1433 case SNDCTL_DSP_GETTRIGGER: 1434 *arg_i = 0; 1435 if (wrch) { 1436 CHN_LOCK(wrch); 1437 if (wrch->flags & CHN_F_TRIGGERED) 1438 *arg_i |= PCM_ENABLE_OUTPUT; 1439 CHN_UNLOCK(wrch); 1440 } 1441 if (rdch) { 1442 CHN_LOCK(rdch); 1443 if (rdch->flags & CHN_F_TRIGGERED) 1444 *arg_i |= PCM_ENABLE_INPUT; 1445 CHN_UNLOCK(rdch); 1446 } 1447 break; 1448 1449 case SNDCTL_DSP_GETODELAY: 1450 if (wrch) { 1451 struct snd_dbuf *bs = wrch->bufsoft; 1452 1453 CHN_LOCK(wrch); 1454 /* XXX abusive DMA update: chn_wrupdate(wrch); */ 1455 *arg_i = sndbuf_getready(bs); 1456 CHN_UNLOCK(wrch); 1457 } else 1458 ret = EINVAL; 1459 break; 1460 1461 case SNDCTL_DSP_POST: 1462 if (wrch) { 1463 CHN_LOCK(wrch); 1464 wrch->flags &= ~CHN_F_NOTRIGGER; 1465 chn_start(wrch, 1); 1466 CHN_UNLOCK(wrch); 1467 } 1468 break; 1469 1470 case SNDCTL_DSP_SETDUPLEX: 1471 /* 1472 * switch to full-duplex mode if card is in half-duplex 1473 * mode and is able to work in full-duplex mode 1474 */ 1475 PCM_LOCK(d); 1476 if (rdch && wrch && (pcm_getflags(d->dev) & SD_F_SIMPLEX)) 1477 pcm_setflags(d->dev, pcm_getflags(d->dev)^SD_F_SIMPLEX); 1478 PCM_UNLOCK(d); 1479 break; 1480 1481 /* 1482 * The following four ioctls are simple wrappers around mixer_ioctl 1483 * with no further processing. xcmd is short for "translated 1484 * command". 1485 */ 1486 case SNDCTL_DSP_GETRECVOL: 1487 if (xcmd == 0) { 1488 xcmd = SOUND_MIXER_READ_RECLEV; 1489 chn = rdch; 1490 } 1491 /* FALLTHROUGH */ 1492 case SNDCTL_DSP_SETRECVOL: 1493 if (xcmd == 0) { 1494 xcmd = SOUND_MIXER_WRITE_RECLEV; 1495 chn = rdch; 1496 } 1497 /* FALLTHROUGH */ 1498 case SNDCTL_DSP_GETPLAYVOL: 1499 if (xcmd == 0) { 1500 xcmd = SOUND_MIXER_READ_PCM; 1501 chn = wrch; 1502 } 1503 /* FALLTHROUGH */ 1504 case SNDCTL_DSP_SETPLAYVOL: 1505 if (xcmd == 0) { 1506 xcmd = SOUND_MIXER_WRITE_PCM; 1507 chn = wrch; 1508 } 1509 1510 ret = dsp_ioctl_channel(priv, chn, xcmd, arg); 1511 if (ret != -1) { 1512 PCM_GIANT_EXIT(d); 1513 return (ret); 1514 } 1515 1516 if (d->mixer_dev != NULL) { 1517 PCM_ACQUIRE_QUICK(d); 1518 ret = mixer_ioctl_cmd(d->mixer_dev, xcmd, arg, -1, td, 1519 MIXER_CMD_DIRECT); 1520 PCM_RELEASE_QUICK(d); 1521 } else 1522 ret = ENOTSUP; 1523 1524 break; 1525 1526 case SNDCTL_DSP_GET_RECSRC_NAMES: 1527 case SNDCTL_DSP_GET_RECSRC: 1528 case SNDCTL_DSP_SET_RECSRC: 1529 if (d->mixer_dev != NULL) { 1530 PCM_ACQUIRE_QUICK(d); 1531 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td, 1532 MIXER_CMD_DIRECT); 1533 PCM_RELEASE_QUICK(d); 1534 } else 1535 ret = ENOTSUP; 1536 break; 1537 1538 /* 1539 * The following 3 ioctls aren't very useful at the moment. For 1540 * now, only a single channel is associated with a cdev (/dev/dspN 1541 * instance), so there's only a single output routing to use (i.e., 1542 * the wrch bound to this cdev). 1543 */ 1544 case SNDCTL_DSP_GET_PLAYTGT_NAMES: 1545 { 1546 oss_mixer_enuminfo *ei; 1547 ei = (oss_mixer_enuminfo *)arg; 1548 ei->dev = 0; 1549 ei->ctrl = 0; 1550 ei->version = 0; /* static for now */ 1551 ei->strindex[0] = 0; 1552 1553 if (wrch != NULL) { 1554 ei->nvalues = 1; 1555 strlcpy(ei->strings, wrch->name, 1556 sizeof(ei->strings)); 1557 } else { 1558 ei->nvalues = 0; 1559 ei->strings[0] = '\0'; 1560 } 1561 } 1562 break; 1563 case SNDCTL_DSP_GET_PLAYTGT: 1564 case SNDCTL_DSP_SET_PLAYTGT: /* yes, they are the same for now */ 1565 /* 1566 * Re: SET_PLAYTGT 1567 * OSSv4: "The value that was accepted by the device will 1568 * be returned back in the variable pointed by the 1569 * argument." 1570 */ 1571 if (wrch != NULL) 1572 *arg_i = 0; 1573 else 1574 ret = EINVAL; 1575 break; 1576 1577 case SNDCTL_DSP_SILENCE: 1578 /* 1579 * Flush the software (pre-feed) buffer, but try to minimize playback 1580 * interruption. (I.e., record unplayed samples with intent to 1581 * restore by SNDCTL_DSP_SKIP.) Intended for application "pause" 1582 * functionality. 1583 */ 1584 if (wrch == NULL) 1585 ret = EINVAL; 1586 else { 1587 struct snd_dbuf *bs; 1588 CHN_LOCK(wrch); 1589 while (wrch->inprog != 0) 1590 cv_wait(&wrch->cv, wrch->lock); 1591 bs = wrch->bufsoft; 1592 if ((bs->shadbuf != NULL) && (sndbuf_getready(bs) > 0)) { 1593 bs->sl = sndbuf_getready(bs); 1594 sndbuf_dispose(bs, bs->shadbuf, sndbuf_getready(bs)); 1595 sndbuf_fillsilence(bs); 1596 chn_start(wrch, 0); 1597 } 1598 CHN_UNLOCK(wrch); 1599 } 1600 break; 1601 1602 case SNDCTL_DSP_SKIP: 1603 /* 1604 * OSSv4 docs: "This ioctl call discards all unplayed samples in the 1605 * playback buffer by moving the current write position immediately 1606 * before the point where the device is currently reading the samples." 1607 */ 1608 if (wrch == NULL) 1609 ret = EINVAL; 1610 else { 1611 struct snd_dbuf *bs; 1612 CHN_LOCK(wrch); 1613 while (wrch->inprog != 0) 1614 cv_wait(&wrch->cv, wrch->lock); 1615 bs = wrch->bufsoft; 1616 if ((bs->shadbuf != NULL) && (bs->sl > 0)) { 1617 sndbuf_softreset(bs); 1618 sndbuf_acquire(bs, bs->shadbuf, bs->sl); 1619 bs->sl = 0; 1620 chn_start(wrch, 0); 1621 } 1622 CHN_UNLOCK(wrch); 1623 } 1624 break; 1625 1626 case SNDCTL_DSP_CURRENT_OPTR: 1627 case SNDCTL_DSP_CURRENT_IPTR: 1628 /** 1629 * @note Changing formats resets the buffer counters, which differs 1630 * from the 4Front drivers. However, I don't expect this to be 1631 * much of a problem. 1632 * 1633 * @note In a test where @c CURRENT_OPTR is called immediately after write 1634 * returns, this driver is about 32K samples behind whereas 1635 * 4Front's is about 8K samples behind. Should determine source 1636 * of discrepancy, even if only out of curiosity. 1637 * 1638 * @todo Actually test SNDCTL_DSP_CURRENT_IPTR. 1639 */ 1640 chn = (cmd == SNDCTL_DSP_CURRENT_OPTR) ? wrch : rdch; 1641 if (chn == NULL) 1642 ret = EINVAL; 1643 else { 1644 struct snd_dbuf *bs; 1645 /* int tmp; */ 1646 1647 oss_count_t *oc = (oss_count_t *)arg; 1648 1649 CHN_LOCK(chn); 1650 bs = chn->bufsoft; 1651 #if 0 1652 tmp = (sndbuf_getsize(b) + chn_getptr(chn) - sndbuf_gethwptr(b)) % sndbuf_getsize(b); 1653 oc->samples = (sndbuf_gettotal(b) + tmp) / sndbuf_getalign(b); 1654 oc->fifo_samples = (sndbuf_getready(b) - tmp) / sndbuf_getalign(b); 1655 #else 1656 oc->samples = sndbuf_gettotal(bs) / sndbuf_getalign(bs); 1657 oc->fifo_samples = sndbuf_getready(bs) / sndbuf_getalign(bs); 1658 #endif 1659 CHN_UNLOCK(chn); 1660 } 1661 break; 1662 1663 case SNDCTL_DSP_HALT_OUTPUT: 1664 case SNDCTL_DSP_HALT_INPUT: 1665 chn = (cmd == SNDCTL_DSP_HALT_OUTPUT) ? wrch : rdch; 1666 if (chn == NULL) 1667 ret = EINVAL; 1668 else { 1669 CHN_LOCK(chn); 1670 chn_abort(chn); 1671 CHN_UNLOCK(chn); 1672 } 1673 break; 1674 1675 case SNDCTL_DSP_LOW_WATER: 1676 /* 1677 * Set the number of bytes required to attract attention by 1678 * select/poll. 1679 */ 1680 if (wrch != NULL) { 1681 CHN_LOCK(wrch); 1682 wrch->lw = (*arg_i > 1) ? *arg_i : 1; 1683 CHN_UNLOCK(wrch); 1684 } 1685 if (rdch != NULL) { 1686 CHN_LOCK(rdch); 1687 rdch->lw = (*arg_i > 1) ? *arg_i : 1; 1688 CHN_UNLOCK(rdch); 1689 } 1690 break; 1691 1692 case SNDCTL_DSP_GETERROR: 1693 /* 1694 * OSSv4 docs: "All errors and counters will automatically be 1695 * cleared to zeroes after the call so each call will return only 1696 * the errors that occurred after the previous invocation. ... The 1697 * play_underruns and rec_overrun fields are the only useful fields 1698 * returned by OSS 4.0." 1699 */ 1700 { 1701 audio_errinfo *ei = (audio_errinfo *)arg; 1702 1703 bzero((void *)ei, sizeof(*ei)); 1704 1705 if (wrch != NULL) { 1706 CHN_LOCK(wrch); 1707 ei->play_underruns = wrch->xruns; 1708 wrch->xruns = 0; 1709 CHN_UNLOCK(wrch); 1710 } 1711 if (rdch != NULL) { 1712 CHN_LOCK(rdch); 1713 ei->rec_overruns = rdch->xruns; 1714 rdch->xruns = 0; 1715 CHN_UNLOCK(rdch); 1716 } 1717 } 1718 break; 1719 1720 case SNDCTL_DSP_SYNCGROUP: 1721 PCM_ACQUIRE_QUICK(d); 1722 ret = dsp_oss_syncgroup(wrch, rdch, (oss_syncgroup *)arg); 1723 PCM_RELEASE_QUICK(d); 1724 break; 1725 1726 case SNDCTL_DSP_SYNCSTART: 1727 PCM_ACQUIRE_QUICK(d); 1728 ret = dsp_oss_syncstart(*arg_i); 1729 PCM_RELEASE_QUICK(d); 1730 break; 1731 1732 case SNDCTL_DSP_POLICY: 1733 PCM_ACQUIRE_QUICK(d); 1734 ret = dsp_oss_policy(wrch, rdch, *arg_i); 1735 PCM_RELEASE_QUICK(d); 1736 break; 1737 1738 case SNDCTL_DSP_COOKEDMODE: 1739 PCM_ACQUIRE_QUICK(d); 1740 if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT)) 1741 ret = dsp_oss_cookedmode(wrch, rdch, *arg_i); 1742 PCM_RELEASE_QUICK(d); 1743 break; 1744 case SNDCTL_DSP_GET_CHNORDER: 1745 PCM_ACQUIRE_QUICK(d); 1746 ret = dsp_oss_getchnorder(wrch, rdch, (unsigned long long *)arg); 1747 PCM_RELEASE_QUICK(d); 1748 break; 1749 case SNDCTL_DSP_SET_CHNORDER: 1750 PCM_ACQUIRE_QUICK(d); 1751 ret = dsp_oss_setchnorder(wrch, rdch, (unsigned long long *)arg); 1752 PCM_RELEASE_QUICK(d); 1753 break; 1754 case SNDCTL_DSP_GETCHANNELMASK: /* XXX vlc */ 1755 PCM_ACQUIRE_QUICK(d); 1756 ret = dsp_oss_getchannelmask(wrch, rdch, (int *)arg); 1757 PCM_RELEASE_QUICK(d); 1758 break; 1759 case SNDCTL_DSP_BIND_CHANNEL: /* XXX what?!? */ 1760 ret = EINVAL; 1761 break; 1762 #ifdef OSSV4_EXPERIMENT 1763 /* 1764 * XXX The following ioctls are not yet supported and just return 1765 * EINVAL. 1766 */ 1767 case SNDCTL_DSP_GETOPEAKS: 1768 case SNDCTL_DSP_GETIPEAKS: 1769 chn = (cmd == SNDCTL_DSP_GETOPEAKS) ? wrch : rdch; 1770 if (chn == NULL) 1771 ret = EINVAL; 1772 else { 1773 oss_peaks_t *op = (oss_peaks_t *)arg; 1774 int lpeak, rpeak; 1775 1776 CHN_LOCK(chn); 1777 ret = chn_getpeaks(chn, &lpeak, &rpeak); 1778 if (ret == -1) 1779 ret = EINVAL; 1780 else { 1781 (*op)[0] = lpeak; 1782 (*op)[1] = rpeak; 1783 } 1784 CHN_UNLOCK(chn); 1785 } 1786 break; 1787 1788 /* 1789 * XXX Once implemented, revisit this for proper cv protection 1790 * (if necessary). 1791 */ 1792 case SNDCTL_GETLABEL: 1793 ret = dsp_oss_getlabel(wrch, rdch, (oss_label_t *)arg); 1794 break; 1795 case SNDCTL_SETLABEL: 1796 ret = dsp_oss_setlabel(wrch, rdch, (oss_label_t *)arg); 1797 break; 1798 case SNDCTL_GETSONG: 1799 ret = dsp_oss_getsong(wrch, rdch, (oss_longname_t *)arg); 1800 break; 1801 case SNDCTL_SETSONG: 1802 ret = dsp_oss_setsong(wrch, rdch, (oss_longname_t *)arg); 1803 break; 1804 case SNDCTL_SETNAME: 1805 ret = dsp_oss_setname(wrch, rdch, (oss_longname_t *)arg); 1806 break; 1807 #if 0 1808 /** 1809 * @note The S/PDIF interface ioctls, @c SNDCTL_DSP_READCTL and 1810 * @c SNDCTL_DSP_WRITECTL have been omitted at the suggestion of 1811 * 4Front Technologies. 1812 */ 1813 case SNDCTL_DSP_READCTL: 1814 case SNDCTL_DSP_WRITECTL: 1815 ret = EINVAL; 1816 break; 1817 #endif /* !0 (explicitly omitted ioctls) */ 1818 1819 #endif /* !OSSV4_EXPERIMENT */ 1820 case SNDCTL_DSP_MAPINBUF: 1821 case SNDCTL_DSP_MAPOUTBUF: 1822 case SNDCTL_DSP_SETSYNCRO: 1823 /* undocumented */ 1824 1825 case SNDCTL_DSP_SUBDIVIDE: 1826 case SOUND_PCM_WRITE_FILTER: 1827 case SOUND_PCM_READ_FILTER: 1828 /* dunno what these do, don't sound important */ 1829 1830 default: 1831 DEB(printf("default ioctl fn 0x%08lx fail\n", cmd)); 1832 ret = EINVAL; 1833 break; 1834 } 1835 1836 PCM_GIANT_LEAVE(d); 1837 1838 return (ret); 1839 } 1840 1841 static int 1842 dsp_poll(struct cdev *i_dev, int events, struct thread *td) 1843 { 1844 struct dsp_cdevpriv *priv; 1845 struct snddev_info *d; 1846 struct pcm_channel *wrch, *rdch; 1847 int ret, e, err; 1848 1849 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0) 1850 return (err); 1851 d = priv->sc; 1852 if (PCM_DETACHING(d) || !DSP_REGISTERED(d)) { 1853 /* XXX many clients don't understand POLLNVAL */ 1854 return (events & (POLLHUP | POLLPRI | POLLIN | 1855 POLLRDNORM | POLLOUT | POLLWRNORM)); 1856 } 1857 PCM_GIANT_ENTER(d); 1858 1859 ret = 0; 1860 1861 getchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR); 1862 wrch = priv->wrch; 1863 rdch = priv->rdch; 1864 1865 if (wrch != NULL && !(wrch->flags & CHN_F_DEAD)) { 1866 e = (events & (POLLOUT | POLLWRNORM)); 1867 if (e) 1868 ret |= chn_poll(wrch, e, td); 1869 } 1870 1871 if (rdch != NULL && !(rdch->flags & CHN_F_DEAD)) { 1872 e = (events & (POLLIN | POLLRDNORM)); 1873 if (e) 1874 ret |= chn_poll(rdch, e, td); 1875 } 1876 1877 relchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR); 1878 1879 PCM_GIANT_LEAVE(d); 1880 1881 return (ret); 1882 } 1883 1884 static int 1885 dsp_mmap(struct cdev *i_dev, vm_ooffset_t offset, vm_paddr_t *paddr, 1886 int nprot, vm_memattr_t *memattr) 1887 { 1888 1889 /* 1890 * offset is in range due to checks in dsp_mmap_single(). 1891 * XXX memattr is not honored. 1892 */ 1893 *paddr = vtophys(offset); 1894 return (0); 1895 } 1896 1897 static int 1898 dsp_mmap_single(struct cdev *i_dev, vm_ooffset_t *offset, 1899 vm_size_t size, struct vm_object **object, int nprot) 1900 { 1901 struct dsp_cdevpriv *priv; 1902 struct snddev_info *d; 1903 struct pcm_channel *wrch, *rdch, *c; 1904 int err; 1905 1906 /* 1907 * Reject PROT_EXEC by default. It just doesn't makes sense. 1908 * Unfortunately, we have to give up this one due to linux_mmap 1909 * changes. 1910 * 1911 * https://lists.freebsd.org/pipermail/freebsd-emulation/2007-June/003698.html 1912 * 1913 */ 1914 #ifdef SV_ABI_LINUX 1915 if ((nprot & PROT_EXEC) && (dsp_mmap_allow_prot_exec < 0 || 1916 (dsp_mmap_allow_prot_exec == 0 && 1917 SV_CURPROC_ABI() != SV_ABI_LINUX))) 1918 #else 1919 if ((nprot & PROT_EXEC) && dsp_mmap_allow_prot_exec < 1) 1920 #endif 1921 return (EINVAL); 1922 1923 /* 1924 * PROT_READ (alone) selects the input buffer. 1925 * PROT_WRITE (alone) selects the output buffer. 1926 * PROT_WRITE|PROT_READ together select the output buffer. 1927 */ 1928 if ((nprot & (PROT_READ | PROT_WRITE)) == 0) 1929 return (EINVAL); 1930 1931 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0) 1932 return (err); 1933 d = priv->sc; 1934 if (PCM_DETACHING(d) || !DSP_REGISTERED(d)) 1935 return (EINVAL); 1936 1937 PCM_GIANT_ENTER(d); 1938 1939 getchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR); 1940 wrch = priv->wrch; 1941 rdch = priv->rdch; 1942 1943 c = ((nprot & PROT_WRITE) != 0) ? wrch : rdch; 1944 if (c == NULL || (c->flags & CHN_F_MMAP_INVALID) || 1945 (*offset + size) > sndbuf_getallocsize(c->bufsoft) || 1946 (wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) || 1947 (rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) { 1948 relchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR); 1949 PCM_GIANT_EXIT(d); 1950 return (EINVAL); 1951 } 1952 1953 if (wrch != NULL) 1954 wrch->flags |= CHN_F_MMAP; 1955 if (rdch != NULL) 1956 rdch->flags |= CHN_F_MMAP; 1957 1958 *offset = (uintptr_t)sndbuf_getbufofs(c->bufsoft, *offset); 1959 relchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR); 1960 *object = vm_pager_allocate(OBJT_DEVICE, i_dev, 1961 size, nprot, *offset, curthread->td_ucred); 1962 1963 PCM_GIANT_LEAVE(d); 1964 1965 if (*object == NULL) 1966 return (EINVAL); 1967 return (0); 1968 } 1969 1970 static void 1971 dsp_clone(void *arg, struct ucred *cred, char *name, int namelen, 1972 struct cdev **dev) 1973 { 1974 struct snddev_info *d; 1975 size_t i; 1976 1977 if (*dev != NULL) 1978 return; 1979 if (strcmp(name, "dsp") == 0 && dsp_basename_clone) 1980 goto found; 1981 for (i = 0; i < nitems(dsp_cdevs); i++) { 1982 if (dsp_cdevs[i].alias != NULL && 1983 strcmp(name, dsp_cdevs[i].name) == 0) 1984 goto found; 1985 } 1986 return; 1987 found: 1988 bus_topo_lock(); 1989 d = devclass_get_softc(pcm_devclass, snd_unit); 1990 /* 1991 * If we only have a single soundcard attached and we detach it right 1992 * before entering dsp_clone(), there is a chance pcm_unregister() will 1993 * have returned already, meaning it will have set snd_unit to -1, and 1994 * thus devclass_get_softc() will return NULL here. 1995 */ 1996 if (d != NULL && PCM_REGISTERED(d) && d->dsp_dev != NULL) { 1997 *dev = d->dsp_dev; 1998 dev_ref(*dev); 1999 } 2000 bus_topo_unlock(); 2001 } 2002 2003 static void 2004 dsp_sysinit(void *p) 2005 { 2006 if (dsp_ehtag != NULL) 2007 return; 2008 dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000); 2009 } 2010 2011 static void 2012 dsp_sysuninit(void *p) 2013 { 2014 if (dsp_ehtag == NULL) 2015 return; 2016 EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag); 2017 dsp_ehtag = NULL; 2018 } 2019 2020 SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL); 2021 SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL); 2022 2023 char * 2024 dsp_unit2name(char *buf, size_t len, struct pcm_channel *ch) 2025 { 2026 size_t i; 2027 2028 KASSERT(buf != NULL && len != 0, 2029 ("bogus buf=%p len=%ju", buf, (uintmax_t)len)); 2030 2031 for (i = 0; i < nitems(dsp_cdevs); i++) { 2032 if (ch->type != dsp_cdevs[i].type || dsp_cdevs[i].alias != NULL) 2033 continue; 2034 snprintf(buf, len, "%s%d%s%d", 2035 dsp_cdevs[i].name, device_get_unit(ch->dev), 2036 dsp_cdevs[i].sep, ch->unit); 2037 return (buf); 2038 } 2039 2040 return (NULL); 2041 } 2042 2043 static void 2044 dsp_oss_audioinfo_unavail(oss_audioinfo *ai, int unit) 2045 { 2046 bzero(ai, sizeof(*ai)); 2047 ai->dev = unit; 2048 snprintf(ai->name, sizeof(ai->name), "pcm%d (unavailable)", unit); 2049 ai->pid = -1; 2050 ai->card_number = unit; 2051 ai->port_number = unit; 2052 ai->mixer_dev = -1; 2053 ai->legacy_device = unit; 2054 } 2055 2056 /** 2057 * @brief Handler for SNDCTL_AUDIOINFO. 2058 * 2059 * Gathers information about the audio device specified in ai->dev. If 2060 * ai->dev == -1, then this function gathers information about the current 2061 * device. If the call comes in on a non-audio device and ai->dev == -1, 2062 * return EINVAL. 2063 * 2064 * This routine is supposed to go practically straight to the hardware, 2065 * getting capabilities directly from the sound card driver, side-stepping 2066 * the intermediate channel interface. 2067 * 2068 * @note 2069 * Calling threads must not hold any snddev_info or pcm_channel locks. 2070 * 2071 * @param dev device on which the ioctl was issued 2072 * @param ai ioctl request data container 2073 * @param ex flag to distinguish between SNDCTL_AUDIOINFO from 2074 * SNDCTL_AUDIOINFO_EX 2075 * 2076 * @retval 0 success 2077 * @retval EINVAL ai->dev specifies an invalid device 2078 */ 2079 int 2080 dsp_oss_audioinfo(struct cdev *i_dev, oss_audioinfo *ai, bool ex) 2081 { 2082 struct pcmchan_caps *caps; 2083 struct pcm_channel *ch; 2084 struct snddev_info *d; 2085 uint32_t fmts; 2086 int i, minch, maxch, unit; 2087 2088 /* 2089 * If probing the device that received the ioctl, make sure it's a 2090 * DSP device. (Users may use this ioctl with /dev/mixer and 2091 * /dev/midi.) 2092 */ 2093 if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw) 2094 return (EINVAL); 2095 2096 for (unit = 0; pcm_devclass != NULL && 2097 unit < devclass_get_maxunit(pcm_devclass); unit++) { 2098 d = devclass_get_softc(pcm_devclass, unit); 2099 if (!PCM_REGISTERED(d)) { 2100 if ((ai->dev == -1 && unit == snd_unit) || 2101 ai->dev == unit) { 2102 dsp_oss_audioinfo_unavail(ai, unit); 2103 return (0); 2104 } else { 2105 d = NULL; 2106 continue; 2107 } 2108 } 2109 2110 PCM_UNLOCKASSERT(d); 2111 PCM_LOCK(d); 2112 if ((ai->dev == -1 && d->dsp_dev == i_dev) || 2113 (ai->dev == unit)) { 2114 PCM_UNLOCK(d); 2115 break; 2116 } else { 2117 PCM_UNLOCK(d); 2118 d = NULL; 2119 } 2120 } 2121 2122 /* Exhausted the search -- nothing is locked, so return. */ 2123 if (d == NULL) 2124 return (EINVAL); 2125 2126 /* XXX Need Giant magic entry ??? */ 2127 2128 PCM_UNLOCKASSERT(d); 2129 PCM_LOCK(d); 2130 2131 bzero((void *)ai, sizeof(oss_audioinfo)); 2132 ai->dev = unit; 2133 strlcpy(ai->name, device_get_desc(d->dev), sizeof(ai->name)); 2134 ai->pid = -1; 2135 ai->card_number = -1; 2136 ai->port_number = -1; 2137 ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1; 2138 ai->legacy_device = unit; 2139 snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit); 2140 ai->enabled = device_is_attached(d->dev) ? 1 : 0; 2141 ai->next_play_engine = 0; 2142 ai->next_rec_engine = 0; 2143 ai->busy = 0; 2144 ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER; 2145 ai->iformats = 0; 2146 ai->oformats = 0; 2147 ai->min_rate = INT_MAX; 2148 ai->max_rate = 0; 2149 ai->min_channels = INT_MAX; 2150 ai->max_channels = 0; 2151 2152 /* Gather global information about the device. */ 2153 CHN_FOREACH(ch, d, channels.pcm) { 2154 CHN_UNLOCKASSERT(ch); 2155 CHN_LOCK(ch); 2156 2157 /* 2158 * Skip physical channels if we are servicing SNDCTL_AUDIOINFO, 2159 * or VCHANs if we are servicing SNDCTL_AUDIOINFO_EX. 2160 */ 2161 if ((ex && (ch->flags & CHN_F_VIRTUAL) != 0) || 2162 (!ex && (ch->flags & CHN_F_VIRTUAL) == 0)) { 2163 CHN_UNLOCK(ch); 2164 continue; 2165 } 2166 2167 if ((ch->flags & CHN_F_BUSY) == 0) { 2168 ai->busy |= (ch->direction == PCMDIR_PLAY) ? 2169 OPEN_WRITE : OPEN_READ; 2170 } 2171 2172 ai->caps |= 2173 ((ch->flags & CHN_F_VIRTUAL) ? PCM_CAP_VIRTUAL : 0) | 2174 ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT : 2175 PCM_CAP_INPUT); 2176 2177 caps = chn_getcaps(ch); 2178 2179 minch = INT_MAX; 2180 maxch = 0; 2181 fmts = 0; 2182 for (i = 0; caps->fmtlist[i]; i++) { 2183 fmts |= AFMT_ENCODING(caps->fmtlist[i]); 2184 minch = min(AFMT_CHANNEL(caps->fmtlist[i]), minch); 2185 maxch = max(AFMT_CHANNEL(caps->fmtlist[i]), maxch); 2186 } 2187 2188 if (ch->direction == PCMDIR_PLAY) 2189 ai->oformats |= fmts; 2190 else 2191 ai->iformats |= fmts; 2192 2193 ai->min_rate = min(ai->min_rate, caps->minspeed); 2194 ai->max_rate = max(ai->max_rate, caps->maxspeed); 2195 ai->min_channels = min(ai->min_channels, minch); 2196 ai->max_channels = max(ai->max_channels, maxch); 2197 2198 CHN_UNLOCK(ch); 2199 } 2200 2201 PCM_UNLOCK(d); 2202 2203 return (0); 2204 } 2205 2206 static int 2207 dsp_oss_engineinfo_cb(void *data, void *arg) 2208 { 2209 struct dsp_cdevpriv *priv = data; 2210 struct pcm_channel *ch = arg; 2211 2212 if (DSP_REGISTERED(priv->sc) && (ch == priv->rdch || ch == priv->wrch)) 2213 return (1); 2214 2215 return (0); 2216 } 2217 2218 /** 2219 * @brief Handler for SNDCTL_ENGINEINFO 2220 * 2221 * Gathers information about the audio device's engine specified in ai->dev. 2222 * If ai->dev == -1, then this function gathers information about the current 2223 * device. If the call comes in on a non-audio device and ai->dev == -1, 2224 * return EINVAL. 2225 * 2226 * This routine is supposed to go practically straight to the hardware, 2227 * getting capabilities directly from the sound card driver, side-stepping 2228 * the intermediate channel interface. 2229 * 2230 * @note 2231 * Calling threads must not hold any snddev_info or pcm_channel locks. 2232 * 2233 * @param dev device on which the ioctl was issued 2234 * @param ai ioctl request data container 2235 * 2236 * @retval 0 success 2237 * @retval EINVAL ai->dev specifies an invalid device 2238 */ 2239 int 2240 dsp_oss_engineinfo(struct cdev *i_dev, oss_audioinfo *ai) 2241 { 2242 struct pcmchan_caps *caps; 2243 struct pcm_channel *ch; 2244 struct snddev_info *d; 2245 uint32_t fmts; 2246 int i, nchan, *rates, minch, maxch, unit; 2247 char *devname, buf[CHN_NAMELEN]; 2248 2249 /* 2250 * If probing the device that received the ioctl, make sure it's a 2251 * DSP device. (Users may use this ioctl with /dev/mixer and 2252 * /dev/midi.) 2253 */ 2254 if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw) 2255 return (EINVAL); 2256 2257 ch = NULL; 2258 devname = NULL; 2259 nchan = 0; 2260 bzero(buf, sizeof(buf)); 2261 2262 /* 2263 * Search for the requested audio device (channel). Start by 2264 * iterating over pcm devices. 2265 */ 2266 for (unit = 0; pcm_devclass != NULL && 2267 unit < devclass_get_maxunit(pcm_devclass); unit++) { 2268 d = devclass_get_softc(pcm_devclass, unit); 2269 if (!PCM_REGISTERED(d)) 2270 continue; 2271 2272 /* XXX Need Giant magic entry ??? */ 2273 2274 /* See the note in function docblock */ 2275 PCM_UNLOCKASSERT(d); 2276 PCM_LOCK(d); 2277 2278 CHN_FOREACH(ch, d, channels.pcm) { 2279 CHN_UNLOCKASSERT(ch); 2280 CHN_LOCK(ch); 2281 if (ai->dev == -1) { 2282 if (devfs_foreach_cdevpriv(i_dev, 2283 dsp_oss_engineinfo_cb, ch) != 0) { 2284 devname = dsp_unit2name(buf, 2285 sizeof(buf), ch); 2286 } 2287 } else if (ai->dev == nchan) 2288 devname = dsp_unit2name(buf, sizeof(buf), ch); 2289 if (devname != NULL) 2290 break; 2291 CHN_UNLOCK(ch); 2292 ++nchan; 2293 } 2294 2295 if (devname != NULL) { 2296 /* 2297 * At this point, the following synchronization stuff 2298 * has happened: 2299 * - a specific PCM device is locked. 2300 * - a specific audio channel has been locked, so be 2301 * sure to unlock when exiting; 2302 */ 2303 2304 caps = chn_getcaps(ch); 2305 2306 /* 2307 * With all handles collected, zero out the user's 2308 * container and begin filling in its fields. 2309 */ 2310 bzero((void *)ai, sizeof(oss_audioinfo)); 2311 2312 ai->dev = nchan; 2313 strlcpy(ai->name, ch->name, sizeof(ai->name)); 2314 2315 if ((ch->flags & CHN_F_BUSY) == 0) 2316 ai->busy = 0; 2317 else 2318 ai->busy = (ch->direction == PCMDIR_PLAY) ? OPEN_WRITE : OPEN_READ; 2319 2320 /** 2321 * @note 2322 * @c cmd - OSSv4 docs: "Only supported under Linux at 2323 * this moment." Cop-out, I know, but I'll save 2324 * running around in the process table for later. 2325 * Is there a risk of leaking information? 2326 */ 2327 ai->pid = ch->pid; 2328 2329 /* 2330 * These flags stolen from SNDCTL_DSP_GETCAPS handler. 2331 * Note, however, that a single channel operates in 2332 * only one direction, so PCM_CAP_DUPLEX is out. 2333 */ 2334 /** 2335 * @todo @c SNDCTL_AUDIOINFO::caps - Make drivers keep 2336 * these in pcmchan::caps? 2337 */ 2338 ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER | 2339 ((ch->flags & CHN_F_VIRTUAL) ? PCM_CAP_VIRTUAL : 0) | 2340 ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT : PCM_CAP_INPUT); 2341 2342 /* 2343 * Collect formats supported @b natively by the 2344 * device. Also determine min/max channels. (I.e., 2345 * mono, stereo, or both?) 2346 * 2347 * If any channel is stereo, maxch = 2; 2348 * if all channels are stereo, minch = 2, too; 2349 * if any channel is mono, minch = 1; 2350 * and if all channels are mono, maxch = 1. 2351 */ 2352 minch = INT_MAX; 2353 maxch = 0; 2354 fmts = 0; 2355 for (i = 0; caps->fmtlist[i]; i++) { 2356 fmts |= AFMT_ENCODING(caps->fmtlist[i]); 2357 minch = min(AFMT_CHANNEL(caps->fmtlist[i]), minch); 2358 maxch = max(AFMT_CHANNEL(caps->fmtlist[i]), maxch); 2359 } 2360 2361 if (ch->direction == PCMDIR_PLAY) 2362 ai->oformats = fmts; 2363 else 2364 ai->iformats = fmts; 2365 2366 /** 2367 * @note 2368 * @c magic - OSSv4 docs: "Reserved for internal use 2369 * by OSS." 2370 * 2371 * @par 2372 * @c card_number - OSSv4 docs: "Number of the sound 2373 * card where this device belongs or -1 if this 2374 * information is not available. Applications 2375 * should normally not use this field for any 2376 * purpose." 2377 */ 2378 ai->card_number = -1; 2379 /** 2380 * @todo @c song_name - depends first on 2381 * SNDCTL_[GS]ETSONG @todo @c label - depends 2382 * on SNDCTL_[GS]ETLABEL 2383 * @todo @c port_number - routing information? 2384 */ 2385 ai->port_number = -1; 2386 ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1; 2387 /** 2388 * @note 2389 * @c legacy_device - OSSv4 docs: "Obsolete." 2390 */ 2391 ai->legacy_device = -1; 2392 snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit); 2393 ai->enabled = device_is_attached(d->dev) ? 1 : 0; 2394 /** 2395 * @note 2396 * @c flags - OSSv4 docs: "Reserved for future use." 2397 * 2398 * @note 2399 * @c binding - OSSv4 docs: "Reserved for future use." 2400 * 2401 * @todo @c handle - haven't decided how to generate 2402 * this yet; bus, vendor, device IDs? 2403 */ 2404 ai->min_rate = caps->minspeed; 2405 ai->max_rate = caps->maxspeed; 2406 2407 ai->min_channels = minch; 2408 ai->max_channels = maxch; 2409 2410 ai->nrates = chn_getrates(ch, &rates); 2411 if (ai->nrates > OSS_MAX_SAMPLE_RATES) 2412 ai->nrates = OSS_MAX_SAMPLE_RATES; 2413 2414 for (i = 0; i < ai->nrates; i++) 2415 ai->rates[i] = rates[i]; 2416 2417 ai->next_play_engine = 0; 2418 ai->next_rec_engine = 0; 2419 2420 CHN_UNLOCK(ch); 2421 } 2422 2423 PCM_UNLOCK(d); 2424 2425 if (devname != NULL) 2426 return (0); 2427 } 2428 2429 /* Exhausted the search -- nothing is locked, so return. */ 2430 return (EINVAL); 2431 } 2432 2433 /** 2434 * @brief Assigns a PCM channel to a sync group. 2435 * 2436 * Sync groups are used to enable audio operations on multiple devices 2437 * simultaneously. They may be used with any number of devices and may 2438 * span across applications. Devices are added to groups with 2439 * the SNDCTL_DSP_SYNCGROUP ioctl, and operations are triggered with the 2440 * SNDCTL_DSP_SYNCSTART ioctl. 2441 * 2442 * If the @c id field of the @c group parameter is set to zero, then a new 2443 * sync group is created. Otherwise, wrch and rdch (if set) are added to 2444 * the group specified. 2445 * 2446 * @todo As far as memory allocation, should we assume that things are 2447 * okay and allocate with M_WAITOK before acquiring channel locks, 2448 * freeing later if not? 2449 * 2450 * @param wrch output channel associated w/ device (if any) 2451 * @param rdch input channel associated w/ device (if any) 2452 * @param group Sync group parameters 2453 * 2454 * @retval 0 success 2455 * @retval non-zero error to be propagated upstream 2456 */ 2457 static int 2458 dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group) 2459 { 2460 struct pcmchan_syncmember *smrd, *smwr; 2461 struct pcmchan_syncgroup *sg; 2462 int ret, sg_ids[3]; 2463 2464 smrd = NULL; 2465 smwr = NULL; 2466 sg = NULL; 2467 ret = 0; 2468 2469 /* 2470 * Free_unr() may sleep, so store released syncgroup IDs until after 2471 * all locks are released. 2472 */ 2473 sg_ids[0] = sg_ids[1] = sg_ids[2] = 0; 2474 2475 PCM_SG_LOCK(); 2476 2477 /* 2478 * - Insert channel(s) into group's member list. 2479 * - Set CHN_F_NOTRIGGER on channel(s). 2480 * - Stop channel(s). 2481 */ 2482 2483 /* 2484 * If device's channels are already mapped to a group, unmap them. 2485 */ 2486 if (wrch) { 2487 CHN_LOCK(wrch); 2488 sg_ids[0] = chn_syncdestroy(wrch); 2489 } 2490 2491 if (rdch) { 2492 CHN_LOCK(rdch); 2493 sg_ids[1] = chn_syncdestroy(rdch); 2494 } 2495 2496 /* 2497 * Verify that mode matches character device properites. 2498 * - Bail if PCM_ENABLE_OUTPUT && wrch == NULL. 2499 * - Bail if PCM_ENABLE_INPUT && rdch == NULL. 2500 */ 2501 if (((wrch == NULL) && (group->mode & PCM_ENABLE_OUTPUT)) || 2502 ((rdch == NULL) && (group->mode & PCM_ENABLE_INPUT))) { 2503 ret = EINVAL; 2504 goto out; 2505 } 2506 2507 /* 2508 * An id of zero indicates the user wants to create a new 2509 * syncgroup. 2510 */ 2511 if (group->id == 0) { 2512 sg = (struct pcmchan_syncgroup *)malloc(sizeof(*sg), M_DEVBUF, M_NOWAIT); 2513 if (sg != NULL) { 2514 SLIST_INIT(&sg->members); 2515 sg->id = alloc_unr(pcmsg_unrhdr); 2516 2517 group->id = sg->id; 2518 SLIST_INSERT_HEAD(&snd_pcm_syncgroups, sg, link); 2519 } else 2520 ret = ENOMEM; 2521 } else { 2522 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) { 2523 if (sg->id == group->id) 2524 break; 2525 } 2526 if (sg == NULL) 2527 ret = EINVAL; 2528 } 2529 2530 /* Couldn't create or find a syncgroup. Fail. */ 2531 if (sg == NULL) 2532 goto out; 2533 2534 /* 2535 * Allocate a syncmember, assign it and a channel together, and 2536 * insert into syncgroup. 2537 */ 2538 if (group->mode & PCM_ENABLE_INPUT) { 2539 smrd = (struct pcmchan_syncmember *)malloc(sizeof(*smrd), M_DEVBUF, M_NOWAIT); 2540 if (smrd == NULL) { 2541 ret = ENOMEM; 2542 goto out; 2543 } 2544 2545 SLIST_INSERT_HEAD(&sg->members, smrd, link); 2546 smrd->parent = sg; 2547 smrd->ch = rdch; 2548 2549 chn_abort(rdch); 2550 rdch->flags |= CHN_F_NOTRIGGER; 2551 rdch->sm = smrd; 2552 } 2553 2554 if (group->mode & PCM_ENABLE_OUTPUT) { 2555 smwr = (struct pcmchan_syncmember *)malloc(sizeof(*smwr), M_DEVBUF, M_NOWAIT); 2556 if (smwr == NULL) { 2557 ret = ENOMEM; 2558 goto out; 2559 } 2560 2561 SLIST_INSERT_HEAD(&sg->members, smwr, link); 2562 smwr->parent = sg; 2563 smwr->ch = wrch; 2564 2565 chn_abort(wrch); 2566 wrch->flags |= CHN_F_NOTRIGGER; 2567 wrch->sm = smwr; 2568 } 2569 2570 out: 2571 if (ret != 0) { 2572 if (smrd != NULL) 2573 free(smrd, M_DEVBUF); 2574 if ((sg != NULL) && SLIST_EMPTY(&sg->members)) { 2575 sg_ids[2] = sg->id; 2576 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link); 2577 free(sg, M_DEVBUF); 2578 } 2579 2580 if (wrch) 2581 wrch->sm = NULL; 2582 if (rdch) 2583 rdch->sm = NULL; 2584 } 2585 2586 if (wrch) 2587 CHN_UNLOCK(wrch); 2588 if (rdch) 2589 CHN_UNLOCK(rdch); 2590 2591 PCM_SG_UNLOCK(); 2592 2593 if (sg_ids[0]) 2594 free_unr(pcmsg_unrhdr, sg_ids[0]); 2595 if (sg_ids[1]) 2596 free_unr(pcmsg_unrhdr, sg_ids[1]); 2597 if (sg_ids[2]) 2598 free_unr(pcmsg_unrhdr, sg_ids[2]); 2599 2600 return (ret); 2601 } 2602 2603 /** 2604 * @brief Launch a sync group into action 2605 * 2606 * Sync groups are established via SNDCTL_DSP_SYNCGROUP. This function 2607 * iterates over all members, triggering them along the way. 2608 * 2609 * @note Caller must not hold any channel locks. 2610 * 2611 * @param sg_id sync group identifier 2612 * 2613 * @retval 0 success 2614 * @retval non-zero error worthy of propagating upstream to user 2615 */ 2616 static int 2617 dsp_oss_syncstart(int sg_id) 2618 { 2619 struct pcmchan_syncmember *sm, *sm_tmp; 2620 struct pcmchan_syncgroup *sg; 2621 struct pcm_channel *c; 2622 int ret, needlocks; 2623 2624 /* Get the synclists lock */ 2625 PCM_SG_LOCK(); 2626 2627 do { 2628 ret = 0; 2629 needlocks = 0; 2630 2631 /* Search for syncgroup by ID */ 2632 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) { 2633 if (sg->id == sg_id) 2634 break; 2635 } 2636 2637 /* Return EINVAL if not found */ 2638 if (sg == NULL) { 2639 ret = EINVAL; 2640 break; 2641 } 2642 2643 /* Any removals resulting in an empty group should've handled this */ 2644 KASSERT(!SLIST_EMPTY(&sg->members), ("found empty syncgroup")); 2645 2646 /* 2647 * Attempt to lock all member channels - if any are already 2648 * locked, unlock those acquired, sleep for a bit, and try 2649 * again. 2650 */ 2651 SLIST_FOREACH(sm, &sg->members, link) { 2652 if (CHN_TRYLOCK(sm->ch) == 0) { 2653 int timo = hz * 5/1000; 2654 if (timo < 1) 2655 timo = 1; 2656 2657 /* Release all locked channels so far, retry */ 2658 SLIST_FOREACH(sm_tmp, &sg->members, link) { 2659 /* sm is the member already locked */ 2660 if (sm == sm_tmp) 2661 break; 2662 CHN_UNLOCK(sm_tmp->ch); 2663 } 2664 2665 /** @todo Is PRIBIO correct/ */ 2666 ret = msleep(sm, &snd_pcm_syncgroups_mtx, 2667 PRIBIO | PCATCH, "pcmsg", timo); 2668 if (ret == EINTR || ret == ERESTART) 2669 break; 2670 2671 needlocks = 1; 2672 ret = 0; /* Assumes ret == EAGAIN... */ 2673 } 2674 } 2675 } while (needlocks && ret == 0); 2676 2677 /* Proceed only if no errors encountered. */ 2678 if (ret == 0) { 2679 /* Launch channels */ 2680 while ((sm = SLIST_FIRST(&sg->members)) != NULL) { 2681 SLIST_REMOVE_HEAD(&sg->members, link); 2682 2683 c = sm->ch; 2684 c->sm = NULL; 2685 chn_start(c, 1); 2686 c->flags &= ~CHN_F_NOTRIGGER; 2687 CHN_UNLOCK(c); 2688 2689 free(sm, M_DEVBUF); 2690 } 2691 2692 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link); 2693 free(sg, M_DEVBUF); 2694 } 2695 2696 PCM_SG_UNLOCK(); 2697 2698 /* 2699 * Free_unr() may sleep, so be sure to give up the syncgroup lock 2700 * first. 2701 */ 2702 if (ret == 0) 2703 free_unr(pcmsg_unrhdr, sg_id); 2704 2705 return (ret); 2706 } 2707 2708 /** 2709 * @brief Handler for SNDCTL_DSP_POLICY 2710 * 2711 * The SNDCTL_DSP_POLICY ioctl is a simpler interface to control fragment 2712 * size and count like with SNDCTL_DSP_SETFRAGMENT. Instead of the user 2713 * specifying those two parameters, s/he simply selects a number from 0..10 2714 * which corresponds to a buffer size. Smaller numbers request smaller 2715 * buffers with lower latencies (at greater overhead from more frequent 2716 * interrupts), while greater numbers behave in the opposite manner. 2717 * 2718 * The 4Front spec states that a value of 5 should be the default. However, 2719 * this implementation deviates slightly by using a linear scale without 2720 * consulting drivers. I.e., even though drivers may have different default 2721 * buffer sizes, a policy argument of 5 will have the same result across 2722 * all drivers. 2723 * 2724 * See http://manuals.opensound.com/developer/SNDCTL_DSP_POLICY.html for 2725 * more information. 2726 * 2727 * @todo When SNDCTL_DSP_COOKEDMODE is supported, it'll be necessary to 2728 * work with hardware drivers directly. 2729 * 2730 * @note PCM channel arguments must not be locked by caller. 2731 * 2732 * @param wrch Pointer to opened playback channel (optional; may be NULL) 2733 * @param rdch " recording channel (optional; may be NULL) 2734 * @param policy Integer from [0:10] 2735 * 2736 * @retval 0 constant (for now) 2737 */ 2738 static int 2739 dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy) 2740 { 2741 int ret; 2742 2743 if (policy < CHN_POLICY_MIN || policy > CHN_POLICY_MAX) 2744 return (EIO); 2745 2746 /* Default: success */ 2747 ret = 0; 2748 2749 if (rdch) { 2750 CHN_LOCK(rdch); 2751 ret = chn_setlatency(rdch, policy); 2752 CHN_UNLOCK(rdch); 2753 } 2754 2755 if (wrch && ret == 0) { 2756 CHN_LOCK(wrch); 2757 ret = chn_setlatency(wrch, policy); 2758 CHN_UNLOCK(wrch); 2759 } 2760 2761 if (ret) 2762 ret = EIO; 2763 2764 return (ret); 2765 } 2766 2767 /** 2768 * @brief Enable or disable "cooked" mode 2769 * 2770 * This is a handler for @c SNDCTL_DSP_COOKEDMODE. When in cooked mode, which 2771 * is the default, the sound system handles rate and format conversions 2772 * automatically (ex: user writing 11025Hz/8 bit/unsigned but card only 2773 * operates with 44100Hz/16bit/signed samples). 2774 * 2775 * Disabling cooked mode is intended for applications wanting to mmap() 2776 * a sound card's buffer space directly, bypassing the FreeBSD 2-stage 2777 * feeder architecture, presumably to gain as much control over audio 2778 * hardware as possible. 2779 * 2780 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_COOKEDMODE.html 2781 * for more details. 2782 * 2783 * @param wrch playback channel (optional; may be NULL) 2784 * @param rdch recording channel (optional; may be NULL) 2785 * @param enabled 0 = raw mode, 1 = cooked mode 2786 * 2787 * @retval EINVAL Operation not yet supported. 2788 */ 2789 static int 2790 dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled) 2791 { 2792 2793 /* 2794 * XXX I just don't get it. Why don't they call it 2795 * "BITPERFECT" ~ SNDCTL_DSP_BITPERFECT !?!?. 2796 * This is just plain so confusing, incoherent, 2797 * <insert any non-printable characters here>. 2798 */ 2799 if (!(enabled == 1 || enabled == 0)) 2800 return (EINVAL); 2801 2802 /* 2803 * I won't give in. I'm inverting its logic here and now. 2804 * Brag all you want, but "BITPERFECT" should be the better 2805 * term here. 2806 */ 2807 enabled ^= 0x00000001; 2808 2809 if (wrch != NULL) { 2810 CHN_LOCK(wrch); 2811 wrch->flags &= ~CHN_F_BITPERFECT; 2812 wrch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000; 2813 CHN_UNLOCK(wrch); 2814 } 2815 2816 if (rdch != NULL) { 2817 CHN_LOCK(rdch); 2818 rdch->flags &= ~CHN_F_BITPERFECT; 2819 rdch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000; 2820 CHN_UNLOCK(rdch); 2821 } 2822 2823 return (0); 2824 } 2825 2826 /** 2827 * @brief Retrieve channel interleaving order 2828 * 2829 * This is the handler for @c SNDCTL_DSP_GET_CHNORDER. 2830 * 2831 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_GET_CHNORDER.html 2832 * for more details. 2833 * 2834 * @note As the ioctl definition is still under construction, FreeBSD 2835 * does not currently support SNDCTL_DSP_GET_CHNORDER. 2836 * 2837 * @param wrch playback channel (optional; may be NULL) 2838 * @param rdch recording channel (optional; may be NULL) 2839 * @param map channel map (result will be stored there) 2840 * 2841 * @retval EINVAL Operation not yet supported. 2842 */ 2843 static int 2844 dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map) 2845 { 2846 struct pcm_channel *ch; 2847 int ret; 2848 2849 ch = (wrch != NULL) ? wrch : rdch; 2850 if (ch != NULL) { 2851 CHN_LOCK(ch); 2852 ret = chn_oss_getorder(ch, map); 2853 CHN_UNLOCK(ch); 2854 } else 2855 ret = EINVAL; 2856 2857 return (ret); 2858 } 2859 2860 /** 2861 * @brief Specify channel interleaving order 2862 * 2863 * This is the handler for @c SNDCTL_DSP_SET_CHNORDER. 2864 * 2865 * @note As the ioctl definition is still under construction, FreeBSD 2866 * does not currently support @c SNDCTL_DSP_SET_CHNORDER. 2867 * 2868 * @param wrch playback channel (optional; may be NULL) 2869 * @param rdch recording channel (optional; may be NULL) 2870 * @param map channel map 2871 * 2872 * @retval EINVAL Operation not yet supported. 2873 */ 2874 static int 2875 dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map) 2876 { 2877 int ret; 2878 2879 ret = 0; 2880 2881 if (wrch != NULL) { 2882 CHN_LOCK(wrch); 2883 ret = chn_oss_setorder(wrch, map); 2884 CHN_UNLOCK(wrch); 2885 } 2886 2887 if (ret == 0 && rdch != NULL) { 2888 CHN_LOCK(rdch); 2889 ret = chn_oss_setorder(rdch, map); 2890 CHN_UNLOCK(rdch); 2891 } 2892 2893 return (ret); 2894 } 2895 2896 static int 2897 dsp_oss_getchannelmask(struct pcm_channel *wrch, struct pcm_channel *rdch, 2898 int *mask) 2899 { 2900 struct pcm_channel *ch; 2901 uint32_t chnmask; 2902 int ret; 2903 2904 chnmask = 0; 2905 ch = (wrch != NULL) ? wrch : rdch; 2906 2907 if (ch != NULL) { 2908 CHN_LOCK(ch); 2909 ret = chn_oss_getmask(ch, &chnmask); 2910 CHN_UNLOCK(ch); 2911 } else 2912 ret = EINVAL; 2913 2914 if (ret == 0) 2915 *mask = chnmask; 2916 2917 return (ret); 2918 } 2919 2920 #ifdef OSSV4_EXPERIMENT 2921 /** 2922 * @brief Retrieve an audio device's label 2923 * 2924 * This is a handler for the @c SNDCTL_GETLABEL ioctl. 2925 * 2926 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html 2927 * for more details. 2928 * 2929 * From Hannu@4Front: "For example ossxmix (just like some HW mixer 2930 * consoles) can show variable "labels" for certain controls. By default 2931 * the application name (say quake) is shown as the label but 2932 * applications may change the labels themselves." 2933 * 2934 * @note As the ioctl definition is still under construction, FreeBSD 2935 * does not currently support @c SNDCTL_GETLABEL. 2936 * 2937 * @param wrch playback channel (optional; may be NULL) 2938 * @param rdch recording channel (optional; may be NULL) 2939 * @param label label gets copied here 2940 * 2941 * @retval EINVAL Operation not yet supported. 2942 */ 2943 static int 2944 dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label) 2945 { 2946 return (EINVAL); 2947 } 2948 2949 /** 2950 * @brief Specify an audio device's label 2951 * 2952 * This is a handler for the @c SNDCTL_SETLABEL ioctl. Please see the 2953 * comments for @c dsp_oss_getlabel immediately above. 2954 * 2955 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html 2956 * for more details. 2957 * 2958 * @note As the ioctl definition is still under construction, FreeBSD 2959 * does not currently support SNDCTL_SETLABEL. 2960 * 2961 * @param wrch playback channel (optional; may be NULL) 2962 * @param rdch recording channel (optional; may be NULL) 2963 * @param label label gets copied from here 2964 * 2965 * @retval EINVAL Operation not yet supported. 2966 */ 2967 static int 2968 dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label) 2969 { 2970 return (EINVAL); 2971 } 2972 2973 /** 2974 * @brief Retrieve name of currently played song 2975 * 2976 * This is a handler for the @c SNDCTL_GETSONG ioctl. Audio players could 2977 * tell the system the name of the currently playing song, which would be 2978 * visible in @c /dev/sndstat. 2979 * 2980 * See @c http://manuals.opensound.com/developer/SNDCTL_GETSONG.html 2981 * for more details. 2982 * 2983 * @note As the ioctl definition is still under construction, FreeBSD 2984 * does not currently support SNDCTL_GETSONG. 2985 * 2986 * @param wrch playback channel (optional; may be NULL) 2987 * @param rdch recording channel (optional; may be NULL) 2988 * @param song song name gets copied here 2989 * 2990 * @retval EINVAL Operation not yet supported. 2991 */ 2992 static int 2993 dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song) 2994 { 2995 return (EINVAL); 2996 } 2997 2998 /** 2999 * @brief Retrieve name of currently played song 3000 * 3001 * This is a handler for the @c SNDCTL_SETSONG ioctl. Audio players could 3002 * tell the system the name of the currently playing song, which would be 3003 * visible in @c /dev/sndstat. 3004 * 3005 * See @c http://manuals.opensound.com/developer/SNDCTL_SETSONG.html 3006 * for more details. 3007 * 3008 * @note As the ioctl definition is still under construction, FreeBSD 3009 * does not currently support SNDCTL_SETSONG. 3010 * 3011 * @param wrch playback channel (optional; may be NULL) 3012 * @param rdch recording channel (optional; may be NULL) 3013 * @param song song name gets copied from here 3014 * 3015 * @retval EINVAL Operation not yet supported. 3016 */ 3017 static int 3018 dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song) 3019 { 3020 return (EINVAL); 3021 } 3022 3023 /** 3024 * @brief Rename a device 3025 * 3026 * This is a handler for the @c SNDCTL_SETNAME ioctl. 3027 * 3028 * See @c http://manuals.opensound.com/developer/SNDCTL_SETNAME.html for 3029 * more details. 3030 * 3031 * From Hannu@4Front: "This call is used to change the device name 3032 * reported in /dev/sndstat and ossinfo. So instead of using some generic 3033 * 'OSS loopback audio (MIDI) driver' the device may be given a meaningfull 3034 * name depending on the current context (for example 'OSS virtual wave table 3035 * synth' or 'VoIP link to London')." 3036 * 3037 * @note As the ioctl definition is still under construction, FreeBSD 3038 * does not currently support SNDCTL_SETNAME. 3039 * 3040 * @param wrch playback channel (optional; may be NULL) 3041 * @param rdch recording channel (optional; may be NULL) 3042 * @param name new device name gets copied from here 3043 * 3044 * @retval EINVAL Operation not yet supported. 3045 */ 3046 static int 3047 dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name) 3048 { 3049 return (EINVAL); 3050 } 3051 #endif /* !OSSV4_EXPERIMENT */ 3052