1 /* $NetBSD: ascaudio.c,v 1.4 2025/01/13 16:23:48 riastradh 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.4 2025/01/13 16:23:48 riastradh 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 0x2000 64 65 #define BUFSIZE 32768 66 #define PLAYBLKSIZE 8192 67 #define RECBLKSIZE 8192 68 69 #define ASC_VIA_CLR_INTR() via_reg(VIA2, vIFR) = V2IF_ASC 70 71 static int ascaudiomatch(device_t, cfdata_t, void *); 72 static void ascaudioattach(device_t, device_t, void *); 73 74 CFATTACH_DECL_NEW(ascaudio, sizeof(struct ascaudio_softc), 75 ascaudiomatch, ascaudioattach, NULL, NULL); 76 77 extern struct cfdriver ascaudio_cd; 78 79 dev_type_open(ascaudioopen); 80 dev_type_close(ascaudioclose); 81 dev_type_read(ascaudioread); 82 dev_type_write(ascaudiowrite); 83 dev_type_ioctl(ascaudioioctl); 84 85 const struct cdevsw ascaudio_cdevsw = { 86 .d_open = ascaudioopen, 87 .d_close = ascaudioclose, 88 .d_read = ascaudioread, 89 .d_write = ascaudiowrite, 90 .d_ioctl = ascaudioioctl, 91 .d_stop = nostop, 92 .d_tty = notty, 93 .d_poll = nopoll, 94 .d_mmap = nommap, 95 .d_kqfilter = nokqfilter, 96 .d_discard = nodiscard, 97 .d_flag = 0 98 }; 99 100 static int ascaudio_query_format(void *, struct audio_format_query *); 101 static int ascaudio_set_format(void *, int, 102 const audio_params_t *, const audio_params_t *, 103 audio_filter_reg_t *, audio_filter_reg_t *); 104 static int ascaudio_start_output(void *, void *, int, 105 void (*)(void *), void *); 106 static int ascaudio_start_input(void *, void *, int, 107 void (*)(void *), void *); 108 static int ascaudio_halt(void *); 109 static int ascaudio_set_port(void *, mixer_ctrl_t *); 110 static int ascaudio_get_port(void *, mixer_ctrl_t *); 111 static int ascaudio_getdev(void *, struct audio_device *); 112 static int ascaudio_query_devinfo(void *, mixer_devinfo_t *); 113 static int ascaudio_get_props(void *); 114 static int 115 ascaudio_round_blocksize(void *, int, int, const audio_params_t *); 116 static void ascaudio_get_locks(void *, kmutex_t **, kmutex_t **); 117 static void ascaudio_intr(void *); 118 static int ascaudio_intr_est(void *); 119 static void ascaudio_intr_enable(void); 120 static void ascaudio_done_output(void *); 121 static void ascaudio_done_input(void *); 122 123 static const struct audio_hw_if ascaudio_hw_if = { 124 .query_format = ascaudio_query_format, 125 .set_format = ascaudio_set_format, 126 .start_output = ascaudio_start_output, 127 .start_input = ascaudio_start_input, 128 .halt_output = ascaudio_halt, 129 .halt_input = ascaudio_halt, 130 .set_port = ascaudio_set_port, 131 .get_port = ascaudio_get_port, 132 .getdev = ascaudio_getdev, 133 .query_devinfo = ascaudio_query_devinfo, 134 .get_props = ascaudio_get_props, 135 .round_blocksize = ascaudio_round_blocksize, 136 .get_locks = ascaudio_get_locks, 137 }; 138 139 #define EASC_VER 0xb0 140 #define EASC_VER2 0xbb 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 277 sc->sc_audiodev = audio_attach_mi(&ascaudio_hw_if, sc, sc->sc_dev); 278 279 if (!pmf_device_register(sc->sc_dev, NULL, NULL)) 280 aprint_error_dev(sc->sc_dev, 281 "couldn't establish power handler\n"); 282 283 if (sc->sc_ver != EASC_VER && sc->sc_ver != EASC_VER2) 284 return; 285 286 if (sc->sc_options & HIGHQUALITY) 287 tmp = CDQUALITY; 288 else 289 tmp = MACDEFAULTS; 290 291 bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOCTRLA, tmp); 292 bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOCTRLB, tmp); 293 294 } 295 296 int 297 ascaudioopen(dev_t dev, int flag, int mode, struct lwp *l) 298 { 299 struct ascaudio_softc *sc; 300 301 sc = device_lookup_private(&ascaudio_cd, ASCAUDIOUNIT(dev)); 302 if (sc == NULL) 303 return (ENXIO); 304 if (sc->sc_open) 305 return (EBUSY); 306 sc->sc_open = 1; 307 308 return (0); 309 } 310 311 int 312 ascaudioclose(dev_t dev, int flag, int mode, struct lwp *l) 313 { 314 struct ascaudio_softc *sc; 315 316 sc = device_lookup_private(&ascaudio_cd, ASCAUDIOUNIT(dev)); 317 sc->sc_open = 0; 318 319 return (0); 320 } 321 322 int 323 ascaudioread(dev_t dev, struct uio *uio, int ioflag) 324 { 325 return (ENXIO); 326 } 327 328 int 329 ascaudiowrite(dev_t dev, struct uio *uio, int ioflag) 330 { 331 return (ENXIO); 332 } 333 334 int 335 ascaudioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 336 { 337 int error; 338 #ifdef notyet 339 struct ascaudio_softc *sc; 340 int unit = ASCAUDIOUNIT(dev); 341 342 sc = device_lookup_private(&ascaudio_cd, unit); 343 #endif 344 error = 0; 345 346 switch (cmd) { 347 default: 348 error = EINVAL; 349 break; 350 } 351 return (error); 352 } 353 354 #define ASCAUDIO_NFORMATS 2 355 static int 356 ascaudio_query_format(void *opaque, struct audio_format_query *ae) 357 { 358 struct ascaudio_softc *sc = opaque; 359 360 const struct audio_format asc_formats[ASCAUDIO_NFORMATS] = { 361 { .mode = AUMODE_PLAY, 362 .encoding = AUDIO_ENCODING_SLINEAR_BE, 363 .validbits = 8, 364 .precision = 8, 365 .channels = sc->sc_speakers, 366 .channel_mask = sc->sc_speakers == 2 ? AUFMT_STEREO : 367 AUFMT_MONAURAL, 368 .frequency_type = 1, 369 .frequency = { sc->sc_rate }, }, 370 { .mode = AUMODE_RECORD, 371 .encoding = AUDIO_ENCODING_SLINEAR_BE, 372 .validbits = 8, 373 .precision = 8, 374 .channels = 1, 375 .channel_mask = AUFMT_MONAURAL, 376 .frequency_type = 1, 377 .frequency = { 11025 }, } 378 }; 379 380 return audio_query_format(asc_formats, ASCAUDIO_NFORMATS, ae); 381 } 382 383 static int 384 ascaudio_set_format(void *opaque, int setmode, 385 const audio_params_t *play, const audio_params_t *rec, 386 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 387 { 388 struct ascaudio_softc *sc = opaque; 389 390 KASSERT(mutex_owned(&sc->sc_lock)); 391 392 return 0; 393 } 394 395 static int 396 ascaudio_start_output(void *opaque, void *block, int blksize, 397 void (*intr)(void *), void *intrarg) 398 { 399 struct ascaudio_softc *sc; 400 uint8_t *loc, tmp; 401 int total; 402 403 sc = (struct ascaudio_softc *)opaque; 404 if (!sc) 405 return (ENODEV); 406 407 sc->sc_pintr = intr; 408 sc->sc_pintrarg = intrarg; 409 410 loc = block; 411 if (bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCMODE) != 412 MODEFIFO) { 413 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 414 415 if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 416 /* disable half interrupts channel a */ 417 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 418 DISABLEHALFIRQ); 419 /* Disable half interrupts channel b */ 420 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 421 DISABLEHALFIRQ); 422 } 423 424 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTEST, 0); 425 bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, 426 CLEARFIFO); 427 tmp = 0; 428 bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, tmp); 429 430 if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 431 /* enable interrupts channel b */ 432 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 0); 433 } 434 } 435 436 /* set the volume. */ 437 if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 438 /* DO NOT CHANGE THESE VALUES UNLESS TESTED. 439 CAN BE VERY LOUD!!!! */ 440 tmp = sc->sc_vol >> 5; 441 KASSERT(tmp <= MACOS_HIGH_VOL); 442 bus_space_write_1(sc->sc_tag, sc->sc_handle, A_LEFT_VOL, tmp); 443 bus_space_write_1(sc->sc_tag, sc->sc_handle, B_LEFT_VOL, tmp); 444 bus_space_write_1(sc->sc_tag, sc->sc_handle, A_RIGHT_VOL, tmp); 445 bus_space_write_1(sc->sc_tag, sc->sc_handle, B_RIGHT_VOL, tmp); 446 } 447 bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, sc->sc_vol); 448 449 total = blksize; 450 if (sc->sc_putptr + blksize >= sc->sc_playbuf + BUFSIZE) 451 total = sc->sc_playbuf + BUFSIZE - sc->sc_putptr; 452 453 if (total) { 454 memcpy(sc->sc_putptr, loc, total); 455 sc->sc_putptr += total; 456 loc += total; 457 } 458 459 total = blksize - total; 460 if (total) { 461 sc->sc_putptr = sc->sc_playbuf; 462 memcpy(sc->sc_playbuf, loc, total); 463 sc->sc_putptr += total; 464 } 465 466 sc->sc_avail += blksize; 467 if (sc->sc_avail > BUFSIZE) 468 sc->sc_avail = BUFSIZE; 469 470 /* start fifo playback */ 471 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO); 472 473 return 0; 474 } 475 476 static int 477 ascaudio_start_input(void *opaque, void *block, int blksize, 478 void (*intr)(void *), void *intrarg) 479 { 480 struct ascaudio_softc *sc; 481 uint8_t tmp; 482 int total; 483 484 sc = (struct ascaudio_softc *)opaque; 485 if (!sc) 486 return (ENODEV); 487 488 uint8_t *loc; 489 loc = block; 490 491 sc->sc_rintr = intr; 492 sc->sc_rintrarg = intrarg; 493 494 if (bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCMODE) != 495 MODEFIFO) { 496 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 497 498 if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 499 /* disable half interrupts channel a */ 500 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 501 DISABLEHALFIRQ); 502 /* Disable half interrupts channel b */ 503 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 504 DISABLEHALFIRQ); 505 } 506 507 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTEST, 0); 508 509 /* start fifo playback */ 510 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO); 511 512 if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 513 /* enable interrupts channel a */ 514 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 0); 515 } 516 517 bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, 518 CLEARFIFO); 519 520 #if 0 521 bus_space_write_4(sc->sc_tag, sc->sc_handle, FIFO_A_ALT, 0); 522 bus_space_write_4(sc->sc_tag, sc->sc_handle, FIFO_B_ALT, 0); 523 #endif 524 525 bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, 526 CLEARFIFO); 527 528 tmp = RECORDA; 529 bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, tmp); 530 531 #if 0 532 int i; 533 for (i = 0; i < 0x400; i++) { 534 bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFO_A); 535 bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFO_B); 536 } 537 #endif 538 539 return 0; 540 } 541 542 /* set the volume. */ 543 if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { 544 /* DO NOT CHANGE THESE VALUES UNLESS TESTED. 545 CAN BE VERY LOUD!!!! */ 546 tmp = sc->sc_vol >> 5; 547 KASSERT(tmp <= MACOS_HIGH_VOL); 548 bus_space_write_1(sc->sc_tag, sc->sc_handle, A_LEFT_VOL, tmp); 549 bus_space_write_1(sc->sc_tag, sc->sc_handle, B_LEFT_VOL, tmp); 550 bus_space_write_1(sc->sc_tag, sc->sc_handle, A_RIGHT_VOL, tmp); 551 bus_space_write_1(sc->sc_tag, sc->sc_handle, B_RIGHT_VOL, tmp); 552 } 553 bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, sc->sc_vol); 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(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_pcallout, &sc->sc_intr_lock); 587 callout_halt(&sc->sc_rcallout, &sc->sc_intr_lock); 588 589 bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); 590 591 sc->sc_pintr = NULL; 592 sc->sc_pintrarg = NULL; 593 sc->sc_rintr = NULL; 594 sc->sc_rintrarg = NULL; 595 596 sc->sc_avail = 0; 597 sc->sc_recavail = 0; 598 599 bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, CLEARFIFO); 600 601 sc->sc_rptr = sc->sc_recbuf; 602 sc->sc_getptr = sc->sc_recbuf; 603 sc->sc_wptr = sc->sc_playbuf; 604 sc->sc_putptr = sc->sc_playbuf; 605 606 if (sc->sc_ver != EASC_VER && sc->sc_ver != EASC_VER2) 607 return 0; 608 609 /* disable half interrupts channel a */ 610 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, DISABLEHALFIRQ); 611 /* disable half interrupts channel b */ 612 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, DISABLEHALFIRQ); 613 614 return 0; 615 } 616 617 static int 618 ascaudio_getdev(void *opaque, struct audio_device *ret) 619 { 620 strlcpy(ret->name, "Apple ASC Audio", sizeof(ret->name)); 621 strlcpy(ret->version, osrelease, sizeof(ret->version)); 622 strlcpy(ret->config, "ascaudio", sizeof(ret->config)); 623 624 return 0; 625 } 626 627 static int 628 ascaudio_set_port(void *opaque, mixer_ctrl_t *mc) 629 { 630 struct ascaudio_softc *sc = opaque; 631 632 KASSERT(mutex_owned(&sc->sc_lock)); 633 634 switch (mc->dev) { 635 case ASC_OUTPUT_MASTER_VOLUME: 636 case ASC_INPUT_DAC_VOLUME: 637 if (mc->un.value.num_channels != 1) 638 return EINVAL; 639 sc->sc_vol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 640 return 0; 641 } 642 643 return ENXIO; 644 } 645 646 static int 647 ascaudio_get_port(void *opaque, mixer_ctrl_t *mc) 648 { 649 struct ascaudio_softc *sc = opaque; 650 651 KASSERT(mutex_owned(&sc->sc_lock)); 652 653 switch (mc->dev) { 654 case ASC_OUTPUT_MASTER_VOLUME: 655 case ASC_INPUT_DAC_VOLUME: 656 if (mc->un.value.num_channels != 1) 657 return EINVAL; 658 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_vol; 659 return 0; 660 } 661 662 return ENXIO; 663 } 664 665 static int 666 ascaudio_query_devinfo(void *opaque, mixer_devinfo_t *di) 667 { 668 ascaudio_softc_t *sc __diagused; 669 670 sc = (ascaudio_softc_t *)opaque; 671 672 KASSERT(mutex_owned(&sc->sc_lock)); 673 674 switch (di->index) { 675 case ASC_OUTPUT_CLASS: 676 di->mixer_class = ASC_OUTPUT_CLASS; 677 strcpy(di->label.name, AudioCoutputs); 678 di->type = AUDIO_MIXER_CLASS; 679 di->next = di->prev = AUDIO_MIXER_LAST; 680 return 0; 681 case ASC_INPUT_CLASS: 682 di->mixer_class = ASC_INPUT_CLASS; 683 strcpy(di->label.name, AudioCinputs); 684 di->type = AUDIO_MIXER_CLASS; 685 di->next = di->prev = AUDIO_MIXER_LAST; 686 return 0; 687 case ASC_OUTPUT_MASTER_VOLUME: 688 di->mixer_class = ASC_OUTPUT_CLASS; 689 strcpy(di->label.name, AudioNmaster); 690 di->type = AUDIO_MIXER_VALUE; 691 di->next = di->prev = AUDIO_MIXER_LAST; 692 di->un.v.num_channels = 1; 693 strcpy(di->un.v.units.name, AudioNvolume); 694 return 0; 695 case ASC_INPUT_DAC_VOLUME: 696 di->mixer_class = ASC_INPUT_CLASS; 697 strcpy(di->label.name, AudioNdac); 698 di->type = AUDIO_MIXER_VALUE; 699 di->next = di->prev = AUDIO_MIXER_LAST; 700 di->un.v.num_channels = 1; 701 strcpy(di->un.v.units.name, AudioNvolume); 702 return 0; 703 } 704 705 return ENXIO; 706 } 707 708 static int 709 ascaudio_get_props(void *opaque) 710 { 711 712 return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE | 713 AUDIO_PROP_INDEPENDENT; 714 } 715 716 static int 717 ascaudio_round_blocksize(void *opaque, int blksize, int mode, 718 const audio_params_t *p) 719 { 720 ascaudio_softc_t *sc __diagused; 721 722 sc = (ascaudio_softc_t *)opaque; 723 KASSERT(mutex_owned(&sc->sc_lock)); 724 725 if (mode == AUMODE_PLAY) 726 return PLAYBLKSIZE; 727 else 728 return RECBLKSIZE; 729 } 730 731 static void 732 ascaudio_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread) 733 { 734 ascaudio_softc_t *sc; 735 736 sc = (ascaudio_softc_t *)opaque; 737 738 *intr = &sc->sc_intr_lock; 739 *thread = &sc->sc_lock; 740 } 741 742 static int 743 ascaudio_intr_est(void *arg) 744 { 745 ascaudio_intr(arg); 746 747 return 0; 748 } 749 750 static void 751 ascaudio_intr(void *arg) 752 { 753 struct ascaudio_softc *sc = arg; 754 uint8_t val; 755 int loc_a, loc_b, total, count, i; 756 757 if (!sc) 758 return; 759 760 if (!sc->sc_pintr && !sc->sc_rintr) 761 return; 762 763 mutex_enter(&sc->sc_intr_lock); 764 765 count = 0x200; 766 if (sc->sc_rintr) { 767 if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) 768 bus_space_write_1(sc->sc_tag, sc->sc_handle, 769 IRQA, DISABLEHALFIRQ); 770 771 total = count; 772 if (sc->sc_rptr + count >= sc->sc_recbuf + BUFSIZE) 773 count = sc->sc_recbuf + BUFSIZE - sc->sc_rptr; 774 while (total) { 775 if (sc->sc_ver == EASC_VER2) { 776 loc_a = FIFO_A_ALT; 777 loc_b = FIFO_B_ALT; 778 } else { 779 loc_a = FIFO_A; 780 loc_b = 0; 781 } 782 for (i = 0; i < count; i++) { 783 val = bus_space_read_1(sc->sc_tag, 784 sc->sc_handle, loc_a); 785 val ^= 0x80; 786 *sc->sc_rptr++ = val; 787 if (loc_b) { 788 (void)bus_space_read_1 789 (sc->sc_tag, sc->sc_handle, loc_b); 790 } 791 } 792 if (sc->sc_rptr >= sc->sc_recbuf + BUFSIZE) 793 sc->sc_rptr = sc->sc_recbuf; 794 total -= count; 795 sc->sc_recavail += count; 796 count = total; 797 } 798 799 if (sc->sc_recavail > BUFSIZE) 800 sc->sc_recavail = BUFSIZE; 801 802 if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) 803 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 0); 804 805 goto more; 806 } 807 808 count = 0x200; 809 if (sc->sc_slowcpu) 810 count /= 2; 811 812 if (sc->sc_avail < count) { 813 if (sc->sc_avail) { 814 count = sc->sc_avail; 815 goto fill_fifo; 816 } 817 if (sc->sc_pintr) { 818 for (i = 0; i < 0x200; i++) { 819 bus_space_write_1(sc->sc_tag, 820 sc->sc_handle, FIFO_A, 0x80); 821 bus_space_write_1(sc->sc_tag, 822 sc->sc_handle, FIFO_B, 0x80); 823 } 824 } else { 825 if (sc->sc_slowcpu) 826 count *= 2; 827 for (i = 0; i < count; i++) { 828 bus_space_write_1(sc->sc_tag, 829 sc->sc_handle, FIFO_B, 0x80); 830 } 831 } 832 goto more; 833 } 834 835 fill_fifo: 836 if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) 837 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 838 DISABLEHALFIRQ); 839 840 total = count; 841 if (sc->sc_wptr + count >= sc->sc_playbuf + BUFSIZE) 842 count = sc->sc_playbuf + BUFSIZE - sc->sc_wptr; 843 844 while (total) { 845 if (sc->sc_slowcpu) { 846 for (i = 0; i < count; i++) { 847 val = *sc->sc_wptr++; 848 val ^= 0x80; 849 bus_space_write_1(sc->sc_tag, 850 sc->sc_handle, FIFO_A, val); 851 bus_space_write_1(sc->sc_tag, 852 sc->sc_handle, FIFO_B, val); 853 bus_space_write_1(sc->sc_tag, 854 sc->sc_handle, FIFO_A, val); 855 bus_space_write_1(sc->sc_tag, 856 sc->sc_handle, FIFO_B, val); 857 } 858 } else { 859 for (i = 0; i < count; i++) { 860 val = *sc->sc_wptr++; 861 val ^= 0x80; 862 bus_space_write_1(sc->sc_tag, 863 sc->sc_handle, FIFO_A, val); 864 bus_space_write_1(sc->sc_tag, 865 sc->sc_handle, FIFO_B, val); 866 } 867 } 868 if (sc->sc_wptr >= sc->sc_playbuf + BUFSIZE) 869 sc->sc_wptr = sc->sc_playbuf; 870 total -= count; 871 sc->sc_avail -= count; 872 count = total; 873 } 874 if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) 875 bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 0); 876 877 more: 878 if (sc->sc_pintr && (sc->sc_avail <= PLAYBLKSIZE)) 879 callout_schedule(&sc->sc_pcallout, 0); 880 881 if (sc->sc_rintr && (sc->sc_recavail >= RECBLKSIZE)) 882 callout_schedule(&sc->sc_rcallout, 0); 883 884 mutex_exit(&sc->sc_intr_lock); 885 } 886 887 static void 888 ascaudio_intr_enable(void) 889 { 890 int s; 891 892 s = splhigh(); 893 if (VIA2 == VIA2OFF) 894 via2_reg(vIER) = 0x80 | V2IF_ASC; 895 else 896 via2_reg(rIER) = 0x80 | V2IF_ASC; 897 splx(s); 898 } 899 900 static void 901 ascaudio_done_output(void *arg) 902 { 903 struct ascaudio_softc *sc = arg; 904 905 mutex_enter(&sc->sc_intr_lock); 906 if (sc->sc_pintr) 907 (*sc->sc_pintr)(sc->sc_pintrarg); 908 mutex_exit(&sc->sc_intr_lock); 909 } 910 911 static void 912 ascaudio_done_input(void *arg) 913 { 914 struct ascaudio_softc *sc = arg; 915 916 mutex_enter(&sc->sc_intr_lock); 917 if (sc->sc_rintr) 918 (*sc->sc_rintr)(sc->sc_rintrarg); 919 mutex_exit(&sc->sc_intr_lock); 920 } 921 922 #ifdef _MODULE 923 924 MODULE(MODULE_CLASS_DRIVER, ascaudio, "audio"); 925 926 static const struct cfiattrdata audiobuscf_iattrdata = { 927 "audiobus", 0, { { NULL, NULL, 0 }, } 928 }; 929 static const struct cfiattrdata * const ascaudio_attrs[] = { 930 &audiobuscf_iattrdata, NULL 931 }; 932 933 CFDRIVER_DECL(ascaudio, DV_DULL, ascaud_attrs); 934 extern struct cfattach ascaudio_ca; 935 static int ascaudioloc[] = { -1, -1 }; 936 937 static struct cfdata ascaudio_cfdata[] = { 938 { 939 .cf_name = "ascaudio", 940 .cf_atname = "ascaudio", 941 .cf_unit = 0, 942 .cf_fstate = FSTATE_STAR, 943 .cf_loc = ascaudioloc, 944 .cf_flags = 0, 945 .cf_pspec = NULL, 946 }, 947 { NULL, NULL, 0, 0, NULL, 0, NULL } 948 }; 949 950 static int 951 ascaudio_modcmd(modcmd_t cmd, void *arg) 952 { 953 devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR; 954 int error; 955 956 switch (cmd) { 957 case MODULE_CMD_INIT: 958 error = config_cfdriver_attach(&ascaudio_cd); 959 if (error) { 960 return error; 961 } 962 963 error = config_cfattach_attach(ascaudio_cd.cd_name, &ascaud_ca); 964 if (error) { 965 config_cfdriver_detach(&ascaudio_cd); 966 aprint_error("%s: unable to register cfattach\n", 967 ascaudio_cd.cd_name); 968 969 return error; 970 } 971 972 error = config_cfdata_attach(ascaudio_cfdata, 1); 973 if (error) { 974 config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca); 975 config_cfdriver_detach(&ascaudio_cd); 976 aprint_error("%s: unable to register cfdata\n", 977 ascaudio_cd.cd_name); 978 979 return error; 980 } 981 982 error = devsw_attach(ascaudio_cd.cd_name, NULL, &bmajor, 983 &ascaudio_cdevsw, &cmajor); 984 if (error) { 985 error = config_cfdata_detach(ascaudio_cfdata); 986 if (error) { 987 return error; 988 } 989 config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca); 990 config_cfdriver_detach(&ascaudio_cd); 991 aprint_error("%s: unable to register devsw\n", 992 ascaudio_cd.cd_name); 993 994 return error; 995 } 996 997 (void)config_attach_pseudo(ascaudio_cfdata); 998 999 return 0; 1000 case MODULE_CMD_FINI: 1001 error = config_cfdata_detach(ascaudio_cfdata); 1002 if (error) { 1003 return error; 1004 } 1005 1006 config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca); 1007 config_cfdriver_detach(&ascaudio_cd); 1008 devsw_detach(NULL, &ascaudio_cdevsw); 1009 1010 return 0; 1011 default: 1012 return ENOTTY; 1013 } 1014 } 1015 1016 #endif 1017