--- /dev/null 2023-02-19 01:31:20.284221455 +1100 +++ mac68k/conf/AUDIO 2023-02-19 01:21:45.310875338 +1100 @@ -0,0 +1,7 @@ +include "arch/mac68k/conf/GENERIC" +no asc0 at obio? + +ascaud* at obio? # ASC/EASC audio +audio* at audiobus? +spkr* at audio? # PC speaker (synthesized) +wsbell* at spkr? # Console beep --- /dev/null 2023-02-19 01:31:47.009162538 +1100 +++ mac68k/obio/ascaudvar.h 2023-02-04 17:52:02.927886933 +1100 @@ -0,0 +1,119 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2017 Nathanial Sloss + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_ARCH_MAC68K_OBIO_ASCAUD_ASCAUDVAR_H +#define _SYS_ARCH_MAC68K_OBIO_ASCAUD_ASCAUDVAR_H + +#define ASCAUDUNIT(d) ((d) & 0x7) + +#define FIFO_A 0 +#define FIFO_B 0x400 +#define FIFO_LEN 0x400 + +#define VERLOC 0x800 + +#define ASCMODE 0x801 +#define MODESTOP 0 +#define MODEFIFO 1 +#define MODEWAVE 2 /* not in easc */ + +#define ASCTRL 0x802 +#define UNDERRUN __BIT(7) +#define STEREO __BIT(1) +#define ANAPWM __BIT(0) + +#define FIFOPARAM 0x803 +#define CLEARFIFO __BIT(7) +#define NONCOMP __BIT(1) +#define ROMCOMP __BIT(0) + +#define FIFOSTATUS 0x804 +#define A_HALF __BIT(0) +#define A_FULL __BIT(1) +#define B_HALF __BIT(2) +#define B_FULL __BIT(3) + +#define INTVOL 0x806 /* b2-b4 Int volume. b5-b7 ext. */ + +#define ASCRATE 0x807 +#define MACFREQ 0 /* 22257 Hz */ +#define F22KHZ 2 /* 22050 Hz */ +#define F44KHZ 3 /* 44100 Hz */ + +#define APLAYREC 0x80a +#define RECORDA __BIT(0) +#define REC22KHZ __BIT(1) + +#define ASCTEST 0x80f + +#define A_WRITEPTRHI 0xf00 +#define A_WRITEPTRLO 0xf01 +#define A_READPTRHI 0xf02 +#define A_READPTRLO 0xf03 +#define B_WRITEPTRHI 0xf20 +#define B_WRITEPTRLO 0xf21 +#define B_READPTRHI 0xf22 +#define B_READPTRLO 0xf23 + +#define A_LEFT_VOL 0xf06 +#define A_RIGHT_VOL 0xf07 +#define B_LEFT_VOL 0xf26 +#define B_RIGHT_VOL 0xf27 + +#define CTRLA 0xf08 +#define CTRLB 0xf28 +#define ENB_CDXA __BIT(7) + +#define IRQA 0xf09 +#define IRQB 0xf29 +#define DISABLEIRQ __BIT(0) + +typedef struct ascaud_softc { + device_t sc_dev; + bus_space_tag_t sc_tag; + bus_space_handle_t sc_handle; + int sc_open; + + device_t sc_audiodev; + struct audio_encoding_set *sc_encodings; + void *sc_intr; + void (*sc_pintr)(void *); + void *sc_pintrarg; + void (*sc_rintr)(void *); + void *sc_rintrarg; + + kmutex_t sc_lock; + kmutex_t sc_intr_lock; + callout_t sc_pcallout; + callout_t sc_rcallout; + bool sc_started; + + uint8_t sc_vol; +} ascaud_softc_t; + +#endif /* !_SYS_ARCH_MAC68K_OBIO_ASCAUD_ASCAUDVAR_H */ --- /dev/null 2023-02-19 01:32:02.114629705 +1100 +++ mac68k/obio/ascaud.c 2023-02-14 02:27:58.599862758 +1100 @@ -0,0 +1,825 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2017 Nathanial Sloss + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Based on pad(4) and asc(4) */ + +#include +__KERNEL_RCSID(0, "$NetBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#if 1 +#define USE_INTRS +#endif + +#define MAC68K_ASCAUD_BASE 0x50f14000 +#define MAC68K_IIFX_ASCAUD_BASE 0x50f10000 +#define MAC68K_ASCAUD_LEN 0x800 + +#ifdef USE_INTRS +#define ASCAUDBLKSIZE 0x400 +#else +#define ASCAUDBLKSIZE 0x600 +#endif + +#define ASCAUDFREQ 22050 +#define ASCAUDCHAN 2 +#define ASCAUDPREC 16 +#define ASCAUDENC AUDIO_ENCODING_ULINEAR_BE + + +static int ascaudmatch(device_t, cfdata_t, void *); +static void ascaudattach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(ascaud, sizeof(struct ascaud_softc), + ascaudmatch, ascaudattach, NULL, NULL); + +extern struct cfdriver ascaud_cd; + +dev_type_open(ascaudopen); +dev_type_close(ascaudclose); +dev_type_read(ascaudread); +dev_type_write(ascaudwrite); +dev_type_ioctl(ascaudioctl); + +const struct cdevsw ascaud_cdevsw = { + .d_open = ascaudopen, + .d_close = ascaudclose, + .d_read = ascaudread, + .d_write = ascaudwrite, + .d_ioctl = ascaudioctl, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = nommap, + .d_kqfilter = nokqfilter, + .d_discard = nodiscard, + .d_flag = 0 +}; + +static int ascaud_query_format(void *, struct audio_format_query *); +static int ascaud_set_format(void *, int, + const audio_params_t *, const audio_params_t *, + audio_filter_reg_t *, audio_filter_reg_t *); +static int ascaud_start_output(void *, void *, int, + void (*)(void *), void *); +static int ascaud_start_input(void *, void *, int, + void (*)(void *), void *); +static int ascaud_halt(void *); +static int ascaud_set_port(void *, mixer_ctrl_t *); +static int ascaud_get_port(void *, mixer_ctrl_t *); +static int ascaud_getdev(void *, struct audio_device *); +static int ascaud_query_devinfo(void *, mixer_devinfo_t *); +static int ascaud_get_props(void *); +static int + ascaud_round_blocksize(void *, int, int, const audio_params_t *); +static void ascaud_get_locks(void *, kmutex_t **, kmutex_t **); +#ifdef USE_INTRS +static void ascaud_intr(void *); +static void ascaud_intr_enable(void); +#else +static void ascaud_done_output(void *); +static void ascaud_done_input(void *); +#endif + +static const struct audio_hw_if ascaud_hw_if = { + .query_format = ascaud_query_format, + .set_format = ascaud_set_format, + .start_output = ascaud_start_output, + .start_input = ascaud_start_input, + .halt_output = ascaud_halt, + .halt_input = ascaud_halt, + .set_port = ascaud_set_port, + .get_port = ascaud_get_port, + .getdev = ascaud_getdev, + .query_devinfo = ascaud_query_devinfo, + .get_props = ascaud_get_props, + .round_blocksize = ascaud_round_blocksize, + .get_locks = ascaud_get_locks, +}; + +#define EASC_VER 0xb0 +#define ASCAUD_NFORMATS 2 +static const struct audio_format asc_formats[ASCAUD_NFORMATS] = { + { NULL, AUMODE_PLAY, ASCAUDENC, ASCAUDPREC, ASCAUDPREC, + ASCAUDCHAN, AUFMT_MONAURAL, 1, { ASCAUDFREQ }, 3 }, + { NULL, AUMODE_RECORD, ASCAUDENC, ASCAUDPREC, ASCAUDPREC, + ASCAUDCHAN, AUFMT_MONAURAL, 1, { ASCAUDFREQ }, 3 }, +}; + +enum { + ASC_OUTPUT_CLASS, + ASC_INPUT_CLASS, + ASC_OUTPUT_MASTER_VOLUME, + ASC_INPUT_DAC_VOLUME, + ASC_ENUM_LAST, +}; + +static int +ascaudmatch(device_t parent, cfdata_t cf, void *aux) +{ + struct obio_attach_args *oa = (struct obio_attach_args *)aux; + bus_addr_t addr; + bus_space_handle_t bsh; + int rval = 0; + + if (oa->oa_addr != (-1)) + addr = (bus_addr_t)oa->oa_addr; + else if (current_mac_model->machineid == MACH_MACTV) + return 0; + else if (current_mac_model->machineid == MACH_MACIIFX) + addr = (bus_addr_t)MAC68K_IIFX_ASCAUD_BASE; + else + addr = (bus_addr_t)MAC68K_ASCAUD_BASE; + + if (bus_space_map(oa->oa_tag, addr, MAC68K_ASCAUD_LEN, 0, &bsh)) + return (0); + + if (mac68k_bus_space_probe(oa->oa_tag, bsh, 0, 1)) { + rval = 1; + } else + rval = 0; + + bus_space_unmap(oa->oa_tag, bsh, MAC68K_ASCAUD_LEN); + + return rval; +} + +static void +ascaudattach(device_t parent, device_t self, void *aux) +{ + struct ascaud_softc *sc = device_private(self); + struct obio_attach_args *oa = (struct obio_attach_args *)aux; + bus_addr_t addr; + uint8_t tmp; + + sc->sc_dev = self; + sc->sc_tag = oa->oa_tag; + if (oa->oa_addr != (-1)) + addr = (bus_addr_t)oa->oa_addr; + else if (current_mac_model->machineid == MACH_MACIIFX) + addr = (bus_addr_t)MAC68K_IIFX_ASCAUD_BASE; + else + addr = (bus_addr_t)MAC68K_ASCAUD_BASE; + if (bus_space_map(sc->sc_tag, addr, MAC68K_ASCAUD_LEN, 0, + &sc->sc_handle)) { + printf(": can't map memory space\n"); + return; + } + + printf(": Apple Sound Chip"); + if (oa->oa_addr != (-1)) + printf(" at %x", oa->oa_addr); + printf("\n"); + +#ifdef USE_INTRS + if (mac68k_machine.aux_interrupts) { + intr_establish((int (*)(void *))ascaud_intr, sc, IPL_VM); + } else { + via2_register_irq(VIA2_ASC, ascaud_intr, sc); + } + ascaud_intr_enable(); +#endif + + mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_HIGH); +#ifndef USE_INTRS + callout_init(&sc->sc_pcallout, CALLOUT_MPSAFE); + callout_setfunc(&sc->sc_pcallout, ascaud_done_output, sc); + callout_init(&sc->sc_rcallout, CALLOUT_MPSAFE); + callout_setfunc(&sc->sc_rcallout, ascaud_done_input, sc); +#endif + + sc->sc_vol = 255; + + sc->sc_audiodev = audio_attach_mi(&ascaud_hw_if, sc, sc->sc_dev); + + if (!pmf_device_register(sc->sc_dev, NULL, NULL)) + aprint_error_dev(sc->sc_dev, "couldn't establish power handler\n"); + + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); + sc->sc_started = false; + + /* Disable CD-XA decompression for channel a */ + tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, CTRLA); + tmp &= ~ENB_CDXA; + bus_space_write_1(sc->sc_tag, sc->sc_handle, CTRLA, tmp); + + /* Disable CD-XA decompression for channel b */ + tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, CTRLB); + tmp &= ~ENB_CDXA; + bus_space_write_1(sc->sc_tag, sc->sc_handle, CTRLB, tmp); +} + +int +ascaudopen(dev_t dev, int flag, int mode, struct lwp *l) +{ + struct ascaud_softc *sc; + + sc = device_lookup_private(&ascaud_cd, ASCAUDUNIT(dev)); + if (sc == NULL) + return (ENXIO); + if (sc->sc_open) + return (EBUSY); + sc->sc_open = 1; + + return (0); +} + +int +ascaudclose(dev_t dev, int flag, int mode, struct lwp *l) +{ + struct ascaud_softc *sc; + + sc = device_lookup_private(&ascaud_cd, ASCAUDUNIT(dev)); + sc->sc_open = 0; + + return (0); +} + +int +ascaudread(dev_t dev, struct uio *uio, int ioflag) +{ + return (ENXIO); +} + +int +ascaudwrite(dev_t dev, struct uio *uio, int ioflag) +{ + return (ENXIO); +} + +int +ascaudioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) +{ + int error; +#ifdef not_yet + struct ascaud_softc *sc; + int unit = ASCAUDUNIT(dev); + + sc = device_lookup_private(&ascaud_cd, unit); +#endif + error = 0; + + switch (cmd) { + default: + error = EINVAL; + break; + } + return (error); +} + +static int +ascaud_query_format(void *opaque, struct audio_format_query *ae) +{ + return audio_query_format(asc_formats, ASCAUD_NFORMATS, ae); +} + +static int +ascaud_set_format(void *opaque, int setmode, + const audio_params_t *play, const audio_params_t *rec, + audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) +{ + struct ascaud_softc *sc = opaque; + + KASSERT(mutex_owned(&sc->sc_lock)); + + return 0; +} + +static int +ascaud_start_output(void *opaque, void *block, int blksize, + void (*intr)(void *), void *intrarg) +{ + struct ascaud_softc *sc; + uint8_t tmp; + int i; + + sc = (struct ascaud_softc *)opaque; + if (!sc) + return (ENODEV); + + sc->sc_pintr = intr; + sc->sc_pintrarg = intrarg; + + + uint8_t *loc; + loc = block; + if (bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCMODE) != + MODEFIFO) { + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); + + /* disable interrupts channel a */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, DISABLEIRQ); + /* Disable interrupts channel b */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, DISABLEIRQ); + + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTEST, 0); + bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, 0); + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCRATE, F22KHZ); + tmp = sc->sc_vol >> 5; + bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, tmp << 5); + bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, + CLEARFIFO); + + /* select stereo/analog mode */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTRL, STEREO); + + /* start fifo playback */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO); + } + + /* set the volume */ + tmp = sc->sc_vol >> 5; + bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, tmp << 5); + /* set volume for channel b left and right speakers */ + 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); + + for (i = 0; i < ASCAUDBLKSIZE; i += 4) { + tmp = *loc++; + tmp ^= 0x80; + bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFO_A, tmp); + bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFO_B, tmp); + loc++; + + tmp = *loc++; + tmp ^= 0x80; + bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFO_A, tmp); + bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFO_B, tmp); + loc++; + } + + +#ifdef USE_INTRS + if (!sc->sc_started) { + sc->sc_started = true; + /* enable interrupts channel a */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 0); + /* enable interrupts channel b */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 0); + } +#endif + +#ifndef USE_INTRS + int ms = blksize * 1000 / ASCAUDCHAN / (ASCAUDPREC / NBBY) / ASCAUDFREQ; + callout_schedule(&sc->sc_pcallout, mstohz(ms)); +#endif + + return 0; +} + +static int +ascaud_start_input(void *opaque, void *block, int blksize, + void (*intr)(void *), void *intrarg) +{ + struct ascaud_softc *sc; + uint8_t tmp; + int i; + + sc = (struct ascaud_softc *)opaque; + if (!sc) + return (ENODEV); + + KASSERT(mutex_owned(&sc->sc_lock)); + + sc->sc_rintr = intr; + sc->sc_rintrarg = intrarg; + + + uint8_t *loc; + loc = block; + + if (bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCMODE) != + MODEFIFO) { + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); + + /* disable interrupts channel a */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, DISABLEIRQ); + /* Disable interrupts channel b */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, DISABLEIRQ); + + + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTEST, 0); + tmp = RECORDA | REC22KHZ; + bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, tmp); + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCRATE, F22KHZ); + tmp = sc->sc_vol >> 5; + bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, tmp << 5); + bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, + CLEARFIFO); + + /* select stereo/analog mode */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTRL, STEREO); + + /* start fifo playback */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO); + } + + /* set the volume */ + tmp = sc->sc_vol >> 5; + bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, tmp << 5); + /* set volume for channel b left and right speakers */ + 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); + + for (i = 0; i < ASCAUDBLKSIZE / 4; i++) { + tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFO_A); + *loc++ = tmp; + *loc++ = 0; + *loc++ = tmp; + *loc++ = 0; + bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFO_B, 0); + bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFO_B, 0); + } + +#ifdef USE_INTRS + if (!sc->sc_started) { + sc->sc_started = true; + /* enable interrupts channel a */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 0); + /* enable interrupts channel b */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 0); + } +#endif + +#ifndef USE_INTRS + callout_schedule(&sc->sc_rcallout, 1); +#endif + + return 0; +} + +static int +ascaud_halt(void *opaque) +{ + ascaud_softc_t *sc; + + sc = (ascaud_softc_t *)opaque; + + KASSERT(mutex_owned(&sc->sc_lock)); + +#ifndef USE_INTRS + callout_halt(&sc->sc_pcallout, &sc->sc_intr_lock); + callout_halt(&sc->sc_rcallout, &sc->sc_intr_lock); +#endif + + sc->sc_pintr = NULL; + sc->sc_pintrarg = NULL; + sc->sc_rintr = NULL; + sc->sc_rintrarg = NULL; + sc->sc_started = false; + +#ifdef USE_INTRS + /* disable interrupts channel a */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, DISABLEIRQ); + /* disable interrupts channel b */ + bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, DISABLEIRQ); +#endif + bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP); + bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, CLEARFIFO); + + return 0; +} + +#ifndef USE_INTRS +static void +ascaud_done_output(void *arg) +{ + struct ascaud_softc *sc = arg; + + mutex_enter(&sc->sc_intr_lock); + if (sc->sc_pintr) + (*sc->sc_pintr)(sc->sc_pintrarg); + mutex_exit(&sc->sc_intr_lock); +} + +static void +ascaud_done_input(void *arg) +{ + struct ascaud_softc *sc = arg; + + mutex_enter(&sc->sc_intr_lock); + if (sc->sc_rintr) + (*sc->sc_rintr)(sc->sc_rintrarg); + mutex_exit(&sc->sc_intr_lock); +} +#endif + +static int +ascaud_getdev(void *opaque, struct audio_device *ret) +{ + strlcpy(ret->name, "Apple ASCAUD Audio", sizeof(ret->name)); + strlcpy(ret->version, osrelease, sizeof(ret->version)); + strlcpy(ret->config, "ascaud", sizeof(ret->config)); + + return 0; +} + +static int +ascaud_set_port(void *opaque, mixer_ctrl_t *mc) +{ + struct ascaud_softc *sc = opaque; + + KASSERT(mutex_owned(&sc->sc_lock)); + + switch (mc->dev) { + case ASC_OUTPUT_MASTER_VOLUME: + case ASC_INPUT_DAC_VOLUME: + if (mc->un.value.num_channels != 1) + return EINVAL; + sc->sc_vol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; + return 0; + } + + return ENXIO; +} + +static int +ascaud_get_port(void *opaque, mixer_ctrl_t *mc) +{ + struct ascaud_softc *sc = opaque; + + KASSERT(mutex_owned(&sc->sc_lock)); + + switch (mc->dev) { + case ASC_OUTPUT_MASTER_VOLUME: + case ASC_INPUT_DAC_VOLUME: + if (mc->un.value.num_channels != 1) + return EINVAL; + mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_vol; + return 0; + } + + return ENXIO; +} + +static int +ascaud_query_devinfo(void *opaque, mixer_devinfo_t *di) +{ + ascaud_softc_t *sc __diagused; + + sc = (ascaud_softc_t *)opaque; + + KASSERT(mutex_owned(&sc->sc_lock)); + + switch (di->index) { + case ASC_OUTPUT_CLASS: + di->mixer_class = ASC_OUTPUT_CLASS; + strcpy(di->label.name, AudioCoutputs); + di->type = AUDIO_MIXER_CLASS; + di->next = di->prev = AUDIO_MIXER_LAST; + return 0; + case ASC_INPUT_CLASS: + di->mixer_class = ASC_INPUT_CLASS; + strcpy(di->label.name, AudioCinputs); + di->type = AUDIO_MIXER_CLASS; + di->next = di->prev = AUDIO_MIXER_LAST; + return 0; + case ASC_OUTPUT_MASTER_VOLUME: + di->mixer_class = ASC_OUTPUT_CLASS; + strcpy(di->label.name, AudioNmaster); + di->type = AUDIO_MIXER_VALUE; + di->next = di->prev = AUDIO_MIXER_LAST; + di->un.v.num_channels = 1; + strcpy(di->un.v.units.name, AudioNvolume); + return 0; + case ASC_INPUT_DAC_VOLUME: + di->mixer_class = ASC_INPUT_CLASS; + strcpy(di->label.name, AudioNdac); + di->type = AUDIO_MIXER_VALUE; + di->next = di->prev = AUDIO_MIXER_LAST; + di->un.v.num_channels = 1; + strcpy(di->un.v.units.name, AudioNvolume); + return 0; + } + + return ENXIO; +} + +static int +ascaud_get_props(void *opaque) +{ + ascaud_softc_t *sc __diagused; + + sc = (ascaud_softc_t *)opaque; + + KASSERT(mutex_owned(&sc->sc_lock)); + + return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE; +} + +static int +ascaud_round_blocksize(void *opaque, int blksize, int mode, + const audio_params_t *p) +{ + ascaud_softc_t *sc __diagused; + + sc = (ascaud_softc_t *)opaque; + KASSERT(mutex_owned(&sc->sc_lock)); + + return ASCAUDBLKSIZE; +} + +static void +ascaud_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread) +{ + ascaud_softc_t *sc; + + sc = (ascaud_softc_t *)opaque; + + *intr = &sc->sc_intr_lock; + *thread = &sc->sc_lock; +} + +#ifdef USE_INTRS +static void +ascaud_intr(void *arg) +{ + struct ascaud_softc *sc = arg; + uint8_t tmp; + + if (!sc) + return; + + if (!sc->sc_pintr && !sc->sc_rintr) + return; + tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFOSTATUS); + while (sc->sc_pintr && tmp) { + mutex_enter(&sc->sc_intr_lock); + (*sc->sc_pintr)(sc->sc_pintrarg); + mutex_exit(&sc->sc_intr_lock); + tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFOSTATUS); + } + + tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFOSTATUS); + while (sc->sc_rintr && (tmp & B_HALF)) { + mutex_enter(&sc->sc_intr_lock); + (*sc->sc_rintr)(sc->sc_rintrarg); + mutex_exit(&sc->sc_intr_lock); + tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFOSTATUS); + } +} + +static void +ascaud_intr_enable(void) +{ + int s; + + s = splhigh(); + if (VIA2 == VIA2OFF) + via2_reg(vIER) = 0x80 | V2IF_ASC; + else + via2_reg(rIER) = 0x80 | V2IF_ASC; + splx(s); +} +#endif + +#ifdef _MODULE + +MODULE(MODULE_CLASS_DRIVER, ascaud, "audio"); + +static const struct cfiattrdata audiobuscf_iattrdata = { + "audiobus", 0, { { NULL, NULL, 0 }, } +}; +static const struct cfiattrdata * const ascaud_attrs[] = { + &audiobuscf_iattrdata, NULL +}; + +CFDRIVER_DECL(ascaud, DV_DULL, ascaud_attrs); +extern struct cfattach ascaud_ca; +static int ascaudloc[] = { -1, -1 }; + +static struct cfdata ascaud_cfdata[] = { + { + .cf_name = "ascaud", + .cf_atname = "ascaud", + .cf_unit = 0, + .cf_fstate = FSTATE_STAR, + .cf_loc = ascaudloc, + .cf_flags = 0, + .cf_pspec = NULL, + }, + { NULL, NULL, 0, 0, NULL, 0, NULL } +}; + +static int +ascaud_modcmd(modcmd_t cmd, void *arg) +{ + devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR; + int error; + + switch (cmd) { + case MODULE_CMD_INIT: + error = config_cfdriver_attach(&ascaud_cd); + if (error) { + return error; + } + + error = config_cfattach_attach(ascaud_cd.cd_name, &ascaud_ca); + if (error) { + config_cfdriver_detach(&ascaud_cd); + aprint_error("%s: unable to register cfattach\n", + ascaud_cd.cd_name); + + return error; + } + + error = config_cfdata_attach(ascaud_cfdata, 1); + if (error) { + config_cfattach_detach(ascaud_cd.cd_name, &ascaud_ca); + config_cfdriver_detach(&ascaud_cd); + aprint_error("%s: unable to register cfdata\n", + ascaud_cd.cd_name); + + return error; + } + + error = devsw_attach(ascaud_cd.cd_name, NULL, &bmajor, + &ascaud_cdevsw, &cmajor); + if (error) { + error = config_cfdata_detach(ascaud_cfdata); + if (error) { + return error; + } + config_cfattach_detach(ascaud_cd.cd_name, &ascaud_ca); + config_cfdriver_detach(&ascaud_cd); + aprint_error("%s: unable to register devsw\n", + ascaud_cd.cd_name); + + return error; + } + + (void)config_attach_pseudo(ascaud_cfdata); + + return 0; + case MODULE_CMD_FINI: + error = config_cfdata_detach(ascaud_cfdata); + if (error) { + return error; + } + + config_cfattach_detach(ascaud_cd.cd_name, &ascaud_ca); + config_cfdriver_detach(&ascaud_cd); + devsw_detach(NULL, &ascaud_cdevsw); + + return 0; + default: + return ENOTTY; + } +} + +#endif diff -r dd49f08c0f10 sys/arch/mac68k/conf/files.mac68k --- mac68k/conf/files.mac68k Sun Oct 30 21:30:34 2022 +1100 +++ mac68k/conf/files.mac68k Sun Feb 19 01:34:37 2023 +1100 @@ -47,6 +47,11 @@ attach asc at obio file arch/mac68k/obio/asc.c asc needs-flag +# ASC audio +device ascaud: audiobus, auconv, mulaw, aurateconv, auvolconv +attach ascaud at obio +file arch/mac68k/obio/ascaud.c ascaud needs-flag + device nubus { } attach nubus at mainbus file arch/mac68k/nubus/nubus.c nubus