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