bba.c revision 1.4
1/*	$OpenBSD: bba.c,v 1.4 2014/07/12 18:48:52 tedu Exp $	*/
2/* $NetBSD: bba.c,v 1.38 2011/06/04 01:27:57 tsutsui Exp $ */
3/*
4 * Copyright (c) 2011 Miodrag Vallat.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18/*
19 * Copyright (c) 2000 The NetBSD Foundation, Inc.
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 *    notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 *    notice, this list of conditions and the following disclaimer in the
29 *    documentation and/or other materials provided with the distribution.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
32 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
33 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
35 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGE.
42 */
43
44/* maxine/alpha baseboard audio (bba) */
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/kernel.h>
49#include <sys/device.h>
50#include <sys/malloc.h>
51
52#include <machine/autoconf.h>
53#include <machine/bus.h>
54#include <machine/cpu.h>
55
56#include <sys/audioio.h>
57#include <dev/audio_if.h>
58
59#include <dev/ic/am7930reg.h>
60#include <dev/ic/am7930var.h>
61
62#include <dev/tc/tcvar.h>
63#include <dev/tc/ioasicreg.h>
64#include <dev/tc/ioasicvar.h>
65
66#ifdef AUDIO_DEBUG
67#define DPRINTF(x)	if (am7930debug) printf x
68#else
69#define DPRINTF(x)
70#endif  /* AUDIO_DEBUG */
71
72#define BBA_MAX_DMA_SEGMENTS	16
73#define BBA_DMABUF_SIZE		(BBA_MAX_DMA_SEGMENTS*IOASIC_DMA_BLOCKSIZE)
74#define BBA_DMABUF_ALIGN	IOASIC_DMA_BLOCKSIZE
75#define BBA_DMABUF_BOUNDARY	0
76
77struct bba_mem {
78	struct bba_mem *next;
79	bus_addr_t addr;
80	bus_size_t size;
81	void *kva;
82};
83
84struct bba_dma_state {
85	bus_dmamap_t dmam;		/* DMA map */
86	size_t size;
87	int active;
88	int curseg;			/* current segment in DMA buffer */
89	void (*intr)(void *);		/* higher-level audio handler */
90	void *intr_arg;
91};
92
93struct bba_softc {
94	struct am7930_softc sc_am7930;		/* glue to MI code */
95
96	bus_space_tag_t sc_bst;			/* IOASIC bus tag/handle */
97	bus_space_handle_t sc_bsh;
98	bus_dma_tag_t sc_dmat;
99	bus_space_handle_t sc_codec_bsh;	/* codec bus space handle */
100
101	struct bba_mem *sc_mem_head;		/* list of buffers */
102
103	struct bba_dma_state sc_tx_dma_state;
104	struct bba_dma_state sc_rx_dma_state;
105};
106
107int	bba_match(struct device *, void *, void *);
108void	bba_attach(struct device *, struct device *, void *);
109
110struct cfdriver bba_cd = {
111	NULL, "bba", DV_DULL
112};
113
114const struct cfattach bba_ca = {
115	sizeof(struct bba_softc), bba_match, bba_attach
116};
117
118/*
119 * Define our interface into the am7930 MI driver.
120 */
121
122uint8_t	 bba_codec_iread(struct am7930_softc *, int);
123uint16_t bba_codec_iread16(struct am7930_softc *, int);
124void	 bba_codec_iwrite(struct am7930_softc *, int, uint8_t);
125void	 bba_codec_iwrite16(struct am7930_softc *, int, uint16_t);
126void	 bba_onopen(struct am7930_softc *);
127void	 bba_onclose(struct am7930_softc *);
128void	 bba_output_conv(void *, u_char *, int);
129void	 bba_input_conv(void *, u_char *, int);
130
131struct am7930_glue bba_glue = {
132	bba_codec_iread,
133	bba_codec_iwrite,
134	bba_codec_iread16,
135	bba_codec_iwrite16,
136	bba_onopen,
137	bba_onclose,
138	4,
139	bba_input_conv,
140	bba_output_conv
141};
142
143/*
144 * Define our interface to the higher level audio driver.
145 */
146
147int	bba_round_blocksize(void *, int);
148int	bba_halt_output(void *);
149int	bba_halt_input(void *);
150int	bba_getdev(void *, struct audio_device *);
151void	*bba_allocm(void *, int, size_t, int, int);
152void	bba_freem(void *, void *, int);
153size_t	bba_round_buffersize(void *, int, size_t);
154int	bba_get_props(void *);
155paddr_t	bba_mappage(void *, void *, off_t, int);
156int	bba_trigger_output(void *, void *, void *, int,
157	    void (*)(void *), void *, struct audio_params *);
158int	bba_trigger_input(void *, void *, void *, int,
159	    void (*)(void *), void *, struct audio_params *);
160
161struct audio_hw_if bba_hw_if = {
162	am7930_open,
163	am7930_close,
164	NULL,
165	am7930_query_encoding,
166	am7930_set_params,
167	bba_round_blocksize,		/* md */
168	am7930_commit_settings,
169	NULL,
170	NULL,
171	NULL,
172	NULL,
173	bba_halt_output,		/* md */
174	bba_halt_input,			/* md */
175	NULL,
176	bba_getdev,
177	NULL,
178	am7930_set_port,
179	am7930_get_port,
180	am7930_query_devinfo,
181	bba_allocm,			/* md */
182	bba_freem,			/* md */
183	bba_round_buffersize,		/* md */
184	bba_mappage,
185	bba_get_props,
186	bba_trigger_output,		/* md */
187	bba_trigger_input,		/* md */
188	NULL
189};
190
191static struct audio_device bba_device = {
192	"am7930",
193	"x",
194	"bba"
195};
196
197int	bba_intr(void *);
198void	bba_reset(struct bba_softc *, int);
199void	bba_codec_dwrite(struct am7930_softc *, int, uint8_t);
200uint8_t	bba_codec_dread(struct am7930_softc *, int);
201
202int
203bba_match(struct device *parent, void *vcf, void *aux)
204{
205	struct ioasicdev_attach_args *ia = aux;
206
207	if (strcmp(ia->iada_modname, "isdn") != 0 &&
208	    strcmp(ia->iada_modname, "AMD79c30") != 0)
209		return 0;
210
211	return 1;
212}
213
214void
215bba_attach(struct device *parent, struct device *self, void *aux)
216{
217	struct ioasicdev_attach_args *ia = aux;
218	struct bba_softc *sc = (struct bba_softc *)self;
219	struct ioasic_softc *iosc = (struct ioasic_softc *)parent;
220
221	sc->sc_bst = iosc->sc_bst;
222	sc->sc_bsh = iosc->sc_bsh;
223	sc->sc_dmat = iosc->sc_dmat;
224
225	/* get the bus space handle for codec */
226	if (bus_space_subregion(sc->sc_bst, sc->sc_bsh,
227	    ia->iada_offset, 0, &sc->sc_codec_bsh)) {
228		printf(": unable to map device\n");
229		return;
230	}
231
232	printf("\n");
233
234	bba_reset(sc,1);
235
236	/*
237	 * Set up glue for MI code early; we use some of it here.
238	 */
239	sc->sc_am7930.sc_glue = &bba_glue;
240
241	/*
242	 *  MI initialisation.  We will be doing DMA.
243	 */
244	am7930_init(&sc->sc_am7930, AUDIOAMD_DMA_MODE);
245
246	ioasic_intr_establish(parent, ia->iada_cookie, IPL_AUDIO,
247	    bba_intr, sc, self->dv_xname);
248
249	audio_attach_mi(&bba_hw_if, sc, self);
250}
251
252void
253bba_onopen(struct am7930_softc *sc)
254{
255}
256
257void
258bba_onclose(struct am7930_softc *sc)
259{
260}
261
262void
263bba_reset(struct bba_softc *sc, int reset)
264{
265	uint32_t ssr;
266
267	/* disable any DMA and reset the codec */
268	ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
269	ssr &= ~(IOASIC_CSR_DMAEN_ISDN_T | IOASIC_CSR_DMAEN_ISDN_R);
270	if (reset)
271		ssr &= ~IOASIC_CSR_ISDN_ENABLE;
272	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
273	DELAY(10);	/* 400ns required for codec to reset */
274
275	/* initialise DMA pointers */
276	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 0);
277	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 0);
278	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 0);
279	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 0);
280
281	/* take out of reset state */
282	if (reset) {
283		ssr |= IOASIC_CSR_ISDN_ENABLE;
284		bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
285	}
286
287}
288
289void *
290bba_allocm(void *v, int direction, size_t size, int mtype, int flags)
291{
292	struct bba_softc *sc = v;
293	bus_dma_segment_t seg;
294	int rseg;
295	caddr_t kva;
296	struct bba_mem *m;
297	int w;
298	int state;
299
300	DPRINTF(("bba_allocm: size = %zu\n", size));
301	state = 0;
302	w = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
303
304	if (bus_dmamem_alloc(sc->sc_dmat, size, BBA_DMABUF_ALIGN,
305	    BBA_DMABUF_BOUNDARY, &seg, 1, &rseg, w)) {
306		printf("%s: can't allocate DMA buffer\n",
307		    sc->sc_am7930.sc_dev.dv_xname);
308		goto bad;
309	}
310	state |= 1;
311
312	if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
313	    &kva, w | BUS_DMA_COHERENT)) {
314		printf("%s: can't map DMA buffer\n",
315		    sc->sc_am7930.sc_dev.dv_xname);
316		goto bad;
317	}
318	state |= 2;
319
320	m = malloc(sizeof(struct bba_mem), mtype, flags | M_CANFAIL);
321	if (m == NULL)
322		goto bad;
323	m->addr = seg.ds_addr;
324	m->size = seg.ds_len;
325	m->kva = kva;
326	m->next = sc->sc_mem_head;
327	sc->sc_mem_head = m;
328
329	return (void *)kva;
330
331bad:
332	if (state & 2)
333		bus_dmamem_unmap(sc->sc_dmat, kva, size);
334	if (state & 1)
335		bus_dmamem_free(sc->sc_dmat, &seg, 1);
336	return NULL;
337}
338
339void
340bba_freem(void *v, void *ptr, int mtype)
341{
342	struct bba_softc *sc = v;
343	struct bba_mem **mp, *m;
344	bus_dma_segment_t seg;
345	void *kva;
346
347	kva = (void *)ptr;
348	for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next)
349		continue;
350	m = *mp;
351	if (m == NULL) {
352		printf("bba_freem: freeing unallocated memory\n");
353		return;
354	}
355	*mp = m->next;
356	bus_dmamem_unmap(sc->sc_dmat, kva, m->size);
357
358	seg.ds_addr = m->addr;
359	seg.ds_len = m->size;
360	bus_dmamem_free(sc->sc_dmat, &seg, 1);
361	free(m, mtype, 0);
362}
363
364size_t
365bba_round_buffersize(void *v, int direction, size_t size)
366{
367
368	DPRINTF(("bba_round_buffersize: size=%zu\n", size));
369	return size > BBA_DMABUF_SIZE ? BBA_DMABUF_SIZE :
370	    roundup(size, IOASIC_DMA_BLOCKSIZE);
371}
372
373int
374bba_halt_output(void *v)
375{
376	struct bba_softc *sc = v;
377	struct bba_dma_state *d;
378	uint32_t ssr;
379
380	mtx_enter(&audio_lock);
381	d = &sc->sc_tx_dma_state;
382	/* disable any DMA */
383	ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
384	ssr &= ~IOASIC_CSR_DMAEN_ISDN_T;
385	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
386	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 0);
387	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 0);
388	mtx_leave(&audio_lock);
389
390	if (d->active) {
391		bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size,
392		    BUS_DMASYNC_POSTWRITE);
393		bus_dmamap_unload(sc->sc_dmat, d->dmam);
394		bus_dmamap_destroy(sc->sc_dmat, d->dmam);
395		d->active = 0;
396	}
397
398	return 0;
399}
400
401int
402bba_halt_input(void *v)
403{
404	struct bba_softc *sc = v;
405	struct bba_dma_state *d;
406	uint32_t ssr;
407
408	mtx_enter(&audio_lock);
409	d = &sc->sc_rx_dma_state;
410	/* disable any DMA */
411	ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
412	ssr &= ~IOASIC_CSR_DMAEN_ISDN_R;
413	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
414	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 0);
415	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 0);
416	mtx_leave(&audio_lock);
417
418	if (d->active) {
419		bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size,
420		    BUS_DMASYNC_POSTREAD);
421		bus_dmamap_unload(sc->sc_dmat, d->dmam);
422		bus_dmamap_destroy(sc->sc_dmat, d->dmam);
423		d->active = 0;
424	}
425
426	return 0;
427}
428
429int
430bba_getdev(void *v, struct audio_device *retp)
431{
432	*retp = bba_device;
433	return 0;
434}
435
436int
437bba_trigger_output(void *v, void *start, void *end, int blksize,
438    void (*intr)(void *), void *arg, struct audio_params *param)
439{
440	struct bba_softc *sc = v;
441	struct bba_dma_state *d;
442	uint32_t ssr;
443	tc_addr_t phys, nphys;
444	int state;
445
446	DPRINTF(("bba_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
447	    sc, start, end, blksize, intr, arg));
448	d = &sc->sc_tx_dma_state;
449	state = 0;
450
451	/* disable any DMA */
452	ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
453	ssr &= ~IOASIC_CSR_DMAEN_ISDN_T;
454	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
455
456	d->size = (vaddr_t)end - (vaddr_t)start;
457	if (bus_dmamap_create(sc->sc_dmat, d->size,
458	    BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE,
459	    BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) {
460		printf("bba_trigger_output: can't create DMA map\n");
461		goto bad;
462	}
463	state |= 1;
464
465	if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, d->size, NULL,
466	    BUS_DMA_WRITE | BUS_DMA_NOWAIT)) {
467		printf("bba_trigger_output: can't load DMA map\n");
468		goto bad;
469	}
470	bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, BUS_DMASYNC_PREWRITE);
471	state |= 2;
472
473	d->intr = intr;
474	d->intr_arg = arg;
475	d->curseg = 1;
476
477	/* get physical address of buffer start */
478	phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr;
479	nphys = (tc_addr_t)d->dmam->dm_segs[1 % d->dmam->dm_nsegs].ds_addr;
480
481	/* setup DMA pointer */
482	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR,
483	    IOASIC_DMA_ADDR(phys));
484	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR,
485	    IOASIC_DMA_ADDR(nphys));
486
487	/* kick off DMA */
488	mtx_enter(&audio_lock);
489	ssr |= IOASIC_CSR_DMAEN_ISDN_T;
490	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
491
492	d->active = 1;
493	mtx_leave(&audio_lock);
494	return 0;
495
496bad:
497	if (state & 2)
498		bus_dmamap_unload(sc->sc_dmat, d->dmam);
499	if (state & 1)
500		bus_dmamap_destroy(sc->sc_dmat, d->dmam);
501	return 1;
502}
503
504int
505bba_trigger_input(void *v, void *start, void *end, int blksize,
506    void (*intr)(void *), void *arg, struct audio_params *param)
507{
508	struct bba_softc *sc = v;
509	struct bba_dma_state *d;
510	uint32_t ssr;
511	tc_addr_t phys, nphys;
512	int state;
513
514	DPRINTF(("bba_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
515	    sc, start, end, blksize, intr, arg));
516	d = &sc->sc_rx_dma_state;
517	state = 0;
518
519	/* disable any DMA */
520	ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
521	ssr &= ~IOASIC_CSR_DMAEN_ISDN_R;
522	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
523
524	d->size = (vaddr_t)end - (vaddr_t)start;
525	if (bus_dmamap_create(sc->sc_dmat, d->size,
526	    BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE,
527	    BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) {
528		printf("bba_trigger_input: can't create DMA map\n");
529		goto bad;
530	}
531	state |= 1;
532
533	if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, d->size, NULL,
534	    BUS_DMA_READ | BUS_DMA_NOWAIT)) {
535		printf("bba_trigger_input: can't load DMA map\n");
536		goto bad;
537	}
538	bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, BUS_DMASYNC_PREREAD);
539	state |= 2;
540
541	d->intr = intr;
542	d->intr_arg = arg;
543	d->curseg = 1;
544
545	/* get physical address of buffer start */
546	phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr;
547	nphys = (tc_addr_t)d->dmam->dm_segs[1 % d->dmam->dm_nsegs].ds_addr;
548
549	/* setup DMA pointer */
550	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR,
551	    IOASIC_DMA_ADDR(phys));
552	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR,
553	    IOASIC_DMA_ADDR(nphys));
554
555	/* kick off DMA */
556	mtx_enter(&audio_lock);
557	ssr |= IOASIC_CSR_DMAEN_ISDN_R;
558	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
559
560	d->active = 1;
561	mtx_leave(&audio_lock);
562	return 0;
563
564bad:
565	if (state & 2)
566		bus_dmamap_unload(sc->sc_dmat, d->dmam);
567	if (state & 1)
568		bus_dmamap_destroy(sc->sc_dmat, d->dmam);
569	return 1;
570}
571
572int
573bba_intr(void *v)
574{
575	struct bba_softc *sc = v;
576	struct bba_dma_state *d;
577	tc_addr_t nphys;
578	int mask;
579
580	mtx_enter(&audio_lock);
581
582	mask = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
583
584	if (mask & IOASIC_INTR_ISDN_TXLOAD) {
585		d = &sc->sc_tx_dma_state;
586		d->curseg = (d->curseg+1) % d->dmam->dm_nsegs;
587		nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
588		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
589		    IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys));
590		if (d->intr != NULL)
591			(*d->intr)(d->intr_arg);
592	}
593	if (mask & IOASIC_INTR_ISDN_RXLOAD) {
594		d = &sc->sc_rx_dma_state;
595		d->curseg = (d->curseg+1) % d->dmam->dm_nsegs;
596		nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
597		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
598		    IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys));
599		if (d->intr != NULL)
600			(*d->intr)(d->intr_arg);
601	}
602
603	mtx_leave(&audio_lock);
604
605	return 0;
606}
607
608int
609bba_get_props(void *v)
610{
611	return AUDIO_PROP_MMAP | am7930_get_props(v);
612}
613
614paddr_t
615bba_mappage(void *v, void *mem, off_t offset, int prot)
616{
617	struct bba_softc *sc = v;
618	struct bba_mem **mp;
619	bus_dma_segment_t seg;
620
621	if (offset < 0)
622		return -1;
623
624	for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != mem;
625	    mp = &(*mp)->next)
626		continue;
627	if (*mp == NULL)
628		return -1;
629
630	seg.ds_addr = (*mp)->addr;
631	seg.ds_len = (*mp)->size;
632
633	return bus_dmamem_mmap(sc->sc_dmat, &seg, 1, offset,
634	    prot, BUS_DMA_WAITOK);
635}
636
637void
638bba_input_conv(void *v, u_char *p, int cc)
639{
640	struct bba_softc *sc = v;
641	u_char *p0 = p;
642	int cc0 = cc;
643	uint32_t *q = (uint32_t *)p;
644
645	DPRINTF(("bba_input_conv(): v=%p p=%p cc=%d\n", v, p, cc));
646
647	/* convert data from dma stream - one byte per longword<23:16> */
648#ifdef __alpha__
649	/* try to avoid smaller than 32 bit accesses whenever possible */
650	if (((vaddr_t)p & 3) == 0) {
651		while (cc >= 4) {
652			uint32_t fp;
653
654			/* alpha is little endian */
655			fp = (*q++ >> 16) & 0xff;
656			fp |= ((*q++ >> 16) & 0xff) << 8;
657			fp |= ((*q++ >> 16) & 0xff) << 16;
658			fp |= ((*q++ >> 16) & 0xff) << 24;
659			*(uint32_t *)p = fp;
660			p += 4;
661			cc -= 4;
662		}
663	}
664#endif
665	while (--cc >= 0)
666		*p++ = (*q++ >> 16) & 0xff;
667
668	/* convert mulaw data to expected encoding if necessary */
669	if (sc->sc_am7930.rec_sw_code != NULL)
670		(*sc->sc_am7930.rec_sw_code)(v, p0, cc0);
671}
672
673void
674bba_output_conv(void *v, u_char *p, int cc)
675{
676	struct bba_softc *sc = v;
677	uint32_t *q = (uint32_t *)p;
678
679	DPRINTF(("bba_output_conv(): v=%p p=%p cc=%d\n", v, p, cc));
680
681	/* convert data to mulaw first if necessary */
682	if (sc->sc_am7930.play_sw_code != NULL)
683		(*sc->sc_am7930.play_sw_code)(v, p, cc);
684
685	/* convert data to dma stream - one byte per longword<23:16> */
686	p += cc;
687	q += cc;
688#ifdef __alpha__
689	/* try to avoid smaller than 32 bit accesses whenever possible */
690	if (((vaddr_t)p & 3) == 0) {
691		while (cc >= 4) {
692			uint32_t fp;
693
694			p -= 4;
695			fp = *(uint32_t *)p;
696			/* alpha is little endian */
697			*--q = ((fp >> 24) & 0xff) << 16;
698			*--q = ((fp >> 16) & 0xff) << 16;
699			*--q = ((fp >> 8) & 0xff) << 16;
700			*--q = (fp & 0xff) << 16;
701			cc -= 4;
702		}
703	}
704#endif
705	while (--cc >= 0)
706		*--q = *--p << 16;
707}
708
709int
710bba_round_blocksize(void *v, int blk)
711{
712	return IOASIC_DMA_BLOCKSIZE;
713}
714
715
716/* indirect write */
717void
718bba_codec_iwrite(struct am7930_softc *sc, int reg, uint8_t val)
719{
720	DPRINTF(("bba_codec_iwrite(): sc=%p, reg=%02x, val=%02x\n", sc, reg, val));
721	bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
722	bba_codec_dwrite(sc, AM7930_DREG_DR, val);
723}
724
725
726void
727bba_codec_iwrite16(struct am7930_softc *sc, int reg, uint16_t val)
728{
729	DPRINTF(("bba_codec_iwrite16(): sc=%p, reg=%02x, val=%04x\n", sc, reg, val));
730	bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
731	bba_codec_dwrite(sc, AM7930_DREG_DR, val);
732	bba_codec_dwrite(sc, AM7930_DREG_DR, val >> 8);
733}
734
735
736/* indirect read */
737uint8_t
738bba_codec_iread(struct am7930_softc *sc, int reg)
739{
740	uint8_t val;
741
742	DPRINTF(("bba_codec_iread(): sc=%p, reg=%02x\n", sc, reg));
743	bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
744	val = bba_codec_dread(sc, AM7930_DREG_DR);
745
746	DPRINTF(("read 0x%02x (%d)\n", val, val));
747
748	return val;
749}
750
751uint16_t
752bba_codec_iread16(struct am7930_softc *sc, int reg)
753{
754	uint16_t val;
755
756	DPRINTF(("bba_codec_iread16(): sc=%p, reg=%02x\n", sc, reg));
757	bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
758	val = bba_codec_dread(sc, AM7930_DREG_DR);
759	val |= bba_codec_dread(sc, AM7930_DREG_DR) << 8;
760
761	return val;
762}
763
764
765/* direct write */
766void
767bba_codec_dwrite(struct am7930_softc *asc, int reg, uint8_t val)
768{
769	struct bba_softc *sc = (struct bba_softc *)asc;
770
771#if defined(__alpha__)
772	bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2, val << 8);
773#else
774	bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6, val);
775#endif
776}
777
778/* direct read */
779uint8_t
780bba_codec_dread(struct am7930_softc *asc, int reg)
781{
782	struct bba_softc *sc = (struct bba_softc *)asc;
783
784#if defined(__alpha__)
785	return (bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2) >> 8) &
786	    0xff;
787#else
788	return bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6) & 0xff;
789#endif
790}
791