Home | History | Annotate | Line # | Download | only in obio
ascaudio.c revision 1.6
      1 /* $NetBSD: ascaudio.c,v 1.6 2025/05/12 00:31:28 nat Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2017, 2023 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.6 2025/05/12 00:31:28 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/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 enum {
    140 	ASC_OUTPUT_CLASS,
    141 	ASC_INPUT_CLASS,
    142 	ASC_OUTPUT_MASTER_VOLUME,
    143 	ASC_INPUT_DAC_VOLUME,
    144 	ASC_ENUM_LAST,
    145 };
    146 
    147 static int
    148 ascaudiomatch(device_t parent, cfdata_t cf, void *aux)
    149 {
    150 	struct obio_attach_args *oa = (struct obio_attach_args *)aux;
    151 	bus_addr_t addr;
    152 	bus_space_handle_t bsh;
    153 	int rval = 0;
    154 
    155 	if (oa->oa_addr != (-1))
    156 		addr = (bus_addr_t)oa->oa_addr;
    157 	else if (current_mac_model->machineid == MACH_MACTV)
    158 		return 0;
    159 	else if (current_mac_model->machineid == MACH_MACIIFX)
    160 		addr = (bus_addr_t)MAC68K_IIFX_ASCAUDIO_BASE;
    161 	else
    162 		addr = (bus_addr_t)MAC68K_ASCAUDIO_BASE;
    163 
    164 	if (bus_space_map(oa->oa_tag, addr, MAC68K_ASCAUDIO_LEN, 0, &bsh))
    165 		return (0);
    166 
    167 	if (mac68k_bus_space_probe(oa->oa_tag, bsh, 0, 1)) {
    168 		rval = 1;
    169 	} else
    170 		rval = 0;
    171 
    172 	bus_space_unmap(oa->oa_tag, bsh, MAC68K_ASCAUDIO_LEN);
    173 
    174 	return rval;
    175 }
    176 
    177 static void
    178 ascaudioattach(device_t parent, device_t self, void *aux)
    179 {
    180 	struct ascaudio_softc *sc = device_private(self);
    181 	struct obio_attach_args *oa = (struct obio_attach_args *)aux;
    182 	bus_addr_t addr;
    183 	uint8_t tmp;
    184 
    185 	sc->sc_dev = self;
    186 	sc->sc_tag = oa->oa_tag;
    187 
    188 	if (oa->oa_addr != (-1))
    189 		addr = (bus_addr_t)oa->oa_addr;
    190 	else if (current_mac_model->machineid == MACH_MACIIFX)
    191 		addr = (bus_addr_t)MAC68K_IIFX_ASCAUDIO_BASE;
    192 	else
    193 		addr = (bus_addr_t)MAC68K_ASCAUDIO_BASE;
    194 	if (bus_space_map(sc->sc_tag, addr, MAC68K_ASCAUDIO_LEN, 0,
    195 	    &sc->sc_handle)) {
    196 		printf(": can't map memory space\n");
    197 		return;
    198 	}
    199 
    200 	/* Pull in the options flags. */
    201 	sc->sc_options = ((device_cfdata(self)->cf_flags) &
    202 			    ASCAUDIO_OPTIONS_MASK);
    203 
    204 	sc->sc_playbuf = kmem_alloc(BUFSIZE, KM_SLEEP);
    205 	sc->sc_recbuf = kmem_alloc(BUFSIZE, KM_SLEEP);
    206 	sc->sc_rptr = sc->sc_recbuf;
    207 	sc->sc_getptr = sc->sc_recbuf;
    208 	sc->sc_wptr = sc->sc_playbuf;
    209 	sc->sc_putptr = sc->sc_playbuf;
    210 
    211 	bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP);
    212 
    213 	sc->sc_ver = bus_space_read_1(oa->oa_tag, sc->sc_handle, 0x800);
    214 
    215 	if (sc->sc_options & HIGHQUALITY) {
    216 		tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCRATE);
    217 		switch (tmp) {
    218 			case 2:
    219 				sc->sc_rate = 22050;
    220 				break;
    221 			case 3:
    222 				sc->sc_rate = 44100;
    223 				break;
    224 			default:
    225 				sc->sc_rate = 22254;
    226 				break;
    227 		}
    228 
    229 		tmp = bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCTRL);
    230 		if (tmp & STEREO)
    231 			sc->sc_speakers = 2;
    232 		else
    233 			sc->sc_speakers = 1;
    234 
    235 	} else {
    236 		__USE(tmp);
    237 		sc->sc_rate = 22254;
    238 		sc->sc_speakers = 1;
    239 	}
    240 
    241 	if (sc->sc_options & LOWQUALITY) {
    242 		sc->sc_slowcpu = true;
    243 		if (sc->sc_slowcpu)
    244 			sc->sc_rate /= 2;
    245 	}
    246 
    247 	if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2)
    248 		printf(": Enhanced Apple Sound Chip");
    249 	else
    250 		printf(": Apple Sound Chip");
    251 
    252 	if (oa->oa_addr != (-1))
    253 		printf(" at %x", oa->oa_addr);
    254 	printf("\n");
    255 
    256 	bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP);
    257 
    258 	if (mac68k_machine.aux_interrupts) {
    259 		intr_establish(ascaudio_intr_est, sc, ASCIRQ);
    260 	} else {
    261 		via2_register_irq(VIA2_ASC, ascaudio_intr, sc);
    262 	}
    263 	ascaudio_intr_enable();
    264 
    265 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    266 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
    267 	callout_init(&sc->sc_pcallout, CALLOUT_MPSAFE);
    268 	callout_setfunc(&sc->sc_pcallout, ascaudio_done_output, sc);
    269 	callout_init(&sc->sc_rcallout, CALLOUT_MPSAFE);
    270 	callout_setfunc(&sc->sc_rcallout, ascaudio_done_input, sc);
    271 
    272 	sc->sc_vol = 180;
    273 	sc->sc_recvol = 255;
    274 
    275 	sc->sc_audiodev = audio_attach_mi(&ascaudio_hw_if, sc, sc->sc_dev);
    276 
    277 	if (!pmf_device_register(sc->sc_dev, NULL, NULL))
    278 		aprint_error_dev(sc->sc_dev,
    279 		    "couldn't establish power handler\n");
    280 
    281 	if (sc->sc_ver != EASC_VER && sc->sc_ver != EASC_VER2)
    282 		return;
    283 
    284 	if (sc->sc_options & HIGHQUALITY)
    285 		tmp = CDQUALITY;
    286 	else
    287 		tmp = MACDEFAULTS;
    288 
    289 	bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOCTRLA, tmp);
    290 	bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOCTRLB, tmp);
    291 
    292 }
    293 
    294 int
    295 ascaudioopen(dev_t dev, int flag, int mode, struct lwp *l)
    296 {
    297 	struct ascaudio_softc *sc;
    298 
    299 	sc = device_lookup_private(&ascaudio_cd, ASCAUDIOUNIT(dev));
    300 	if (sc == NULL)
    301 		return (ENXIO);
    302 	if (sc->sc_open)
    303 		return (EBUSY);
    304 	sc->sc_open = 1;
    305 
    306 	return (0);
    307 }
    308 
    309 int
    310 ascaudioclose(dev_t dev, int flag, int mode, struct lwp *l)
    311 {
    312 	struct ascaudio_softc *sc;
    313 
    314 	sc = device_lookup_private(&ascaudio_cd, ASCAUDIOUNIT(dev));
    315 	sc->sc_open = 0;
    316 
    317 	return (0);
    318 }
    319 
    320 int
    321 ascaudioread(dev_t dev, struct uio *uio, int ioflag)
    322 {
    323 	return (ENXIO);
    324 }
    325 
    326 int
    327 ascaudiowrite(dev_t dev, struct uio *uio, int ioflag)
    328 {
    329 	return (ENXIO);
    330 }
    331 
    332 int
    333 ascaudioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    334 {
    335 	int error;
    336 #ifdef notyet
    337 	struct ascaudio_softc *sc;
    338 	int unit = ASCAUDIOUNIT(dev);
    339 
    340 	sc = device_lookup_private(&ascaudio_cd, unit);
    341 #endif
    342 	error = 0;
    343 
    344 	switch (cmd) {
    345 	default:
    346 		error = EINVAL;
    347 		break;
    348 	}
    349 	return (error);
    350 }
    351 
    352 #define ASCAUDIO_NFORMATS	2
    353 static int
    354 ascaudio_query_format(void *opaque, struct audio_format_query *ae)
    355 {
    356 	struct ascaudio_softc *sc = opaque;
    357 
    358 	const struct audio_format asc_formats[ASCAUDIO_NFORMATS] = {
    359 	      { .mode		= AUMODE_PLAY,
    360 		.encoding	= AUDIO_ENCODING_SLINEAR_BE,
    361 		.validbits	= 8,
    362 		.precision	= 8,
    363 		.channels	= sc->sc_speakers,
    364 		.channel_mask	= sc->sc_speakers == 2 ? AUFMT_STEREO :
    365 		    AUFMT_MONAURAL,
    366 		.frequency_type	= 1,
    367 		.frequency	= { sc->sc_rate }, },
    368 	      { .mode		= AUMODE_RECORD,
    369 		.encoding	= AUDIO_ENCODING_SLINEAR_BE,
    370 		.validbits	= 8,
    371 		.precision	= 8,
    372 		.channels	= 1,
    373 		.channel_mask	= AUFMT_MONAURAL,
    374 		.frequency_type	= 1,
    375 		.frequency	= { 11025 }, }
    376 	};
    377 
    378 	return audio_query_format(asc_formats, ASCAUDIO_NFORMATS, ae);
    379 }
    380 
    381 static int
    382 ascaudio_set_format(void *opaque, int setmode,
    383     const audio_params_t *play, const audio_params_t *rec,
    384     audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
    385 {
    386 	struct ascaudio_softc *sc = opaque;
    387 
    388 	KASSERT(mutex_owned(&sc->sc_lock));
    389 
    390 	return 0;
    391 }
    392 
    393 static int
    394 ascaudio_start_output(void *opaque, void *block, int blksize,
    395     void (*intr)(void *), void *intrarg)
    396 {
    397 	struct ascaudio_softc *sc;
    398 	uint8_t *loc, tmp;
    399 	int total;
    400 
    401 	sc = (struct ascaudio_softc *)opaque;
    402 	if (!sc)
    403 		return (ENODEV);
    404 
    405 	sc->sc_pintr = intr;
    406 	sc->sc_pintrarg = intrarg;
    407 
    408 	loc = block;
    409  	if (bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCMODE) !=
    410 								 MODEFIFO) {
    411 		bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP);
    412 
    413 		if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) {
    414 			/* disable half interrupts channel a */
    415 			bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA,
    416 			    DISABLEHALFIRQ);
    417 			/* Disable half interrupts channel b */
    418 			bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB,
    419 			    DISABLEHALFIRQ);
    420 		}
    421 
    422 		bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTEST, 0);
    423 		bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM,
    424 		    CLEARFIFO);
    425 		tmp = 0;
    426 		bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, tmp);
    427 
    428 		if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) {
    429 			/* enable interrupts channel b */
    430 			bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 0);
    431 		}
    432 	}
    433 
    434 	/* set the volume. */
    435 	if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) {
    436 		/* DO NOT CHANGE THESE VALUES UNLESS TESTED.
    437 		   CAN BE VERY LOUD!!!! */
    438 		tmp = sc->sc_vol >> 5;
    439 		KASSERT(tmp <= MACOS_HIGH_VOL);
    440  		bus_space_write_1(sc->sc_tag, sc->sc_handle, A_LEFT_VOL, tmp);
    441  		bus_space_write_1(sc->sc_tag, sc->sc_handle, B_LEFT_VOL, tmp);
    442  		bus_space_write_1(sc->sc_tag, sc->sc_handle, A_RIGHT_VOL, tmp);
    443  		bus_space_write_1(sc->sc_tag, sc->sc_handle, B_RIGHT_VOL, tmp);
    444 	}
    445 	bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, sc->sc_vol);
    446 
    447 	total = blksize;
    448 	if (sc->sc_putptr + blksize >= sc->sc_playbuf + BUFSIZE)
    449 		total = sc->sc_playbuf + BUFSIZE - sc->sc_putptr;
    450 
    451 	if (total) {
    452 		memcpy(sc->sc_putptr, loc, total);
    453 		sc->sc_putptr += total;
    454 		loc += total;
    455 	}
    456 
    457 	total = blksize - total;
    458 	if (total) {
    459 		sc->sc_putptr = sc->sc_playbuf;
    460 		memcpy(sc->sc_playbuf, loc, total);
    461 		sc->sc_putptr += total;
    462 	}
    463 
    464 	sc->sc_avail += blksize;
    465 	if (sc->sc_avail > BUFSIZE)
    466 		sc->sc_avail = BUFSIZE;
    467 
    468 	/* start fifo playback */
    469 	bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO);
    470 
    471 	return 0;
    472 }
    473 
    474 static int
    475 ascaudio_start_input(void *opaque, void *block, int blksize,
    476     void (*intr)(void *), void *intrarg)
    477 {
    478 	struct ascaudio_softc *sc;
    479 	uint8_t tmp;
    480 	int total;
    481 
    482 	sc = (struct ascaudio_softc *)opaque;
    483 	if (!sc)
    484 		return (ENODEV);
    485 
    486 	uint8_t *loc;
    487 	loc = block;
    488 
    489 	sc->sc_rintr = intr;
    490 	sc->sc_rintrarg = intrarg;
    491 
    492  	if (bus_space_read_1(sc->sc_tag, sc->sc_handle, ASCMODE) !=
    493 								 MODEFIFO) {
    494 		bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP);
    495 
    496 		if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) {
    497 			/* disable half interrupts channel a */
    498 			bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA,
    499 			    DISABLEHALFIRQ);
    500 			/* Disable half interrupts channel b */
    501 			bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB,
    502 			    DISABLEHALFIRQ);
    503 		}
    504 
    505 		bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCTEST, 0);
    506 
    507 		/* start fifo playback */
    508 		bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODEFIFO);
    509 
    510 		if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) {
    511 			/* enable interrupts channel a */
    512 			bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 0);
    513 		}
    514 
    515 		bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM,
    516 		    CLEARFIFO);
    517 
    518 #if 0
    519 		bus_space_write_4(sc->sc_tag, sc->sc_handle, FIFO_A_ALT, 0);
    520 		bus_space_write_4(sc->sc_tag, sc->sc_handle, FIFO_B_ALT, 0);
    521 #endif
    522 
    523 		bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM,
    524 		    CLEARFIFO);
    525 
    526 		tmp = RECORDA;
    527 		bus_space_write_1(sc->sc_tag, sc->sc_handle, APLAYREC, tmp);
    528 
    529 #if 0
    530 		int i;
    531 		for (i = 0; i < 0x400; i++) {
    532 			bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFO_A);
    533 			bus_space_read_1(sc->sc_tag, sc->sc_handle, FIFO_B);
    534 		}
    535 #endif
    536 
    537 		return 0;
    538 	}
    539 
    540 	/* set the volume. */
    541 	if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2) {
    542 		/* DO NOT CHANGE THESE VALUES UNLESS TESTED.
    543 		   CAN BE VERY LOUD!!!! */
    544 		tmp = sc->sc_recvol >> 5;
    545 		KASSERT(tmp <= MACOS_HIGH_VOL);
    546  		bus_space_write_1(sc->sc_tag, sc->sc_handle, A_LEFT_VOL, tmp);
    547  		bus_space_write_1(sc->sc_tag, sc->sc_handle, B_LEFT_VOL, tmp);
    548  		bus_space_write_1(sc->sc_tag, sc->sc_handle, A_RIGHT_VOL, tmp);
    549  		bus_space_write_1(sc->sc_tag, sc->sc_handle, B_RIGHT_VOL, tmp);
    550 	}
    551 	bus_space_write_1(sc->sc_tag, sc->sc_handle, INTVOL, sc->sc_recvol);
    552 
    553 	total = blksize;
    554 	if (sc->sc_getptr + blksize >= sc->sc_recbuf + BUFSIZE)
    555 		total = sc->sc_recbuf + BUFSIZE - sc->sc_getptr;
    556 
    557 	if (total) {
    558 		memcpy(loc, sc->sc_getptr, total);
    559 		sc->sc_getptr += total;
    560 		loc += total;
    561 	}
    562 
    563 	total = blksize - total;
    564 	if (total) {
    565 		sc->sc_getptr = sc->sc_recbuf;
    566 		memcpy(loc, sc->sc_getptr, total);
    567 		sc->sc_getptr += total;
    568 	}
    569 
    570 	sc->sc_recavail -= blksize;
    571 
    572 	return 0;
    573 }
    574 
    575 static int
    576 ascaudio_halt(void *opaque)
    577 {
    578 	ascaudio_softc_t *sc;
    579 
    580 	sc = (ascaudio_softc_t *)opaque;
    581 
    582 	KASSERT(mutex_owned(&sc->sc_lock));
    583 
    584 	callout_halt(&sc->sc_pcallout, &sc->sc_intr_lock);
    585 	callout_halt(&sc->sc_rcallout, &sc->sc_intr_lock);
    586 
    587 	bus_space_write_1(sc->sc_tag, sc->sc_handle, ASCMODE, MODESTOP);
    588 
    589 	sc->sc_pintr = NULL;
    590 	sc->sc_pintrarg = NULL;
    591 	sc->sc_rintr = NULL;
    592 	sc->sc_rintrarg = NULL;
    593 
    594 	sc->sc_avail = 0;
    595 	sc->sc_recavail = 0;
    596 
    597 	bus_space_write_1(sc->sc_tag, sc->sc_handle, FIFOPARAM, CLEARFIFO);
    598 
    599 	sc->sc_rptr = sc->sc_recbuf;
    600 	sc->sc_getptr = sc->sc_recbuf;
    601 	sc->sc_wptr = sc->sc_playbuf;
    602 	sc->sc_putptr = sc->sc_playbuf;
    603 
    604 	if (sc->sc_ver != EASC_VER && sc->sc_ver != EASC_VER2)
    605 		return 0;
    606 
    607 	/* disable half interrupts channel a */
    608 	bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, DISABLEHALFIRQ);
    609 	/* disable half interrupts channel b */
    610 	bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, DISABLEHALFIRQ);
    611 
    612 	return 0;
    613 }
    614 
    615 static int
    616 ascaudio_getdev(void *opaque, struct audio_device *ret)
    617 {
    618 	strlcpy(ret->name, "Apple ASC Audio", sizeof(ret->name));
    619 	strlcpy(ret->version, osrelease, sizeof(ret->version));
    620 	strlcpy(ret->config, "ascaudio", sizeof(ret->config));
    621 
    622 	return 0;
    623 }
    624 
    625 static int
    626 ascaudio_set_port(void *opaque, mixer_ctrl_t *mc)
    627 {
    628 	struct ascaudio_softc *sc = opaque;
    629 
    630 	KASSERT(mutex_owned(&sc->sc_lock));
    631 
    632 	switch (mc->dev) {
    633 	case ASC_OUTPUT_MASTER_VOLUME:
    634 		if (mc->un.value.num_channels != 1)
    635 			return EINVAL;
    636 		sc->sc_vol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    637 		return 0;
    638 	case ASC_INPUT_DAC_VOLUME:
    639 		if (mc->un.value.num_channels != 1)
    640 			return EINVAL;
    641 		sc->sc_recvol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    642 		return 0;
    643 	}
    644 
    645 	return ENXIO;
    646 }
    647 
    648 static int
    649 ascaudio_get_port(void *opaque, mixer_ctrl_t *mc)
    650 {
    651 	struct ascaudio_softc *sc = opaque;
    652 
    653 	KASSERT(mutex_owned(&sc->sc_lock));
    654 
    655 	switch (mc->dev) {
    656 	case ASC_OUTPUT_MASTER_VOLUME:
    657 		if (mc->un.value.num_channels != 1)
    658 			return EINVAL;
    659 		mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_vol;
    660 		return 0;
    661 	case ASC_INPUT_DAC_VOLUME:
    662 		if (mc->un.value.num_channels != 1)
    663 			return EINVAL;
    664 		mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_recvol;
    665 		return 0;
    666 	}
    667 
    668 	return ENXIO;
    669 }
    670 
    671 static int
    672 ascaudio_query_devinfo(void *opaque, mixer_devinfo_t *di)
    673 {
    674 	ascaudio_softc_t *sc __diagused;
    675 
    676 	sc = (ascaudio_softc_t *)opaque;
    677 
    678 	KASSERT(mutex_owned(&sc->sc_lock));
    679 
    680 	switch (di->index) {
    681 	case ASC_OUTPUT_CLASS:
    682 		di->mixer_class = ASC_OUTPUT_CLASS;
    683 		strcpy(di->label.name, AudioCoutputs);
    684 		di->type = AUDIO_MIXER_CLASS;
    685 		di->next = di->prev = AUDIO_MIXER_LAST;
    686 		return 0;
    687 	case ASC_INPUT_CLASS:
    688 		di->mixer_class = ASC_INPUT_CLASS;
    689 		strcpy(di->label.name, AudioCinputs);
    690 		di->type = AUDIO_MIXER_CLASS;
    691 		di->next = di->prev = AUDIO_MIXER_LAST;
    692 		return 0;
    693 	case ASC_OUTPUT_MASTER_VOLUME:
    694 		di->mixer_class = ASC_OUTPUT_CLASS;
    695 		strcpy(di->label.name, AudioNmaster);
    696 		di->type = AUDIO_MIXER_VALUE;
    697 		di->next = di->prev = AUDIO_MIXER_LAST;
    698 		di->un.v.num_channels = 1;
    699 		strcpy(di->un.v.units.name, AudioNvolume);
    700 		return 0;
    701 	case ASC_INPUT_DAC_VOLUME:
    702 		di->mixer_class = ASC_INPUT_CLASS;
    703 		strcpy(di->label.name, AudioNdac);
    704 		di->type = AUDIO_MIXER_VALUE;
    705 		di->next = di->prev = AUDIO_MIXER_LAST;
    706 		di->un.v.num_channels = 1;
    707 		strcpy(di->un.v.units.name, AudioNvolume);
    708 		return 0;
    709 	}
    710 
    711 	return ENXIO;
    712 }
    713 
    714 static int
    715 ascaudio_get_props(void *opaque)
    716 {
    717 
    718 	return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
    719 	    AUDIO_PROP_INDEPENDENT;
    720 }
    721 
    722 static int
    723 ascaudio_round_blocksize(void *opaque, int blksize, int mode,
    724     const audio_params_t *p)
    725 {
    726 	ascaudio_softc_t *sc __diagused;
    727 
    728 	sc = (ascaudio_softc_t *)opaque;
    729 	KASSERT(mutex_owned(&sc->sc_lock));
    730 
    731 	if (mode == AUMODE_PLAY)
    732 		return PLAYBLKSIZE;
    733 	else
    734 		return RECBLKSIZE;
    735 }
    736 
    737 static void
    738 ascaudio_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
    739 {
    740 	ascaudio_softc_t *sc;
    741 
    742 	sc = (ascaudio_softc_t *)opaque;
    743 
    744 	*intr = &sc->sc_intr_lock;
    745 	*thread = &sc->sc_lock;
    746 }
    747 
    748 static int
    749 ascaudio_intr_est(void *arg)
    750 {
    751 	ascaudio_intr(arg);
    752 
    753 	return 0;
    754 }
    755 
    756 static void
    757 ascaudio_intr(void *arg)
    758 {
    759 	struct ascaudio_softc *sc = arg;
    760 	uint8_t val;
    761 	int loc_a, loc_b, total, count, i;
    762 
    763 	if (!sc)
    764 		return;
    765 
    766 	if (!sc->sc_pintr && !sc->sc_rintr)
    767 		return;
    768 
    769 	mutex_enter(&sc->sc_intr_lock);
    770 
    771 	count = 0x200;
    772 	if (sc->sc_rintr) {
    773 		if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2)
    774 			bus_space_write_1(sc->sc_tag, sc->sc_handle,
    775 			    IRQA, DISABLEHALFIRQ);
    776 
    777 		total = count;
    778 		if (sc->sc_rptr + count >= sc->sc_recbuf + BUFSIZE)
    779 			count = sc->sc_recbuf + BUFSIZE - sc->sc_rptr;
    780 		while (total) {
    781 			if (sc->sc_ver == EASC_VER2) {
    782 				loc_a = FIFO_A_ALT;
    783 				loc_b = FIFO_B_ALT;
    784 			} else {
    785 				loc_a = FIFO_A;
    786 				loc_b = 0;
    787 			}
    788 			for (i = 0; i < count; i++) {
    789 				val = bus_space_read_1(sc->sc_tag,
    790 				    sc->sc_handle, loc_a);
    791 				val ^= 0x80;
    792 				*sc->sc_rptr++ = val;
    793 				if (loc_b) {
    794 					(void)bus_space_read_1
    795 					    (sc->sc_tag, sc->sc_handle, loc_b);
    796 				}
    797 			}
    798 			if (sc->sc_rptr >= sc->sc_recbuf + BUFSIZE)
    799 				sc->sc_rptr = sc->sc_recbuf;
    800 			total -= count;
    801 			sc->sc_recavail += count;
    802 			count = total;
    803 		}
    804 
    805 		if (sc->sc_recavail > BUFSIZE)
    806 			sc->sc_recavail = BUFSIZE;
    807 
    808 		if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2)
    809 			bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQA, 0);
    810 
    811 		goto more;
    812 	}
    813 
    814 	count = 0x200;
    815 	if (sc->sc_slowcpu)
    816 		count /= 2;
    817 
    818 	if (sc->sc_avail < count) {
    819 		if (sc->sc_avail) {
    820 			count = sc->sc_avail;
    821 			goto fill_fifo;
    822 		}
    823 		if (sc->sc_pintr) {
    824 			for (i = 0; i < 0x200; i++) {
    825 				bus_space_write_1(sc->sc_tag,
    826 				    sc->sc_handle, FIFO_A, 0x80);
    827 				bus_space_write_1(sc->sc_tag,
    828 				    sc->sc_handle, FIFO_B, 0x80);
    829 			}
    830 		} else {
    831 			if (sc->sc_slowcpu)
    832 				count *= 2;
    833 			for (i = 0; i < count; i++) {
    834 				bus_space_write_1(sc->sc_tag,
    835 				    sc->sc_handle, FIFO_B, 0x80);
    836 			}
    837 		}
    838 		goto more;
    839 	}
    840 
    841 fill_fifo:
    842 	if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2)
    843 		bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB,
    844 		    DISABLEHALFIRQ);
    845 
    846 	total = count;
    847 	if (sc->sc_wptr + count >= sc->sc_playbuf + BUFSIZE)
    848 		count = sc->sc_playbuf + BUFSIZE - sc->sc_wptr;
    849 
    850 	while (total) {
    851 		if (sc->sc_slowcpu) {
    852 			for (i = 0; i < count; i++) {
    853 				val = *sc->sc_wptr++;
    854 				val ^= 0x80;
    855 				bus_space_write_1(sc->sc_tag,
    856 				    sc->sc_handle, FIFO_A, val);
    857 				bus_space_write_1(sc->sc_tag,
    858 				    sc->sc_handle, FIFO_B, val);
    859 				bus_space_write_1(sc->sc_tag,
    860 				    sc->sc_handle, FIFO_A, val);
    861 				bus_space_write_1(sc->sc_tag,
    862 				    sc->sc_handle, FIFO_B, val);
    863 			}
    864 		} else {
    865 			for (i = 0; i < count; i++) {
    866 				val = *sc->sc_wptr++;
    867 				val ^= 0x80;
    868 				bus_space_write_1(sc->sc_tag,
    869 				    sc->sc_handle, FIFO_A, val);
    870 				bus_space_write_1(sc->sc_tag,
    871 				    sc->sc_handle, FIFO_B, val);
    872 			}
    873 		}
    874 		if (sc->sc_wptr >= sc->sc_playbuf + BUFSIZE)
    875 			sc->sc_wptr = sc->sc_playbuf;
    876 		total -= count;
    877 		sc->sc_avail -= count;
    878 		count = total;
    879 	}
    880 	if (sc->sc_ver == EASC_VER || sc->sc_ver == EASC_VER2)
    881 		bus_space_write_1(sc->sc_tag, sc->sc_handle, IRQB, 0);
    882 
    883 more:
    884 	if (sc->sc_pintr && (sc->sc_avail <= PLAYBLKSIZE))
    885 		callout_schedule(&sc->sc_pcallout, 0);
    886 
    887 	if (sc->sc_rintr && (sc->sc_recavail >= RECBLKSIZE))
    888 		callout_schedule(&sc->sc_rcallout, 0);
    889 
    890 	mutex_exit(&sc->sc_intr_lock);
    891 }
    892 
    893 static void
    894 ascaudio_intr_enable(void)
    895 {
    896 	int s;
    897 
    898 	s = splhigh();
    899 	if (VIA2 == VIA2OFF)
    900 		via2_reg(vIER) = 0x80 | V2IF_ASC;
    901 	else
    902 		via2_reg(rIER) = 0x80 | V2IF_ASC;
    903 	splx(s);
    904 }
    905 
    906 static void
    907 ascaudio_done_output(void *arg)
    908 {
    909 	struct ascaudio_softc *sc = arg;
    910 
    911 	mutex_enter(&sc->sc_intr_lock);
    912 	if (sc->sc_pintr)
    913 		(*sc->sc_pintr)(sc->sc_pintrarg);
    914 	mutex_exit(&sc->sc_intr_lock);
    915 }
    916 
    917 static void
    918 ascaudio_done_input(void *arg)
    919 {
    920 	struct ascaudio_softc *sc = arg;
    921 
    922 	mutex_enter(&sc->sc_intr_lock);
    923 	if (sc->sc_rintr)
    924 		(*sc->sc_rintr)(sc->sc_rintrarg);
    925 	mutex_exit(&sc->sc_intr_lock);
    926 }
    927 
    928 #ifdef _MODULE
    929 
    930 MODULE(MODULE_CLASS_DRIVER, ascaudio, "audio");
    931 
    932 static const struct cfiattrdata audiobuscf_iattrdata = {
    933 	"audiobus", 0, { { NULL, NULL, 0 }, }
    934 };
    935 static const struct cfiattrdata * const ascaudio_attrs[] = {
    936 	&audiobuscf_iattrdata, NULL
    937 };
    938 
    939 CFDRIVER_DECL(ascaudio, DV_DULL, ascaud_attrs);
    940 extern struct cfattach ascaudio_ca;
    941 static int ascaudioloc[] = { -1, -1 };
    942 
    943 static struct cfdata ascaudio_cfdata[] = {
    944 	{
    945 		.cf_name = "ascaudio",
    946 		.cf_atname = "ascaudio",
    947 		.cf_unit = 0,
    948 		.cf_fstate = FSTATE_STAR,
    949 		.cf_loc = ascaudioloc,
    950 		.cf_flags = 0,
    951 		.cf_pspec = NULL,
    952 	},
    953 	{ NULL, NULL, 0, 0, NULL, 0, NULL }
    954 };
    955 
    956 static int
    957 ascaudio_modcmd(modcmd_t cmd, void *arg)
    958 {
    959 	devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR;
    960 	int error;
    961 
    962 	switch (cmd) {
    963 	case MODULE_CMD_INIT:
    964 		error = config_cfdriver_attach(&ascaudio_cd);
    965 		if (error) {
    966 			return error;
    967 		}
    968 
    969 		error = config_cfattach_attach(ascaudio_cd.cd_name, &ascaud_ca);
    970 		if (error) {
    971 			config_cfdriver_detach(&ascaudio_cd);
    972 			aprint_error("%s: unable to register cfattach\n",
    973 				ascaudio_cd.cd_name);
    974 
    975 			return error;
    976 		}
    977 
    978 		error = config_cfdata_attach(ascaudio_cfdata, 1);
    979 		if (error) {
    980 			config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca);
    981 			config_cfdriver_detach(&ascaudio_cd);
    982 			aprint_error("%s: unable to register cfdata\n",
    983 				ascaudio_cd.cd_name);
    984 
    985 			return error;
    986 		}
    987 
    988 		error = devsw_attach(ascaudio_cd.cd_name, NULL, &bmajor,
    989 		    &ascaudio_cdevsw, &cmajor);
    990 		if (error) {
    991 			error = config_cfdata_detach(ascaudio_cfdata);
    992 			if (error) {
    993 				return error;
    994 			}
    995 			config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca);
    996 			config_cfdriver_detach(&ascaudio_cd);
    997 			aprint_error("%s: unable to register devsw\n",
    998 				ascaudio_cd.cd_name);
    999 
   1000 			return error;
   1001 		}
   1002 
   1003 		(void)config_attach_pseudo(ascaudio_cfdata);
   1004 
   1005 		return 0;
   1006 	case MODULE_CMD_FINI:
   1007 		error = config_cfdata_detach(ascaudio_cfdata);
   1008 		if (error) {
   1009 			return error;
   1010 		}
   1011 
   1012 		config_cfattach_detach(ascaudio_cd.cd_name, &ascaud_ca);
   1013 		config_cfdriver_detach(&ascaudio_cd);
   1014 		devsw_detach(NULL, &ascaudio_cdevsw);
   1015 
   1016 		return 0;
   1017 	default:
   1018 		return ENOTTY;
   1019 	}
   1020 }
   1021 
   1022 #endif
   1023