Module Name: src Committed By: nat Date: Sun Jan 12 09:28:26 UTC 2025
Modified Files: src/sys/arch/mac68k/obio: ascaudio.c ascreg.h Log Message: Overhaul of ascaudio(4). Simpler interrrupt function. Volume control works properly on different variants of EASCs. Alternate FIFOs identified for some EASCs. Recording still does not work as yet as microphone audio needs to be routed to the sound chip. However attempting to record should no longer cause a lockup or panic. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/sys/arch/mac68k/obio/ascaudio.c cvs rdiff -u -r1.1 -r1.2 src/sys/arch/mac68k/obio/ascreg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/mac68k/obio/ascaudio.c diff -u src/sys/arch/mac68k/obio/ascaudio.c:1.2 src/sys/arch/mac68k/obio/ascaudio.c:1.3 --- src/sys/arch/mac68k/obio/ascaudio.c:1.2 Sun Oct 13 12:34:56 2024 +++ src/sys/arch/mac68k/obio/ascaudio.c Sun Jan 12 09:28:26 2025 @@ -1,4 +1,4 @@ -/* $NetBSD: ascaudio.c,v 1.2 2024/10/13 12:34:56 nat Exp $ */ +/* $NetBSD: ascaudio.c,v 1.3 2025/01/12 09:28:26 nat Exp $ */ /*- * Copyright (c) 2017, 2023 Nathanial Sloss <nathanialsl...@yahoo.com.au> @@ -29,7 +29,7 @@ /* Based on pad(4) and asc(4) */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ascaudio.c,v 1.2 2024/10/13 12:34:56 nat Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ascaudio.c,v 1.3 2025/01/12 09:28:26 nat Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -60,12 +60,14 @@ __KERNEL_RCSID(0, "$NetBSD: ascaudio.c,v #define MAC68K_ASCAUDIO_BASE 0x50f14000 #define MAC68K_IIFX_ASCAUDIO_BASE 0x50f10000 -#define MAC68K_ASCAUDIO_LEN 0x1000 +#define MAC68K_ASCAUDIO_LEN 0x2000 #define BUFSIZE 32768 #define PLAYBLKSIZE 8192 #define RECBLKSIZE 8192 +#define ASC_VIA_CLR_INTR() via_reg(VIA2, vIFR) = V2IF_ASC + static int ascaudiomatch(device_t, cfdata_t, void *); static void ascaudioattach(device_t, device_t, void *); @@ -245,13 +247,11 @@ ascaudioattach(device_t parent, device_t sc->sc_rate /= 2; } - if (sc->sc_ver == EASC_VER2) - sc->sc_ver = EASC_VER; - - if (sc->sc_ver != EASC_VER) - printf(": Apple Sound Chip"); - else + if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) printf(": Enhanced Apple Sound Chip"); + else + printf(": Apple Sound Chip"); + if (oa->oa_addr != (-1)) printf(" at %x", oa->oa_addr); printf("\n"); @@ -266,13 +266,13 @@ ascaudioattach(device_t parent, device_t ascaudio_intr_enable(); mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); - mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_HIGH); + mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); callout_init(&sc->sc_pcallout, CALLOUT_MPSAFE); callout_setfunc(&sc->sc_pcallout, ascaudio_done_output, sc); callout_init(&sc->sc_rcallout, CALLOUT_MPSAFE); callout_setfunc(&sc->sc_rcallout, ascaudio_done_input, sc); - sc->sc_vol = 255; + sc->sc_vol = 180; sc->sc_audiodev = audio_attach_mi(&ascaudio_hw_if, sc, sc->sc_dev); @@ -281,7 +281,7 @@ ascaudioattach(device_t parent, device_t "couldn't establish power handler\n"); - if (sc->sc_ver != EASC_VER) + if (sc->sc_ver != EASC_VER && sc->sc_ver != EASC_VER2) return; if (sc->sc_options & HIGHQUALITY) @@ -360,7 +360,7 @@ ascaudio_query_format(void *opaque, stru const struct audio_format asc_formats[ASCAUDIO_NFORMATS] = { { .mode = AUMODE_PLAY, - .encoding = AUDIO_ENCODING_SLINEAR_LE, + .encoding = AUDIO_ENCODING_SLINEAR_BE, .validbits = 8, .precision = 8, .channels = sc->sc_speakers, @@ -369,7 +369,7 @@ ascaudio_query_format(void *opaque, stru .frequency_type = 1, .frequency = { sc->sc_rate }, }, { .mode = AUMODE_RECORD, - .encoding = AUDIO_ENCODING_SLINEAR_LE, + .encoding = AUDIO_ENCODING_SLINEAR_BE, .validbits = 8, .precision = 8, .channels = 1, @@ -414,7 +414,7 @@ ascaudio_start_output(void *opaque, void MODEFIFO) { bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); - if (sc->sc_ver == EASC_VER) { + if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { /* disable half interrupts channel a */ bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, DISABLEHALFIRQ); @@ -429,30 +429,34 @@ ascaudio_start_output(void *opaque, void tmp = 0; bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, tmp); - if (sc->sc_ver == EASC_VER) { + if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { /* enable interrupts channel b */ bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 0); } } - /* set the volume */ - tmp = sc->sc_vol >> 5; - /* set volume for channel b left and right speakers */ - if (sc->sc_ver == EASC_VER) { + /* set the volume. */ + if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { + /* DO NOT CHANGE THESE VALUES UNLESS TESTED. + CAN BE VERY LOUD!!!! */ + tmp = sc->sc_vol >> 5; + KASSERT(tmp <= MACOS_HIGH_VOL); bus_space_write_1(sc->sc_tag, sc->sc_handle, A_LEFT_VOL, tmp); bus_space_write_1(sc->sc_tag, sc->sc_handle, B_LEFT_VOL, tmp); bus_space_write_1(sc->sc_tag, sc->sc_handle, A_RIGHT_VOL, tmp); bus_space_write_1(sc->sc_tag, sc->sc_handle, B_RIGHT_VOL, tmp); - } else - bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, tmp << 5); + } + bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, sc->sc_vol); total = blksize; - if (sc->sc_putptr + blksize > sc->sc_playbuf + BUFSIZE) + if (sc->sc_putptr + blksize >= sc->sc_playbuf + BUFSIZE) total = sc->sc_playbuf + BUFSIZE - sc->sc_putptr; - memcpy(sc->sc_putptr, loc, total); - sc->sc_putptr += total; - loc += total; + if (total) { + memcpy(sc->sc_putptr, loc, total); + sc->sc_putptr += total; + loc += total; + } total = blksize - total; if (total) { @@ -494,7 +498,7 @@ ascaudio_start_input(void *opaque, void MODEFIFO) { bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); - if (sc->sc_ver == EASC_VER) { + if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { /* disable half interrupts channel a */ bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, DISABLEHALFIRQ); @@ -504,47 +508,66 @@ ascaudio_start_input(void *opaque, void } bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTEST, 0); - bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, - CLEARFIFO); - tmp = RECORDA; - bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, tmp); - bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, 0xa0); - if (sc->sc_ver == EASC_VER) { + /* start fifo playback */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO); + + if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { /* enable interrupts channel a */ bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 0); } - /* start fifo playback */ - bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO); + bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, + CLEARFIFO); + +#if 0 + bus_space_write_4(sc->sc_tag, sc->sc_handle, FIFO_A_ALT, 0); + bus_space_write_4(sc->sc_tag, sc->sc_handle, FIFO_B_ALT, 0); +#endif + bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, + CLEARFIFO); + + tmp = RECORDA; + bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, tmp); + +#if 0 + int i; + for (i = 0; i < 0x400; i++) { + bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFO_A); + bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFO_B); + } +#endif + return 0; } - /* set the volume */ - tmp = sc->sc_vol >> 5; - /* set volume for channel b left and right speakers */ - if (sc->sc_ver == EASC_VER) { + /* set the volume. */ + if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) { + /* DO NOT CHANGE THESE VALUES UNLESS TESTED. + CAN BE VERY LOUD!!!! */ + tmp = sc->sc_vol >> 5; + KASSERT(tmp <= MACOS_HIGH_VOL); bus_space_write_1(sc->sc_tag, sc->sc_handle, A_LEFT_VOL, tmp); bus_space_write_1(sc->sc_tag, sc->sc_handle, B_LEFT_VOL, tmp); bus_space_write_1(sc->sc_tag, sc->sc_handle, A_RIGHT_VOL, tmp); bus_space_write_1(sc->sc_tag, sc->sc_handle, B_RIGHT_VOL, tmp); - } else - bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, tmp << 5); + } + bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, sc->sc_vol); total = blksize; - if (sc->sc_getptr + blksize > sc->sc_recbuf + BUFSIZE) + if (sc->sc_getptr + blksize >= sc->sc_recbuf + BUFSIZE) total = sc->sc_recbuf + BUFSIZE - sc->sc_getptr; - memcpy(loc, sc->sc_getptr, total); - sc->sc_getptr += total; - loc += total; - - if (sc->sc_getptr >= sc->sc_recbuf + BUFSIZE) - sc->sc_getptr = sc->sc_recbuf; + if (total) { + memcpy(loc, sc->sc_getptr, total); + sc->sc_getptr += total; + loc += total; + } total = blksize - total; if (total) { + sc->sc_getptr = sc->sc_recbuf; memcpy(loc, sc->sc_getptr, total); sc->sc_getptr += total; } @@ -563,6 +586,10 @@ ascaudio_halt(void *opaque) KASSERT(mutex_owned(&sc->sc_lock)); + callout_halt(&sc->sc_pcallout, &sc->sc_intr_lock); + callout_halt(&sc->sc_rcallout, &sc->sc_intr_lock); + + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); sc->sc_pintr = NULL; sc->sc_pintrarg = NULL; @@ -572,10 +599,6 @@ ascaudio_halt(void *opaque) sc->sc_avail = 0; sc->sc_recavail = 0; - callout_halt(&sc->sc_pcallout, &sc->sc_lock); - callout_halt(&sc->sc_rcallout, &sc->sc_lock); - - bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, CLEARFIFO); @@ -584,7 +607,7 @@ ascaudio_halt(void *opaque) sc->sc_wptr = sc->sc_playbuf; sc->sc_putptr = sc->sc_playbuf; - if (sc->sc_ver != EASC_VER) + if (sc->sc_ver != EASC_VER && sc->sc_ver != EASC_VER2) return 0; /* disable half interrupts channel a */ @@ -732,9 +755,8 @@ static void ascaudio_intr(void *arg) { struct ascaudio_softc *sc = arg; - uint8_t status, val; - bool again; - int total, count, i; + uint8_t val; + int loc_a, loc_b, total, count, i; if (!sc) return; @@ -743,102 +765,126 @@ ascaudio_intr(void *arg) return; mutex_enter(&sc->sc_intr_lock); - do { - status = bus_space_read_1(sc->sc_tag, sc->sc_handle, - FIFOSTATUS); - again = false; - count = 0; - if ((status & A_HALF) == 0) - count = 0x200; - if (count && ((status & A_FULL) == 0)) - count = 0x400; - - if (sc->sc_rintr && count) { - total = count; - if (sc->sc_rptr + count > sc->sc_recbuf + BUFSIZE) - count = sc->sc_recbuf + BUFSIZE - sc->sc_rptr; - - while (total) { - for (i = 0; i < count; i++) { - val = bus_space_read_1(sc->sc_tag, - sc->sc_handle, FIFO_A); - val ^= 0x80; - *sc->sc_rptr++ = val; + + count = 0x200; + if (sc->sc_rintr) { + if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) + bus_space_write_1(sc->sc_tag, sc->sc_handle, + IRQA, DISABLEHALFIRQ); + + total = count; + if (sc->sc_rptr + count >= sc->sc_recbuf + BUFSIZE) + count = sc->sc_recbuf + BUFSIZE - sc->sc_rptr; + while (total) { + if (sc->sc_ver == EASC_VER2) { + loc_a = FIFO_A_ALT; + loc_b = FIFO_B_ALT; + } else { + loc_a = FIFO_A; + loc_b = 0; + } + for (i = 0; i < count; i++) { + val = bus_space_read_1(sc->sc_tag, + sc->sc_handle, loc_a); + val ^= 0x80; + *sc->sc_rptr++ = val; + if (loc_b) { + (void)bus_space_read_1 + (sc->sc_tag, sc->sc_handle, loc_b); } - if (sc->sc_rptr >= sc->sc_recbuf + BUFSIZE) - sc->sc_rptr = sc->sc_recbuf; - total -= count; - sc->sc_recavail += count; } - - if (sc->sc_recavail > BUFSIZE) - sc->sc_recavail = BUFSIZE; + if (sc->sc_rptr >= sc->sc_recbuf + BUFSIZE) + sc->sc_rptr = sc->sc_recbuf; + total -= count; + sc->sc_recavail += count; + count = total; } - count = 0; - if (status & B_FULL) - count = 0x400; - else if (status & B_HALF) - count = 0x200; + if (sc->sc_recavail > BUFSIZE) + sc->sc_recavail = BUFSIZE; - if (sc->sc_slowcpu) - count /= 2; + if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 0); - if (sc->sc_pintr && count) { - if (sc->sc_avail < count) { - if (sc->sc_pintr) { - for (i = 0; i < 0x200; i++) { - bus_space_write_1(sc->sc_tag, - sc->sc_handle, FIFO_A, - 0x80); - bus_space_write_1(sc->sc_tag, - sc->sc_handle, FIFO_B, - 0x80); - } - } else { - for (i = 0; i < 0x200; i++) { - bus_space_write_1(sc->sc_tag, - sc->sc_handle, FIFO_B, - 0x80); - } - } - } else if (sc->sc_slowcpu) { - for (i = 0; i < count; i++) { - val = *sc->sc_wptr++; - val ^= 0x80; - bus_space_write_1(sc->sc_tag, - sc->sc_handle, FIFO_A, val); - bus_space_write_1(sc->sc_tag, - sc->sc_handle, FIFO_B, val); - bus_space_write_1(sc->sc_tag, - sc->sc_handle, FIFO_A, val); - bus_space_write_1(sc->sc_tag, - sc->sc_handle, FIFO_B, val); - } - sc->sc_avail -= count; - again = true; - } else { - for (i = 0; i < count; i++) { - val = *sc->sc_wptr++; - val ^= 0x80; - bus_space_write_1(sc->sc_tag, - sc->sc_handle, FIFO_A, val); - bus_space_write_1(sc->sc_tag, - sc->sc_handle, FIFO_B, val); - } - sc->sc_avail -= count; - again = true; + goto more; + } + + count = 0x200; + if (sc->sc_slowcpu) + count /= 2; + + if (sc->sc_avail < count) { + if (sc->sc_avail) { + count = sc->sc_avail; + goto fill_fifo; + } + if (sc->sc_pintr) { + for (i = 0; i < 0x200; i++) { + bus_space_write_1(sc->sc_tag, + sc->sc_handle, FIFO_A, 0x80); + bus_space_write_1(sc->sc_tag, + sc->sc_handle, FIFO_B, 0x80); + } + } else { + if (sc->sc_slowcpu) + count *= 2; + for (i = 0; i < count; i++) { + bus_space_write_1(sc->sc_tag, + sc->sc_handle, FIFO_B, 0x80); + } + } + goto more; + } + +fill_fifo: + if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, + DISABLEHALFIRQ); + + total = count; + if (sc->sc_wptr + count >= sc->sc_playbuf + BUFSIZE) + count = sc->sc_playbuf + BUFSIZE - sc->sc_wptr; + + while (total) { + if (sc->sc_slowcpu) { + for (i = 0; i < count; i++) { + val = *sc->sc_wptr++; + val ^= 0x80; + bus_space_write_1(sc->sc_tag, + sc->sc_handle, FIFO_A, val); + bus_space_write_1(sc->sc_tag, + sc->sc_handle, FIFO_B, val); + bus_space_write_1(sc->sc_tag, + sc->sc_handle, FIFO_A, val); + bus_space_write_1(sc->sc_tag, + sc->sc_handle, FIFO_B, val); + } + } else { + for (i = 0; i < count; i++) { + val = *sc->sc_wptr++; + val ^= 0x80; + bus_space_write_1(sc->sc_tag, + sc->sc_handle, FIFO_A, val); + bus_space_write_1(sc->sc_tag, + sc->sc_handle, FIFO_B, val); } - if (sc->sc_wptr >= sc->sc_playbuf + BUFSIZE) - sc->sc_wptr = sc->sc_playbuf; } + if (sc->sc_wptr >= sc->sc_playbuf + BUFSIZE) + sc->sc_wptr = sc->sc_playbuf; + total -= count; + sc->sc_avail -= count; + count = total; + } + if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 0); + +more: + if (sc->sc_pintr && (sc->sc_avail <= PLAYBLKSIZE)) + callout_schedule(&sc->sc_pcallout, 0); - if (sc->sc_pintr && (sc->sc_avail <= PLAYBLKSIZE)) - callout_schedule(&sc->sc_pcallout, 0); + if (sc->sc_rintr && (sc->sc_recavail >= RECBLKSIZE)) + callout_schedule(&sc->sc_rcallout, 0); - if (sc->sc_rintr && (sc->sc_recavail >= RECBLKSIZE)) - callout_schedule(&sc->sc_rcallout, 0); - } while (again); mutex_exit(&sc->sc_intr_lock); } Index: src/sys/arch/mac68k/obio/ascreg.h diff -u src/sys/arch/mac68k/obio/ascreg.h:1.1 src/sys/arch/mac68k/obio/ascreg.h:1.2 --- src/sys/arch/mac68k/obio/ascreg.h:1.1 Wed Mar 13 07:55:28 2024 +++ src/sys/arch/mac68k/obio/ascreg.h Sun Jan 12 09:28:26 2025 @@ -1,4 +1,4 @@ -/* $NetBSD: ascreg.h,v 1.1 2024/03/13 07:55:28 nat Exp $ */ +/* $NetBSD: ascreg.h,v 1.2 2025/01/12 09:28:26 nat Exp $ */ /*- * Copyright (c) 2017, 2023 Nathanial Sloss <nathanialsl...@yahoo.com.au> @@ -33,6 +33,8 @@ #define FIFO_A 0 #define FIFO_B 0x400 +#define FIFO_A_ALT 0x1000 +#define FIFO_B_ALT 0x1800 #define FIFO_LEN 0x400 #define VERLOC 0x800 @@ -80,6 +82,8 @@ #define B_READPTRHI 0xf22 #define B_READPTRLO 0xf23 +#define MACOS_HIGH_VOL 0x36 /* Should NOT exceed this value */ + #define A_LEFT_VOL 0xf06 #define A_RIGHT_VOL 0xf07 #define B_LEFT_VOL 0xf26