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 } 2216 break; 2217 case EVFILT_WRITE: 2218 if (wrch) { 2219 kn->kn_fop = &dsp_write_filtops; 2220 kn->kn_hook = (caddr_t)wrch; 2221 bs = wrch->bufsoft; 2222 ap->a_result = 0; 2223 } 2224 break; 2225 default: 2226 ap->a_result = EOPNOTSUPP; 2227 break; 2228 } 2229 2230 if (ap->a_result == 0) { 2231 klist = &sndbuf_getkq(bs)->ki_note; 2232 knote_insert(klist, kn); 2233 } 2234 2235 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 2236 2237 PCM_GIANT_LEAVE(d); 2238 2239 return (ret); 2240 } 2241 2242 static void 2243 dsp_filter_detach(struct knote *kn) 2244 { 2245 struct pcm_channel *ch = (struct pcm_channel *)kn->kn_hook; 2246 struct snd_dbuf *bs = ch->bufsoft; 2247 struct klist *klist; 2248 2249 CHN_LOCK(ch); 2250 klist = &sndbuf_getkq(bs)->ki_note; 2251 knote_remove(klist, kn); 2252 CHN_UNLOCK(ch); 2253 } 2254 2255 static int 2256 dsp_filter_read(struct knote *kn, long hint) 2257 { 2258 struct pcm_channel *rdch = (struct pcm_channel *)kn->kn_hook; 2259 struct thread *td = curthread; 2260 int ready; 2261 2262 CHN_LOCK(rdch); 2263 ready = chn_poll(rdch, 1, td); 2264 CHN_UNLOCK(rdch); 2265 2266 return (ready); 2267 } 2268 2269 static int 2270 dsp_filter_write(struct knote *kn, long hint) 2271 { 2272 struct pcm_channel *wrch = (struct pcm_channel *)kn->kn_hook; 2273 struct thread *td = curthread; 2274 int ready; 2275 2276 CHN_LOCK(wrch); 2277 ready = chn_poll(wrch, 1, td); 2278 CHN_UNLOCK(wrch); 2279 2280 return (ready); 2281 } 2282 2283 static int 2284 dsp_mmap(struct dev_mmap_args *ap) 2285 { 2286 vm_offset_t offset = ap->a_offset; 2287 2288 ap->a_result = atop(vtophys(offset)); 2289 return (0); 2290 } 2291 2292 static int 2293 dsp_mmap_single(struct dev_mmap_single_args *ap) 2294 { 2295 struct cdev *i_dev = ap->a_head.a_dev; 2296 vm_ooffset_t *offset = ap->a_offset; 2297 vm_size_t size = ap->a_size; 2298 struct vm_object **object = ap->a_object; 2299 int nprot = ap->a_nprot; 2300 struct snddev_info *d; 2301 struct pcm_channel *wrch, *rdch, *c; 2302 2303 /* 2304 * Reject PROT_EXEC by default. It just doesn't makes sense. 2305 * Unfortunately, we have to give up this one due to linux_mmap 2306 * changes. 2307 * 2308 * http://lists.freebsd.org/pipermail/freebsd-emulation/2007-June/003698.html 2309 * 2310 */ 2311 #ifdef SV_ABI_LINUX 2312 if ((nprot & PROT_EXEC) && (dsp_mmap_allow_prot_exec < 0 || 2313 (dsp_mmap_allow_prot_exec == 0 && 2314 SV_CURPROC_ABI() != SV_ABI_LINUX))) 2315 #else 2316 if ((nprot & PROT_EXEC) && dsp_mmap_allow_prot_exec < 1) 2317 #endif 2318 return (EINVAL); 2319 2320 /* 2321 * PROT_READ (alone) selects the input buffer. 2322 * PROT_WRITE (alone) selects the output buffer. 2323 * PROT_WRITE|PROT_READ together select the output buffer. 2324 */ 2325 if ((nprot & (PROT_READ | PROT_WRITE)) == 0) 2326 return (EINVAL); 2327 2328 d = dsp_get_info(i_dev); 2329 if (!DSP_REGISTERED(d, i_dev)) 2330 return (EINVAL); 2331 2332 PCM_GIANT_ENTER(d); 2333 2334 getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 2335 2336 c = ((nprot & PROT_WRITE) != 0) ? wrch : rdch; 2337 if (c == NULL || (c->flags & CHN_F_MMAP_INVALID) || 2338 (*offset + size) > sndbuf_getsize(c->bufsoft) || 2339 (wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) || 2340 (rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) { 2341 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 2342 PCM_GIANT_EXIT(d); 2343 return (EINVAL); 2344 } 2345 2346 if (wrch != NULL) 2347 wrch->flags |= CHN_F_MMAP; 2348 if (rdch != NULL) 2349 rdch->flags |= CHN_F_MMAP; 2350 2351 *offset = (uintptr_t)sndbuf_getbufofs(c->bufsoft, *offset); 2352 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 2353 *object = dev_pager_alloc(i_dev, size, nprot, *offset); 2354 2355 PCM_GIANT_LEAVE(d); 2356 2357 if (*object == NULL) 2358 return (EINVAL); 2359 return (0); 2360 } 2361 2362 /* 2363 * for i = 0 to channels of device N 2364 * if dspN.i isn't busy and in the right dir, create a dev_t and return it 2365 */ 2366 int 2367 dsp_clone(struct dev_clone_args *ap) 2368 { 2369 struct cdev *i_dev = ap->a_head.a_dev; 2370 struct snddev_info *d; 2371 struct snd_clone_entry *ce; 2372 struct pcm_channel *c; 2373 int i, unit, udcmask, cunit, devtype, devhw, devcmax, tumax; 2374 size_t len; 2375 char sname[64]; 2376 int err = EBUSY; 2377 static struct cdev *dev = NULL; 2378 2379 KASSERT(dsp_umax >= 0 && dsp_cmax >= 0, ("Uninitialized unit!")); 2380 2381 /* 2382 * The default dsp device has a special unit which must be adjusted, 2383 * otherwise the unit number is already correct. 2384 */ 2385 unit = PCMUNIT(i_dev); 2386 if (unit == PCMUNIT_DEFAULT) 2387 unit = snd_unit; 2388 2389 ksnprintf(sname, sizeof(sname), "%s", ap->a_name); 2390 len = strlen(sname); 2391 while (len && sname[len-1] >= '0' && sname[len-1] <= '9') 2392 --len; 2393 sname[len] = 0; 2394 2395 cunit = -1; 2396 devtype = -1; 2397 devhw = 0; 2398 devcmax = -1; 2399 tumax = -1; 2400 2401 for (i = 0; i < sizeof(dsp_cdevs) / sizeof(dsp_cdevs[0]); ++i) { 2402 if (strcmp(dsp_cdevs[i].name, sname) != 0) 2403 continue; 2404 devtype = dsp_cdevs[i].type; 2405 devhw = dsp_cdevs[i].hw; 2406 devcmax = dsp_cdevs[i].max - 1; 2407 break; 2408 } 2409 2410 d = devclass_get_softc(pcm_devclass, unit); 2411 if (!PCM_REGISTERED(d) || d->clones == NULL) { 2412 return (ENODEV); 2413 } 2414 2415 /* XXX Need Giant magic entry ??? */ 2416 2417 PCM_LOCK(d); 2418 if (snd_clone_disabled(d->clones)) { 2419 PCM_UNLOCK(d); 2420 return (ENODEV); 2421 } 2422 2423 PCM_WAIT(d); 2424 PCM_ACQUIRE(d); 2425 PCM_UNLOCK(d); 2426 2427 udcmask = snd_u2unit(unit) | snd_d2unit(devtype); 2428 2429 if (devhw != 0) { 2430 KASSERT(devcmax <= dsp_cmax, 2431 ("overflow: devcmax=%d, dsp_cmax=%d", devcmax, dsp_cmax)); 2432 if (cunit > devcmax) { 2433 PCM_RELEASE_QUICK(d); 2434 return (ENODEV); 2435 } 2436 udcmask |= snd_c2unit(cunit); 2437 CHN_FOREACH(c, d, channels.pcm) { 2438 CHN_LOCK(c); 2439 if (c->unit != udcmask) { 2440 CHN_UNLOCK(c); 2441 continue; 2442 } 2443 CHN_UNLOCK(c); 2444 udcmask &= ~snd_c2unit(cunit); 2445 /* 2446 * Temporarily increase clone maxunit to overcome 2447 * vchan flexibility. 2448 * 2449 * # sysctl dev.pcm.0.play.vchans=256 2450 * dev.pcm.0.play.vchans: 1 -> 256 2451 * # cat /dev/zero > /dev/dsp0.vp255 & 2452 * [1] 17296 2453 * # sysctl dev.pcm.0.play.vchans=0 2454 * dev.pcm.0.play.vchans: 256 -> 1 2455 * # fg 2456 * [1] + running cat /dev/zero > /dev/dsp0.vp255 2457 * ^C 2458 * # cat /dev/zero > /dev/dsp0.vp255 2459 * zsh: operation not supported: /dev/dsp0.vp255 2460 */ 2461 tumax = snd_clone_getmaxunit(d->clones); 2462 if (cunit > tumax) 2463 snd_clone_setmaxunit(d->clones, cunit); 2464 else 2465 tumax = -1; 2466 goto dsp_clone_alloc; 2467 } 2468 /* 2469 * Ok, so we're requesting unallocated vchan, but still 2470 * within maximum vchan limit. 2471 */ 2472 if (((devtype == SND_DEV_DSPHW_VPLAY && d->pvchancount > 0) || 2473 (devtype == SND_DEV_DSPHW_VREC && d->rvchancount > 0)) && 2474 cunit < snd_maxautovchans) { 2475 udcmask &= ~snd_c2unit(cunit); 2476 tumax = snd_clone_getmaxunit(d->clones); 2477 if (cunit > tumax) 2478 snd_clone_setmaxunit(d->clones, cunit); 2479 else 2480 tumax = -1; 2481 goto dsp_clone_alloc; 2482 } 2483 PCM_RELEASE_QUICK(d); 2484 return (err); 2485 } 2486 2487 /* 2488 * Allocate channel, create device if necessary. 2489 */ 2490 dsp_clone_alloc: 2491 ce = snd_clone_alloc(d->clones, &dev, &cunit, udcmask); 2492 if (tumax != -1) 2493 snd_clone_setmaxunit(d->clones, tumax); 2494 if (ce != NULL) { 2495 /* 2496 * NOTE: Subunit is a unique number unrelated to the 2497 * channel id. 2498 */ 2499 udcmask |= snd_c2unit(cunit); 2500 int subunit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(dsp), 0); 2501 2502 dev = make_only_dev(&dsp_ops, 2503 PCMMKMINOR(unit, devtype, subunit), 2504 UID_ROOT, GID_WHEEL, 0666, "%s%d.%d", 2505 sname, unit, subunit); 2506 snd_clone_register(ce, dev); 2507 err = 0; 2508 } else { 2509 /* 2510 * Use device already registered, we must add a ref to the 2511 * device. 2512 */ 2513 err = 0; 2514 } 2515 2516 ap->a_dev = dev; 2517 2518 PCM_RELEASE_QUICK(d); 2519 2520 return (err); 2521 } 2522 2523 static void 2524 dsp_sysinit(void *p) 2525 { 2526 if (dsp_ehtag != NULL) 2527 return; 2528 /* initialize unit numbering */ 2529 snd_unit_init(); 2530 dsp_umax = PCMMAXUNIT; 2531 dsp_cmax = PCMMAXCHAN; 2532 dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000); 2533 2534 devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(dsp)); 2535 } 2536 2537 static void 2538 dsp_sysuninit(void *p) 2539 { 2540 if (dsp_ehtag == NULL) 2541 return; 2542 EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag); 2543 dsp_ehtag = NULL; 2544 } 2545 2546 SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL); 2547 SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL); 2548 2549 char * 2550 dsp_unit2name(char *buf, size_t len, int unit) 2551 { 2552 int i, dtype; 2553 2554 KASSERT(buf != NULL && len != 0, 2555 ("bogus buf=%p len=%ju", buf, (uintmax_t)len)); 2556 2557 dtype = snd_unit2d(unit); 2558 2559 for (i = 0; i < (sizeof(dsp_cdevs) / sizeof(dsp_cdevs[0])); i++) { 2560 if (dtype != dsp_cdevs[i].type || dsp_cdevs[i].alias != NULL) 2561 continue; 2562 ksnprintf(buf, len, "%s%d%s%d", dsp_cdevs[i].name, 2563 snd_unit2u(unit), dsp_cdevs[i].sep, snd_unit2c(unit)); 2564 return (buf); 2565 } 2566 2567 return (NULL); 2568 } 2569 2570 /** 2571 * @brief Handler for SNDCTL_AUDIOINFO. 2572 * 2573 * Gathers information about the audio device specified in ai->dev. If 2574 * ai->dev == -1, then this function gathers information about the current 2575 * device. If the call comes in on a non-audio device and ai->dev == -1, 2576 * return EINVAL. 2577 * 2578 * This routine is supposed to go practically straight to the hardware, 2579 * getting capabilities directly from the sound card driver, side-stepping 2580 * the intermediate channel interface. 2581 * 2582 * Note, however, that the usefulness of this command is significantly 2583 * decreased when requesting info about any device other than the one serving 2584 * the request. While each snddev_channel refers to a specific device node, 2585 * the converse is *not* true. Currently, when a sound device node is opened, 2586 * the sound subsystem scans for an available audio channel (or channels, if 2587 * opened in read+write) and then assigns them to the si_drv[12] private 2588 * data fields. As a result, any information returned linking a channel to 2589 * a specific character device isn't necessarily accurate. 2590 * 2591 * @note 2592 * Calling threads must not hold any snddev_info or pcm_channel locks. 2593 * 2594 * @param dev device on which the ioctl was issued 2595 * @param ai ioctl request data container 2596 * 2597 * @retval 0 success 2598 * @retval EINVAL ai->dev specifies an invalid device 2599 * 2600 * @todo Verify correctness of Doxygen tags. ;) 2601 */ 2602 int 2603 dsp_oss_audioinfo(struct cdev *i_dev, oss_audioinfo *ai) 2604 { 2605 struct pcmchan_caps *caps; 2606 struct pcm_channel *ch; 2607 struct snddev_info *d; 2608 uint32_t fmts; 2609 int i, nchan, *rates, minch, maxch; 2610 char *devname, buf[CHN_NAMELEN]; 2611 2612 /* 2613 * If probing the device that received the ioctl, make sure it's a 2614 * DSP device. (Users may use this ioctl with /dev/mixer and 2615 * /dev/midi.) 2616 */ 2617 if (ai->dev == -1 && i_dev->si_ops != &dsp_ops) 2618 return (EINVAL); 2619 2620 ch = NULL; 2621 devname = NULL; 2622 nchan = 0; 2623 bzero(buf, sizeof(buf)); 2624 2625 /* 2626 * Search for the requested audio device (channel). Start by 2627 * iterating over pcm devices. 2628 */ 2629 for (i = 0; pcm_devclass != NULL && 2630 i < devclass_get_maxunit(pcm_devclass); i++) { 2631 d = devclass_get_softc(pcm_devclass, i); 2632 if (!PCM_REGISTERED(d)) 2633 continue; 2634 2635 /* XXX Need Giant magic entry ??? */ 2636 2637 /* See the note in function docblock */ 2638 PCM_UNLOCKASSERT(d); 2639 PCM_LOCK(d); 2640 2641 CHN_FOREACH(ch, d, channels.pcm) { 2642 CHN_UNLOCKASSERT(ch); 2643 CHN_LOCK(ch); 2644 if (ai->dev == -1) { 2645 if (DSP_REGISTERED(d, i_dev) && 2646 (ch == PCM_RDCH(i_dev) || /* record ch */ 2647 ch == PCM_WRCH(i_dev))) { /* playback ch */ 2648 devname = dsp_unit2name(buf, 2649 sizeof(buf), ch->unit); 2650 } 2651 } else if (ai->dev == nchan) { 2652 devname = dsp_unit2name(buf, sizeof(buf), 2653 ch->unit); 2654 } 2655 if (devname != NULL) 2656 break; 2657 CHN_UNLOCK(ch); 2658 ++nchan; 2659 } 2660 2661 if (devname != NULL) { 2662 /* 2663 * At this point, the following synchronization stuff 2664 * has happened: 2665 * - a specific PCM device is locked. 2666 * - a specific audio channel has been locked, so be 2667 * sure to unlock when exiting; 2668 */ 2669 2670 caps = chn_getcaps(ch); 2671 2672 /* 2673 * With all handles collected, zero out the user's 2674 * container and begin filling in its fields. 2675 */ 2676 bzero((void *)ai, sizeof(oss_audioinfo)); 2677 2678 ai->dev = nchan; 2679 strlcpy(ai->name, ch->name, sizeof(ai->name)); 2680 2681 if ((ch->flags & CHN_F_BUSY) == 0) 2682 ai->busy = 0; 2683 else 2684 ai->busy = (ch->direction == PCMDIR_PLAY) ? OPEN_WRITE : OPEN_READ; 2685 2686 /** 2687 * @note 2688 * @c cmd - OSSv4 docs: "Only supported under Linux at 2689 * this moment." Cop-out, I know, but I'll save 2690 * running around in the process table for later. 2691 * Is there a risk of leaking information? 2692 */ 2693 ai->pid = ch->pid; 2694 2695 /* 2696 * These flags stolen from SNDCTL_DSP_GETCAPS handler. 2697 * Note, however, that a single channel operates in 2698 * only one direction, so PCM_CAP_DUPLEX is out. 2699 */ 2700 /** 2701 * @todo @c SNDCTL_AUDIOINFO::caps - Make drivers keep 2702 * these in pcmchan::caps? 2703 */ 2704 ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER | 2705 ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT : PCM_CAP_INPUT); 2706 2707 /* 2708 * Collect formats supported @b natively by the 2709 * device. Also determine min/max channels. (I.e., 2710 * mono, stereo, or both?) 2711 * 2712 * If any channel is stereo, maxch = 2; 2713 * if all channels are stereo, minch = 2, too; 2714 * if any channel is mono, minch = 1; 2715 * and if all channels are mono, maxch = 1. 2716 */ 2717 minch = 0; 2718 maxch = 0; 2719 fmts = 0; 2720 for (i = 0; caps->fmtlist[i]; i++) { 2721 fmts |= caps->fmtlist[i]; 2722 if (AFMT_CHANNEL(caps->fmtlist[i]) > 1) { 2723 minch = (minch == 0) ? 2 : minch; 2724 maxch = 2; 2725 } else { 2726 minch = 1; 2727 maxch = (maxch == 0) ? 1 : maxch; 2728 } 2729 } 2730 2731 if (ch->direction == PCMDIR_PLAY) 2732 ai->oformats = fmts; 2733 else 2734 ai->iformats = fmts; 2735 2736 /** 2737 * @note 2738 * @c magic - OSSv4 docs: "Reserved for internal use 2739 * by OSS." 2740 * 2741 * @par 2742 * @c card_number - OSSv4 docs: "Number of the sound 2743 * card where this device belongs or -1 if this 2744 * information is not available. Applications 2745 * should normally not use this field for any 2746 * purpose." 2747 */ 2748 ai->card_number = -1; 2749 /** 2750 * @todo @c song_name - depends first on 2751 * SNDCTL_[GS]ETSONG @todo @c label - depends 2752 * on SNDCTL_[GS]ETLABEL 2753 * @todo @c port_number - routing information? 2754 */ 2755 ai->port_number = -1; 2756 ai->mixer_dev = (d->mixer_dev != NULL) ? PCMUNIT(d->mixer_dev) : -1; 2757 /** 2758 * @note 2759 * @c real_device - OSSv4 docs: "Obsolete." 2760 */ 2761 ai->real_device = -1; 2762 strlcpy(ai->devnode, "/dev/", sizeof(ai->devnode)); 2763 strlcat(ai->devnode, devname, sizeof(ai->devnode)); 2764 ai->enabled = device_is_attached(d->dev) ? 1 : 0; 2765 /** 2766 * @note 2767 * @c flags - OSSv4 docs: "Reserved for future use." 2768 * 2769 * @note 2770 * @c binding - OSSv4 docs: "Reserved for future use." 2771 * 2772 * @todo @c handle - haven't decided how to generate 2773 * this yet; bus, vendor, device IDs? 2774 */ 2775 ai->min_rate = caps->minspeed; 2776 ai->max_rate = caps->maxspeed; 2777 2778 ai->min_channels = minch; 2779 ai->max_channels = maxch; 2780 2781 ai->nrates = chn_getrates(ch, &rates); 2782 if (ai->nrates > OSS_MAX_SAMPLE_RATES) 2783 ai->nrates = OSS_MAX_SAMPLE_RATES; 2784 2785 for (i = 0; i < ai->nrates; i++) 2786 ai->rates[i] = rates[i]; 2787 2788 ai->next_play_engine = 0; 2789 ai->next_rec_engine = 0; 2790 2791 CHN_UNLOCK(ch); 2792 } 2793 2794 PCM_UNLOCK(d); 2795 2796 if (devname != NULL) 2797 return (0); 2798 } 2799 2800 /* Exhausted the search -- nothing is locked, so return. */ 2801 return (EINVAL); 2802 } 2803 2804 /** 2805 * @brief Assigns a PCM channel to a sync group. 2806 * 2807 * Sync groups are used to enable audio operations on multiple devices 2808 * simultaneously. They may be used with any number of devices and may 2809 * span across applications. Devices are added to groups with 2810 * the SNDCTL_DSP_SYNCGROUP ioctl, and operations are triggered with the 2811 * SNDCTL_DSP_SYNCSTART ioctl. 2812 * 2813 * If the @c id field of the @c group parameter is set to zero, then a new 2814 * sync group is created. Otherwise, wrch and rdch (if set) are added to 2815 * the group specified. 2816 * 2817 * @todo As far as memory allocation, should we assume that things are 2818 * okay and allocate with M_WAITOK before acquiring channel locks, 2819 * freeing later if not? 2820 * 2821 * @param wrch output channel associated w/ device (if any) 2822 * @param rdch input channel associated w/ device (if any) 2823 * @param group Sync group parameters 2824 * 2825 * @retval 0 success 2826 * @retval non-zero error to be propagated upstream 2827 */ 2828 static int 2829 dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group) 2830 { 2831 struct pcmchan_syncmember *smrd, *smwr; 2832 struct pcmchan_syncgroup *sg; 2833 int ret, sg_ids[3]; 2834 2835 smrd = NULL; 2836 smwr = NULL; 2837 sg = NULL; 2838 ret = 0; 2839 2840 /* 2841 * Free_unr() may sleep, so store released syncgroup IDs until after 2842 * all locks are released. 2843 */ 2844 sg_ids[0] = sg_ids[1] = sg_ids[2] = 0; 2845 2846 PCM_SG_LOCK(); 2847 2848 /* 2849 * - Insert channel(s) into group's member list. 2850 * - Set CHN_F_NOTRIGGER on channel(s). 2851 * - Stop channel(s). 2852 */ 2853 2854 /* 2855 * If device's channels are already mapped to a group, unmap them. 2856 */ 2857 if (wrch) { 2858 CHN_LOCK(wrch); 2859 sg_ids[0] = chn_syncdestroy(wrch); 2860 } 2861 2862 if (rdch) { 2863 CHN_LOCK(rdch); 2864 sg_ids[1] = chn_syncdestroy(rdch); 2865 } 2866 2867 /* 2868 * Verify that mode matches character device properites. 2869 * - Bail if PCM_ENABLE_OUTPUT && wrch == NULL. 2870 * - Bail if PCM_ENABLE_INPUT && rdch == NULL. 2871 */ 2872 if (((wrch == NULL) && (group->mode & PCM_ENABLE_OUTPUT)) || 2873 ((rdch == NULL) && (group->mode & PCM_ENABLE_INPUT))) { 2874 ret = EINVAL; 2875 goto out; 2876 } 2877 2878 /* 2879 * An id of zero indicates the user wants to create a new 2880 * syncgroup. 2881 */ 2882 if (group->id == 0) { 2883 sg = (struct pcmchan_syncgroup *)kmalloc(sizeof(*sg), M_DEVBUF, M_WAITOK | M_ZERO); 2884 if (sg != NULL) { 2885 SLIST_INIT(&sg->members); 2886 sg->id = alloc_unr(pcmsg_unrhdr); 2887 2888 group->id = sg->id; 2889 SLIST_INSERT_HEAD(&snd_pcm_syncgroups, sg, link); 2890 } else 2891 ret = ENOMEM; 2892 } else { 2893 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) { 2894 if (sg->id == group->id) 2895 break; 2896 } 2897 if (sg == NULL) 2898 ret = EINVAL; 2899 } 2900 2901 /* Couldn't create or find a syncgroup. Fail. */ 2902 if (sg == NULL) 2903 goto out; 2904 2905 /* 2906 * Allocate a syncmember, assign it and a channel together, and 2907 * insert into syncgroup. 2908 */ 2909 if (group->mode & PCM_ENABLE_INPUT) { 2910 smrd = (struct pcmchan_syncmember *)kmalloc(sizeof(*smrd), M_DEVBUF, M_WAITOK | M_ZERO); 2911 if (smrd == NULL) { 2912 ret = ENOMEM; 2913 goto out; 2914 } 2915 2916 SLIST_INSERT_HEAD(&sg->members, smrd, link); 2917 smrd->parent = sg; 2918 smrd->ch = rdch; 2919 2920 chn_abort(rdch); 2921 rdch->flags |= CHN_F_NOTRIGGER; 2922 rdch->sm = smrd; 2923 } 2924 2925 if (group->mode & PCM_ENABLE_OUTPUT) { 2926 smwr = (struct pcmchan_syncmember *)kmalloc(sizeof(*smwr), M_DEVBUF, M_WAITOK | M_ZERO); 2927 if (smwr == NULL) { 2928 ret = ENOMEM; 2929 goto out; 2930 } 2931 2932 SLIST_INSERT_HEAD(&sg->members, smwr, link); 2933 smwr->parent = sg; 2934 smwr->ch = wrch; 2935 2936 chn_abort(wrch); 2937 wrch->flags |= CHN_F_NOTRIGGER; 2938 wrch->sm = smwr; 2939 } 2940 2941 2942 out: 2943 if (ret != 0) { 2944 if (smrd != NULL) 2945 kfree(smrd, M_DEVBUF); 2946 if ((sg != NULL) && SLIST_EMPTY(&sg->members)) { 2947 sg_ids[2] = sg->id; 2948 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link); 2949 kfree(sg, M_DEVBUF); 2950 } 2951 2952 if (wrch) 2953 wrch->sm = NULL; 2954 if (rdch) 2955 rdch->sm = NULL; 2956 } 2957 2958 if (wrch) 2959 CHN_UNLOCK(wrch); 2960 if (rdch) 2961 CHN_UNLOCK(rdch); 2962 2963 PCM_SG_UNLOCK(); 2964 2965 if (sg_ids[0]) 2966 free_unr(pcmsg_unrhdr, sg_ids[0]); 2967 if (sg_ids[1]) 2968 free_unr(pcmsg_unrhdr, sg_ids[1]); 2969 if (sg_ids[2]) 2970 free_unr(pcmsg_unrhdr, sg_ids[2]); 2971 2972 return (ret); 2973 } 2974 2975 /** 2976 * @brief Launch a sync group into action 2977 * 2978 * Sync groups are established via SNDCTL_DSP_SYNCGROUP. This function 2979 * iterates over all members, triggering them along the way. 2980 * 2981 * @note Caller must not hold any channel locks. 2982 * 2983 * @param sg_id sync group identifier 2984 * 2985 * @retval 0 success 2986 * @retval non-zero error worthy of propagating upstream to user 2987 */ 2988 static int 2989 dsp_oss_syncstart(int sg_id) 2990 { 2991 struct pcmchan_syncmember *sm, *sm_tmp; 2992 struct pcmchan_syncgroup *sg; 2993 struct pcm_channel *c; 2994 int ret, needlocks; 2995 2996 /* Get the synclists lock */ 2997 PCM_SG_LOCK(); 2998 2999 do { 3000 ret = 0; 3001 needlocks = 0; 3002 3003 /* Search for syncgroup by ID */ 3004 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) { 3005 if (sg->id == sg_id) 3006 break; 3007 } 3008 3009 /* Return EINVAL if not found */ 3010 if (sg == NULL) { 3011 ret = EINVAL; 3012 break; 3013 } 3014 3015 /* Any removals resulting in an empty group should've handled this */ 3016 KASSERT(!SLIST_EMPTY(&sg->members), ("found empty syncgroup")); 3017 3018 /* 3019 * Attempt to lock all member channels - if any are already 3020 * locked, unlock those acquired, sleep for a bit, and try 3021 * again. 3022 */ 3023 SLIST_FOREACH(sm, &sg->members, link) { 3024 if (CHN_TRYLOCK(sm->ch) == 0) { 3025 int timo = hz * 5/1000; 3026 if (timo < 1) 3027 timo = 1; 3028 3029 /* Release all locked channels so far, retry */ 3030 SLIST_FOREACH(sm_tmp, &sg->members, link) { 3031 /* sm is the member already locked */ 3032 if (sm == sm_tmp) 3033 break; 3034 CHN_UNLOCK(sm_tmp->ch); 3035 } 3036 3037 /** @todo Is PRIBIO correct/ */ 3038 ret = lksleep(sm, &snd_pcm_syncgroups_mtx, 3039 PCATCH, "pcmsg", timo); 3040 if (ret == EINTR || ret == ERESTART) 3041 break; 3042 3043 needlocks = 1; 3044 ret = 0; /* Assumes ret == EAGAIN... */ 3045 } 3046 } 3047 } while (needlocks && ret == 0); 3048 3049 /* Proceed only if no errors encountered. */ 3050 if (ret == 0) { 3051 /* Launch channels */ 3052 while ((sm = SLIST_FIRST(&sg->members)) != NULL) { 3053 SLIST_REMOVE_HEAD(&sg->members, link); 3054 3055 c = sm->ch; 3056 c->sm = NULL; 3057 chn_start(c, 1); 3058 c->flags &= ~CHN_F_NOTRIGGER; 3059 CHN_UNLOCK(c); 3060 3061 kfree(sm, M_DEVBUF); 3062 } 3063 3064 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link); 3065 kfree(sg, M_DEVBUF); 3066 } 3067 3068 PCM_SG_UNLOCK(); 3069 3070 /* 3071 * Free_unr() may sleep, so be sure to give up the syncgroup lock 3072 * first. 3073 */ 3074 if (ret == 0) 3075 free_unr(pcmsg_unrhdr, sg_id); 3076 3077 return (ret); 3078 } 3079 3080 /** 3081 * @brief Handler for SNDCTL_DSP_POLICY 3082 * 3083 * The SNDCTL_DSP_POLICY ioctl is a simpler interface to control fragment 3084 * size and count like with SNDCTL_DSP_SETFRAGMENT. Instead of the user 3085 * specifying those two parameters, s/he simply selects a number from 0..10 3086 * which corresponds to a buffer size. Smaller numbers request smaller 3087 * buffers with lower latencies (at greater overhead from more frequent 3088 * interrupts), while greater numbers behave in the opposite manner. 3089 * 3090 * The 4Front spec states that a value of 5 should be the default. However, 3091 * this implementation deviates slightly by using a linear scale without 3092 * consulting drivers. I.e., even though drivers may have different default 3093 * buffer sizes, a policy argument of 5 will have the same result across 3094 * all drivers. 3095 * 3096 * See http://manuals.opensound.com/developer/SNDCTL_DSP_POLICY.html for 3097 * more information. 3098 * 3099 * @todo When SNDCTL_DSP_COOKEDMODE is supported, it'll be necessary to 3100 * work with hardware drivers directly. 3101 * 3102 * @note PCM channel arguments must not be locked by caller. 3103 * 3104 * @param wrch Pointer to opened playback channel (optional; may be NULL) 3105 * @param rdch " recording channel (optional; may be NULL) 3106 * @param policy Integer from [0:10] 3107 * 3108 * @retval 0 constant (for now) 3109 */ 3110 static int 3111 dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy) 3112 { 3113 int ret; 3114 3115 if (policy < CHN_POLICY_MIN || policy > CHN_POLICY_MAX) 3116 return (EIO); 3117 3118 /* Default: success */ 3119 ret = 0; 3120 3121 if (rdch) { 3122 CHN_LOCK(rdch); 3123 ret = chn_setlatency(rdch, policy); 3124 CHN_UNLOCK(rdch); 3125 } 3126 3127 if (wrch && ret == 0) { 3128 CHN_LOCK(wrch); 3129 ret = chn_setlatency(wrch, policy); 3130 CHN_UNLOCK(wrch); 3131 } 3132 3133 if (ret) 3134 ret = EIO; 3135 3136 return (ret); 3137 } 3138 3139 /** 3140 * @brief Enable or disable "cooked" mode 3141 * 3142 * This is a handler for @c SNDCTL_DSP_COOKEDMODE. When in cooked mode, which 3143 * is the default, the sound system handles rate and format conversions 3144 * automatically (ex: user writing 11025Hz/8 bit/unsigned but card only 3145 * operates with 44100Hz/16bit/signed samples). 3146 * 3147 * Disabling cooked mode is intended for applications wanting to mmap() 3148 * a sound card's buffer space directly, bypassing the FreeBSD 2-stage 3149 * feeder architecture, presumably to gain as much control over audio 3150 * hardware as possible. 3151 * 3152 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_COOKEDMODE.html 3153 * for more details. 3154 * 3155 * @param wrch playback channel (optional; may be NULL) 3156 * @param rdch recording channel (optional; may be NULL) 3157 * @param enabled 0 = raw mode, 1 = cooked mode 3158 * 3159 * @retval EINVAL Operation not yet supported. 3160 */ 3161 static int 3162 dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled) 3163 { 3164 3165 /* 3166 * XXX I just don't get it. Why don't they call it 3167 * "BITPERFECT" ~ SNDCTL_DSP_BITPERFECT !?!?. 3168 * This is just plain so confusing, incoherent, 3169 * <insert any non-printable characters here>. 3170 */ 3171 if (!(enabled == 1 || enabled == 0)) 3172 return (EINVAL); 3173 3174 /* 3175 * I won't give in. I'm inverting its logic here and now. 3176 * Brag all you want, but "BITPERFECT" should be the better 3177 * term here. 3178 */ 3179 enabled ^= 0x00000001; 3180 3181 if (wrch != NULL) { 3182 CHN_LOCK(wrch); 3183 wrch->flags &= ~CHN_F_BITPERFECT; 3184 wrch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000; 3185 CHN_UNLOCK(wrch); 3186 } 3187 3188 if (rdch != NULL) { 3189 CHN_LOCK(rdch); 3190 rdch->flags &= ~CHN_F_BITPERFECT; 3191 rdch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000; 3192 CHN_UNLOCK(rdch); 3193 } 3194 3195 return (0); 3196 } 3197 3198 /** 3199 * @brief Retrieve channel interleaving order 3200 * 3201 * This is the handler for @c SNDCTL_DSP_GET_CHNORDER. 3202 * 3203 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_GET_CHNORDER.html 3204 * for more details. 3205 * 3206 * @note As the ioctl definition is still under construction, FreeBSD 3207 * does not currently support SNDCTL_DSP_GET_CHNORDER. 3208 * 3209 * @param wrch playback channel (optional; may be NULL) 3210 * @param rdch recording channel (optional; may be NULL) 3211 * @param map channel map (result will be stored there) 3212 * 3213 * @retval EINVAL Operation not yet supported. 3214 */ 3215 static int 3216 dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map) 3217 { 3218 struct pcm_channel *ch; 3219 int ret; 3220 3221 ch = (wrch != NULL) ? wrch : rdch; 3222 if (ch != NULL) { 3223 CHN_LOCK(ch); 3224 ret = chn_oss_getorder(ch, map); 3225 CHN_UNLOCK(ch); 3226 } else 3227 ret = EINVAL; 3228 3229 return (ret); 3230 } 3231 3232 /** 3233 * @brief Specify channel interleaving order 3234 * 3235 * This is the handler for @c SNDCTL_DSP_SET_CHNORDER. 3236 * 3237 * @note As the ioctl definition is still under construction, FreeBSD 3238 * does not currently support @c SNDCTL_DSP_SET_CHNORDER. 3239 * 3240 * @param wrch playback channel (optional; may be NULL) 3241 * @param rdch recording channel (optional; may be NULL) 3242 * @param map channel map 3243 * 3244 * @retval EINVAL Operation not yet supported. 3245 */ 3246 static int 3247 dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map) 3248 { 3249 int ret; 3250 3251 ret = 0; 3252 3253 if (wrch != NULL) { 3254 CHN_LOCK(wrch); 3255 ret = chn_oss_setorder(wrch, map); 3256 CHN_UNLOCK(wrch); 3257 } 3258 3259 if (ret == 0 && rdch != NULL) { 3260 CHN_LOCK(rdch); 3261 ret = chn_oss_setorder(rdch, map); 3262 CHN_UNLOCK(rdch); 3263 } 3264 3265 return (ret); 3266 } 3267 3268 static int 3269 dsp_oss_getchannelmask(struct pcm_channel *wrch, struct pcm_channel *rdch, 3270 int *mask) 3271 { 3272 struct pcm_channel *ch; 3273 uint32_t chnmask; 3274 int ret; 3275 3276 chnmask = 0; 3277 ch = (wrch != NULL) ? wrch : rdch; 3278 3279 if (ch != NULL) { 3280 CHN_LOCK(ch); 3281 ret = chn_oss_getmask(ch, &chnmask); 3282 CHN_UNLOCK(ch); 3283 } else 3284 ret = EINVAL; 3285 3286 if (ret == 0) 3287 *mask = chnmask; 3288 3289 return (ret); 3290 } 3291 3292 #ifdef OSSV4_EXPERIMENT 3293 /** 3294 * @brief Retrieve an audio device's label 3295 * 3296 * This is a handler for the @c SNDCTL_GETLABEL ioctl. 3297 * 3298 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html 3299 * for more details. 3300 * 3301 * From Hannu@4Front: "For example ossxmix (just like some HW mixer 3302 * consoles) can show variable "labels" for certain controls. By default 3303 * the application name (say quake) is shown as the label but 3304 * applications may change the labels themselves." 3305 * 3306 * @note As the ioctl definition is still under construction, FreeBSD 3307 * does not currently support @c SNDCTL_GETLABEL. 3308 * 3309 * @param wrch playback channel (optional; may be NULL) 3310 * @param rdch recording channel (optional; may be NULL) 3311 * @param label label gets copied here 3312 * 3313 * @retval EINVAL Operation not yet supported. 3314 */ 3315 static int 3316 dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label) 3317 { 3318 return (EINVAL); 3319 } 3320 3321 /** 3322 * @brief Specify an audio device's label 3323 * 3324 * This is a handler for the @c SNDCTL_SETLABEL ioctl. Please see the 3325 * comments for @c dsp_oss_getlabel immediately above. 3326 * 3327 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html 3328 * for more details. 3329 * 3330 * @note As the ioctl definition is still under construction, FreeBSD 3331 * does not currently support SNDCTL_SETLABEL. 3332 * 3333 * @param wrch playback channel (optional; may be NULL) 3334 * @param rdch recording channel (optional; may be NULL) 3335 * @param label label gets copied from here 3336 * 3337 * @retval EINVAL Operation not yet supported. 3338 */ 3339 static int 3340 dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label) 3341 { 3342 return (EINVAL); 3343 } 3344 3345 /** 3346 * @brief Retrieve name of currently played song 3347 * 3348 * This is a handler for the @c SNDCTL_GETSONG ioctl. Audio players could 3349 * tell the system the name of the currently playing song, which would be 3350 * visible in @c /dev/sndstat. 3351 * 3352 * See @c http://manuals.opensound.com/developer/SNDCTL_GETSONG.html 3353 * for more details. 3354 * 3355 * @note As the ioctl definition is still under construction, FreeBSD 3356 * does not currently support SNDCTL_GETSONG. 3357 * 3358 * @param wrch playback channel (optional; may be NULL) 3359 * @param rdch recording channel (optional; may be NULL) 3360 * @param song song name gets copied here 3361 * 3362 * @retval EINVAL Operation not yet supported. 3363 */ 3364 static int 3365 dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song) 3366 { 3367 return (EINVAL); 3368 } 3369 3370 /** 3371 * @brief Retrieve name of currently played song 3372 * 3373 * This is a handler for the @c SNDCTL_SETSONG ioctl. Audio players could 3374 * tell the system the name of the currently playing song, which would be 3375 * visible in @c /dev/sndstat. 3376 * 3377 * See @c http://manuals.opensound.com/developer/SNDCTL_SETSONG.html 3378 * for more details. 3379 * 3380 * @note As the ioctl definition is still under construction, FreeBSD 3381 * does not currently support SNDCTL_SETSONG. 3382 * 3383 * @param wrch playback channel (optional; may be NULL) 3384 * @param rdch recording channel (optional; may be NULL) 3385 * @param song song name gets copied from here 3386 * 3387 * @retval EINVAL Operation not yet supported. 3388 */ 3389 static int 3390 dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song) 3391 { 3392 return (EINVAL); 3393 } 3394 3395 /** 3396 * @brief Rename a device 3397 * 3398 * This is a handler for the @c SNDCTL_SETNAME ioctl. 3399 * 3400 * See @c http://manuals.opensound.com/developer/SNDCTL_SETNAME.html for 3401 * more details. 3402 * 3403 * From Hannu@4Front: "This call is used to change the device name 3404 * reported in /dev/sndstat and ossinfo. So instead of using some generic 3405 * 'OSS loopback audio (MIDI) driver' the device may be given a meaningfull 3406 * name depending on the current context (for example 'OSS virtual wave table 3407 * synth' or 'VoIP link to London')." 3408 * 3409 * @note As the ioctl definition is still under construction, FreeBSD 3410 * does not currently support SNDCTL_SETNAME. 3411 * 3412 * @param wrch playback channel (optional; may be NULL) 3413 * @param rdch recording channel (optional; may be NULL) 3414 * @param name new device name gets copied from here 3415 * 3416 * @retval EINVAL Operation not yet supported. 3417 */ 3418 static int 3419 dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name) 3420 { 3421 return (EINVAL); 3422 } 3423 #endif /* !OSSV4_EXPERIMENT */ 3424