1 /* $NetBSD: pad.c,v 1.52 2018/01/26 23:36:01 pgoyette Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.52 2018/01/26 23:36:01 pgoyette Exp $"); 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/conf.h> 35 #include <sys/buf.h> 36 #include <sys/file.h> 37 #include <sys/filedesc.h> 38 #include <sys/vnode.h> 39 #include <sys/kauth.h> 40 #include <sys/kmem.h> 41 #include <sys/kernel.h> 42 #include <sys/device.h> 43 #include <sys/proc.h> 44 #include <sys/condvar.h> 45 #include <sys/select.h> 46 #include <sys/stat.h> 47 #include <sys/audioio.h> 48 #include <sys/vnode.h> 49 #include <sys/module.h> 50 #include <sys/atomic.h> 51 #include <sys/time.h> 52 53 #include <dev/audio_if.h> 54 #include <dev/audiovar.h> 55 #include <dev/auconv.h> 56 #include <dev/auvolconv.h> 57 58 #include <dev/pad/padvar.h> 59 60 #define MAXDEVS 128 61 #define PADCLONER 254 62 #define PADUNIT(x) minor(x) 63 64 #define PADFREQ 44100 65 #define PADCHAN 2 66 #define PADPREC 16 67 #define PADENC AUDIO_ENCODING_SLINEAR_LE 68 69 extern struct cfdriver pad_cd; 70 kmutex_t padconfig; 71 72 typedef struct pad_block { 73 uint8_t *pb_ptr; 74 int pb_len; 75 } pad_block_t; 76 77 enum { 78 PAD_OUTPUT_CLASS, 79 PAD_INPUT_CLASS, 80 PAD_OUTPUT_MASTER_VOLUME, 81 PAD_INPUT_DAC_VOLUME, 82 PAD_ENUM_LAST, 83 }; 84 85 static int pad_match(device_t, cfdata_t, void *); 86 static void pad_attach(device_t, device_t, void *); 87 static int pad_detach(device_t, int); 88 static void pad_childdet(device_t, device_t); 89 90 static int pad_audio_open(void *, int); 91 static int pad_query_encoding(void *, struct audio_encoding *); 92 static int pad_set_params(void *, int, int, 93 audio_params_t *, audio_params_t *, 94 stream_filter_list_t *, stream_filter_list_t *); 95 static int pad_start_output(void *, void *, int, 96 void (*)(void *), void *); 97 static int pad_start_input(void *, void *, int, 98 void (*)(void *), void *); 99 static int pad_halt_output(void *); 100 static int pad_halt_input(void *); 101 static int pad_getdev(void *, struct audio_device *); 102 static int pad_set_port(void *, mixer_ctrl_t *); 103 static int pad_get_port(void *, mixer_ctrl_t *); 104 static int pad_query_devinfo(void *, mixer_devinfo_t *); 105 static int pad_get_props(void *); 106 static int pad_round_blocksize(void *, int, int, const audio_params_t *); 107 static void pad_get_locks(void *, kmutex_t **, kmutex_t **); 108 109 static stream_filter_t *pad_swvol_filter_le(struct audio_softc *, 110 const audio_params_t *, const audio_params_t *); 111 static stream_filter_t *pad_swvol_filter_be(struct audio_softc *, 112 const audio_params_t *, const audio_params_t *); 113 static void pad_swvol_dtor(stream_filter_t *); 114 115 static int pad_close(struct pad_softc *); 116 static int pad_read(struct pad_softc *, off_t *, struct uio *, kauth_cred_t, int); 117 118 static int fops_pad_close(struct file *); 119 static int fops_pad_read(struct file *, off_t *, struct uio *, kauth_cred_t, int); 120 static int pad_write(struct file *, off_t *, struct uio *, kauth_cred_t, int); 121 static int pad_ioctl(struct file *, u_long, void *); 122 static int pad_kqfilter(struct file *, struct knote *); 123 static int pad_poll(struct file *, int); 124 static int pad_stat(struct file *, struct stat *); 125 static int pad_mmap(struct file *, off_t *, size_t, int, int *, int *, 126 struct uvm_object **, int *); 127 128 static const struct audio_hw_if pad_hw_if = { 129 .open = pad_audio_open, 130 .query_encoding = pad_query_encoding, 131 .set_params = pad_set_params, 132 .start_output = pad_start_output, 133 .start_input = pad_start_input, 134 .halt_output = pad_halt_output, 135 .halt_input = pad_halt_input, 136 .getdev = pad_getdev, 137 .set_port = pad_set_port, 138 .get_port = pad_get_port, 139 .query_devinfo = pad_query_devinfo, 140 .get_props = pad_get_props, 141 .round_blocksize = pad_round_blocksize, 142 .get_locks = pad_get_locks, 143 }; 144 145 #define PAD_NFORMATS 1 146 static const struct audio_format pad_formats[PAD_NFORMATS] = { 147 { NULL, AUMODE_PLAY|AUMODE_RECORD, PADENC, PADPREC, PADPREC, 148 PADCHAN, AUFMT_STEREO, 1, { PADFREQ } }, 149 }; 150 151 extern void padattach(int); 152 153 static int pad_add_block(pad_softc_t *, uint8_t *, int); 154 static int pad_get_block(pad_softc_t *, pad_block_t *, int); 155 156 dev_type_open(pad_open); 157 dev_type_close(cdev_pad_close); 158 dev_type_read(cdev_pad_read); 159 160 const struct cdevsw pad_cdevsw = { 161 .d_open = pad_open, 162 .d_close = cdev_pad_close, 163 .d_read = cdev_pad_read, 164 .d_write = nowrite, 165 .d_ioctl = noioctl, 166 .d_stop = nostop, 167 .d_tty = notty, 168 .d_poll = nopoll, 169 .d_mmap = nommap, 170 .d_kqfilter = nokqfilter, 171 .d_discard = nodiscard, 172 .d_flag = D_OTHER | D_MPSAFE, 173 }; 174 175 const struct fileops pad_fileops = { 176 .fo_name = "pad", 177 .fo_read = fops_pad_read, 178 .fo_write = pad_write, 179 .fo_ioctl = pad_ioctl, 180 .fo_fcntl = fnullop_fcntl, 181 .fo_stat = pad_stat, 182 .fo_poll = pad_poll, 183 .fo_close = fops_pad_close, 184 .fo_mmap = pad_mmap, 185 .fo_kqfilter = pad_kqfilter, 186 .fo_restart = fnullop_restart 187 }; 188 189 CFATTACH_DECL2_NEW(pad, sizeof(pad_softc_t), pad_match, pad_attach, pad_detach, 190 NULL, NULL, pad_childdet); 191 192 void 193 padattach(int n) 194 { 195 int error; 196 197 error = config_cfattach_attach(pad_cd.cd_name, &pad_ca); 198 if (error) { 199 aprint_error("%s: couldn't register cfattach: %d\n", 200 pad_cd.cd_name, error); 201 config_cfdriver_detach(&pad_cd); 202 return; 203 } 204 mutex_init(&padconfig, MUTEX_DEFAULT, IPL_NONE); 205 206 return; 207 } 208 209 static int 210 pad_add_block(pad_softc_t *sc, uint8_t *blk, int blksize) 211 { 212 int l; 213 214 if (sc->sc_open == 0) 215 return EIO; 216 217 KASSERT(mutex_owned(&sc->sc_lock)); 218 219 if (sc->sc_buflen + blksize > PAD_BUFSIZE) 220 return ENOBUFS; 221 222 if (sc->sc_wpos + blksize <= PAD_BUFSIZE) 223 memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, blksize); 224 else { 225 l = PAD_BUFSIZE - sc->sc_wpos; 226 memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, l); 227 memcpy(sc->sc_audiobuf, blk + l, blksize - l); 228 } 229 230 sc->sc_wpos += blksize; 231 if (sc->sc_wpos > PAD_BUFSIZE) 232 sc->sc_wpos -= PAD_BUFSIZE; 233 234 sc->sc_buflen += blksize; 235 236 return 0; 237 } 238 239 static int 240 pad_get_block(pad_softc_t *sc, pad_block_t *pb, int blksize) 241 { 242 int l; 243 244 KASSERT(mutex_owned(&sc->sc_lock)); 245 KASSERT(pb != NULL); 246 247 if (sc->sc_buflen < (uint)blksize) 248 return ERESTART; 249 250 pb->pb_ptr = (sc->sc_audiobuf + sc->sc_rpos); 251 if (sc->sc_rpos + blksize < PAD_BUFSIZE) { 252 pb->pb_len = blksize; 253 sc->sc_rpos += blksize; 254 } else { 255 l = PAD_BUFSIZE - sc->sc_rpos; 256 pb->pb_len = l; 257 sc->sc_rpos = 0; 258 } 259 sc->sc_buflen -= pb->pb_len; 260 261 return 0; 262 } 263 264 static int 265 pad_match(device_t parent, cfdata_t data, void *opaque) 266 { 267 268 return 1; 269 } 270 271 static void 272 pad_childdet(device_t self, device_t child) 273 { 274 pad_softc_t *sc = device_private(self); 275 276 sc->sc_audiodev = NULL; 277 } 278 279 static void 280 pad_attach(device_t parent, device_t self, void *opaque) 281 { 282 aprint_normal_dev(self, "outputs: 44100Hz, 16-bit, stereo\n"); 283 284 return; 285 } 286 287 static int 288 pad_detach(device_t self, int flags) 289 { 290 pad_softc_t *sc; 291 int cmaj, mn; 292 293 sc = device_private(self); 294 cmaj = cdevsw_lookup_major(&pad_cdevsw); 295 mn = device_unit(sc->sc_dev); 296 if (!sc->sc_dying) 297 vdevgone(cmaj, mn, mn, VCHR); 298 299 return 0; 300 } 301 302 int 303 pad_open(dev_t dev, int flags, int fmt, struct lwp *l) 304 { 305 pad_softc_t *sc; 306 struct file *fp; 307 device_t paddev; 308 cfdata_t cf; 309 int error, fd, i; 310 311 error = 0; 312 313 mutex_enter(&padconfig); 314 if (PADUNIT(dev) == PADCLONER) { 315 for (i = 0; i < MAXDEVS; i++) { 316 if (device_lookup(&pad_cd, i) == NULL) 317 break; 318 } 319 if (i == MAXDEVS) 320 goto bad; 321 } else { 322 if (PADUNIT(dev) >= MAXDEVS) 323 goto bad; 324 i = PADUNIT(dev); 325 } 326 327 cf = kmem_alloc(sizeof(struct cfdata), KM_SLEEP); 328 cf->cf_name = pad_cd.cd_name; 329 cf->cf_atname = pad_cd.cd_name; 330 cf->cf_unit = i; 331 cf->cf_fstate = FSTATE_STAR; 332 333 bool existing = false; 334 paddev = device_lookup(&pad_cd, minor(dev)); 335 if (paddev == NULL) 336 paddev = config_attach_pseudo(cf); 337 else 338 existing = true; 339 if (paddev == NULL) 340 goto bad; 341 342 sc = device_private(paddev); 343 if (sc == NULL) 344 goto bad; 345 346 if (sc->sc_open == 1) { 347 mutex_exit(&padconfig); 348 return EBUSY; 349 } 350 351 sc->sc_dev = paddev; 352 sc->sc_dying = false; 353 354 if (PADUNIT(dev) == PADCLONER) { 355 error = fd_allocfile(&fp, &fd); 356 if (error) { 357 if (existing == false) 358 config_detach(sc->sc_dev, 0); 359 mutex_exit(&padconfig); 360 return error; 361 } 362 } 363 364 if (auconv_create_encodings(pad_formats, PAD_NFORMATS, 365 &sc->sc_encodings) != 0) { 366 aprint_error_dev(sc->sc_dev, "couldn't create encodings\n"); 367 if (existing == false) 368 config_detach(sc->sc_dev, 0); 369 mutex_exit(&padconfig); 370 return EINVAL; 371 } 372 373 cv_init(&sc->sc_condvar, device_xname(sc->sc_dev)); 374 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 375 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE); 376 377 sc->sc_swvol = 255; 378 sc->sc_buflen = 0; 379 sc->sc_rpos = sc->sc_wpos = 0; 380 sc->sc_audiodev = audio_attach_mi(&pad_hw_if, sc, sc->sc_dev); 381 382 if (!pmf_device_register(sc->sc_dev, NULL, NULL)) 383 aprint_error_dev(sc->sc_dev, "couldn't establish power handler\n"); 384 385 if (PADUNIT(dev) == PADCLONER) { 386 error = fd_clone(fp, fd, flags, &pad_fileops, sc); 387 KASSERT(error == EMOVEFD); 388 } 389 sc->sc_open = 1; 390 mutex_exit(&padconfig); 391 392 return error; 393 bad: 394 mutex_exit(&padconfig); 395 return ENXIO; 396 } 397 398 static int 399 pad_close(struct pad_softc *sc) 400 { 401 int rc; 402 403 if (sc == NULL) 404 return ENXIO; 405 406 mutex_enter(&padconfig); 407 config_deactivate(sc->sc_audiodev); 408 409 /* Start draining existing accessors of the device. */ 410 if ((rc = config_detach_children(sc->sc_dev, 411 DETACH_SHUTDOWN|DETACH_FORCE)) != 0) { 412 mutex_exit(&padconfig); 413 return rc; 414 } 415 416 mutex_enter(&sc->sc_lock); 417 sc->sc_dying = true; 418 cv_broadcast(&sc->sc_condvar); 419 mutex_exit(&sc->sc_lock); 420 421 KASSERT(sc->sc_open > 0); 422 sc->sc_open = 0; 423 424 pmf_device_deregister(sc->sc_dev); 425 426 mutex_destroy(&sc->sc_lock); 427 mutex_destroy(&sc->sc_intr_lock); 428 cv_destroy(&sc->sc_condvar); 429 430 auconv_delete_encodings(sc->sc_encodings); 431 432 rc = config_detach(sc->sc_dev, 0); 433 mutex_exit(&padconfig); 434 435 return rc; 436 } 437 438 static int 439 fops_pad_close(struct file *fp) 440 { 441 pad_softc_t *sc; 442 int error; 443 444 sc = fp->f_pad; 445 446 error = pad_close(sc); 447 448 if (error == 0) 449 fp->f_pad = NULL; 450 451 return error; 452 } 453 454 int 455 cdev_pad_close(dev_t dev, int flags, int ifmt, struct lwp *l) 456 { 457 pad_softc_t *sc; 458 sc = device_private(device_lookup(&pad_cd, PADUNIT(dev))); 459 460 return pad_close(sc); 461 } 462 463 static int 464 pad_poll(struct file *fp, int events) 465 { 466 return ENODEV; 467 } 468 469 static int 470 pad_kqfilter(struct file *fp, struct knote *kn) 471 { 472 struct pad_softc *sc; 473 dev_t dev; 474 475 sc = fp->f_pad; 476 if (sc == NULL) 477 return EIO; 478 479 dev = makedev(cdevsw_lookup_major(&pad_cdevsw), device_unit(sc->sc_dev)); 480 481 return seltrue_kqfilter(dev, kn); 482 } 483 484 static int 485 pad_ioctl(struct file *fp, u_long cmd, void *data) 486 { 487 return ENODEV; 488 } 489 490 static int 491 pad_stat(struct file *fp, struct stat *st) 492 { 493 struct pad_softc *sc; 494 495 sc = fp->f_pad; 496 if (sc == NULL) 497 return EIO; 498 499 memset(st, 0, sizeof(*st)); 500 501 st->st_dev = makedev(cdevsw_lookup_major(&pad_cdevsw), device_unit(sc->sc_dev)); 502 503 st->st_uid = kauth_cred_geteuid(fp->f_cred); 504 st->st_gid = kauth_cred_getegid(fp->f_cred); 505 st->st_mode = S_IFCHR; 506 507 return 0; 508 } 509 510 static int 511 pad_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp, 512 int *advicep, struct uvm_object **uobjp, int *maxprotp) 513 { 514 return 1; 515 } 516 517 #define PAD_BYTES_PER_SEC (PADFREQ * PADPREC / NBBY * PADCHAN) 518 #define BYTESTOSLEEP (int64_t)(PAD_BLKSIZE) 519 #define TIMENEXTREAD (int64_t)(BYTESTOSLEEP * 1000000 / PAD_BYTES_PER_SEC) 520 521 int 522 cdev_pad_read(dev_t dev, struct uio *uio, int ioflag) 523 { 524 pad_softc_t *sc; 525 sc = device_private(device_lookup(&pad_cd, PADUNIT(dev))); 526 if (sc == NULL) 527 return ENXIO; 528 529 return pad_read(sc, NULL, uio, NULL, ioflag); 530 } 531 532 static int 533 fops_pad_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, 534 int ioflag) 535 { 536 pad_softc_t *sc; 537 538 sc = fp->f_pad; 539 if (sc == NULL) 540 return ENXIO; 541 542 return pad_read(sc, offp, uio, cred, ioflag); 543 } 544 545 static int 546 pad_read(struct pad_softc *sc, off_t *offp, struct uio *uio, kauth_cred_t cred, 547 int ioflag) 548 { 549 struct timeval now; 550 uint64_t nowusec, lastusec; 551 pad_block_t pb; 552 void (*intr)(void *); 553 void *intrarg; 554 int err, wait_ticks; 555 556 err = 0; 557 558 while (uio->uio_resid > 0 && !err) { 559 mutex_enter(&sc->sc_lock); 560 if (sc->sc_dying == true) { 561 mutex_exit(&sc->sc_lock); 562 return EIO; 563 } 564 intr = sc->sc_intr; 565 intrarg = sc->sc_intrarg; 566 567 getmicrotime(&now); 568 nowusec = (now.tv_sec * 1000000) + now.tv_usec; 569 lastusec = (sc->sc_last.tv_sec * 1000000) + 570 sc->sc_last.tv_usec; 571 if (lastusec + TIMENEXTREAD > nowusec) { 572 if (sc->sc_bytes_count >= BYTESTOSLEEP) { 573 sc->sc_remainder += 574 ((lastusec + TIMENEXTREAD) - nowusec); 575 } 576 577 wait_ticks = (hz * sc->sc_remainder) / 1000000; 578 if (wait_ticks > 0) { 579 sc->sc_remainder -= wait_ticks * 1000000 / hz; 580 err = kpause("padwait", TRUE, wait_ticks, 581 &sc->sc_lock); 582 if (err != EWOULDBLOCK) { 583 mutex_exit(&sc->sc_lock); 584 continue; 585 } 586 } 587 } 588 589 if (sc->sc_bytes_count >= BYTESTOSLEEP) 590 sc->sc_bytes_count -= BYTESTOSLEEP; 591 592 err = pad_get_block(sc, &pb, min(uio->uio_resid, PAD_BLKSIZE)); 593 if (!err) { 594 getmicrotime(&sc->sc_last); 595 sc->sc_bytes_count += pb.pb_len; 596 mutex_exit(&sc->sc_lock); 597 err = uiomove(pb.pb_ptr, pb.pb_len, uio); 598 continue; 599 } 600 601 if (intr) { 602 mutex_enter(&sc->sc_intr_lock); 603 kpreempt_disable(); 604 (*intr)(intrarg); 605 kpreempt_enable(); 606 mutex_exit(&sc->sc_intr_lock); 607 intr = sc->sc_intr; 608 intrarg = sc->sc_intrarg; 609 err = 0; 610 mutex_exit(&sc->sc_lock); 611 continue; 612 } 613 err = cv_wait_sig(&sc->sc_condvar, &sc->sc_lock); 614 if (err != 0) { 615 mutex_exit(&sc->sc_lock); 616 break; 617 } 618 619 mutex_exit(&sc->sc_lock); 620 } 621 622 return err; 623 } 624 625 static int 626 pad_write(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, 627 int ioflag) 628 { 629 return EOPNOTSUPP; 630 } 631 632 static int 633 pad_audio_open(void *opaque, int flags) 634 { 635 pad_softc_t *sc; 636 sc = opaque; 637 638 if (sc->sc_open == 0) 639 return EIO; 640 641 getmicrotime(&sc->sc_last); 642 sc->sc_bytes_count = 0; 643 sc->sc_remainder = 0; 644 645 return 0; 646 } 647 648 static int 649 pad_query_encoding(void *opaque, struct audio_encoding *ae) 650 { 651 pad_softc_t *sc; 652 653 sc = (pad_softc_t *)opaque; 654 655 KASSERT(mutex_owned(&sc->sc_lock)); 656 657 return auconv_query_encoding(sc->sc_encodings, ae); 658 } 659 660 static int 661 pad_set_params(void *opaque, int setmode, int usemode, 662 audio_params_t *play, audio_params_t *rec, 663 stream_filter_list_t *pfil, stream_filter_list_t *rfil) 664 { 665 pad_softc_t *sc __diagused; 666 667 sc = (pad_softc_t *)opaque; 668 669 KASSERT(mutex_owned(&sc->sc_lock)); 670 671 if (auconv_set_converter(pad_formats, PAD_NFORMATS, AUMODE_PLAY, 672 play, true, pfil) < 0) 673 return EINVAL; 674 if (auconv_set_converter(pad_formats, PAD_NFORMATS, AUMODE_RECORD, 675 rec, true, rfil) < 0) 676 return EINVAL; 677 678 if (pfil->req_size > 0) 679 play = &pfil->filters[0].param; 680 switch (play->encoding) { 681 case AUDIO_ENCODING_SLINEAR_LE: 682 if (play->precision == 16 && play->validbits == 16) 683 pfil->prepend(pfil, pad_swvol_filter_le, play); 684 break; 685 case AUDIO_ENCODING_SLINEAR_BE: 686 if (play->precision == 16 && play->validbits == 16) 687 pfil->prepend(pfil, pad_swvol_filter_be, play); 688 break; 689 default: 690 break; 691 } 692 693 return 0; 694 } 695 696 static int 697 pad_start_output(void *opaque, void *block, int blksize, 698 void (*intr)(void *), void *intrarg) 699 { 700 pad_softc_t *sc; 701 int err; 702 703 sc = (pad_softc_t *)opaque; 704 705 KASSERT(mutex_owned(&sc->sc_lock)); 706 if (!sc->sc_open) 707 return EIO; 708 709 sc->sc_intr = intr; 710 sc->sc_intrarg = intrarg; 711 sc->sc_blksize = blksize; 712 713 err = pad_add_block(sc, block, blksize); 714 715 cv_broadcast(&sc->sc_condvar); 716 717 return err; 718 } 719 720 static int 721 pad_start_input(void *opaque, void *block, int blksize, 722 void (*intr)(void *), void *intrarg) 723 { 724 pad_softc_t *sc __diagused; 725 726 sc = (pad_softc_t *)opaque; 727 728 KASSERT(mutex_owned(&sc->sc_lock)); 729 730 return EOPNOTSUPP; 731 } 732 733 static int 734 pad_halt_output(void *opaque) 735 { 736 pad_softc_t *sc; 737 738 sc = (pad_softc_t *)opaque; 739 740 KASSERT(mutex_owned(&sc->sc_lock)); 741 742 sc->sc_intr = NULL; 743 sc->sc_intrarg = NULL; 744 sc->sc_buflen = 0; 745 sc->sc_rpos = sc->sc_wpos = 0; 746 747 return 0; 748 } 749 750 static int 751 pad_halt_input(void *opaque) 752 { 753 pad_softc_t *sc __diagused; 754 755 sc = (pad_softc_t *)opaque; 756 757 KASSERT(mutex_owned(&sc->sc_lock)); 758 759 return 0; 760 } 761 762 static int 763 pad_getdev(void *opaque, struct audio_device *ret) 764 { 765 strlcpy(ret->name, "Virtual Audio", sizeof(ret->name)); 766 strlcpy(ret->version, osrelease, sizeof(ret->version)); 767 strlcpy(ret->config, "pad", sizeof(ret->config)); 768 769 return 0; 770 } 771 772 static int 773 pad_set_port(void *opaque, mixer_ctrl_t *mc) 774 { 775 pad_softc_t *sc; 776 777 sc = (pad_softc_t *)opaque; 778 779 KASSERT(mutex_owned(&sc->sc_lock)); 780 781 switch (mc->dev) { 782 case PAD_OUTPUT_MASTER_VOLUME: 783 case PAD_INPUT_DAC_VOLUME: 784 sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 785 return 0; 786 } 787 788 return ENXIO; 789 } 790 791 static int 792 pad_get_port(void *opaque, mixer_ctrl_t *mc) 793 { 794 pad_softc_t *sc; 795 796 sc = (pad_softc_t *)opaque; 797 798 KASSERT(mutex_owned(&sc->sc_lock)); 799 800 switch (mc->dev) { 801 case PAD_OUTPUT_MASTER_VOLUME: 802 case PAD_INPUT_DAC_VOLUME: 803 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_swvol; 804 return 0; 805 } 806 807 return ENXIO; 808 } 809 810 static int 811 pad_query_devinfo(void *opaque, mixer_devinfo_t *di) 812 { 813 pad_softc_t *sc __diagused; 814 815 sc = (pad_softc_t *)opaque; 816 817 KASSERT(mutex_owned(&sc->sc_lock)); 818 819 switch (di->index) { 820 case PAD_OUTPUT_CLASS: 821 di->mixer_class = PAD_OUTPUT_CLASS; 822 strcpy(di->label.name, AudioCoutputs); 823 di->type = AUDIO_MIXER_CLASS; 824 di->next = di->prev = AUDIO_MIXER_LAST; 825 return 0; 826 case PAD_INPUT_CLASS: 827 di->mixer_class = PAD_INPUT_CLASS; 828 strcpy(di->label.name, AudioCinputs); 829 di->type = AUDIO_MIXER_CLASS; 830 di->next = di->prev = AUDIO_MIXER_LAST; 831 return 0; 832 case PAD_OUTPUT_MASTER_VOLUME: 833 di->mixer_class = PAD_OUTPUT_CLASS; 834 strcpy(di->label.name, AudioNmaster); 835 di->type = AUDIO_MIXER_VALUE; 836 di->next = di->prev = AUDIO_MIXER_LAST; 837 di->un.v.num_channels = 1; 838 strcpy(di->un.v.units.name, AudioNvolume); 839 return 0; 840 case PAD_INPUT_DAC_VOLUME: 841 di->mixer_class = PAD_INPUT_CLASS; 842 strcpy(di->label.name, AudioNdac); 843 di->type = AUDIO_MIXER_VALUE; 844 di->next = di->prev = AUDIO_MIXER_LAST; 845 di->un.v.num_channels = 1; 846 strcpy(di->un.v.units.name, AudioNvolume); 847 return 0; 848 } 849 850 return ENXIO; 851 } 852 853 static int 854 pad_get_props(void *opaque) 855 { 856 pad_softc_t *sc __diagused; 857 858 sc = (pad_softc_t *)opaque; 859 860 KASSERT(mutex_owned(&sc->sc_lock)); 861 862 return 0; 863 } 864 865 static int 866 pad_round_blocksize(void *opaque, int blksize, int mode, 867 const audio_params_t *p) 868 { 869 pad_softc_t *sc __diagused; 870 871 sc = (pad_softc_t *)opaque; 872 KASSERT(mutex_owned(&sc->sc_lock)); 873 874 return PAD_BLKSIZE; 875 } 876 877 static void 878 pad_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread) 879 { 880 pad_softc_t *sc; 881 882 sc = (pad_softc_t *)opaque; 883 884 *intr = &sc->sc_intr_lock; 885 *thread = &sc->sc_lock; 886 } 887 888 static stream_filter_t * 889 pad_swvol_filter_le(struct audio_softc *asc, 890 const audio_params_t *from, const audio_params_t *to) 891 { 892 auvolconv_filter_t *this; 893 device_t dev = audio_get_device(asc); 894 struct pad_softc *sc = device_private(dev); 895 896 this = kmem_alloc(sizeof(auvolconv_filter_t), KM_SLEEP); 897 this->base.base.fetch_to = auvolconv_slinear16_le_fetch_to; 898 this->base.dtor = pad_swvol_dtor; 899 this->base.set_fetcher = stream_filter_set_fetcher; 900 this->base.set_inputbuffer = stream_filter_set_inputbuffer; 901 this->vol = &sc->sc_swvol; 902 903 return (stream_filter_t *)this; 904 } 905 906 static stream_filter_t * 907 pad_swvol_filter_be(struct audio_softc *asc, 908 const audio_params_t *from, const audio_params_t *to) 909 { 910 auvolconv_filter_t *this; 911 device_t dev = audio_get_device(asc); 912 struct pad_softc *sc = device_private(dev); 913 914 this = kmem_alloc(sizeof(auvolconv_filter_t), KM_SLEEP); 915 this->base.base.fetch_to = auvolconv_slinear16_be_fetch_to; 916 this->base.dtor = pad_swvol_dtor; 917 this->base.set_fetcher = stream_filter_set_fetcher; 918 this->base.set_inputbuffer = stream_filter_set_inputbuffer; 919 this->vol = &sc->sc_swvol; 920 921 return (stream_filter_t *)this; 922 } 923 924 static void 925 pad_swvol_dtor(stream_filter_t *this) 926 { 927 if (this) 928 kmem_free(this, sizeof(auvolconv_filter_t)); 929 } 930 931 MODULE(MODULE_CLASS_DRIVER, pad, "audio"); 932 933 #ifdef _MODULE 934 935 #include "ioconf.c" 936 937 devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR; 938 939 /* 940 * We need our own version of cfattach since config(1)'s ioconf does not 941 * generate what we need 942 */ 943 944 static struct cfattach *pad_cfattachinit[] = { &pad_ca, NULL }; 945 946 static struct cfattachinit pad_cfattach[] = { 947 { "pad", pad_cfattachinit }, 948 { NULL, NULL } 949 }; 950 #endif 951 952 static int 953 pad_modcmd(modcmd_t cmd, void *arg) 954 { 955 int error = 0; 956 957 switch (cmd) { 958 case MODULE_CMD_INIT: 959 #ifdef _MODULE 960 pad_cfattach[1] = cfattach_ioconf_pad[0]; 961 error = config_init_component(cfdriver_ioconf_pad, 962 pad_cfattach, cfdata_ioconf_pad); 963 if (error) 964 break; 965 966 error = devsw_attach(pad_cd.cd_name, NULL, &bmajor, 967 &pad_cdevsw, &cmajor); 968 if (error) { 969 config_fini_component(cfdriver_ioconf_pad, 970 pad_cfattach, cfdata_ioconf_pad); 971 break; 972 } 973 mutex_init(&padconfig, MUTEX_DEFAULT, IPL_NONE); 974 975 #endif 976 break; 977 978 case MODULE_CMD_FINI: 979 #ifdef _MODULE 980 error = devsw_detach(NULL, &pad_cdevsw); 981 if (error) 982 break; 983 984 error = config_fini_component(cfdriver_ioconf_pad, 985 pad_cfattach, cfdata_ioconf_pad); 986 if (error) { 987 devsw_attach(pad_cd.cd_name, NULL, &bmajor, 988 &pad_cdevsw, &cmajor); 989 break; 990 } 991 mutex_destroy(&padconfig); 992 #endif 993 break; 994 995 default: 996 error = ENOTTY; 997 } 998 999 return error; 1000 } 1001