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