1 /*- 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/queue.h> 29 30 #include <dev/sound/pcm/sound.h> 31 32 SND_DECLARE_FILE("$FreeBSD$"); 33 34 #define OLDPCM_IOCTL 35 36 static d_open_t dsp_open; 37 static d_close_t dsp_close; 38 static d_read_t dsp_read; 39 static d_write_t dsp_write; 40 static d_ioctl_t dsp_ioctl; 41 static d_poll_t dsp_poll; 42 static d_mmap_t dsp_mmap; 43 44 struct cdevsw dsp_cdevsw = { 45 .d_version = D_VERSION, 46 .d_flags = D_NEEDGIANT, 47 .d_open = dsp_open, 48 .d_close = dsp_close, 49 .d_read = dsp_read, 50 .d_write = dsp_write, 51 .d_ioctl = dsp_ioctl, 52 .d_poll = dsp_poll, 53 .d_mmap = dsp_mmap, 54 .d_name = "dsp", 55 }; 56 57 #ifdef USING_DEVFS 58 static eventhandler_tag dsp_ehtag; 59 #endif 60 61 static struct snddev_info * 62 dsp_get_info(struct cdev *dev) 63 { 64 struct snddev_info *d; 65 int unit; 66 67 unit = PCMUNIT(dev); 68 if (unit >= devclass_get_maxunit(pcm_devclass)) 69 return NULL; 70 d = devclass_get_softc(pcm_devclass, unit); 71 72 return d; 73 } 74 75 static u_int32_t 76 dsp_get_flags(struct cdev *dev) 77 { 78 device_t bdev; 79 int unit; 80 81 unit = PCMUNIT(dev); 82 if (unit >= devclass_get_maxunit(pcm_devclass)) 83 return 0xffffffff; 84 bdev = devclass_get_device(pcm_devclass, unit); 85 86 return pcm_getflags(bdev); 87 } 88 89 static void 90 dsp_set_flags(struct cdev *dev, u_int32_t flags) 91 { 92 device_t bdev; 93 int unit; 94 95 unit = PCMUNIT(dev); 96 if (unit >= devclass_get_maxunit(pcm_devclass)) 97 return; 98 bdev = devclass_get_device(pcm_devclass, unit); 99 100 pcm_setflags(bdev, flags); 101 } 102 103 /* 104 * return the channels associated with an open device instance. 105 * set the priority if the device is simplex and one direction (only) is 106 * specified. 107 * lock channels specified. 108 */ 109 static int 110 getchns(struct cdev *dev, struct pcm_channel **rdch, struct pcm_channel **wrch, u_int32_t prio) 111 { 112 struct snddev_info *d; 113 u_int32_t flags; 114 115 flags = dsp_get_flags(dev); 116 d = dsp_get_info(dev); 117 pcm_inprog(d, 1); 118 pcm_lock(d); 119 KASSERT((flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \ 120 ("getchns: read and write both prioritised")); 121 122 if ((flags & SD_F_PRIO_SET) == 0 && (prio != (SD_F_PRIO_RD | SD_F_PRIO_WR))) { 123 flags |= prio & (SD_F_PRIO_RD | SD_F_PRIO_WR); 124 dsp_set_flags(dev, flags); 125 } 126 127 *rdch = dev->si_drv1; 128 *wrch = dev->si_drv2; 129 if ((flags & SD_F_SIMPLEX) && (flags & SD_F_PRIO_SET)) { 130 if (prio) { 131 if (*rdch && flags & SD_F_PRIO_WR) { 132 dev->si_drv1 = NULL; 133 *rdch = pcm_getfakechan(d); 134 } else if (*wrch && flags & SD_F_PRIO_RD) { 135 dev->si_drv2 = NULL; 136 *wrch = pcm_getfakechan(d); 137 } 138 } 139 140 pcm_getfakechan(d)->flags |= CHN_F_BUSY; 141 } 142 pcm_unlock(d); 143 144 if (*rdch && *rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD)) 145 CHN_LOCK(*rdch); 146 if (*wrch && *wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR)) 147 CHN_LOCK(*wrch); 148 149 return 0; 150 } 151 152 /* unlock specified channels */ 153 static void 154 relchns(struct cdev *dev, struct pcm_channel *rdch, struct pcm_channel *wrch, u_int32_t prio) 155 { 156 struct snddev_info *d; 157 158 d = dsp_get_info(dev); 159 if (wrch && wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR)) 160 CHN_UNLOCK(wrch); 161 if (rdch && rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD)) 162 CHN_UNLOCK(rdch); 163 pcm_inprog(d, -1); 164 } 165 166 static int 167 dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 168 { 169 struct pcm_channel *rdch, *wrch; 170 struct snddev_info *d; 171 u_int32_t fmt; 172 int devtype; 173 int rdref; 174 int error; 175 176 d = dsp_get_info(i_dev); 177 devtype = PCMDEV(i_dev); 178 179 /* decide default format */ 180 switch (devtype) { 181 case SND_DEV_DSP16: 182 fmt = AFMT_S16_LE; 183 break; 184 185 case SND_DEV_DSP: 186 fmt = AFMT_U8; 187 break; 188 189 case SND_DEV_AUDIO: 190 fmt = AFMT_MU_LAW; 191 break; 192 193 case SND_DEV_NORESET: 194 fmt = 0; 195 break; 196 197 case SND_DEV_DSPREC: 198 fmt = AFMT_U8; 199 if (mode & FWRITE) { 200 return EINVAL; 201 } 202 break; 203 204 default: 205 panic("impossible devtype %d", devtype); 206 } 207 208 rdref = 0; 209 210 /* lock snddev so nobody else can monkey with it */ 211 pcm_lock(d); 212 213 rdch = i_dev->si_drv1; 214 wrch = i_dev->si_drv2; 215 216 if ((dsp_get_flags(i_dev) & SD_F_SIMPLEX) && (rdch || wrch)) { 217 /* we're a simplex device and already open, no go */ 218 pcm_unlock(d); 219 return EBUSY; 220 } 221 222 if (((flags & FREAD) && rdch) || ((flags & FWRITE) && wrch)) { 223 /* 224 * device already open in one or both directions that 225 * the opener wants; we can't handle this. 226 */ 227 pcm_unlock(d); 228 return EBUSY; 229 } 230 231 /* 232 * if we get here, the open request is valid- either: 233 * * we were previously not open 234 * * we were open for play xor record and the opener wants 235 * the non-open direction 236 */ 237 if (flags & FREAD) { 238 /* open for read */ 239 pcm_unlock(d); 240 if (devtype == SND_DEV_DSPREC) 241 rdch = pcm_chnalloc(d, PCMDIR_REC, td->td_proc->p_pid, PCMCHAN(i_dev)); 242 else 243 rdch = pcm_chnalloc(d, PCMDIR_REC, td->td_proc->p_pid, -1); 244 if (!rdch) { 245 /* no channel available, exit */ 246 return EBUSY; 247 } 248 /* got a channel, already locked for us */ 249 if (chn_reset(rdch, fmt) || 250 (fmt && chn_setspeed(rdch, DSP_DEFAULT_SPEED))) { 251 pcm_chnrelease(rdch); 252 pcm_lock(d); 253 i_dev->si_drv1 = NULL; 254 pcm_unlock(d); 255 return ENODEV; 256 } 257 258 if (flags & O_NONBLOCK) 259 rdch->flags |= CHN_F_NBIO; 260 pcm_chnref(rdch, 1); 261 CHN_UNLOCK(rdch); 262 rdref = 1; 263 /* 264 * Record channel created, ref'ed and unlocked 265 */ 266 pcm_lock(d); 267 } 268 269 if (flags & FWRITE) { 270 /* open for write */ 271 pcm_unlock(d); 272 wrch = pcm_chnalloc(d, PCMDIR_PLAY, td->td_proc->p_pid, -1); 273 error = 0; 274 275 if (!wrch) 276 error = EBUSY; /* XXX Right return code? */ 277 else if (chn_reset(wrch, fmt) || 278 (fmt && chn_setspeed(wrch, DSP_DEFAULT_SPEED))) 279 error = ENODEV; 280 281 if (error != 0) { 282 if (wrch) { 283 /* 284 * Free play channel 285 */ 286 pcm_chnrelease(wrch); 287 pcm_lock(d); 288 i_dev->si_drv2 = NULL; 289 pcm_unlock(d); 290 } 291 if (rdref) { 292 /* 293 * Lock, deref and release previously created record channel 294 */ 295 CHN_LOCK(rdch); 296 pcm_chnref(rdch, -1); 297 pcm_chnrelease(rdch); 298 pcm_lock(d); 299 i_dev->si_drv1 = NULL; 300 pcm_unlock(d); 301 } 302 303 return error; 304 } 305 306 if (flags & O_NONBLOCK) 307 wrch->flags |= CHN_F_NBIO; 308 pcm_chnref(wrch, 1); 309 CHN_UNLOCK(wrch); 310 pcm_lock(d); 311 } 312 313 i_dev->si_drv1 = rdch; 314 i_dev->si_drv2 = wrch; 315 316 pcm_unlock(d); 317 return 0; 318 } 319 320 static int 321 dsp_close(struct cdev *i_dev, int flags, int mode, struct thread *td) 322 { 323 struct pcm_channel *rdch, *wrch; 324 struct snddev_info *d; 325 int refs; 326 327 d = dsp_get_info(i_dev); 328 pcm_lock(d); 329 rdch = i_dev->si_drv1; 330 wrch = i_dev->si_drv2; 331 pcm_unlock(d); 332 333 refs = 0; 334 335 if (rdch) { 336 CHN_LOCK(rdch); 337 refs += pcm_chnref(rdch, -1); 338 CHN_UNLOCK(rdch); 339 } 340 if (wrch) { 341 CHN_LOCK(wrch); 342 refs += pcm_chnref(wrch, -1); 343 CHN_UNLOCK(wrch); 344 } 345 346 /* 347 * If there are no more references, release the channels. 348 */ 349 if ((rdch || wrch) && refs == 0) { 350 351 pcm_lock(d); 352 353 if (pcm_getfakechan(d)) 354 pcm_getfakechan(d)->flags = 0; 355 356 i_dev->si_drv1 = NULL; 357 i_dev->si_drv2 = NULL; 358 359 dsp_set_flags(i_dev, dsp_get_flags(i_dev) & ~SD_F_TRANSIENT); 360 361 pcm_unlock(d); 362 363 if (rdch) { 364 CHN_LOCK(rdch); 365 chn_abort(rdch); /* won't sleep */ 366 rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD); 367 chn_reset(rdch, 0); 368 pcm_chnrelease(rdch); 369 } 370 if (wrch) { 371 CHN_LOCK(wrch); 372 /* 373 * XXX: Maybe the right behaviour is to abort on non_block. 374 * It seems that mplayer flushes the audio queue by quickly 375 * closing and re-opening. In FBSD, there's a long pause 376 * while the audio queue flushes that I presume isn't there in 377 * linux. 378 */ 379 chn_flush(wrch); /* may sleep */ 380 wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD); 381 chn_reset(wrch, 0); 382 pcm_chnrelease(wrch); 383 } 384 } 385 return 0; 386 } 387 388 static int 389 dsp_read(struct cdev *i_dev, struct uio *buf, int flag) 390 { 391 struct pcm_channel *rdch, *wrch; 392 int ret; 393 394 getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD); 395 396 KASSERT(rdch, ("dsp_read: nonexistant channel")); 397 KASSERT(rdch->flags & CHN_F_BUSY, ("dsp_read: nonbusy channel")); 398 399 if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) { 400 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD); 401 return EINVAL; 402 } 403 if (!(rdch->flags & CHN_F_RUNNING)) 404 rdch->flags |= CHN_F_RUNNING; 405 ret = chn_read(rdch, buf); 406 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD); 407 408 return ret; 409 } 410 411 static int 412 dsp_write(struct cdev *i_dev, struct uio *buf, int flag) 413 { 414 struct pcm_channel *rdch, *wrch; 415 int ret; 416 417 getchns(i_dev, &rdch, &wrch, SD_F_PRIO_WR); 418 419 KASSERT(wrch, ("dsp_write: nonexistant channel")); 420 KASSERT(wrch->flags & CHN_F_BUSY, ("dsp_write: nonbusy channel")); 421 422 if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) { 423 relchns(i_dev, rdch, wrch, SD_F_PRIO_WR); 424 return EINVAL; 425 } 426 if (!(wrch->flags & CHN_F_RUNNING)) 427 wrch->flags |= CHN_F_RUNNING; 428 ret = chn_write(wrch, buf); 429 relchns(i_dev, rdch, wrch, SD_F_PRIO_WR); 430 431 return ret; 432 } 433 434 static int 435 dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td) 436 { 437 struct pcm_channel *chn, *rdch, *wrch; 438 struct snddev_info *d; 439 int kill; 440 int ret = 0, *arg_i = (int *)arg, tmp; 441 442 /* 443 * this is an evil hack to allow broken apps to perform mixer ioctls 444 * on dsp devices. 445 */ 446 447 d = dsp_get_info(i_dev); 448 if (IOCGROUP(cmd) == 'M') 449 return mixer_ioctl(d->mixer_dev, cmd, arg, mode, td); 450 451 getchns(i_dev, &rdch, &wrch, 0); 452 453 kill = 0; 454 if (wrch && (wrch->flags & CHN_F_DEAD)) 455 kill |= 1; 456 if (rdch && (rdch->flags & CHN_F_DEAD)) 457 kill |= 2; 458 if (kill == 3) { 459 relchns(i_dev, rdch, wrch, 0); 460 return EINVAL; 461 } 462 if (kill & 1) 463 wrch = NULL; 464 if (kill & 2) 465 rdch = NULL; 466 467 switch(cmd) { 468 #ifdef OLDPCM_IOCTL 469 /* 470 * we start with the new ioctl interface. 471 */ 472 case AIONWRITE: /* how many bytes can write ? */ 473 if (wrch) { 474 CHN_LOCK(wrch); 475 /* 476 if (wrch && wrch->bufhard.dl) 477 while (chn_wrfeed(wrch) == 0); 478 */ 479 *arg_i = sndbuf_getfree(wrch->bufsoft); 480 CHN_UNLOCK(wrch); 481 } else { 482 *arg_i = 0; 483 ret = EINVAL; 484 } 485 break; 486 487 case AIOSSIZE: /* set the current blocksize */ 488 { 489 struct snd_size *p = (struct snd_size *)arg; 490 491 p->play_size = 0; 492 p->rec_size = 0; 493 if (wrch) { 494 CHN_LOCK(wrch); 495 chn_setblocksize(wrch, 2, p->play_size); 496 p->play_size = sndbuf_getblksz(wrch->bufsoft); 497 CHN_UNLOCK(wrch); 498 } 499 if (rdch) { 500 CHN_LOCK(rdch); 501 chn_setblocksize(rdch, 2, p->rec_size); 502 p->rec_size = sndbuf_getblksz(rdch->bufsoft); 503 CHN_UNLOCK(rdch); 504 } 505 } 506 break; 507 case AIOGSIZE: /* get the current blocksize */ 508 { 509 struct snd_size *p = (struct snd_size *)arg; 510 511 if (wrch) { 512 CHN_LOCK(wrch); 513 p->play_size = sndbuf_getblksz(wrch->bufsoft); 514 CHN_UNLOCK(wrch); 515 } 516 if (rdch) { 517 CHN_LOCK(rdch); 518 p->rec_size = sndbuf_getblksz(rdch->bufsoft); 519 CHN_UNLOCK(rdch); 520 } 521 } 522 break; 523 524 case AIOSFMT: 525 case AIOGFMT: 526 { 527 snd_chan_param *p = (snd_chan_param *)arg; 528 529 if (cmd == AIOSFMT && 530 ((p->play_format != 0 && p->play_rate == 0) || 531 (p->rec_format != 0 && p->rec_rate == 0))) { 532 ret = EINVAL; 533 break; 534 } 535 if (wrch) { 536 CHN_LOCK(wrch); 537 if (cmd == AIOSFMT && p->play_format != 0) { 538 chn_setformat(wrch, p->play_format); 539 chn_setspeed(wrch, p->play_rate); 540 } 541 p->play_rate = wrch->speed; 542 p->play_format = wrch->format; 543 CHN_UNLOCK(wrch); 544 } else { 545 p->play_rate = 0; 546 p->play_format = 0; 547 } 548 if (rdch) { 549 CHN_LOCK(rdch); 550 if (cmd == AIOSFMT && p->rec_format != 0) { 551 chn_setformat(rdch, p->rec_format); 552 chn_setspeed(rdch, p->rec_rate); 553 } 554 p->rec_rate = rdch->speed; 555 p->rec_format = rdch->format; 556 CHN_UNLOCK(rdch); 557 } else { 558 p->rec_rate = 0; 559 p->rec_format = 0; 560 } 561 } 562 break; 563 564 case AIOGCAP: /* get capabilities */ 565 { 566 snd_capabilities *p = (snd_capabilities *)arg; 567 struct pcmchan_caps *pcaps = NULL, *rcaps = NULL; 568 struct cdev *pdev; 569 570 if (rdch) { 571 CHN_LOCK(rdch); 572 rcaps = chn_getcaps(rdch); 573 } 574 if (wrch) { 575 CHN_LOCK(wrch); 576 pcaps = chn_getcaps(wrch); 577 } 578 p->rate_min = max(rcaps? rcaps->minspeed : 0, 579 pcaps? pcaps->minspeed : 0); 580 p->rate_max = min(rcaps? rcaps->maxspeed : 1000000, 581 pcaps? pcaps->maxspeed : 1000000); 582 p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000, 583 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000); 584 /* XXX bad on sb16 */ 585 p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) & 586 (wrch? chn_getformats(wrch) : 0xffffffff); 587 if (rdch && wrch) 588 p->formats |= (dsp_get_flags(i_dev) & SD_F_SIMPLEX)? 0 : AFMT_FULLDUPLEX; 589 pdev = d->mixer_dev; 590 p->mixers = 1; /* default: one mixer */ 591 p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0; 592 p->left = p->right = 100; 593 if (rdch) 594 CHN_UNLOCK(rdch); 595 if (wrch) 596 CHN_UNLOCK(wrch); 597 } 598 break; 599 600 case AIOSTOP: 601 if (*arg_i == AIOSYNC_PLAY && wrch) { 602 CHN_LOCK(wrch); 603 *arg_i = chn_abort(wrch); 604 CHN_UNLOCK(wrch); 605 } else if (*arg_i == AIOSYNC_CAPTURE && rdch) { 606 CHN_LOCK(rdch); 607 *arg_i = chn_abort(rdch); 608 CHN_UNLOCK(rdch); 609 } else { 610 printf("AIOSTOP: bad channel 0x%x\n", *arg_i); 611 *arg_i = 0; 612 } 613 break; 614 615 case AIOSYNC: 616 printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n", 617 ((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos); 618 break; 619 #endif 620 /* 621 * here follow the standard ioctls (filio.h etc.) 622 */ 623 case FIONREAD: /* get # bytes to read */ 624 if (rdch) { 625 CHN_LOCK(rdch); 626 /* if (rdch && rdch->bufhard.dl) 627 while (chn_rdfeed(rdch) == 0); 628 */ 629 *arg_i = sndbuf_getready(rdch->bufsoft); 630 CHN_UNLOCK(rdch); 631 } else { 632 *arg_i = 0; 633 ret = EINVAL; 634 } 635 break; 636 637 case FIOASYNC: /*set/clear async i/o */ 638 DEB( printf("FIOASYNC\n") ; ) 639 break; 640 641 case SNDCTL_DSP_NONBLOCK: 642 case FIONBIO: /* set/clear non-blocking i/o */ 643 if (rdch) { 644 CHN_LOCK(rdch); 645 if (*arg_i) 646 rdch->flags |= CHN_F_NBIO; 647 else 648 rdch->flags &= ~CHN_F_NBIO; 649 CHN_UNLOCK(rdch); 650 } 651 if (wrch) { 652 CHN_LOCK(wrch); 653 if (*arg_i) 654 wrch->flags |= CHN_F_NBIO; 655 else 656 wrch->flags &= ~CHN_F_NBIO; 657 CHN_UNLOCK(wrch); 658 } 659 break; 660 661 /* 662 * Finally, here is the linux-compatible ioctl interface 663 */ 664 #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int) 665 case THE_REAL_SNDCTL_DSP_GETBLKSIZE: 666 case SNDCTL_DSP_GETBLKSIZE: 667 chn = wrch ? wrch : rdch; 668 if (chn) { 669 CHN_LOCK(chn); 670 *arg_i = sndbuf_getblksz(chn->bufsoft); 671 CHN_UNLOCK(chn); 672 } else { 673 *arg_i = 0; 674 ret = EINVAL; 675 } 676 break ; 677 678 case SNDCTL_DSP_SETBLKSIZE: 679 RANGE(*arg_i, 16, 65536); 680 if (wrch) { 681 CHN_LOCK(wrch); 682 chn_setblocksize(wrch, 2, *arg_i); 683 CHN_UNLOCK(wrch); 684 } 685 if (rdch) { 686 CHN_LOCK(rdch); 687 chn_setblocksize(rdch, 2, *arg_i); 688 CHN_UNLOCK(rdch); 689 } 690 break; 691 692 case SNDCTL_DSP_RESET: 693 DEB(printf("dsp reset\n")); 694 if (wrch) { 695 CHN_LOCK(wrch); 696 chn_abort(wrch); 697 chn_resetbuf(wrch); 698 CHN_UNLOCK(wrch); 699 } 700 if (rdch) { 701 CHN_LOCK(rdch); 702 chn_abort(rdch); 703 chn_resetbuf(rdch); 704 CHN_UNLOCK(rdch); 705 } 706 break; 707 708 case SNDCTL_DSP_SYNC: 709 DEB(printf("dsp sync\n")); 710 /* chn_sync may sleep */ 711 if (wrch) { 712 CHN_LOCK(wrch); 713 chn_sync(wrch, sndbuf_getsize(wrch->bufsoft) - 4); 714 CHN_UNLOCK(wrch); 715 } 716 break; 717 718 case SNDCTL_DSP_SPEED: 719 /* chn_setspeed may sleep */ 720 tmp = 0; 721 if (wrch) { 722 CHN_LOCK(wrch); 723 ret = chn_setspeed(wrch, *arg_i); 724 tmp = wrch->speed; 725 CHN_UNLOCK(wrch); 726 } 727 if (rdch && ret == 0) { 728 CHN_LOCK(rdch); 729 ret = chn_setspeed(rdch, *arg_i); 730 if (tmp == 0) 731 tmp = rdch->speed; 732 CHN_UNLOCK(rdch); 733 } 734 *arg_i = tmp; 735 break; 736 737 case SOUND_PCM_READ_RATE: 738 chn = wrch ? wrch : rdch; 739 if (chn) { 740 CHN_LOCK(chn); 741 *arg_i = chn->speed; 742 CHN_UNLOCK(chn); 743 } else { 744 *arg_i = 0; 745 ret = EINVAL; 746 } 747 break; 748 749 case SNDCTL_DSP_STEREO: 750 tmp = -1; 751 *arg_i = (*arg_i)? AFMT_STEREO : 0; 752 if (wrch) { 753 CHN_LOCK(wrch); 754 ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i); 755 tmp = (wrch->format & AFMT_STEREO)? 1 : 0; 756 CHN_UNLOCK(wrch); 757 } 758 if (rdch && ret == 0) { 759 CHN_LOCK(rdch); 760 ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i); 761 if (tmp == -1) 762 tmp = (rdch->format & AFMT_STEREO)? 1 : 0; 763 CHN_UNLOCK(rdch); 764 } 765 *arg_i = tmp; 766 break; 767 768 case SOUND_PCM_WRITE_CHANNELS: 769 /* case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */ 770 if (*arg_i != 0) { 771 tmp = 0; 772 *arg_i = (*arg_i != 1)? AFMT_STEREO : 0; 773 if (wrch) { 774 CHN_LOCK(wrch); 775 ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) | *arg_i); 776 tmp = (wrch->format & AFMT_STEREO)? 2 : 1; 777 CHN_UNLOCK(wrch); 778 } 779 if (rdch && ret == 0) { 780 CHN_LOCK(rdch); 781 ret = chn_setformat(rdch, (rdch->format & ~AFMT_STEREO) | *arg_i); 782 if (tmp == 0) 783 tmp = (rdch->format & AFMT_STEREO)? 2 : 1; 784 CHN_UNLOCK(rdch); 785 } 786 *arg_i = tmp; 787 } else { 788 chn = wrch ? wrch : rdch; 789 CHN_LOCK(chn); 790 *arg_i = (chn->format & AFMT_STEREO) ? 2 : 1; 791 CHN_UNLOCK(chn); 792 } 793 break; 794 795 case SOUND_PCM_READ_CHANNELS: 796 chn = wrch ? wrch : rdch; 797 if (chn) { 798 CHN_LOCK(chn); 799 *arg_i = (chn->format & AFMT_STEREO) ? 2 : 1; 800 CHN_UNLOCK(chn); 801 } else { 802 *arg_i = 0; 803 ret = EINVAL; 804 } 805 break; 806 807 case SNDCTL_DSP_GETFMTS: /* returns a mask of supported fmts */ 808 chn = wrch ? wrch : rdch; 809 if (chn) { 810 CHN_LOCK(chn); 811 *arg_i = chn_getformats(chn); 812 CHN_UNLOCK(chn); 813 } else { 814 *arg_i = 0; 815 ret = EINVAL; 816 } 817 break ; 818 819 case SNDCTL_DSP_SETFMT: /* sets _one_ format */ 820 if ((*arg_i != AFMT_QUERY)) { 821 tmp = 0; 822 if (wrch) { 823 CHN_LOCK(wrch); 824 ret = chn_setformat(wrch, (*arg_i) | (wrch->format & AFMT_STEREO)); 825 tmp = wrch->format & ~AFMT_STEREO; 826 CHN_UNLOCK(wrch); 827 } 828 if (rdch && ret == 0) { 829 CHN_LOCK(rdch); 830 ret = chn_setformat(rdch, (*arg_i) | (rdch->format & AFMT_STEREO)); 831 if (tmp == 0) 832 tmp = rdch->format & ~AFMT_STEREO; 833 CHN_UNLOCK(rdch); 834 } 835 *arg_i = tmp; 836 } else { 837 chn = wrch ? wrch : rdch; 838 CHN_LOCK(chn); 839 *arg_i = chn->format & ~AFMT_STEREO; 840 CHN_UNLOCK(chn); 841 } 842 break; 843 844 case SNDCTL_DSP_SETFRAGMENT: 845 DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg)); 846 { 847 u_int32_t fragln = (*arg_i) & 0x0000ffff; 848 u_int32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16; 849 u_int32_t fragsz; 850 u_int32_t r_maxfrags, r_fragsz; 851 852 RANGE(fragln, 4, 16); 853 fragsz = 1 << fragln; 854 855 if (maxfrags == 0) 856 maxfrags = CHN_2NDBUFMAXSIZE / fragsz; 857 if (maxfrags < 2) 858 maxfrags = 2; 859 if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE) 860 maxfrags = CHN_2NDBUFMAXSIZE / fragsz; 861 862 DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz)); 863 if (rdch) { 864 CHN_LOCK(rdch); 865 ret = chn_setblocksize(rdch, maxfrags, fragsz); 866 r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft); 867 r_fragsz = sndbuf_getblksz(rdch->bufsoft); 868 CHN_UNLOCK(rdch); 869 } else { 870 r_maxfrags = maxfrags; 871 r_fragsz = fragsz; 872 } 873 if (wrch && ret == 0) { 874 CHN_LOCK(wrch); 875 ret = chn_setblocksize(wrch, maxfrags, fragsz); 876 maxfrags = sndbuf_getblkcnt(wrch->bufsoft); 877 fragsz = sndbuf_getblksz(wrch->bufsoft); 878 CHN_UNLOCK(wrch); 879 } else { /* use whatever came from the read channel */ 880 maxfrags = r_maxfrags; 881 fragsz = r_fragsz; 882 } 883 884 fragln = 0; 885 while (fragsz > 1) { 886 fragln++; 887 fragsz >>= 1; 888 } 889 *arg_i = (maxfrags << 16) | fragln; 890 } 891 break; 892 893 case SNDCTL_DSP_GETISPACE: 894 /* return the size of data available in the input queue */ 895 { 896 audio_buf_info *a = (audio_buf_info *)arg; 897 if (rdch) { 898 struct snd_dbuf *bs = rdch->bufsoft; 899 900 CHN_LOCK(rdch); 901 a->bytes = sndbuf_getready(bs); 902 a->fragments = a->bytes / sndbuf_getblksz(bs); 903 a->fragstotal = sndbuf_getblkcnt(bs); 904 a->fragsize = sndbuf_getblksz(bs); 905 CHN_UNLOCK(rdch); 906 } 907 } 908 break; 909 910 case SNDCTL_DSP_GETOSPACE: 911 /* return space available in the output queue */ 912 { 913 audio_buf_info *a = (audio_buf_info *)arg; 914 if (wrch) { 915 struct snd_dbuf *bs = wrch->bufsoft; 916 917 CHN_LOCK(wrch); 918 /* XXX abusive DMA update: chn_wrupdate(wrch); */ 919 a->bytes = sndbuf_getfree(bs); 920 a->fragments = a->bytes / sndbuf_getblksz(bs); 921 a->fragstotal = sndbuf_getblkcnt(bs); 922 a->fragsize = sndbuf_getblksz(bs); 923 CHN_UNLOCK(wrch); 924 } 925 } 926 break; 927 928 case SNDCTL_DSP_GETIPTR: 929 { 930 count_info *a = (count_info *)arg; 931 if (rdch) { 932 struct snd_dbuf *bs = rdch->bufsoft; 933 934 CHN_LOCK(rdch); 935 /* XXX abusive DMA update: chn_rdupdate(rdch); */ 936 a->bytes = sndbuf_gettotal(bs); 937 a->blocks = sndbuf_getblocks(bs) - rdch->blocks; 938 a->ptr = sndbuf_getreadyptr(bs); 939 rdch->blocks = sndbuf_getblocks(bs); 940 CHN_UNLOCK(rdch); 941 } else 942 ret = EINVAL; 943 } 944 break; 945 946 case SNDCTL_DSP_GETOPTR: 947 { 948 count_info *a = (count_info *)arg; 949 if (wrch) { 950 struct snd_dbuf *bs = wrch->bufsoft; 951 952 CHN_LOCK(wrch); 953 /* XXX abusive DMA update: chn_wrupdate(wrch); */ 954 a->bytes = sndbuf_gettotal(bs); 955 a->blocks = sndbuf_getblocks(bs) - wrch->blocks; 956 a->ptr = sndbuf_getreadyptr(bs); 957 wrch->blocks = sndbuf_getblocks(bs); 958 CHN_UNLOCK(wrch); 959 } else 960 ret = EINVAL; 961 } 962 break; 963 964 case SNDCTL_DSP_GETCAPS: 965 *arg_i = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER; 966 if (rdch && wrch && !(dsp_get_flags(i_dev) & SD_F_SIMPLEX)) 967 *arg_i |= DSP_CAP_DUPLEX; 968 break; 969 970 case SOUND_PCM_READ_BITS: 971 chn = wrch ? wrch : rdch; 972 if (chn) { 973 CHN_LOCK(chn); 974 if (chn->format & AFMT_8BIT) 975 *arg_i = 8; 976 else if (chn->format & AFMT_16BIT) 977 *arg_i = 16; 978 else if (chn->format & AFMT_24BIT) 979 *arg_i = 24; 980 else if (chn->format & AFMT_32BIT) 981 *arg_i = 32; 982 else 983 ret = EINVAL; 984 CHN_UNLOCK(chn); 985 } else { 986 *arg_i = 0; 987 ret = EINVAL; 988 } 989 break; 990 991 case SNDCTL_DSP_SETTRIGGER: 992 if (rdch) { 993 CHN_LOCK(rdch); 994 rdch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER); 995 if (*arg_i & PCM_ENABLE_INPUT) 996 chn_start(rdch, 1); 997 else 998 rdch->flags |= CHN_F_NOTRIGGER; 999 CHN_UNLOCK(rdch); 1000 } 1001 if (wrch) { 1002 CHN_LOCK(wrch); 1003 wrch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER); 1004 if (*arg_i & PCM_ENABLE_OUTPUT) 1005 chn_start(wrch, 1); 1006 else 1007 wrch->flags |= CHN_F_NOTRIGGER; 1008 CHN_UNLOCK(wrch); 1009 } 1010 break; 1011 1012 case SNDCTL_DSP_GETTRIGGER: 1013 *arg_i = 0; 1014 if (wrch) { 1015 CHN_LOCK(wrch); 1016 if (wrch->flags & CHN_F_TRIGGERED) 1017 *arg_i |= PCM_ENABLE_OUTPUT; 1018 CHN_UNLOCK(wrch); 1019 } 1020 if (rdch) { 1021 CHN_LOCK(rdch); 1022 if (rdch->flags & CHN_F_TRIGGERED) 1023 *arg_i |= PCM_ENABLE_INPUT; 1024 CHN_UNLOCK(rdch); 1025 } 1026 break; 1027 1028 case SNDCTL_DSP_GETODELAY: 1029 if (wrch) { 1030 struct snd_dbuf *b = wrch->bufhard; 1031 struct snd_dbuf *bs = wrch->bufsoft; 1032 1033 CHN_LOCK(wrch); 1034 /* XXX abusive DMA update: chn_wrupdate(wrch); */ 1035 *arg_i = sndbuf_getready(b) + sndbuf_getready(bs); 1036 CHN_UNLOCK(wrch); 1037 } else 1038 ret = EINVAL; 1039 break; 1040 1041 case SNDCTL_DSP_POST: 1042 if (wrch) { 1043 CHN_LOCK(wrch); 1044 wrch->flags &= ~CHN_F_NOTRIGGER; 1045 chn_start(wrch, 1); 1046 CHN_UNLOCK(wrch); 1047 } 1048 break; 1049 1050 case SNDCTL_DSP_SETDUPLEX: 1051 /* 1052 * switch to full-duplex mode if card is in half-duplex 1053 * mode and is able to work in full-duplex mode 1054 */ 1055 if (rdch && wrch && (dsp_get_flags(i_dev) & SD_F_SIMPLEX)) 1056 dsp_set_flags(i_dev, dsp_get_flags(i_dev)^SD_F_SIMPLEX); 1057 break; 1058 1059 case SNDCTL_DSP_MAPINBUF: 1060 case SNDCTL_DSP_MAPOUTBUF: 1061 case SNDCTL_DSP_SETSYNCRO: 1062 /* undocumented */ 1063 1064 case SNDCTL_DSP_SUBDIVIDE: 1065 case SOUND_PCM_WRITE_FILTER: 1066 case SOUND_PCM_READ_FILTER: 1067 /* dunno what these do, don't sound important */ 1068 1069 default: 1070 DEB(printf("default ioctl fn 0x%08lx fail\n", cmd)); 1071 ret = EINVAL; 1072 break; 1073 } 1074 relchns(i_dev, rdch, wrch, 0); 1075 return ret; 1076 } 1077 1078 static int 1079 dsp_poll(struct cdev *i_dev, int events, struct thread *td) 1080 { 1081 struct pcm_channel *wrch = NULL, *rdch = NULL; 1082 int ret, e; 1083 1084 ret = 0; 1085 getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1086 1087 if (wrch) { 1088 e = (events & (POLLOUT | POLLWRNORM)); 1089 if (e) 1090 ret |= chn_poll(wrch, e, td); 1091 } 1092 if (rdch) { 1093 e = (events & (POLLIN | POLLRDNORM)); 1094 if (e) 1095 ret |= chn_poll(rdch, e, td); 1096 } 1097 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1098 1099 return ret; 1100 } 1101 1102 static int 1103 dsp_mmap(struct cdev *i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 1104 { 1105 struct pcm_channel *wrch = NULL, *rdch = NULL, *c; 1106 1107 if (nprot & PROT_EXEC) 1108 return -1; 1109 1110 getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1111 #if 0 1112 /* 1113 * XXX the linux api uses the nprot to select read/write buffer 1114 * our vm system doesn't allow this, so force write buffer 1115 */ 1116 1117 if (wrch && (nprot & PROT_WRITE)) { 1118 c = wrch; 1119 } else if (rdch && (nprot & PROT_READ)) { 1120 c = rdch; 1121 } else { 1122 return -1; 1123 } 1124 #else 1125 c = wrch; 1126 #endif 1127 1128 if (c == NULL) { 1129 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1130 return -1; 1131 } 1132 1133 if (offset >= sndbuf_getsize(c->bufsoft)) { 1134 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1135 return -1; 1136 } 1137 1138 if (!(c->flags & CHN_F_MAPPED)) 1139 c->flags |= CHN_F_MAPPED; 1140 1141 *paddr = vtophys(sndbuf_getbufofs(c->bufsoft, offset)); 1142 relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR); 1143 1144 return 0; 1145 } 1146 1147 #ifdef USING_DEVFS 1148 1149 /* 1150 * Clone logic is this: 1151 * x E X = {dsp, dspW, audio} 1152 * x -> x${sysctl("hw.snd.unit")} 1153 * xN-> 1154 * for i N = 1 to channels of device N 1155 * if xN.i isn't busy, return its dev_t 1156 */ 1157 static void 1158 dsp_clone(void *arg, struct ucred *cred, char *name, int namelen, 1159 struct cdev **dev) 1160 { 1161 struct cdev *pdev; 1162 struct snddev_info *pcm_dev; 1163 struct snddev_channel *pcm_chan; 1164 int i, unit, devtype; 1165 int devtypes[3] = {SND_DEV_DSP, SND_DEV_DSP16, SND_DEV_AUDIO}; 1166 char *devnames[3] = {"dsp", "dspW", "audio"}; 1167 1168 if (*dev != NULL) 1169 return; 1170 if (pcm_devclass == NULL) 1171 return; 1172 1173 devtype = 0; 1174 unit = -1; 1175 for (i = 0; (i < 3) && (unit == -1); i++) { 1176 devtype = devtypes[i]; 1177 if (strcmp(name, devnames[i]) == 0) { 1178 unit = snd_unit; 1179 } else { 1180 if (dev_stdclone(name, NULL, devnames[i], &unit) != 1) 1181 unit = -1; 1182 } 1183 } 1184 if (unit == -1 || unit >= devclass_get_maxunit(pcm_devclass)) 1185 return; 1186 1187 pcm_dev = devclass_get_softc(pcm_devclass, unit); 1188 1189 if (pcm_dev == NULL) 1190 return; 1191 1192 SLIST_FOREACH(pcm_chan, &pcm_dev->channels, link) { 1193 1194 switch(devtype) { 1195 case SND_DEV_DSP: 1196 pdev = pcm_chan->dsp_devt; 1197 break; 1198 case SND_DEV_DSP16: 1199 pdev = pcm_chan->dspW_devt; 1200 break; 1201 case SND_DEV_AUDIO: 1202 pdev = pcm_chan->audio_devt; 1203 break; 1204 default: 1205 panic("Unknown devtype %d", devtype); 1206 } 1207 1208 if ((pdev != NULL) && (pdev->si_drv1 == NULL) && (pdev->si_drv2 == NULL)) { 1209 *dev = pdev; 1210 dev_ref(*dev); 1211 return; 1212 } 1213 } 1214 } 1215 1216 static void 1217 dsp_sysinit(void *p) 1218 { 1219 dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000); 1220 } 1221 1222 static void 1223 dsp_sysuninit(void *p) 1224 { 1225 if (dsp_ehtag != NULL) 1226 EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag); 1227 } 1228 1229 SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL); 1230 SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL); 1231 #endif 1232 1233 1234