Home | History | Annotate | Line # | Download | only in obio
      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