Subject: kern/10034: turbochannel audio for NetBSD/alpha and NetBSD/pmax
To: None <gnats-bugs@gnats.netbsd.org>
From: None <g.mcgarry@qut.edu.au>
List: netbsd-bugs
Date: 05/01/2000 15:38:22
>Number:         10034
>Category:       kern
>Synopsis:       turbochannel audio for NetBSD/alpha and NetBSD/pmax
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          support
>Submitter-Id:   net
>Arrival-Date:   Mon May 01 15:39:00 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     Gregory McGarry
>Release:        1.4X
>Organization:
>Environment:
NetBSD/pmax.
>Description:
Provides a turbochannel audio driver for the am7930, found in
NetBSD/pmax and NetBSD/alpha.  I haven't tested on NetBSD/alpha,
however any changes should be minimal.  Requires kern/10029 and
kern/10032.  See also port-sparc/10033.
>How-To-Repeat:


>Fix:
*** /dev/null	Mon May  1 12:50:13 2000
--- bba.c	Mon May  1 13:42:02 2000
***************
*** 0 ****
--- 1,802 ----
+ /* $NetBSD$ */
+ 
+ /*
+  * Copyright (c) 2000 The NetBSD Foundation, Inc.
+  * All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 3. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *        This product includes software developed by the NetBSD
+  *        Foundation, Inc. and its contributors.
+  * 4. Neither the name of The NetBSD Foundation nor the names of its
+  *    contributors may be used to endorse or promote products derived
+  *    from this software without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  * POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+ /* maxine/alpha baseboard audio (bba) */
+ 
+ #include "audio.h"
+ #if NAUDIO > 0
+ 
+ #include <sys/param.h>
+ #include <sys/systm.h>
+ #include <sys/kernel.h>
+ #include <sys/device.h>
+ #include <sys/malloc.h>
+ 
+ #include <machine/bus.h>
+ #include <machine/autoconf.h>
+ #include <machine/cpu.h>
+ 
+ #include <vm/vm.h>	/* for PAGE_SIZE */
+ 
+ #include <sys/audioio.h>
+ #include <dev/audio_if.h>
+ 
+ #include <dev/ic/am7930reg.h>
+ #include <dev/ic/am7930var.h>
+ 
+ #include <dev/tc/tcvar.h>
+ #include <dev/tc/ioasicreg.h>
+ #include <dev/tc/ioasicvar.h>
+ 
+ #ifdef pmax
+ #include <pmax/pmax/maxine.h>
+ #define IOASIC_CSR_ISDN_ENABLE	XINE_CSR_ISDN_ENABLE
+ #define IOASIC_INTR_ISDN_TXLOAD	IOASIC_INTR_ISDN_DS_TXLOAD
+ #define IOASIC_INTR_ISDN_RXLOAD	IOASIC_INTR_ISDN_DS_RXLOAD
+ #ifdef IOASIC_INTR_ISDN_OVRUN
+ #undef IOASIC_INTR_ISDN_OVRUN
+ #endif
+ #define IOASIC_INTR_ISDN_OVRUN	IOASIC_INTR_ISDN_DS_OVRUN
+ #endif
+ 
+ #ifdef AUDIO_DEBUG
+ #define DPRINTF(x)	if (am7930debug) printf x
+ #else
+ #define DPRINTF(x)
+ #endif  /* AUDIO_DEBUG */
+ 
+ #define BBA_MAX_DMA_SEGMENTS	16
+ 
+ struct bba_mem {
+ 	bus_addr_t addr;
+ 	bus_size_t size;
+ 	caddr_t kva;
+         struct bba_mem *next;
+ };
+ 
+ struct bba_dma_state {
+ 	bus_dmamap_t dmam;		/* dma map */
+ 	int active;
+ 	int curseg;			/* current segment in dma buffer */
+ 	void (*intr)__P((void *));	/* higher-level audio handler */
+ 	void *intr_arg;
+ };
+ 
+ struct bba_softc {
+ 	struct am7930_softc sc_am7930;		/* glue to MI code */
+ 
+ 	bus_space_tag_t sc_bst;			/* IOASIC bus tag/handle */
+ 	bus_space_handle_t sc_bsh;
+ 	bus_dma_tag_t sc_dmat;
+ 	bus_space_handle_t sc_codec_bsh;	/* codec bus space handle */
+ 
+ 	struct bba_mem *sc_mem_head;		/* list of buffers */
+ 
+ 	struct bba_dma_state sc_tx_dma_state;
+ 	struct bba_dma_state sc_rx_dma_state;
+ };
+ 
+ int	bba_match __P((struct device *, struct cfdata *, void *));
+ void	bba_attach __P((struct device *, struct device *, void *));
+ 
+ struct cfattach bba_ca = {
+ 	sizeof(struct bba_softc), bba_match, bba_attach
+ };
+ 
+ /*
+  * Define our interface into the am7930 MI driver.
+  */
+ 
+ u_int8_t	bba_codec_iread __P((struct am7930_softc *, int));
+ u_int16_t	bba_codec_iread16 __P((struct am7930_softc *, int));
+ void	bba_codec_iwrite __P((struct am7930_softc *, int, u_int8_t));
+ void	bba_codec_iwrite16 __P((struct am7930_softc *, int, u_int16_t));
+ void	bba_onopen __P((struct am7930_softc *sc));
+ void	bba_onclose __P((struct am7930_softc *sc));
+ void	bba_output_conv __P((void *, u_int8_t *, int));
+ void	bba_input_conv __P((void *, u_int8_t *, int));
+ 
+ struct am7930_glue bba_glue = {
+ 	bba_codec_iread,
+ 	bba_codec_iwrite,
+ 	bba_codec_iread16,
+ 	bba_codec_iwrite16,
+ 	bba_onopen,
+ 	bba_onclose,
+ 	4,
+ 	bba_input_conv,
+ 	bba_output_conv,
+ };
+ 
+ /*
+  * Define our interface to the higher level audio driver.
+  */
+ 
+ int	bba_round_blocksize __P((void *, int));
+ int	bba_halt_output __P((void *));
+ int	bba_halt_input __P((void *));
+ int	bba_getdev __P((void *, struct audio_device *));
+ void	*bba_allocm __P((void *, int, size_t, int, int));
+ void	bba_freem __P((void *, void *, int));
+ size_t	bba_round_buffersize __P((void *, int, size_t));
+ int	bba_trigger_output __P((void *, void *, void *, int,
+ 		void (*)(void *), void *, struct audio_params *));
+ int	bba_trigger_input __P((void *, void *, void *, int,
+ 		void (*)(void *), void *, struct audio_params *));
+ 
+ struct audio_hw_if sa_hw_if = {
+ 	am7930_open,
+ 	am7930_close,
+ 	0,
+ 	am7930_query_encoding,
+ 	am7930_set_params,
+ 	bba_round_blocksize,		/* md */
+ 	am7930_commit_settings,
+ 	0,
+ 	0,
+ 	0,
+ 	0,
+ 	bba_halt_output,		/* md */
+ 	bba_halt_input,			/* md */
+ 	0,
+ 	bba_getdev,
+ 	0,
+ 	am7930_set_port,
+ 	am7930_get_port,
+ 	am7930_query_devinfo,
+ 	bba_allocm,			/* md */
+ 	bba_freem,			/* md */
+ 	bba_round_buffersize,		/* md */
+ 	0,
+ 	am7930_get_props,
+ 	bba_trigger_output,		/* md */
+ 	bba_trigger_input		/* md */
+ };
+ 
+ struct audio_device bba_device = {
+ 	"am7930",
+ 	"x",
+ 	"bba"
+ };
+ 
+ int	bba_intr __P((void *));
+ void	bba_reset __P((struct bba_softc *, int));
+ void	bba_codec_dwrite __P((struct am7930_softc *, int, u_int8_t));
+ u_int8_t	bba_codec_dread __P((struct am7930_softc *, int));
+ 
+ int bba_match(parent, cf, aux)
+ 	struct device *parent;
+ 	struct cfdata *cf;
+ 	void *aux;
+ {
+ 	struct ioasicdev_attach_args *ia = aux;
+ 
+         if (strcmp(ia->iada_modname, "isdn") != 0 &&
+             strcmp(ia->iada_modname, "AMD79c30") != 0)
+                 return 0;
+ 
+ 	return 1;
+ }
+ 
+ 
+ void
+ bba_attach(parent, self, aux)
+ 	struct device *parent;
+ 	struct device *self;
+ 	void *aux;
+ {
+ 	struct ioasicdev_attach_args *ia = aux;
+ 	struct bba_softc *sc = (struct bba_softc *)self;
+ 	struct am7930_softc *asc = &sc->sc_am7930;
+ 
+ 	sc->sc_bst = ((struct ioasic_softc *)parent)->sc_bst;
+ 	sc->sc_bsh = ((struct ioasic_softc *)parent)->sc_bsh;
+ 	sc->sc_dmat = ((struct ioasic_softc *)parent)->sc_dmat;
+ 
+ 	/* get the bus space handle for codec */
+ 	if (bus_space_subregion(sc->sc_bst, sc->sc_bsh,
+ 		ia->iada_offset, 0, &sc->sc_codec_bsh)) {
+ 		printf("%s: unable to map device\n", asc->sc_dev.dv_xname);
+ 		return;
+ 	}
+ 
+ 	printf("\n");
+ 
+ 	bba_reset(sc,1);
+ 
+ 	/*
+ 	 * Set up glue for MI code early; we use some of it here.
+ 	 */
+ 	asc->sc_glue = &bba_glue;
+ 
+ 	/*
+ 	 *  MI initialisation.  We will be doing DMA.
+ 	 */
+ 	am7930_init(asc, AUDIOAMD_DMA_MODE);
+ 
+ 	ioasic_intr_establish(parent, ia->iada_cookie, TC_IPL_NONE,
+ 		 bba_intr, sc);
+ 
+ 	audio_attach_mi(&sa_hw_if, asc, &asc->sc_dev);
+ }
+ 
+ 
+ void
+ bba_onopen(sc)
+ 	struct am7930_softc *sc;
+ {
+ 	bba_reset((struct bba_softc *)sc, 0);
+ }
+ 
+ 
+ void
+ bba_onclose(sc)
+ 	struct am7930_softc *sc;
+ {
+ 	bba_halt_input((struct bba_softc *)sc);
+ 	bba_halt_output((struct bba_softc *)sc);
+ }
+ 
+ 
+ void
+ bba_reset(sc, reset)
+ 	struct bba_softc *sc;
+ 	int reset;
+ {
+ 	u_int32_t ssr;
+ 
+ 	/* disable any DMA and reset the codec */
+ 	ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
+ 	ssr &= ~(IOASIC_CSR_DMAEN_ISDN_T | IOASIC_CSR_DMAEN_ISDN_R);
+ 	if (reset)
+ 		ssr &= ~IOASIC_CSR_ISDN_ENABLE;
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
+ 	DELAY(10);	/* 400ns required for codec to reset */
+ 
+ 	/* initialise DMA pointers */
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, -1);
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, -1);
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, -1);
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, -1);
+ 
+ 	/* take out of reset state */
+ 	if (reset) {
+ 		ssr |= IOASIC_CSR_ISDN_ENABLE;
+ 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
+ 	}
+ 
+ }
+ 
+ 
+ void *
+ bba_allocm(addr, direction, size, pool, flags)
+ 	void *addr;
+ 	int direction;
+ 	size_t size;
+ 	int pool, flags;
+ {
+ 	struct am7930_softc *asc = addr;
+ 	struct bba_softc *sc = addr;
+ 	bus_dma_segment_t seg;
+ 	int rseg;
+ 	caddr_t kva;
+ 	struct bba_mem *m;
+ 	int state = 0;
+ 
+ 	DPRINTF(("bba_allocm: size = %d\n",size));
+ 
+ 	if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg,
+ 		1, &rseg, BUS_DMA_NOWAIT)) {
+ 		printf("%s: can't allocate DMA buffer\n",
+ 			asc->sc_dev.dv_xname);
+ 		goto bad;
+ 	}
+ 	state |= 1;
+ 
+ 	if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
+ 		&kva, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
+ 		printf("%s: can't map DMA buffer\n", asc->sc_dev.dv_xname);
+ 		goto bad;
+ 	}
+ 	state |= 2;
+ 
+ 	m = malloc(sizeof(struct bba_mem), pool, flags);
+ 	if (m == NULL)
+ 		goto bad;
+ 	m->addr = seg.ds_addr;
+ 	m->size = seg.ds_len;
+         m->kva = kva;
+         m->next = sc->sc_mem_head;
+         sc->sc_mem_head = m;
+ 
+         return (void *)kva;
+ 
+ bad:
+ 	if (state & 2)
+ 		bus_dmamem_unmap(sc->sc_dmat, kva, size);
+ 	if (state & 1)
+ 		bus_dmamem_free(sc->sc_dmat, &seg, 1);
+ 	return NULL;
+ }
+ 
+ 
+ void
+ bba_freem(addr, ptr, pool)
+ 	void *addr;
+ 	void *ptr;
+ 	int pool;
+ {
+ 	struct bba_softc *sc = addr;
+         struct bba_mem **mp, *m;
+ 	bus_dma_segment_t seg;
+         caddr_t kva = (caddr_t)addr;
+ 
+ 	for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != kva;
+ 		mp = &(*mp)->next)
+ 		/* nothing */ ;
+ 	m = *mp;
+ 	if (m != NULL) {
+ 		printf("bba_freem: freeing unallocted memory\n");
+ 		return;
+ 	}
+ 	*mp = m->next;
+ 	bus_dmamem_unmap(sc->sc_dmat, kva, m->size);
+ 
+         seg.ds_addr = m->addr;
+         seg.ds_len = m->size;
+ 	bus_dmamem_free(sc->sc_dmat, &seg, 1);
+         free(m, pool);
+ }
+ 
+ 
+ size_t
+ bba_round_buffersize(addr, direction, size)
+ 	void *addr;
+ 	int direction;
+ 	size_t size;
+ {
+ 	DPRINTF(("bba_round_buffersize: size=%d\n", size));
+ 
+ #define BBA_BUFFERSIZE (BBA_MAX_DMA_SEGMENTS * PAGE_SIZE)
+ 	return  (size > BBA_BUFFERSIZE ? BBA_BUFFERSIZE : round_page(size));
+ }
+ 
+ 
+ int
+ bba_halt_output(addr)
+ 	void *addr;
+ {
+ 	struct bba_softc *sc = addr;
+ 	struct bba_dma_state *d = &sc->sc_tx_dma_state;
+ 	u_int32_t ssr;
+ 
+ 	/* disable any DMA */
+ 	ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
+ 	ssr &= ~IOASIC_CSR_DMAEN_ISDN_T;
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, -1);
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, -1);
+ 
+ 	if (d->active) {
+ 		bus_dmamap_unload(sc->sc_dmat, d->dmam);
+ 		bus_dmamap_destroy(sc->sc_dmat, d->dmam);
+ 		d->active = 0;
+ 	}
+ 
+ 	return 0;
+ }
+ 
+ 
+ int
+ bba_halt_input(addr)
+ 	void *addr;
+ {
+ 	struct bba_softc *sc = addr;
+ 	struct bba_dma_state *d = &sc->sc_rx_dma_state;
+ 	u_int32_t ssr;
+ 
+ 	/* disable any DMA */
+ 	ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
+ 	ssr &= ~IOASIC_CSR_DMAEN_ISDN_R;
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, -1);
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, -1);
+ 
+ 	if (d->active) {
+ 		bus_dmamap_unload(sc->sc_dmat, d->dmam);
+ 		bus_dmamap_destroy(sc->sc_dmat, d->dmam);
+ 		d->active = 0;
+ 	}
+ 
+ 	return 0;
+ }
+ 
+ 
+ int
+ bba_getdev(addr, retp)
+ 	void *addr;
+ 	struct audio_device *retp;
+ {
+ 	*retp = bba_device;
+ 	return 0;
+ }
+ 
+ 
+ int
+ bba_trigger_output(addr, start, end, blksize, intr, arg, param)
+ 	void *addr;
+ 	void *start, *end;
+ 	int blksize;
+ 	void (*intr) __P((void *));
+ 	void *arg;
+ 	struct audio_params *param;
+ {
+ 	struct bba_softc *sc = addr;
+ 	struct bba_dma_state *d = &sc->sc_tx_dma_state;
+ 	u_int32_t ssr;
+         tc_addr_t phys, nphys;
+ 	int state = 0;
+ 
+ 	DPRINTF(("bba_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
+ 		addr, start, end, blksize, intr, arg));
+ 
+ 	if (bus_dmamap_create(sc->sc_dmat, (char *)end - (char *)start,
+ 		BBA_MAX_DMA_SEGMENTS, PAGE_SIZE, 0, BUS_DMA_NOWAIT, &d->dmam)) {
+ 		printf("bba_trigger_output: can't create DMA map\n");
+ 		goto bad;
+ 	}
+ 	state |= 1;
+ 
+ 	if (bus_dmamap_load(sc->sc_dmat, d->dmam, start,
+ 		(char *)end - (char *)start, NULL, BUS_DMA_NOWAIT)) {
+ 		printf("bba_trigger_output: can't load DMA map\n");
+ 		goto bad;
+ 	}
+ 	state |= 2;
+ 
+ 	/* disable any DMA */
+ 	ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
+ 	ssr &= ~IOASIC_CSR_DMAEN_ISDN_T;
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
+ 
+ 	d->intr = intr;
+ 	d->intr_arg = arg;
+ 	d->curseg = 1;
+ 
+ 	/* get physical address of buffer start */
+ 	phys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
+ 	nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg+1].ds_addr;
+ 
+ 	/* setup DMA pointer */
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR,
+ 		IOASIC_DMA_ADDR(phys));
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR,
+ 		IOASIC_DMA_ADDR(nphys));
+ 
+ 	/* kick off DMA */
+ 	ssr |= IOASIC_CSR_DMAEN_ISDN_T;
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
+ 
+ 	wbflush();
+ 
+ 	d->active = 1;
+ 
+ 	return 0;
+ 
+ bad:
+ 	if (state & 2)
+ 		bus_dmamap_unload(sc->sc_dmat, d->dmam);
+ 	if (state & 1)
+ 		bus_dmamap_destroy(sc->sc_dmat, d->dmam);
+ 	return 1;
+ }
+ 
+ 
+ int
+ bba_trigger_input(addr, start, end, blksize, intr, arg, param)
+ 	void *addr;
+ 	void *start, *end;
+ 	int blksize;
+ 	void (*intr) __P((void *));
+ 	void *arg;
+ 	struct audio_params *param;
+ {
+ 	struct bba_softc *sc = (struct bba_softc *)addr;
+ 	struct bba_dma_state *d = &sc->sc_rx_dma_state;
+         tc_addr_t phys, nphys;
+ 	u_int32_t ssr;
+ 	int state = 0;
+ 
+ 	DPRINTF(("bba_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
+ 		addr, start, end, blksize, intr, arg));
+ 
+ 	if (bus_dmamap_create(sc->sc_dmat, (char *)end - (char *)start,
+ 		BBA_MAX_DMA_SEGMENTS, PAGE_SIZE, 0, BUS_DMA_NOWAIT, &d->dmam)) {
+ 		printf("bba_trigger_input: can't create DMA map\n");
+ 		goto bad;
+ 	}
+ 	state |= 1;
+ 
+ 	if (bus_dmamap_load(sc->sc_dmat, d->dmam, start,
+ 		(char *)end - (char *)start, NULL, BUS_DMA_NOWAIT)) {
+ 		printf("bba_trigger_input: can't load DMA map\n");
+ 		goto bad;
+ 	}
+ 	state |= 2;
+ 
+ 	/* disable any DMA */
+ 	ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
+ 	ssr &= ~IOASIC_CSR_DMAEN_ISDN_R;
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
+ 
+ 	d->intr = intr;
+ 	d->intr_arg = arg;
+ 	d->curseg = 1;
+ 
+ 	/* get physical address of buffer start */
+ 	phys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
+ 	nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg+1].ds_addr;
+ 
+ 	/* setup DMA pointer */
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR,
+ 		IOASIC_DMA_ADDR(phys));
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR,
+ 		IOASIC_DMA_ADDR(nphys));
+ 
+ 	/* kick off DMA */
+ 	ssr |= IOASIC_CSR_DMAEN_ISDN_R;
+ 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
+ 
+ 	wbflush();
+ 
+ 	d->active = 1;
+ 
+ 	return 0;
+ 
+ bad:
+ 	if (state & 2)
+ 		bus_dmamap_unload(sc->sc_dmat, d->dmam);
+ 	if (state & 1)
+ 		bus_dmamap_destroy(sc->sc_dmat, d->dmam);
+ 	return 1;
+ }
+ 
+ int 
+ bba_intr(addr)
+ 	void *addr;
+ {
+ 	struct bba_softc *sc = addr;
+ 	struct bba_dma_state *d;
+ 	tc_addr_t nphys;
+ 	int s, mask;
+ 
+ 	s = splaudio();
+ 
+ 	mask = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
+ 
+ 	if (mask & IOASIC_INTR_ISDN_TXLOAD) {
+ 		d = &sc->sc_tx_dma_state;
+ 		d->curseg = (d->curseg+1) % d->dmam->dm_nsegs;
+ 		nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
+ 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
+ 			IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys));
+ 		if (d->intr != NULL)
+ 			(*d->intr)(d->intr_arg);
+ 	}
+ 	if (mask & IOASIC_INTR_ISDN_RXLOAD) {
+ 		d = &sc->sc_rx_dma_state;
+ 		d->curseg = (d->curseg+1) % d->dmam->dm_nsegs;
+ 		nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
+ 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
+ 			IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys));
+ 		if (d->intr != NULL)
+ 			(*d->intr)(d->intr_arg);
+ 	}
+ 
+ 	splx(s);
+ 
+ 	return 0;
+ }
+ 
+ 
+ void
+ bba_input_conv(v, p, cc)
+ 	void *v;
+ 	u_int8_t *p;
+ 	int cc;
+ {
+ 	u_int8_t *q = p;
+ 
+ 	DPRINTF(("bba_input_conv(): v=%p p=%p cc=%d\n", v, p, cc));
+ 
+ 	/*
+ 	 * p points start of buffer
+ 	 * cc is the number of bytes in the destination buffer
+ 	 */
+ 
+ 	while (--cc >= 0) {
+ 		*p = ((*(u_int32_t *)q)>>16)&0xff;
+ 		q += 4;
+ 		p++;
+ 	}
+ }
+ 
+ 
+ void
+ bba_output_conv(v, p, cc)
+ 	void *v;
+ 	u_int8_t *p;
+ 	int cc;
+ {
+ 	u_int8_t *q = p;
+ 
+ 	DPRINTF(("bba_output_conv(): v=%p p=%p cc=%d\n", v, p, cc));
+ 
+ 	/*
+ 	 * p points start of buffer
+ 	 * cc is the number of bytes in the source buffer
+ 	 */
+ 
+ 	p += cc;
+ 	q += cc * 4;
+ 	while (--cc >= 0) {
+ 		q -= 4;
+ 		p -= 1;
+ 		*(u_int32_t *)q = (*p<<16);
+ 	}
+ }
+ 
+ 
+ int
+ bba_round_blocksize(addr, blk)
+ 	void *addr;
+ 	int blk;
+ {
+ 	return (PAGE_SIZE);
+ }
+ 
+ 
+ /* indirect write */
+ void
+ bba_codec_iwrite(sc, reg, val)
+ 	struct am7930_softc *sc;
+ 	int reg;
+ 	u_int8_t val;
+ {
+ 	DPRINTF(("bba_codec_iwrite(): sc=%p, reg=%d, val=%d\n",sc,reg,val));
+ 
+ 	bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
+ 	bba_codec_dwrite(sc, AM7930_DREG_DR, val);
+ }
+ 
+ 
+ void
+ bba_codec_iwrite16(sc, reg, val)
+ 	struct am7930_softc *sc;
+ 	int reg;
+ 	u_int16_t val;
+ {
+ 	DPRINTF(("bba_codec_iwrite16(): sc=%p, reg=%d, val=%d\n",sc,reg,val));
+ 
+ 	bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
+ #if 0
+ 	bba_codec_dwrite(sc, AM7930_DREG_DR, val>>8);
+ 	bba_codec_dwrite(sc, AM7930_DREG_DR, val);
+ #else
+ 	bba_codec_dwrite(sc, AM7930_DREG_DR, val);
+ 	bba_codec_dwrite(sc, AM7930_DREG_DR, val>>8);
+ #endif
+ }
+ 
+ 
+ u_int16_t
+ bba_codec_iread16(sc, reg)
+ 	struct am7930_softc *sc;
+ 	int reg;
+ {
+ 	u_int16_t val;
+ 	DPRINTF(("bba_codec_iread16(): sc=%p, reg=%d\n",sc,reg));
+ 
+ 	bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
+ #if 0
+ 	bba_codec_dwrite(sc, AM7930_DREG_DR, val>>8);
+ 	bba_codec_dwrite(sc, AM7930_DREG_DR, val);
+ #else
+ 	val = bba_codec_dread(sc, AM7930_DREG_DR) << 8;
+ 	val |= bba_codec_dread(sc, AM7930_DREG_DR);
+ #endif
+ 
+ 	return val;
+ }
+ 
+ 
+ /* indirect read */
+ u_int8_t
+ bba_codec_iread(sc, reg)
+ 	struct am7930_softc *sc;
+ 	int reg;
+ {
+ 	u_int8_t val;
+ 
+ 	DPRINTF(("bba_codec_iread(): sc=%p, reg=%d\n",sc,reg));
+ 
+ 	bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
+ 	val = bba_codec_dread(sc, AM7930_DREG_DR);
+ 
+ 	DPRINTF(("read 0x%x (%d)\n", val, val));
+ 
+ 	return val;
+ }
+ 
+ 
+ #define TIMETOWASTE	50
+ 
+ /* direct write */
+ void
+ bba_codec_dwrite(asc, reg, val)
+ 	struct am7930_softc *asc;
+ 	int reg;
+ 	u_int8_t val;
+ {
+ 	struct bba_softc *sc = (struct bba_softc *)asc;
+ 	int i;
+ 
+ 	DPRINTF(("bba_codec_dwrite(): sc=%p, reg=%d, val=%d\n",sc,reg,val));
+ 
+ 	bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, (reg<<6), val);
+ 
+ 	for (i=0; i<TIMETOWASTE; i++) {};
+ }
+ 
+ /* direct read */
+ u_int8_t
+ bba_codec_dread(asc, reg)
+ 	struct am7930_softc *asc;
+ 	int reg;
+ {
+ 	struct bba_softc *sc = (struct bba_softc *)asc;
+ 	u_int8_t val;
+ 	int i;
+ 
+ 	DPRINTF(("bba_codec_dread(): sc=%p, reg=%d\n",sc,reg));
+ 
+ 	val = bus_space_read_1(sc->sc_bst, sc->sc_codec_bsh, (reg<<6));
+ 
+ 	for (i=0; i<TIMETOWASTE; i++) {};
+ 
+ 	return val;
+ }
+ 
+ #endif /* NAUDIO > 0 */
*** files.tc.orig	Mon May  1 13:43:16 2000
--- files.tc	Mon May  1 11:43:20 2000
***************
*** 24,33 ****
  file	dev/tc/if_le_ioasic.c		le_ioasic
  file	dev/tc/if_le_tc.c		le_tc
  
! # ioasic audio
! attach audioamd at ioasic with am7930_ioasic
! file	dev/tc/am7930_ioasic.c		am7930_ioasic
! 
  
  # DEC DEFTA TC FDDI Controller
  device	fta: pdq, fddi, ifnet, arp
--- 24,33 ----
  file	dev/tc/if_le_ioasic.c		le_ioasic
  file	dev/tc/if_le_tc.c		le_tc
  
! # baseboard audio
! device  bba: audio,am7930
! attach  bba at ioasic
! file    dev/tc/bba.c                    bba
  
  # DEC DEFTA TC FDDI Controller
  device	fta: pdq, fddi, ifnet, arp
*** dec_maxine.c.orig	Mon May  1 13:46:40 2000
--- dec_maxine.c	Mon May  1 13:29:40 2000
***************
*** 326,338 ****
  			CHECKINTR(SYS_DEV_LANCE, IOASIC_INTR_LANCE);
  			CHECKINTR(SYS_DEV_SCSI, IOASIC_INTR_SCSI);
  			/* CHECKINTR(SYS_DEV_OPT2, XINE_INTR_VINT);	*/
! 			/* CHECKINTR(SYS_DEV_ISDN, IOASIC_INTR_ISDN);	*/
  			/* CHECKINTR(SYS_DEV_FDC, IOASIC_INTR_FDC);	*/
  			CHECKINTR(SYS_DEV_OPT1, XINE_INTR_TC_1); 
  			CHECKINTR(SYS_DEV_OPT0, XINE_INTR_TC_0); 
   
! #define ERRORS	(IOASIC_INTR_ISDN_OVRUN|IOASIC_INTR_ISDN_READ_E|IOASIC_INTR_SCSI_OVRUN|IOASIC_INTR_SCSI_READ_E|IOASIC_INTR_LANCE_READ_E)
! #define PTRLOAD (IOASIC_INTR_ISDN_PTR_LOAD|IOASIC_INTR_SCSI_PTR_LOAD)
   
  #if 0	
  	if (can_serve & IOASIC_INTR_SCSI_PTR_LOAD) {
--- 326,338 ----
  			CHECKINTR(SYS_DEV_LANCE, IOASIC_INTR_LANCE);
  			CHECKINTR(SYS_DEV_SCSI, IOASIC_INTR_SCSI);
  			/* CHECKINTR(SYS_DEV_OPT2, XINE_INTR_VINT);	*/
! 			CHECKINTR(SYS_DEV_ISDN, (IOASIC_INTR_ISDN_DS_TXLOAD | IOASIC_INTR_ISDN_DS_RXLOAD));
  			/* CHECKINTR(SYS_DEV_FDC, IOASIC_INTR_FDC);	*/
  			CHECKINTR(SYS_DEV_OPT1, XINE_INTR_TC_1); 
  			CHECKINTR(SYS_DEV_OPT0, XINE_INTR_TC_0); 
   
! #define ERRORS	(IOASIC_INTR_ISDN|IOASIC_INTR_ISDN_OVRUN|IOASIC_INTR_ISDN_READ_E|IOASIC_INTR_SCSI_OVRUN|IOASIC_INTR_SCSI_READ_E|IOASIC_INTR_LANCE_READ_E)
! #define PTRLOAD (IOASIC_INTR_ISDN_DS_TXLOAD|IOASIC_INTR_ISDN_DS_RXLOAD|IOASIC_INTR_SCSI_PTR_LOAD)
   
  #if 0	
  	if (can_serve & IOASIC_INTR_SCSI_PTR_LOAD) {
*** conf.c.orig	Mon May  1 13:48:13 2000
--- conf.c	Mon May  1 11:47:36 2000
***************
*** 58,64 ****
  bdev_decl(st);
  bdev_decl(sw);
  bdev_decl(vnd);
! 
  #include "rz.h"
  #include "tz.h"
  bdev_decl(rz);
--- 58,65 ----
  bdev_decl(st);
  bdev_decl(sw);
  bdev_decl(vnd);
! #include "audio.h"
! cdev_decl(audio);
  #include "rz.h"
  #include "tz.h"
  bdev_decl(rz);
***************
*** 285,290 ****
--- 286,292 ----
  	cdev_disk_init(NRAID,raid),	/* 96: RAIDframe disk driver */
  	cdev_disk_init(NMD,md),	/* 97: memory disk  driver */
  	cdev_fbm_init(NPX,px),	/* 98: PixelStamp board driver */
+ 	cdev_audio_init(NAUDIO,audio),  /* 99 generic audio I/O */
  };
  int	nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]);
  

>Release-Note:
>Audit-Trail:
>Unformatted: