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 <[email protected]>
@@ -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 <[email protected]>
@@ -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