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