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