1 /* $NetBSD: ascaudio.c,v 1.1 2024/03/13 07:55:28 nat Exp $ */ 2 3 /*- 4 * Copyright (c) 2017, 2023 Nathanial Sloss <nathanialsloss@yahoo.com.au> 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 /* Based on pad(4) and asc(4) */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: ascaudio.c,v 1.1 2024/03/13 07:55:28 nat Exp $"); 33 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/conf.h> 37 #include <sys/buf.h> 38 #include <sys/kauth.h> 39 #include <sys/kmem.h> 40 #include <sys/kernel.h> 41 #include <sys/device.h> 42 #include <sys/proc.h> 43 #include <sys/audioio.h> 44 #include <sys/module.h> 45 #include <sys/atomic.h> 46 47 #include <uvm/uvm_extern.h> 48 49 #include <dev/audio/audio_if.h> 50 #include <dev/audio/audiovar.h> 51 52 #include <machine/autoconf.h> 53 #include <machine/cpu.h> 54 #include <machine/bus.h> 55 #include <machine/viareg.h> 56 57 #include <mac68k/obio/ascaudiovar.h> 58 #include <mac68k/obio/ascreg.h> 59 #include <mac68k/obio/obiovar.h> 60 61 #define MAC68K_ASCAUDIO_BASE 0x50f14000 62 #define MAC68K_IIFX_ASCAUDIO_BASE 0x50f10000 63 #define MAC68K_ASCAUDIO_LEN 0x1000 64 65 #define BUFSIZE 32768 66 #define PLAYBLKSIZE 8192 67 #define RECBLKSIZE 8192 68 69 static int ascaudiomatch(device_t, cfdata_t, void *); 70 static void ascaudioattach(device_t, device_t, void *); 71 72 CFATTACH_DECL_NEW(ascaudio, sizeof(struct ascaudio_softc), 73 ascaudiomatch, ascaudioattach, NULL, NULL); 74 75 extern struct cfdriver ascaudio_cd; 76 77 dev_type_open(ascaudioopen); 78 dev_type_close(ascaudioclose); 79 dev_type_read(ascaudioread); 80 dev_type_write(ascaudiowrite); 81 dev_type_ioctl(ascaudioioctl); 82 83 const struct cdevsw ascaudio_cdevsw = { 84 .d_open = ascaudioopen, 85 .d_close = ascaudioclose, 86 .d_read = ascaudioread, 87 .d_write = ascaudiowrite, 88 .d_ioctl = ascaudioioctl, 89 .d_stop = nostop, 90 .d_tty = notty, 91 .d_poll = nopoll, 92 .d_mmap = nommap, 93 .d_kqfilter = nokqfilter, 94 .d_discard = nodiscard, 95 .d_flag = 0 96 }; 97 98 static int ascaudio_query_format(void *, struct audio_format_query *); 99 static int ascaudio_set_format(void *, int, 100 const audio_params_t *, const audio_params_t *, 101 audio_filter_reg_t *, audio_filter_reg_t *); 102 static int ascaudio_start_output(void *, void *, int, 103 void (*)(void *), void *); 104 static int ascaudio_start_input(void *, void *, int, 105 void (*)(void *), void *); 106 static int ascaudio_halt(void *); 107 static int ascaudio_set_port(void *, mixer_ctrl_t *); 108 static int ascaudio_get_port(void *, mixer_ctrl_t *); 109 static int ascaudio_getdev(void *, struct audio_device *); 110 static int ascaudio_query_devinfo(void *, mixer_devinfo_t *); 111 static int ascaudio_get_props(void *); 112 static int 113 ascaudio_round_blocksize(void *, int, int, const audio_params_t *); 114 static void ascaudio_get_locks(void *, kmutex_t **, kmutex_t **); 115 static void ascaudio_intr(void *); 116 static int ascaudio_intr_est(void *); 117 static void ascaudio_intr_enable(void); 118 static void ascaudio_done_output(void *); 119 static void ascaudio_done_input(void *); 120 121 static const struct audio_hw_if ascaudio_hw_if = { 122 .query_format = ascaudio_query_format, 123 .set_format = ascaudio_set_format, 124 .start_output = ascaudio_start_output, 125 .start_input = ascaudio_start_input, 126 .halt_output = ascaudio_halt, 127 .halt_input = ascaudio_halt, 128 .set_port = ascaudio_set_port, 129 .get_port = ascaudio_get_port, 130 .getdev = ascaudio_getdev, 131 .query_devinfo = ascaudio_query_devinfo, 132 .get_props = ascaudio_get_props, 133 .round_blocksize = ascaudio_round_blocksize, 134 .get_locks = ascaudio_get_locks, 135 }; 136 137 #define EASC_VER 0xb0 138 139 enum { 140 ASC_OUTPUT_CLASS, 141 ASC_INPUT_CLASS, 142 ASC_OUTPUT_MASTER_VOLUME, 143 ASC_INPUT_DAC_VOLUME, 144 ASC_ENUM_LAST, 145 }; 146 147 static int 148 ascaudiomatch(device_t parent, cfdata_t cf, void *aux) 149 { 150 struct obio_attach_args *oa = (struct obio_attach_args *)aux; 151 bus_addr_t addr; 152 bus_space_handle_t bsh; 153 int rval = 0; 154 155 if (oa->oa_addr != (-1)) 156 addr = (bus_addr_t)oa->oa_addr; 157 else if (current_mac_model->machineid == MACH_MACTV) 158 return 0; 159 else if (current_mac_model->machineid == MACH_MACIIFX) 160 addr = (bus_addr_t)MAC68K_IIFX_ASCAUDIO_BASE; 161 else 162 addr = (bus_addr_t)MAC68K_ASCAUDIO_BASE; 163 164 if (bus_space_map(oa->oa_tag, addr, MAC68K_ASCAUDIO_LEN, 0, &bsh)) 165 return (0); 166 167 if (mac68k_bus_space_probe(oa->oa_tag, bsh, 0, 1)) { 168 rval = 1; 169 } else 170 rval = 0; 171 172 bus_space_unmap(oa->oa_tag, bsh, MAC68K_ASCAUDIO_LEN); 173 174 return rval; 175 } 176 177 static void 178 ascaudioattach(device_t parent, device_t self, void *aux) 179 { 180 struct ascaudio_softc *sc = device_private(self); 181 struct obio_attach_args *oa = (struct obio_attach_args *)aux; 182 bus_addr_t addr; 183 uint8_t tmp; 184 185 sc->sc_dev = self; 186 sc->sc_tag = oa->oa_tag; 187 188 if (oa->oa_addr != (-1)) 189 addr = (bus_addr_t)oa->oa_addr; 190 else if (current_mac_model->machineid == MACH_MACIIFX) 191 addr = (bus_addr_t)MAC68K_IIFX_ASCAUDIO_BASE; 192 else 193 addr = (bus_addr_t)MAC68K_ASCAUDIO_BASE; 194 if (bus_space_map(sc->sc_tag, addr, MAC68K_ASCAUDIO_LEN, 0, 195 &sc->sc_handle)) { 196 printf(": can't map memory space\n"); 197 return; 198 } 199 200 /* Pull in the options flags. */ 201 sc->sc_options = ((device_cfdata(self)->cf_flags) & 202 ASCAUDIO_OPTIONS_MASK); 203 204 sc->sc_playbuf = kmem_alloc(BUFSIZE, KM_SLEEP); 205 sc->sc_recbuf = kmem_alloc(BUFSIZE, KM_SLEEP); 206 sc->sc_rptr = sc->sc_recbuf; 207 sc->sc_getptr = sc->sc_recbuf; 208 sc->sc_wptr = sc->sc_playbuf; 209 sc->sc_putptr = sc->sc_playbuf; 210 211 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 212 213 sc->sc_ver = bus_space_read_1(oa->oa_tag, sc->sc_handle, 0x800); 214 215 if (sc->sc_options & HIGHQUALITY) { 216 tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCRATE); 217 switch (tmp) { 218 case 2: 219 sc->sc_rate = 22050; 220 break; 221 case 3: 222 sc->sc_rate = 44100; 223 break; 224 default: 225 sc->sc_rate = 22254; 226 break; 227 } 228 229 tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCTRL); 230 if (tmp & STEREO) 231 sc->sc_speakers = 2; 232 else 233 sc->sc_speakers = 1; 234 235 } else { 236 __USE(tmp); 237 sc->sc_rate = 22254; 238 sc->sc_speakers = 1; 239 } 240 241 if (sc->sc_options & LOWQUALITY) { 242 sc->sc_slowcpu = true; 243 if (sc->sc_slowcpu) 244 sc->sc_rate /= 2; 245 } 246 247 if (sc->sc_ver != EASC_VER) 248 printf(": Apple Sound Chip"); 249 else 250 printf(": Enhanced Apple Sound Chip"); 251 if (oa->oa_addr != (-1)) 252 printf(" at %x", oa->oa_addr); 253 printf("\n"); 254 255 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 256 257 if (mac68k_machine.aux_interrupts) { 258 intr_establish(ascaudio_intr_est, sc, ASCIRQ); 259 } else { 260 via2_register_irq(VIA2_ASC, ascaudio_intr, sc); 261 } 262 ascaudio_intr_enable(); 263 264 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 265 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_HIGH); 266 callout_init(&sc->sc_pcallout, CALLOUT_MPSAFE); 267 callout_setfunc(&sc->sc_pcallout, ascaudio_done_output, sc); 268 callout_init(&sc->sc_rcallout, CALLOUT_MPSAFE); 269 callout_setfunc(&sc->sc_rcallout, ascaudio_done_input, sc); 270 271 sc->sc_vol = 255; 272 273 sc->sc_audiodev = audio_attach_mi(&ascaudio_hw_if, sc, sc->sc_dev); 274 275 if (!pmf_device_register(sc->sc_dev, NULL, NULL)) 276 aprint_error_dev(sc->sc_dev, 277 "couldn't establish power handler\n"); 278 279 280 if (sc->sc_ver != EASC_VER) 281 return; 282 283 if (sc->sc_options & HIGHQUALITY) 284 tmp = CDQUALITY; 285 else 286 tmp = MACDEFAULTS; 287 288 bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOCTRLA, tmp); 289 bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOCTRLB, tmp); 290 291 } 292 293 int 294 ascaudioopen(dev_t dev, int flag, int mode, struct lwp *l) 295 { 296 struct ascaudio_softc *sc; 297 298 sc = device_lookup_private(&ascaudio_cd, ASCAUDIOUNIT(dev)); 299 if (sc == NULL) 300 return (ENXIO); 301 if (sc->sc_open) 302 return (EBUSY); 303 sc->sc_open = 1; 304 305 return (0); 306 } 307 308 int 309 ascaudioclose(dev_t dev, int flag, int mode, struct lwp *l) 310 { 311 struct ascaudio_softc *sc; 312 313 sc = device_lookup_private(&ascaudio_cd, ASCAUDIOUNIT(dev)); 314 sc->sc_open = 0; 315 316 return (0); 317 } 318 319 int 320 ascaudioread(dev_t dev, struct uio *uio, int ioflag) 321 { 322 return (ENXIO); 323 } 324 325 int 326 ascaudiowrite(dev_t dev, struct uio *uio, int ioflag) 327 { 328 return (ENXIO); 329 } 330 331 int 332 ascaudioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 333 { 334 int error; 335 #ifdef notyet 336 struct ascaudio_softc *sc; 337 int unit = ASCAUDIOUNIT(dev); 338 339 sc = device_lookup_private(&ascaudio_cd, unit); 340 #endif 341 error = 0; 342 343 switch (cmd) { 344 default: 345 error = EINVAL; 346 break; 347 } 348 return (error); 349 } 350 351 #define ASCAUDIO_NFORMATS 2 352 static int 353 ascaudio_query_format(void *opaque, struct audio_format_query *ae) 354 { 355 struct ascaudio_softc *sc = opaque; 356 357 const struct audio_format asc_formats[ASCAUDIO_NFORMATS] = { 358 { .mode = AUMODE_PLAY, 359 .encoding = AUDIO_ENCODING_SLINEAR_LE, 360 .validbits = 8, 361 .precision = 8, 362 .channels = sc->sc_speakers, 363 .channel_mask = sc->sc_speakers == 2 ? AUFMT_STEREO : 364 AUFMT_MONAURAL, 365 .frequency_type = 1, 366 .frequency = { sc->sc_rate }, }, 367 { .mode = AUMODE_RECORD, 368 .encoding = AUDIO_ENCODING_SLINEAR_LE, 369 .validbits = 8, 370 .precision = 8, 371 .channels = 1, 372 .channel_mask = AUFMT_MONAURAL, 373 .frequency_type = 1, 374 .frequency = { 11025 }, } 375 }; 376 377 return audio_query_format(asc_formats, ASCAUDIO_NFORMATS, ae); 378 } 379 380 static int 381 ascaudio_set_format(void *opaque, int setmode, 382 const audio_params_t *play, const audio_params_t *rec, 383 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 384 { 385 struct ascaudio_softc *sc = opaque; 386 387 KASSERT(mutex_owned(&sc->sc_lock)); 388 389 return 0; 390 } 391 392 static int 393 ascaudio_start_output(void *opaque, void *block, int blksize, 394 void (*intr)(void *), void *intrarg) 395 { 396 struct ascaudio_softc *sc; 397 uint8_t *loc, tmp; 398 int total; 399 400 sc = (struct ascaudio_softc *)opaque; 401 if (!sc) 402 return (ENODEV); 403 404 sc->sc_pintr = intr; 405 sc->sc_pintrarg = intrarg; 406 407 408 loc = block; 409 if (bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCMODE) != 410 MODEFIFO) { 411 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 412 413 if (sc->sc_ver == EASC_VER) { 414 /* disable half interrupts channel a */ 415 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 416 DISABLEHALFIRQ); 417 /* Disable half interrupts channel b */ 418 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 419 DISABLEHALFIRQ); 420 } 421 422 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTEST, 0); 423 bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, 424 CLEARFIFO); 425 tmp = 0; 426 bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, tmp); 427 428 if (sc->sc_ver == EASC_VER) { 429 /* enable interrupts channel b */ 430 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 0); 431 } 432 } 433 434 /* set the volume */ 435 tmp = sc->sc_vol >> 5; 436 /* set volume for channel b left and right speakers */ 437 if (sc->sc_ver == EASC_VER) { 438 bus_space_write_1(sc->sc_tag, sc->sc_handle, A_LEFT_VOL, tmp); 439 bus_space_write_1(sc->sc_tag, sc->sc_handle, B_LEFT_VOL, tmp); 440 bus_space_write_1(sc->sc_tag, sc->sc_handle, A_RIGHT_VOL, tmp); 441 bus_space_write_1(sc->sc_tag, sc->sc_handle, B_RIGHT_VOL, tmp); 442 } else 443 bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, tmp << 5); 444 445 total = blksize; 446 if (sc->sc_putptr + blksize > sc->sc_playbuf + BUFSIZE) 447 total = sc->sc_playbuf + BUFSIZE - sc->sc_putptr; 448 449 memcpy(sc->sc_putptr, loc, total); 450 sc->sc_putptr += total; 451 loc += total; 452 453 total = blksize - total; 454 if (total) { 455 sc->sc_putptr = sc->sc_playbuf; 456 memcpy(sc->sc_playbuf, loc, total); 457 sc->sc_putptr += total; 458 } 459 460 sc->sc_avail += blksize; 461 if (sc->sc_avail > BUFSIZE) 462 sc->sc_avail = BUFSIZE; 463 464 /* start fifo playback */ 465 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO); 466 467 return 0; 468 } 469 470 static int 471 ascaudio_start_input(void *opaque, void *block, int blksize, 472 void (*intr)(void *), void *intrarg) 473 { 474 struct ascaudio_softc *sc; 475 uint8_t tmp; 476 int total; 477 478 sc = (struct ascaudio_softc *)opaque; 479 if (!sc) 480 return (ENODEV); 481 482 483 uint8_t *loc; 484 loc = block; 485 486 sc->sc_rintr = intr; 487 sc->sc_rintrarg = intrarg; 488 489 if (bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCMODE) != 490 MODEFIFO) { 491 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 492 493 if (sc->sc_ver == EASC_VER) { 494 /* disable half interrupts channel a */ 495 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 496 DISABLEHALFIRQ); 497 /* Disable half interrupts channel b */ 498 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 499 DISABLEHALFIRQ); 500 } 501 502 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTEST, 0); 503 bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, 504 CLEARFIFO); 505 tmp = RECORDA; 506 bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, tmp); 507 bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, 0xa0); 508 509 if (sc->sc_ver == EASC_VER) { 510 /* enable interrupts channel a */ 511 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 0); 512 } 513 514 /* start fifo playback */ 515 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO); 516 517 return 0; 518 } 519 520 /* set the volume */ 521 tmp = sc->sc_vol >> 5; 522 /* set volume for channel b left and right speakers */ 523 if (sc->sc_ver == EASC_VER) { 524 bus_space_write_1(sc->sc_tag, sc->sc_handle, A_LEFT_VOL, tmp); 525 bus_space_write_1(sc->sc_tag, sc->sc_handle, B_LEFT_VOL, tmp); 526 bus_space_write_1(sc->sc_tag, sc->sc_handle, A_RIGHT_VOL, tmp); 527 bus_space_write_1(sc->sc_tag, sc->sc_handle, B_RIGHT_VOL, tmp); 528 } else 529 bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, tmp << 5); 530 531 total = blksize; 532 if (sc->sc_getptr + blksize > sc->sc_recbuf + BUFSIZE) 533 total = sc->sc_recbuf + BUFSIZE - sc->sc_getptr; 534 535 memcpy(loc, sc->sc_getptr, total); 536 sc->sc_getptr += total; 537 loc += total; 538 539 if (sc->sc_getptr >= sc->sc_recbuf + BUFSIZE) 540 sc->sc_getptr = sc->sc_recbuf; 541 542 total = blksize - total; 543 if (total) { 544 memcpy(loc, sc->sc_getptr, total); 545 sc->sc_getptr += total; 546 } 547 548 sc->sc_recavail -= blksize; 549 550 return 0; 551 } 552 553 static int 554 ascaudio_halt(void *opaque) 555 { 556 ascaudio_softc_t *sc; 557 558 sc = (ascaudio_softc_t *)opaque; 559 560 KASSERT(mutex_owned(&sc->sc_lock)); 561 562 563 sc->sc_pintr = NULL; 564 sc->sc_pintrarg = NULL; 565 sc->sc_rintr = NULL; 566 sc->sc_rintrarg = NULL; 567 568 sc->sc_avail = 0; 569 sc->sc_recavail = 0; 570 571 callout_halt(&sc->sc_pcallout, &sc->sc_lock); 572 callout_halt(&sc->sc_rcallout, &sc->sc_lock); 573 574 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 575 576 bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, CLEARFIFO); 577 578 sc->sc_rptr = sc->sc_recbuf; 579 sc->sc_getptr = sc->sc_recbuf; 580 sc->sc_wptr = sc->sc_playbuf; 581 sc->sc_putptr = sc->sc_playbuf; 582 583 if (sc->sc_ver != EASC_VER) 584 return 0; 585 586 /* disable half interrupts channel a */ 587 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, DISABLEHALFIRQ); 588 /* disable half interrupts channel b */ 589 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, DISABLEHALFIRQ); 590 591 return 0; 592 } 593 594 static int 595 ascaudio_getdev(void *opaque, struct audio_device *ret) 596 { 597 strlcpy(ret->name, "Apple ASC Audio", sizeof(ret->name)); 598 strlcpy(ret->version, osrelease, sizeof(ret->version)); 599 strlcpy(ret->config, "ascaudio", sizeof(ret->config)); 600 601 return 0; 602 } 603 604 static int 605 ascaudio_set_port(void *opaque, mixer_ctrl_t *mc) 606 { 607 struct ascaudio_softc *sc = opaque; 608 609 KASSERT(mutex_owned(&sc->sc_lock)); 610 611 switch (mc->dev) { 612 case ASC_OUTPUT_MASTER_VOLUME: 613 case ASC_INPUT_DAC_VOLUME: 614 if (mc->un.value.num_channels != 1) 615 return EINVAL; 616 sc->sc_vol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 617 return 0; 618 } 619 620 return ENXIO; 621 } 622 623 static int 624 ascaudio_get_port(void *opaque, mixer_ctrl_t *mc) 625 { 626 struct ascaudio_softc *sc = opaque; 627 628 KASSERT(mutex_owned(&sc->sc_lock)); 629 630 switch (mc->dev) { 631 case ASC_OUTPUT_MASTER_VOLUME: 632 case ASC_INPUT_DAC_VOLUME: 633 if (mc->un.value.num_channels != 1) 634 return EINVAL; 635 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_vol; 636 return 0; 637 } 638 639 return ENXIO; 640 } 641 642 static int 643 ascaudio_query_devinfo(void *opaque, mixer_devinfo_t *di) 644 { 645 ascaudio_softc_t *sc __diagused; 646 647 sc = (ascaudio_softc_t *)opaque; 648 649 KASSERT(mutex_owned(&sc->sc_lock)); 650 651 switch (di->index) { 652 case ASC_OUTPUT_CLASS: 653 di->mixer_class = ASC_OUTPUT_CLASS; 654 strcpy(di->label.name, AudioCoutputs); 655 di->type = AUDIO_MIXER_CLASS; 656 di->next = di->prev = AUDIO_MIXER_LAST; 657 return 0; 658 case ASC_INPUT_CLASS: 659 di->mixer_class = ASC_INPUT_CLASS; 660 strcpy(di->label.name, AudioCinputs); 661 di->type = AUDIO_MIXER_CLASS; 662 di->next = di->prev = AUDIO_MIXER_LAST; 663 return 0; 664 case ASC_OUTPUT_MASTER_VOLUME: 665 di->mixer_class = ASC_OUTPUT_CLASS; 666 strcpy(di->label.name, AudioNmaster); 667 di->type = AUDIO_MIXER_VALUE; 668 di->next = di->prev = AUDIO_MIXER_LAST; 669 di->un.v.num_channels = 1; 670 strcpy(di->un.v.units.name, AudioNvolume); 671 return 0; 672 case ASC_INPUT_DAC_VOLUME: 673 di->mixer_class = ASC_INPUT_CLASS; 674 strcpy(di->label.name, AudioNdac); 675 di->type = AUDIO_MIXER_VALUE; 676 di->next = di->prev = AUDIO_MIXER_LAST; 677 di->un.v.num_channels = 1; 678 strcpy(di->un.v.units.name, AudioNvolume); 679 return 0; 680 } 681 682 return ENXIO; 683 } 684 685 static int 686 ascaudio_get_props(void *opaque) 687 { 688 689 return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE | 690 AUDIO_PROP_INDEPENDENT; 691 } 692 693 static int 694 ascaudio_round_blocksize(void *opaque, int blksize, int mode, 695 const audio_params_t *p) 696 { 697 ascaudio_softc_t *sc __diagused; 698 699 sc = (ascaudio_softc_t *)opaque; 700 KASSERT(mutex_owned(&sc->sc_lock)); 701 702 if (mode == AUMODE_PLAY) 703 return PLAYBLKSIZE; 704 else 705 return RECBLKSIZE; 706 } 707 708 static void 709 ascaudio_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread) 710 { 711 ascaudio_softc_t *sc; 712 713 sc = (ascaudio_softc_t *)opaque; 714 715 *intr = &sc->sc_intr_lock; 716 *thread = &sc->sc_lock; 717 } 718 719 static int 720 ascaudio_intr_est(void *arg) 721 { 722 ascaudio_intr(arg); 723 724 return 0; 725 } 726 727 static void 728 ascaudio_intr(void *arg) 729 { 730 struct ascaudio_softc *sc = arg; 731 uint8_t status, val; 732 bool again; 733 int total, count, i; 734 735 if (!sc) 736 return; 737 738 if (!sc->sc_pintr && !sc->sc_rintr) 739 return; 740 741 mutex_enter(&sc->sc_intr_lock); 742 do { 743 status = bus_space_read_1(sc->sc_tag, sc->sc_handle, 744 FIFOSTATUS); 745 again = false; 746 count = 0; 747 if ((status & A_HALF) == 0) 748 count = 0x200; 749 if (count && ((status & A_FULL) == 0)) 750 count = 0x400; 751 752 if (sc->sc_rintr && count) { 753 total = count; 754 if (sc->sc_rptr + count > sc->sc_recbuf + BUFSIZE) 755 count = sc->sc_recbuf + BUFSIZE - sc->sc_rptr; 756 757 while (total) { 758 for (i = 0; i < count; i++) { 759 val = bus_space_read_1(sc->sc_tag, 760 sc->sc_handle, FIFO_A); 761 val ^= 0x80; 762 *sc->sc_rptr++ = val; 763 } 764 if (sc->sc_rptr >= sc->sc_recbuf + BUFSIZE) 765 sc->sc_rptr = sc->sc_recbuf; 766 total -= count; 767 sc->sc_recavail += count; 768 } 769 770 if (sc->sc_recavail > BUFSIZE) 771 sc->sc_recavail = BUFSIZE; 772 } 773 774 count = 0; 775 if (status & B_FULL) 776 count = 0x400; 777 else if (status & B_HALF) 778 count = 0x200; 779 780 if (sc->sc_slowcpu) 781 count /= 2; 782 783 if (sc->sc_pintr && count) { 784 if (sc->sc_avail < count) { 785 if (sc->sc_pintr) { 786 for (i = 0; i < 0x200; i++) { 787 bus_space_write_1(sc->sc_tag, 788 sc->sc_handle, FIFO_A, 789 0x80); 790 bus_space_write_1(sc->sc_tag, 791 sc->sc_handle, FIFO_B, 792 0x80); 793 } 794 } else { 795 for (i = 0; i < 0x200; i++) { 796 bus_space_write_1(sc->sc_tag, 797 sc->sc_handle, FIFO_B, 798 0x80); 799 } 800 } 801 } else if (sc->sc_slowcpu) { 802 for (i = 0; i < count; i++) { 803 val = *sc->sc_wptr++; 804 val ^= 0x80; 805 bus_space_write_1(sc->sc_tag, 806 sc->sc_handle, FIFO_A, val); 807 bus_space_write_1(sc->sc_tag, 808 sc->sc_handle, FIFO_B, val); 809 bus_space_write_1(sc->sc_tag, 810 sc->sc_handle, FIFO_A, val); 811 bus_space_write_1(sc->sc_tag, 812 sc->sc_handle, FIFO_B, val); 813 } 814 sc->sc_avail -= count; 815 again = true; 816 } else { 817 for (i = 0; i < count; i++) { 818 val = *sc->sc_wptr++; 819 val ^= 0x80; 820 bus_space_write_1(sc->sc_tag, 821 sc->sc_handle, FIFO_A, val); 822 bus_space_write_1(sc->sc_tag, 823 sc->sc_handle, FIFO_B, val); 824 } 825 sc->sc_avail -= count; 826 again = true; 827 } 828 if (sc->sc_wptr >= sc->sc_playbuf + BUFSIZE) 829 sc->sc_wptr = sc->sc_playbuf; 830 } 831 832 if (sc->sc_pintr && (sc->sc_avail <= PLAYBLKSIZE)) 833 callout_schedule(&sc->sc_pcallout, 0); 834 835 if (sc->sc_rintr && (sc->sc_recavail >= RECBLKSIZE)) 836 callout_schedule(&sc->sc_rcallout, 0); 837 } while (again); 838 mutex_exit(&sc->sc_intr_lock); 839 } 840 841 static void 842 ascaudio_intr_enable(void) 843 { 844 int s; 845 846 s = splhigh(); 847 if (VIA2 == VIA2OFF) 848 via2_reg(vIER) = 0x80 | V2IF_ASC; 849 else 850 via2_reg(rIER) = 0x80 | V2IF_ASC; 851 splx(s); 852 } 853 854 static void 855 ascaudio_done_output(void *arg) 856 { 857 struct ascaudio_softc *sc = arg; 858 859 mutex_enter(&sc->sc_intr_lock); 860 if (sc->sc_pintr) 861 (*sc->sc_pintr)(sc->sc_pintrarg); 862 mutex_exit(&sc->sc_intr_lock); 863 } 864 865 static void 866 ascaudio_done_input(void *arg) 867 { 868 struct ascaudio_softc *sc = arg; 869 870 mutex_enter(&sc->sc_intr_lock); 871 if (sc->sc_rintr) 872 (*sc->sc_rintr)(sc->sc_rintrarg); 873 mutex_exit(&sc->sc_intr_lock); 874 } 875 876 #ifdef _MODULE 877 878 MODULE(MODULE_CLASS_DRIVER, ascaudio, "audio"); 879 880 static const struct cfiattrdata audiobuscf_iattrdata = { 881 "audiobus", 0, { { NULL, NULL, 0 }, } 882 }; 883 static const struct cfiattrdata * const ascaudio_attrs[] = { 884 &audiobuscf_iattrdata, NULL 885 }; 886 887 CFDRIVER_DECL(ascaudio, DV_DULL, ascaud_attrs); 888 extern struct cfattach ascaudio_ca; 889 static int ascaudioloc[] = { -1, -1 }; 890 891 static struct cfdata ascaudio_cfdata[] = { 892 { 893 .cf_name = "ascaudio", 894 .cf_atname = "ascaudio", 895 .cf_unit = 0, 896 .cf_fstate = FSTATE_STAR, 897 .cf_loc = ascaudioloc, 898 .cf_flags = 0, 899 .cf_pspec = NULL, 900 }, 901 { NULL, NULL, 0, 0, NULL, 0, NULL } 902 }; 903 904 static int 905 ascaudio_modcmd(modcmd_t cmd, void *arg) 906 { 907 devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR; 908 int error; 909 910 switch (cmd) { 911 case MODULE_CMD_INIT: 912 error = config_cfdriver_attach(&ascaudio_cd); 913 if (error) { 914 return error; 915 } 916 917 error = config_cfattach_attach(ascaudio_cd.cd_name, &ascaud_ca); 918 if (error) { 919 config_cfdriver_detach(&ascaudio_cd); 920 aprint_error("%s: unable to register cfattach\n", 921 ascaudio_cd.cd_name); 922 923 return error; 924 } 925 926 error = config_cfdata_attach(ascaudio_cfdata, 1); 927 if (error) { 928 config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca); 929 config_cfdriver_detach(&ascaudio_cd); 930 aprint_error("%s: unable to register cfdata\n", 931 ascaudio_cd.cd_name); 932 933 return error; 934 } 935 936 error = devsw_attach(ascaudio_cd.cd_name, NULL, &bmajor, 937 &ascaudio_cdevsw, &cmajor); 938 if (error) { 939 error = config_cfdata_detach(ascaudio_cfdata); 940 if (error) { 941 return error; 942 } 943 config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca); 944 config_cfdriver_detach(&ascaudio_cd); 945 aprint_error("%s: unable to register devsw\n", 946 ascaudio_cd.cd_name); 947 948 return error; 949 } 950 951 (void)config_attach_pseudo(ascaudio_cfdata); 952 953 return 0; 954 case MODULE_CMD_FINI: 955 error = config_cfdata_detach(ascaudio_cfdata); 956 if (error) { 957 return error; 958 } 959 960 config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca); 961 config_cfdriver_detach(&ascaudio_cd); 962 devsw_detach(NULL, &ascaudio_cdevsw); 963 964 return 0; 965 default: 966 return ENOTTY; 967 } 968 } 969 970 #endif 971