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