Home | History | Annotate | Line # | Download | only in ic
cs4231.c revision 1.5
      1 /*	$NetBSD: cs4231.c,v 1.5 2001/10/03 00:04:49 augustss Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Paul Kranenburg.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include "audio.h"
     40 #if NAUDIO > 0
     41 
     42 #include <sys/param.h>
     43 #include <sys/systm.h>
     44 #include <sys/errno.h>
     45 #include <sys/device.h>
     46 #include <sys/malloc.h>
     47 
     48 #include <machine/autoconf.h>
     49 #include <machine/cpu.h>
     50 
     51 #include <sys/audioio.h>
     52 #include <dev/audio_if.h>
     53 
     54 #include <dev/ic/ad1848reg.h>
     55 #include <dev/ic/cs4231reg.h>
     56 #include <dev/ic/ad1848var.h>
     57 #include <dev/ic/cs4231var.h>
     58 #include <dev/ic/apcdmareg.h>
     59 
     60 /*---*/
     61 #define CSAUDIO_DAC_LVL		0
     62 #define CSAUDIO_LINE_IN_LVL	1
     63 #define CSAUDIO_MONO_LVL	2
     64 #define CSAUDIO_CD_LVL		3
     65 #define CSAUDIO_MONITOR_LVL	4
     66 #define CSAUDIO_OUT_LVL		5
     67 #define CSAUDIO_LINE_IN_MUTE	6
     68 #define CSAUDIO_DAC_MUTE	7
     69 #define CSAUDIO_CD_MUTE		8
     70 #define CSAUDIO_MONO_MUTE	9
     71 #define CSAUDIO_MONITOR_MUTE	10
     72 #define CSAUDIO_REC_LVL		11
     73 #define CSAUDIO_RECORD_SOURCE	12
     74 
     75 #define CSAUDIO_INPUT_CLASS	13
     76 #define CSAUDIO_OUTPUT_CLASS	14
     77 #define CSAUDIO_RECORD_CLASS	15
     78 #define CSAUDIO_MONITOR_CLASS	16
     79 
     80 #ifdef AUDIO_DEBUG
     81 int     cs4231debug = 0;
     82 #define DPRINTF(x)      if (cs4231debug) printf x
     83 #else
     84 #define DPRINTF(x)
     85 #endif
     86 
     87 struct audio_device cs4231_device = {
     88 	"cs4231",
     89 	"x",
     90 	"audio"
     91 };
     92 
     93 
     94 /*
     95  * Define our interface to the higher level audio driver.
     96  */
     97 int	cs4231_open __P((void *, int));
     98 void	cs4231_close __P((void *));
     99 size_t	cs4231_round_buffersize __P((void *, int, size_t));
    100 int	cs4231_round_blocksize __P((void *, int));
    101 int	cs4231_halt_output __P((void *));
    102 int	cs4231_halt_input __P((void *));
    103 int	cs4231_getdev __P((void *, struct audio_device *));
    104 int	cs4231_set_port __P((void *, mixer_ctrl_t *));
    105 int	cs4231_get_port __P((void *, mixer_ctrl_t *));
    106 int	cs4231_query_devinfo __P((void *, mixer_devinfo_t *));
    107 int	cs4231_get_props __P((void *));
    108 
    109 void   *cs4231_malloc __P((void *, int, size_t, int, int));
    110 void	cs4231_free __P((void *, void *, int));
    111 int	cs4231_trigger_output __P((void *, void *, void *, int,
    112 				   void (*)(void *), void *,
    113 				   struct audio_params *));
    114 int	cs4231_trigger_input __P((void *, void *, void *, int,
    115 				  void (*)(void *), void *,
    116 				  struct audio_params *));
    117 
    118 #ifdef AUDIO_DEBUG
    119 static void	cs4231_regdump __P((char *, struct cs4231_softc *));
    120 #endif
    121 
    122 int
    123 cs4231_read(sc, index)
    124 	struct ad1848_softc	*sc;
    125 	int			index;
    126 {
    127 	return bus_space_read_1(sc->sc_iot, sc->sc_ioh, (index << 2));
    128 }
    129 
    130 void
    131 cs4231_write(sc, index, value)
    132 	struct ad1848_softc	*sc;
    133 	int			index, value;
    134 {
    135 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, (index << 2), value);
    136 }
    137 
    138 struct audio_hw_if audiocs_hw_if = {
    139 	cs4231_open,
    140 	cs4231_close,
    141 	0,
    142 	ad1848_query_encoding,
    143 	ad1848_set_params,
    144 	cs4231_round_blocksize,
    145 	ad1848_commit_settings,
    146 	0,
    147 	0,
    148 	NULL,
    149 	NULL,
    150 	cs4231_halt_output,
    151 	cs4231_halt_input,
    152 	0,
    153 	cs4231_getdev,
    154 	0,
    155 	cs4231_set_port,
    156 	cs4231_get_port,
    157 	cs4231_query_devinfo,
    158 	cs4231_malloc,
    159 	cs4231_free,
    160 	cs4231_round_buffersize,
    161         0,
    162 	cs4231_get_props,
    163 	cs4231_trigger_output,
    164 	cs4231_trigger_input,
    165 	NULL,
    166 };
    167 
    168 
    169 #ifdef AUDIO_DEBUG
    170 static void
    171 cs4231_regdump(label, sc)
    172 	char *label;
    173 	struct cs4231_softc *sc;
    174 {
    175 	char bits[128];
    176 	volatile struct apc_dma *dma = sc->sc_dmareg;
    177 
    178 	printf("cs4231regdump(%s): regs:", label);
    179 	printf("dmapva: 0x%x; ", dma->dmapva);
    180 	printf("dmapc: 0x%x; ", dma->dmapc);
    181 	printf("dmapnva: 0x%x; ", dma->dmapnva);
    182 	printf("dmapnc: 0x%x\n", dma->dmapnc);
    183 	printf("dmacva: 0x%x; ", dma->dmacva);
    184 	printf("dmacc: 0x%x; ", dma->dmacc);
    185 	printf("dmacnva: 0x%x; ", dma->dmacnva);
    186 	printf("dmacnc: 0x%x\n", dma->dmacnc);
    187 
    188 	printf("apc_dmacsr=%s\n",
    189 		bitmask_snprintf(dma->dmacsr, APC_BITS, bits, sizeof(bits)) );
    190 
    191 	ad1848_dump_regs(&sc->sc_ad1848);
    192 }
    193 #endif
    194 
    195 void
    196 cs4231_init(sc)
    197 	struct cs4231_softc *sc;
    198 {
    199 	char *buf;
    200 #if 0
    201 	volatile struct apc_dma *dma = sc->sc_dmareg;
    202 #endif
    203 	int reg;
    204 
    205 #if 0
    206 	dma->dmacsr = APC_CODEC_PDN;
    207 	delay(20);
    208 	dma->dmacsr &= ~APC_CODEC_PDN;
    209 #endif
    210 	/* First, put chip in native mode */
    211 	reg = ad_read(&sc->sc_ad1848, SP_MISC_INFO);
    212 	ad_write(&sc->sc_ad1848, SP_MISC_INFO, reg | MODE2);
    213 
    214 	/* Read version numbers from I25 */
    215 	reg = ad_read(&sc->sc_ad1848, CS_VERSION_ID);
    216 	switch (reg & (CS_VERSION_NUMBER | CS_VERSION_CHIPID)) {
    217 	case 0xa0:
    218 		sc->sc_ad1848.chip_name = "CS4231A";
    219 		break;
    220 	case 0x80:
    221 		sc->sc_ad1848.chip_name = "CS4231";
    222 		break;
    223 	case 0x82:
    224 		sc->sc_ad1848.chip_name = "CS4232";
    225 		break;
    226 	default:
    227 		if ((buf = malloc(32, M_TEMP, M_NOWAIT)) != NULL) {
    228 			sprintf(buf, "unknown rev: %x/%x", reg&0xe, reg&7);
    229 			sc->sc_ad1848.chip_name = buf;
    230 		}
    231 	}
    232 }
    233 
    234 void *
    235 cs4231_malloc(addr, direction, size, pool, flags)
    236 	void *addr;
    237 	int direction;
    238 	size_t size;
    239 	int pool, flags;
    240 {
    241 	struct cs4231_softc *sc = addr;
    242 	bus_dma_tag_t dmatag = sc->sc_dmatag;
    243 	struct cs_dma *p;
    244 
    245 	p = malloc(sizeof(*p), pool, flags);
    246 	if (p == NULL)
    247 		return (NULL);
    248 
    249 	/* Allocate a DMA map */
    250 	if (bus_dmamap_create(dmatag, size, 1, size, 0,
    251 				BUS_DMA_NOWAIT, &p->dmamap) != 0)
    252 		goto fail1;
    253 
    254 	/* Allocate DMA memory */
    255 	p->size = size;
    256 	if (bus_dmamem_alloc(dmatag, size, 64*1024, 0,
    257 				p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
    258 				&p->nsegs, BUS_DMA_NOWAIT) != 0)
    259 		goto fail2;
    260 
    261 	/* Map DMA memory into kernel space */
    262 	if (bus_dmamem_map(dmatag, p->segs, p->nsegs, p->size,
    263 			   &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT) != 0)
    264 		goto fail3;
    265 
    266 	/* Load the buffer */
    267 	if (bus_dmamap_load(dmatag, p->dmamap,
    268 			    p->addr, size, NULL, BUS_DMA_NOWAIT) != 0)
    269 		goto fail4;
    270 
    271 	p->next = sc->sc_dmas;
    272 	sc->sc_dmas = p;
    273 	return (p->addr);
    274 
    275 fail4:
    276 	bus_dmamem_unmap(dmatag, p->addr, p->size);
    277 fail3:
    278 	bus_dmamem_free(dmatag, p->segs, p->nsegs);
    279 fail2:
    280 	bus_dmamap_destroy(dmatag, p->dmamap);
    281 fail1:
    282 	free(p, pool);
    283 	return (NULL);
    284 }
    285 
    286 void
    287 cs4231_free(addr, ptr, pool)
    288 	void *addr;
    289 	void *ptr;
    290 	int pool;
    291 {
    292 	struct cs4231_softc *sc = addr;
    293 	bus_dma_tag_t dmatag = sc->sc_dmatag;
    294 	struct cs_dma *p, **pp;
    295 
    296 	for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) {
    297 		if (p->addr != ptr)
    298 			continue;
    299 		bus_dmamap_unload(dmatag, p->dmamap);
    300 		bus_dmamem_unmap(dmatag, p->addr, p->size);
    301 		bus_dmamem_free(dmatag, p->segs, p->nsegs);
    302 		bus_dmamap_destroy(dmatag, p->dmamap);
    303 		*pp = p->next;
    304 		free(p, pool);
    305 		return;
    306 	}
    307 	printf("cs4231_free: rogue pointer\n");
    308 }
    309 
    310 int
    311 cs4231_open(addr, flags)
    312 	void *addr;
    313 	int flags;
    314 {
    315 	struct cs4231_softc *sc = addr;
    316 #if 0
    317 	struct apc_dma *dma = sc->sc_dmareg;
    318 #endif
    319 
    320 	DPRINTF(("sa_open: unit %p\n", sc));
    321 
    322 	if (sc->sc_open)
    323 		return (EBUSY);
    324 	sc->sc_open = 1;
    325 	sc->sc_locked = 0;
    326 	sc->sc_rintr = 0;
    327 	sc->sc_rarg = 0;
    328 	sc->sc_pintr = 0;
    329 	sc->sc_parg = 0;
    330 #if 1
    331 	/*No interrupts from ad1848 */
    332 	ad_write(&sc->sc_ad1848, SP_PIN_CONTROL, 0);
    333 #endif
    334 #if 0
    335 	dma->dmacsr = APC_RESET;
    336 	delay(10);
    337 	dma->dmacsr = 0;
    338 	delay(10);
    339 #endif
    340 	ad1848_reset(&sc->sc_ad1848);
    341 
    342 	DPRINTF(("saopen: ok -> sc=%p\n", sc));
    343 	return (0);
    344 }
    345 
    346 void
    347 cs4231_close(addr)
    348 	void *addr;
    349 {
    350 	struct cs4231_softc *sc = addr;
    351 
    352 	DPRINTF(("sa_close: sc=%p\n", sc));
    353 	/*
    354 	 * halt i/o, clear open flag, and done.
    355 	 */
    356 	cs4231_halt_input(sc);
    357 	cs4231_halt_output(sc);
    358 	sc->sc_open = 0;
    359 
    360 	DPRINTF(("sa_close: closed.\n"));
    361 }
    362 
    363 size_t
    364 cs4231_round_buffersize(addr, direction, size)
    365 	void *addr;
    366 	int direction;
    367 	size_t size;
    368 {
    369 #if 0
    370 	if (size > APC_MAX)
    371 		size = APC_MAX;
    372 #endif
    373 	return (size);
    374 }
    375 
    376 int
    377 cs4231_round_blocksize(addr, blk)
    378 	void *addr;
    379 	int blk;
    380 {
    381 	return (blk & -4);
    382 }
    383 
    384 int
    385 cs4231_getdev(addr, retp)
    386         void *addr;
    387         struct audio_device *retp;
    388 {
    389         *retp = cs4231_device;
    390         return (0);
    391 }
    392 
    393 static ad1848_devmap_t csmapping[] = {
    394 	{ CSAUDIO_DAC_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL },
    395 	{ CSAUDIO_LINE_IN_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL },
    396 	{ CSAUDIO_MONO_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL },
    397 	{ CSAUDIO_CD_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL },
    398 	{ CSAUDIO_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL },
    399 	{ CSAUDIO_OUT_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL },
    400 	{ CSAUDIO_DAC_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL },
    401 	{ CSAUDIO_LINE_IN_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL },
    402 	{ CSAUDIO_MONO_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL },
    403 	{ CSAUDIO_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL },
    404 	{ CSAUDIO_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL },
    405 	{ CSAUDIO_REC_LVL, AD1848_KIND_RECORDGAIN, -1 },
    406 	{ CSAUDIO_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1 }
    407 };
    408 
    409 static int nummap = sizeof(csmapping) / sizeof(csmapping[0]);
    410 
    411 
    412 int
    413 cs4231_set_port(addr, cp)
    414 	void *addr;
    415 	mixer_ctrl_t *cp;
    416 {
    417 	struct ad1848_softc *ac = addr;
    418 
    419 	DPRINTF(("cs4231_set_port: port=%d", cp->dev));
    420 	return (ad1848_mixer_set_port(ac, csmapping, nummap, cp));
    421 }
    422 
    423 int
    424 cs4231_get_port(addr, cp)
    425 	void *addr;
    426 	mixer_ctrl_t *cp;
    427 {
    428 	struct ad1848_softc *ac = addr;
    429 
    430 	DPRINTF(("cs4231_get_port: port=%d", cp->dev));
    431 	return (ad1848_mixer_get_port(ac, csmapping, nummap, cp));
    432 }
    433 
    434 int
    435 cs4231_get_props(addr)
    436 	void *addr;
    437 {
    438 	return (AUDIO_PROP_FULLDUPLEX);
    439 }
    440 
    441 int
    442 cs4231_query_devinfo(addr, dip)
    443 	void *addr;
    444 	mixer_devinfo_t *dip;
    445 {
    446 
    447 	switch(dip->index) {
    448 #if 0
    449 	case CSAUDIO_MIC_IN_LVL:	/* Microphone */
    450 		dip->type = AUDIO_MIXER_VALUE;
    451 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
    452 		dip->prev = AUDIO_MIXER_LAST;
    453 		dip->next = CSAUDIO_MIC_IN_MUTE;
    454 		strcpy(dip->label.name, AudioNmicrophone);
    455 		dip->un.v.num_channels = 2;
    456 		strcpy(dip->un.v.units.name, AudioNvolume);
    457 		break;
    458 #endif
    459 
    460 	case CSAUDIO_MONO_LVL:	/* mono/microphone mixer */
    461 		dip->type = AUDIO_MIXER_VALUE;
    462 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
    463 		dip->prev = AUDIO_MIXER_LAST;
    464 		dip->next = CSAUDIO_MONO_MUTE;
    465 		strcpy(dip->label.name, AudioNmicrophone);
    466 		dip->un.v.num_channels = 1;
    467 		strcpy(dip->un.v.units.name, AudioNvolume);
    468 		break;
    469 
    470 	case CSAUDIO_DAC_LVL:		/*  dacout */
    471 		dip->type = AUDIO_MIXER_VALUE;
    472 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
    473 		dip->prev = AUDIO_MIXER_LAST;
    474 		dip->next = CSAUDIO_DAC_MUTE;
    475 		strcpy(dip->label.name, AudioNdac);
    476 		dip->un.v.num_channels = 2;
    477 		strcpy(dip->un.v.units.name, AudioNvolume);
    478 		break;
    479 
    480 	case CSAUDIO_LINE_IN_LVL:	/* line */
    481 		dip->type = AUDIO_MIXER_VALUE;
    482 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
    483 		dip->prev = AUDIO_MIXER_LAST;
    484 		dip->next = CSAUDIO_LINE_IN_MUTE;
    485 		strcpy(dip->label.name, AudioNline);
    486 		dip->un.v.num_channels = 2;
    487 		strcpy(dip->un.v.units.name, AudioNvolume);
    488 		break;
    489 
    490 	case CSAUDIO_CD_LVL:		/* cd */
    491 		dip->type = AUDIO_MIXER_VALUE;
    492 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
    493 		dip->prev = AUDIO_MIXER_LAST;
    494 		dip->next = CSAUDIO_CD_MUTE;
    495 		strcpy(dip->label.name, AudioNcd);
    496 		dip->un.v.num_channels = 2;
    497 		strcpy(dip->un.v.units.name, AudioNvolume);
    498 		break;
    499 
    500 
    501 	case CSAUDIO_MONITOR_LVL:	/* monitor level */
    502 		dip->type = AUDIO_MIXER_VALUE;
    503 		dip->mixer_class = CSAUDIO_MONITOR_CLASS;
    504 		dip->next = CSAUDIO_MONITOR_MUTE;
    505 		dip->prev = AUDIO_MIXER_LAST;
    506 		strcpy(dip->label.name, AudioNmonitor);
    507 		dip->un.v.num_channels = 1;
    508 		strcpy(dip->un.v.units.name, AudioNvolume);
    509 		break;
    510 
    511 	case CSAUDIO_OUT_LVL:		/* cs4231 output volume: not useful? */
    512 		dip->type = AUDIO_MIXER_VALUE;
    513 		dip->mixer_class = CSAUDIO_MONITOR_CLASS;
    514 		dip->prev = dip->next = AUDIO_MIXER_LAST;
    515 		strcpy(dip->label.name, AudioNoutput);
    516 		dip->un.v.num_channels = 2;
    517 		strcpy(dip->un.v.units.name, AudioNvolume);
    518 		break;
    519 
    520 	case CSAUDIO_LINE_IN_MUTE:
    521 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
    522 		dip->type = AUDIO_MIXER_ENUM;
    523 		dip->prev = CSAUDIO_LINE_IN_LVL;
    524 		dip->next = AUDIO_MIXER_LAST;
    525 		goto mute;
    526 
    527 	case CSAUDIO_DAC_MUTE:
    528 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
    529 		dip->type = AUDIO_MIXER_ENUM;
    530 		dip->prev = CSAUDIO_DAC_LVL;
    531 		dip->next = AUDIO_MIXER_LAST;
    532 		goto mute;
    533 
    534 	case CSAUDIO_CD_MUTE:
    535 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
    536 		dip->type = AUDIO_MIXER_ENUM;
    537 		dip->prev = CSAUDIO_CD_LVL;
    538 		dip->next = AUDIO_MIXER_LAST;
    539 		goto mute;
    540 
    541 	case CSAUDIO_MONO_MUTE:
    542 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
    543 		dip->type = AUDIO_MIXER_ENUM;
    544 		dip->prev = CSAUDIO_MONO_LVL;
    545 		dip->next = AUDIO_MIXER_LAST;
    546 		goto mute;
    547 
    548 	case CSAUDIO_MONITOR_MUTE:
    549 		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
    550 		dip->type = AUDIO_MIXER_ENUM;
    551 		dip->prev = CSAUDIO_MONITOR_LVL;
    552 		dip->next = AUDIO_MIXER_LAST;
    553 	mute:
    554 		strcpy(dip->label.name, AudioNmute);
    555 		dip->un.e.num_mem = 2;
    556 		strcpy(dip->un.e.member[0].label.name, AudioNoff);
    557 		dip->un.e.member[0].ord = 0;
    558 		strcpy(dip->un.e.member[1].label.name, AudioNon);
    559 		dip->un.e.member[1].ord = 1;
    560 		break;
    561 
    562 	case CSAUDIO_REC_LVL:	/* record level */
    563 		dip->type = AUDIO_MIXER_VALUE;
    564 		dip->mixer_class = CSAUDIO_RECORD_CLASS;
    565 		dip->prev = AUDIO_MIXER_LAST;
    566 		dip->next = CSAUDIO_RECORD_SOURCE;
    567 		strcpy(dip->label.name, AudioNrecord);
    568 		dip->un.v.num_channels = 2;
    569 		strcpy(dip->un.v.units.name, AudioNvolume);
    570 		break;
    571 
    572 	case CSAUDIO_RECORD_SOURCE:
    573 		dip->mixer_class = CSAUDIO_RECORD_CLASS;
    574 		dip->type = AUDIO_MIXER_ENUM;
    575 		dip->prev = CSAUDIO_REC_LVL;
    576 		dip->next = AUDIO_MIXER_LAST;
    577 		strcpy(dip->label.name, AudioNsource);
    578 		dip->un.e.num_mem = 4;
    579 		strcpy(dip->un.e.member[0].label.name, AudioNoutput);
    580 		dip->un.e.member[0].ord = DAC_IN_PORT;
    581 		strcpy(dip->un.e.member[1].label.name, AudioNmicrophone);
    582 		dip->un.e.member[1].ord = MIC_IN_PORT;
    583 		strcpy(dip->un.e.member[2].label.name, AudioNdac);
    584 		dip->un.e.member[2].ord = AUX1_IN_PORT;
    585 		strcpy(dip->un.e.member[3].label.name, AudioNline);
    586 		dip->un.e.member[3].ord = LINE_IN_PORT;
    587 		break;
    588 
    589 	case CSAUDIO_INPUT_CLASS:		/* input class descriptor */
    590 		dip->type = AUDIO_MIXER_CLASS;
    591 		dip->mixer_class = CSAUDIO_INPUT_CLASS;
    592 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    593 		strcpy(dip->label.name, AudioCinputs);
    594 		break;
    595 
    596 	case CSAUDIO_OUTPUT_CLASS:		/* output class descriptor */
    597 		dip->type = AUDIO_MIXER_CLASS;
    598 		dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
    599 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    600 		strcpy(dip->label.name, AudioCoutputs);
    601 		break;
    602 
    603 	case CSAUDIO_MONITOR_CLASS:		/* monitor class descriptor */
    604 		dip->type = AUDIO_MIXER_CLASS;
    605 		dip->mixer_class = CSAUDIO_MONITOR_CLASS;
    606 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    607 		strcpy(dip->label.name, AudioCmonitor);
    608 		break;
    609 
    610 	case CSAUDIO_RECORD_CLASS:		/* record source class */
    611 		dip->type = AUDIO_MIXER_CLASS;
    612 		dip->mixer_class = CSAUDIO_RECORD_CLASS;
    613 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    614 		strcpy(dip->label.name, AudioCrecord);
    615 		break;
    616 
    617 	default:
    618 		return ENXIO;
    619 		/*NOTREACHED*/
    620 	}
    621 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
    622 
    623 	return (0);
    624 }
    625 
    626 int
    627 cs4231_trigger_output(addr, start, end, blksize, intr, arg, param)
    628 	void *addr;
    629 	void *start, *end;
    630 	int blksize;
    631 	void (*intr) __P((void *));
    632 	void *arg;
    633 	struct audio_params *param;
    634 {
    635 	struct cs4231_softc *sc = addr;
    636 	struct cs_dma *p;
    637 	volatile struct apc_dma *dma = sc->sc_dmareg;
    638 	int csr;
    639 	vsize_t n;
    640 
    641 	if (sc->sc_locked != 0) {
    642 		printf("cs4231_trigger_output: already running\n");
    643 		return (EINVAL);
    644 	}
    645 
    646 	sc->sc_locked = 1;
    647 	sc->sc_pintr = intr;
    648 	sc->sc_parg = arg;
    649 
    650 	for (p = sc->sc_dmas; p != NULL && p->addr != start; p = p->next)
    651 		/*void*/;
    652 	if (p == NULL) {
    653 		printf("cs4231_trigger_output: bad addr %p\n", start);
    654 		return (EINVAL);
    655 	}
    656 
    657 	n = (char *)end - (char *)start;
    658 
    659 	/* XXX
    660 	 * Do only `blksize' at a time, so audio_pint() is kept
    661 	 * synchronous with us...
    662 	 */
    663 	/*XXX*/sc->sc_blksz = blksize;
    664 	/*XXX*/sc->sc_nowplaying = p;
    665 	/*XXX*/sc->sc_playsegsz = n;
    666 
    667 	if (n > APC_MAX)
    668 		n = APC_MAX;
    669 
    670 	sc->sc_playcnt = n;
    671 
    672 	DPRINTF(("trigger_out: start %p, end %p, size %lu; "
    673 		 "dmaaddr 0x%lx, dmacnt %lu, segsize %lu\n",
    674 		 start, end, (u_long)sc->sc_playsegsz,
    675 		 (u_long)p->dmamap->dm_segs[0].ds_addr,
    676 		 (u_long)n, (u_long)p->size));
    677 
    678 	csr = dma->dmacsr;
    679 	dma->dmapnva = (u_long)p->dmamap->dm_segs[0].ds_addr;
    680 	dma->dmapnc = (u_long)n;
    681 	if ((csr & PDMA_GO) == 0 || (csr & APC_PPAUSE) != 0) {
    682 		int reg;
    683 
    684 		dma->dmacsr &= ~(APC_PIE|APC_PPAUSE);
    685 		dma->dmacsr |= APC_EI|APC_IE|APC_PIE|APC_EIE|APC_PMIE|PDMA_GO;
    686 
    687 		/* Start chip */
    688 
    689 		/* Probably should just ignore this.. */
    690 		ad_write(&sc->sc_ad1848, SP_LOWER_BASE_COUNT, 0xff);
    691 		ad_write(&sc->sc_ad1848, SP_UPPER_BASE_COUNT, 0xff);
    692 
    693 		reg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
    694 		ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG,
    695 			 (PLAYBACK_ENABLE|reg));
    696 	}
    697 
    698 	return (0);
    699 }
    700 
    701 int
    702 cs4231_trigger_input(addr, start, end, blksize, intr, arg, param)
    703 	void *addr;
    704 	void *start, *end;
    705 	int blksize;
    706 	void (*intr) __P((void *));
    707 	void *arg;
    708 	struct audio_params *param;
    709 {
    710 	return (ENXIO);
    711 }
    712 
    713 int
    714 cs4231_halt_output(addr)
    715 	void *addr;
    716 {
    717 	struct cs4231_softc *sc = addr;
    718 	volatile struct apc_dma *dma = sc->sc_dmareg;
    719 	int reg;
    720 
    721 	dma->dmacsr &= ~(APC_EI | APC_IE | APC_PIE | APC_EIE | PDMA_GO | APC_PMIE);
    722 	reg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
    723 	ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, (reg & ~PLAYBACK_ENABLE));
    724 	sc->sc_locked = 0;
    725 
    726 	return (0);
    727 }
    728 
    729 int
    730 cs4231_halt_input(addr)
    731 	void *addr;
    732 {
    733 	struct cs4231_softc *sc = addr;
    734 	int reg;
    735 
    736 	reg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
    737 	ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, (reg & ~CAPTURE_ENABLE));
    738 	sc->sc_locked = 0;
    739 
    740 	return (0);
    741 }
    742 
    743 
    744 int
    745 cs4231_intr(arg)
    746 	void *arg;
    747 {
    748 	struct cs4231_softc *sc = arg;
    749 	volatile struct apc_dma *dma = sc->sc_dmareg;
    750 	struct cs_dma *p;
    751 	int ret = 0;
    752 	int csr;
    753 	int reg, status;
    754 #if defined(DEBUG) || defined(AUDIO_DEBUG)
    755 	char bits[128];
    756 #endif
    757 
    758 #ifdef AUDIO_DEBUG
    759 	if (cs4231debug > 1)
    760 		cs4231_regdump("audiointr", sc);
    761 #endif
    762 
    763 	/* Read DMA status */
    764 	csr = dma->dmacsr;
    765 	DPRINTF((
    766 	    "intr: csr=%s; dmapva=0x%lx,dmapc=%lu;dmapnva=0x%lx,dmapnc=%lu\n",
    767 		bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits)),
    768 		(u_long)dma->dmapva, (u_long)dma->dmapc,
    769 		(u_long)dma->dmapnva, (u_long)dma->dmapnc));
    770 
    771 	status = ADREAD(&sc->sc_ad1848, AD1848_STATUS);
    772 	DPRINTF(("%s: status: %s\n", sc->sc_ad1848.sc_dev.dv_xname,
    773 		bitmask_snprintf(status, AD_R2_BITS, bits, sizeof(bits))));
    774 	if (status & (INTERRUPT_STATUS | SAMPLE_ERROR)) {
    775 		reg = ad_read(&sc->sc_ad1848, CS_IRQ_STATUS);
    776 		DPRINTF(("%s: i24: %s\n", sc->sc_ad1848.sc_dev.dv_xname,
    777 		       bitmask_snprintf(reg, CS_I24_BITS, bits, sizeof(bits))));
    778 
    779 		if (reg & CS_IRQ_PI) {
    780 			ad_write(&sc->sc_ad1848, SP_LOWER_BASE_COUNT, 0xff);
    781 			ad_write(&sc->sc_ad1848, SP_UPPER_BASE_COUNT, 0xff);
    782 		}
    783 		/* Clear interrupt bit */
    784 		ADWRITE(&sc->sc_ad1848, AD1848_STATUS, 0);
    785 	}
    786 
    787 	/* Write back DMA status (clears interrupt) */
    788 	dma->dmacsr = csr;
    789 
    790 	/*
    791 	 * Simplistic.. if "play emtpy" is set advance to next chunk.
    792 	 */
    793 #if 1
    794 	/* Ack all play interrupts*/
    795 	if ((csr & (APC_PI|APC_PD|APC_PIE|APC_PMI)) != 0)
    796 		ret = 1;
    797 #endif
    798 	if (csr & APC_PM) {
    799 		u_long nextaddr, togo;
    800 
    801 		p = sc->sc_nowplaying;
    802 
    803 		togo = sc->sc_playsegsz - sc->sc_playcnt;
    804 		if (togo == 0) {
    805 			/* Roll over */
    806 			nextaddr = (u_long)p->dmamap->dm_segs[0].ds_addr;
    807 			sc->sc_playcnt = togo = APC_MAX;
    808 		} else {
    809 			nextaddr = dma->dmapnva + APC_MAX;
    810 			if (togo > APC_MAX)
    811 				togo = APC_MAX;
    812 			sc->sc_playcnt += togo;
    813 		}
    814 
    815 		dma->dmapnva = nextaddr;
    816 		dma->dmapnc = togo;
    817 
    818 		if (sc->sc_pintr != NULL)
    819 			(*sc->sc_pintr)(sc->sc_parg);
    820 
    821 		ret = 1;
    822 	}
    823 
    824 	if (csr & APC_CI) {
    825 		if (sc->sc_rintr != NULL) {
    826 			ret = 1;
    827 			(*sc->sc_rintr)(sc->sc_rarg);
    828 		}
    829 	}
    830 
    831 #ifdef DEBUG
    832 if (ret == 0) {
    833 	printf(
    834 	    "oops: csr=%s; dmapva=0x%lx,dmapc=%lu;dmapnva=0x%lx,dmapnc=%lu\n",
    835 		bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits)),
    836 		(u_long)dma->dmapva, (u_long)dma->dmapc,
    837 		(u_long)dma->dmapnva, (u_long)dma->dmapnc);
    838 	ret = 1;
    839 }
    840 #endif
    841 
    842 	return (ret);
    843 }
    844 #endif /* NAUDIO > 0 */
    845