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