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