Module Name: src Committed By: jklos Date: Fri Dec 19 04:44:13 UTC 2014
Modified Files: src/sys/arch/vax/conf: GENERIC files.vax majors.vax Added Files: src/sys/arch/vax/vsa: vsaudio.c Log Message: Add audio support for VAXstation VLC, 60 and 90 machines. Originally rom Blaz Antonic and ported from OpenBSD by Björn Johannesso. Tested on VLC and 4000/60. To generate a diff of this commit: cvs rdiff -u -r1.193 -r1.194 src/sys/arch/vax/conf/GENERIC cvs rdiff -u -r1.118 -r1.119 src/sys/arch/vax/conf/files.vax cvs rdiff -u -r1.24 -r1.25 src/sys/arch/vax/conf/majors.vax cvs rdiff -u -r0 -r1.1 src/sys/arch/vax/vsa/vsaudio.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/vax/conf/GENERIC diff -u src/sys/arch/vax/conf/GENERIC:1.193 src/sys/arch/vax/conf/GENERIC:1.194 --- src/sys/arch/vax/conf/GENERIC:1.193 Sun Nov 16 16:01:43 2014 +++ src/sys/arch/vax/conf/GENERIC Fri Dec 19 04:44:13 2014 @@ -1,4 +1,4 @@ -# $NetBSD: GENERIC,v 1.193 2014/11/16 16:01:43 manu Exp $ +# $NetBSD: GENERIC,v 1.194 2014/12/19 04:44:13 jklos Exp $ # # GENERIC machine description file # @@ -22,7 +22,7 @@ include "arch/vax/conf/std.vax" options INCLUDE_CONFIG_FILE # embed config file in kernel binary -#ident "GENERIC-$Revision: 1.193 $" +#ident "GENERIC-$Revision: 1.194 $" # Here are all different supported CPU types listed. #options VAX8800 # VAX 8500, 8530, 8550, 8700, 8800 @@ -206,6 +206,9 @@ smg0 at vsbus0 csr 0x200f0000 # Small m #clr0 at vsbus0 csr 0x30000000 # 4- or 8-bitplans color graphics spx0 at vsbus0 csr 0x38000000 # Low Cost SPX on VS4000/90. #lcg0 at vsbus0 csr 0x21801000 # VS4000/60 (or VLC) graphics +vsaudio0 at vsbus0 csr 0x200d0000 # VS4000/60 (or VLC) audio +vsaudio0 at vsbus0 csr 0x26800000 # VS4000/90 audio +audio* at audiobus? tc0 at vsbus0 csr 0x36000000 # VS4000/60 or 90 TC adapter tcds* at tc0 slot ? offset ? # TC dual SCSI controller asc* at tcds? chip ? # PMAZB/C Index: src/sys/arch/vax/conf/files.vax diff -u src/sys/arch/vax/conf/files.vax:1.118 src/sys/arch/vax/conf/files.vax:1.119 --- src/sys/arch/vax/conf/files.vax:1.118 Sun Jun 12 03:35:49 2011 +++ src/sys/arch/vax/conf/files.vax Fri Dec 19 04:44:13 2014 @@ -1,4 +1,4 @@ -# $NetBSD: files.vax,v 1.118 2011/06/12 03:35:49 rmind Exp $ +# $NetBSD: files.vax,v 1.119 2014/12/19 04:44:13 jklos Exp $ # # new style config file for vax architecture # @@ -315,6 +315,11 @@ device dh # XXX? attach dh at uba file arch/vax/uba/dh.c dh needs-flag +# Vaxstation 4000 audio +device vsaudio: audiobus, am7930 +attach vsaudio at vsbus +file arch/vax/vsa/vsaudio.c vsaudio needs-flag + # These are general files needed for compilation. file dev/cons.c file dev/cninit.c Index: src/sys/arch/vax/conf/majors.vax diff -u src/sys/arch/vax/conf/majors.vax:1.24 src/sys/arch/vax/conf/majors.vax:1.25 --- src/sys/arch/vax/conf/majors.vax:1.24 Fri Jun 22 20:42:23 2012 +++ src/sys/arch/vax/conf/majors.vax Fri Dec 19 04:44:13 2014 @@ -1,4 +1,4 @@ -# $NetBSD: majors.vax,v 1.24 2012/06/22 20:42:23 abs Exp $ +# $NetBSD: majors.vax,v 1.25 2014/12/19 04:44:13 jklos Exp $ # # Device majors for vax # @@ -84,6 +84,7 @@ device-major wsfont char 80 wsfont device-major ses char 81 ses device-major nsmb char 98 nsmb +device-major audio char 99 audio # # block-device-only devices Added files: Index: src/sys/arch/vax/vsa/vsaudio.c diff -u /dev/null src/sys/arch/vax/vsa/vsaudio.c:1.1 --- /dev/null Fri Dec 19 04:44:13 2014 +++ src/sys/arch/vax/vsa/vsaudio.c Fri Dec 19 04:44:13 2014 @@ -0,0 +1,587 @@ +/* $OpenBSD: vsaudio.c,v 1.4 2013/05/15 21:21:11 ratchov Exp $ */ + +/* + * Copyright (c) 2011 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Copyright (c) 1995 Rolf Grossmann + * 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 Rolf Grossmann. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * Audio backend for the VAXstation 4000 AMD79C30 audio chip. + * Currently working in pseudo-DMA mode; DMA operation may be possible and + * needs to be investigated. + */ +/* + * Although he did not claim copyright for his work, this code owes a lot + * to Blaz Antonic <blaz.anto...@siol.net> who figured out a working + * interrupt triggering routine in vsaudio_match(). + */ +/* + * Ported to NetBSD, from OpenBSD, by Björn Johannesson (rherdw...@yahoo.com) + * in December 2014 + */ + +#include "audio.h" +#if NAUDIO > 0 + +#include <sys/errno.h> +#include <sys/evcnt.h> +#include <sys/intr.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/cpu.h> +#include <machine/sid.h> +#include <machine/scb.h> +#include <machine/vsbus.h> + +#include <sys/audioio.h> +#include <dev/audio_if.h> +#include <dev/auconv.h> + +#include <dev/ic/am7930reg.h> +#include <dev/ic/am7930var.h> + +#ifdef AUDIO_DEBUG +#define DPRINTF(x) if (am7930debug) printf x +#define DPRINTFN(n,x) if (am7930debug>(n)) printf x +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif /* AUDIO_DEBUG */ + +/* physical addresses of the AM79C30 chip */ +#define VSAUDIO_CSR 0x200d0000 +#define VSAUDIO_CSR_KA49 0x26800000 + +/* pdma state */ +struct auio { + bus_space_tag_t au_bt; /* bus tag */ + bus_space_handle_t au_bh; /* handle to chip registers */ + + uint8_t *au_rdata; /* record data */ + uint8_t *au_rend; /* end of record data */ + uint8_t *au_pdata; /* play data */ + uint8_t *au_pend; /* end of play data */ + struct evcnt au_intrcnt; /* statistics */ +}; + +struct am7930_intrhand { + int (*ih_fun)(void *); + void *ih_arg; +}; + + +struct vsaudio_softc { + struct am7930_softc sc_am7930; /* glue to MI code */ + bus_space_tag_t sc_bt; /* bus cookie */ + bus_space_handle_t sc_bh; /* device registers */ + + struct am7930_intrhand sc_ih; /* interrupt vector (hw or sw) */ + void (*sc_rintr)(void*); /* input completion intr handler */ + void *sc_rarg; /* arg for sc_rintr() */ + void (*sc_pintr)(void*); /* output completion intr handler */ + void *sc_parg; /* arg for sc_pintr() */ + + uint8_t *sc_rdata; /* record data */ + uint8_t *sc_rend; /* end of record data */ + uint8_t *sc_pdata; /* play data */ + uint8_t *sc_pend; /* end of play data */ + + struct auio sc_au; /* recv and xmit buffers, etc */ +#define sc_intrcnt sc_au.au_intrcnt /* statistics */ + void *sc_sicookie; /* softintr(9) cookie */ + int sc_cvec; + kmutex_t sc_lock; +}; + +static int vsaudio_match(struct device *parent, struct cfdata *match, void *); +static void vsaudio_attach(device_t parent, device_t self, void *); + +CFATTACH_DECL_NEW(vsaudio, sizeof(struct vsaudio_softc), vsaudio_match, + vsaudio_attach, NULL, NULL); + +/* + * Hardware access routines for the MI code + */ +uint8_t vsaudio_codec_iread(struct am7930_softc *, int); +uint16_t vsaudio_codec_iread16(struct am7930_softc *, int); +uint8_t vsaudio_codec_dread(struct vsaudio_softc *, int); +void vsaudio_codec_iwrite(struct am7930_softc *, int, uint8_t); +void vsaudio_codec_iwrite16(struct am7930_softc *, int, uint16_t); +void vsaudio_codec_dwrite(struct vsaudio_softc *, int, uint8_t); +void vsaudio_onopen(struct am7930_softc *); +void vsaudio_onclose(struct am7930_softc *); + +/* +static stream_filter_factory_t vsaudio_output_conv; +static stream_filter_factory_t vsaudio_input_conv; +static int vsaudio_output_conv_fetch_to(struct audio_softc *, + stream_fetcher_t *, audio_stream_t *, int); +static int vsaudio_input_conv_fetch_to(struct audio_softc *, + stream_fetcher_t *, audio_stream_t *, int); + */ + +struct am7930_glue vsaudio_glue = { + vsaudio_codec_iread, + vsaudio_codec_iwrite, + vsaudio_codec_iread16, + vsaudio_codec_iwrite16, + vsaudio_onopen, + vsaudio_onclose, + 0, + /*vsaudio_input_conv*/0, + /*vsaudio_output_conv*/0, +}; + +/* + * Interface to the MI audio layer. + */ +int vsaudio_start_output(void *, void *, int, void (*)(void *), void *); +int vsaudio_start_input(void *, void *, int, void (*)(void *), void *); +int vsaudio_getdev(void *, struct audio_device *); +void vsaudio_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread); + +struct audio_hw_if vsaudio_hw_if = { + am7930_open, + am7930_close, + NULL, + am7930_query_encoding, + am7930_set_params, + am7930_round_blocksize, + am7930_commit_settings, + NULL, + NULL, + vsaudio_start_output, + vsaudio_start_input, + am7930_halt_output, + am7930_halt_input, + NULL, + vsaudio_getdev, + NULL, + am7930_set_port, + am7930_get_port, + am7930_query_devinfo, + NULL, + NULL, + NULL, + NULL, + am7930_get_props, + NULL, + NULL, + NULL, + vsaudio_get_locks, +}; + + +struct audio_device vsaudio_device = { + "am7930", + "x", + "vsaudio" +}; + +void vsaudio_hwintr(void *); +void vsaudio_swintr(void *); +struct auio *auiop; + + +static int +vsaudio_match(struct device *parent, struct cfdata *match, void *aux) +{ + struct vsbus_softc *sc __attribute__((__unused__)) = device_private(parent); + struct vsbus_attach_args *va = aux; + volatile uint32_t *regs; + int i; + + switch (vax_boardtype) { +#if defined(VAX_BTYP_46) || defined(VAX_BTYP_48) + case VAX_BTYP_46: + case VAX_BTYP_48: + if (va->va_paddr != VSAUDIO_CSR) + return 0; + break; +#endif +#if defined(VAX_BTYP_49) + case VAX_BTYP_49: + if (va->va_paddr != VSAUDIO_CSR_KA49) + return 0; + break; +#endif + default: + return 0; + } + + regs = (volatile uint32_t *)va->va_addr; + regs[AM7930_DREG_CR] = AM7930_IREG_INIT; + regs[AM7930_DREG_DR] = AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_ENABLE; + + regs[AM7930_DREG_CR] = AM7930_IREG_MUX_MCR1; + regs[AM7930_DREG_DR] = 0; + + regs[AM7930_DREG_CR] = AM7930_IREG_MUX_MCR2; + regs[AM7930_DREG_DR] = 0; + + regs[AM7930_DREG_CR] = AM7930_IREG_MUX_MCR3; + regs[AM7930_DREG_DR] = (AM7930_MCRCHAN_BB << 4) | AM7930_MCRCHAN_BA; + + regs[AM7930_DREG_CR] = AM7930_IREG_MUX_MCR4; + regs[AM7930_DREG_DR] = AM7930_MCR4_INT_ENABLE; + + for (i = 10; i < 20; i++) + regs[AM7930_DREG_BBTB] = i; + delay(1000000); /* XXX too large */ + + return 1; +} + + +static void +vsaudio_attach(device_t parent, device_t self, void *aux) +{ + struct vsbus_attach_args *va = aux; + struct vsaudio_softc *sc = device_private(self); + + if (bus_space_map(va->va_memt, va->va_paddr, AM7930_DREG_SIZE << 2, 0, + &sc->sc_bh) != 0) { + printf(": can't map registers\n"); + return; + } + sc->sc_bt = va->va_memt; + sc->sc_am7930.sc_dev = device_private(self); + sc->sc_am7930.sc_glue = &vsaudio_glue; + mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH); + am7930_init(&sc->sc_am7930, AUDIOAMD_POLL_MODE); + auiop = &sc->sc_au; + /* Copy bus tag & handle for use by am7930_trap */ + sc->sc_au.au_bt = sc->sc_bt; + sc->sc_au.au_bh = sc->sc_bh; + scb_vecalloc(va->va_cvec, vsaudio_hwintr, sc, SCB_ISTACK, + &sc->sc_intrcnt); + sc->sc_cvec = va->va_cvec; + evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, + device_xname(self), "intr"); + + sc->sc_sicookie = softint_establish(SOFTINT_SERIAL, &vsaudio_swintr, sc); + if (sc->sc_sicookie == NULL) { + aprint_normal("\n%s: cannot establish software interrupt\n", + device_xname(self)); + return; + } + + aprint_normal("\n"); + audio_attach_mi(&vsaudio_hw_if, sc, self); + +} + +void +vsaudio_onopen(struct am7930_softc *sc) +{ + struct vsaudio_softc *vssc = (struct vsaudio_softc *)sc; + + mutex_spin_enter(&vssc->sc_lock); + /* reset pdma state */ + vssc->sc_rintr = NULL; + vssc->sc_rarg = 0; + vssc->sc_pintr = NULL; + vssc->sc_parg = 0; + + vssc->sc_rdata = NULL; + vssc->sc_pdata = NULL; + mutex_spin_exit(&vssc->sc_lock); +} + +void +vsaudio_onclose(struct am7930_softc *sc) +{ + am7930_halt_input(sc); + am7930_halt_output(sc); +} + +/* + * this is called by interrupt code-path, don't lock + */ +int +vsaudio_start_output(void *addr, void *p, int cc, + void (*intr)(void *), void *arg) +{ + struct vsaudio_softc *sc = addr; + + DPRINTFN(1, ("sa_start_output: cc=%d %p (%p)\n", cc, intr, arg)); + + mutex_spin_enter(&sc->sc_lock); + vsaudio_codec_iwrite(&sc->sc_am7930, + AM7930_IREG_INIT, AM7930_INIT_PMS_ACTIVE); + DPRINTF(("sa_start_output: started intrs.\n")); + sc->sc_pintr = intr; + sc->sc_parg = arg; + sc->sc_au.au_pdata = p; + sc->sc_au.au_pend = (char *)p + cc - 1; + mutex_spin_exit(&sc->sc_lock); + return 0; +} + +/* + * this is called by interrupt code-path, don't lock + */ +int +vsaudio_start_input(void *addr, void *p, int cc, + void (*intr)(void *), void *arg) +{ + struct vsaudio_softc *sc = addr; + + DPRINTFN(1, ("sa_start_input: cc=%d %p (%p)\n", cc, intr, arg)); + + mutex_spin_enter(&sc->sc_lock); + vsaudio_codec_iwrite(&sc->sc_am7930, + AM7930_IREG_INIT, AM7930_INIT_PMS_ACTIVE); + + sc->sc_rintr = intr; + sc->sc_rarg = arg; + sc->sc_au.au_rdata = p; + sc->sc_au.au_rend = (char *)p + cc -1; + mutex_spin_exit(&sc->sc_lock); + DPRINTF(("sa_start_input: started intrs.\n")); + return 0; +} + + +void +vsaudio_hwintr(void *v) +{ + struct vsaudio_softc *sc; + struct auio *au; + uint8_t *d, *e; + int __attribute__((__unused__)) k; + + sc = v; + au = &sc->sc_au; + mutex_spin_enter(&sc->sc_lock); + /* clear interrupt */ + k = vsaudio_codec_dread(sc, AM7930_DREG_IR); +#if 0 /* interrupt is not shared, this shouldn't happen */ + if ((k & (AM7930_IR_DTTHRSH | AM7930_IR_DRTHRSH | AM7930_IR_DSRI | + AM7930_IR_DERI | AM7930_IR_BBUFF)) == 0) { + mtx_leave(&audio_lock); + return 0; + } +#endif + /* receive incoming data */ + d = au->au_rdata; + e = au->au_rend; + if (d != NULL && d <= e) { + *d = vsaudio_codec_dread(sc, AM7930_DREG_BBRB); + au->au_rdata++; + if (d == e) { + DPRINTFN(1, ("vsaudio_hwintr: swintr(r) requested")); + softint_schedule(sc->sc_sicookie); + } + } + + /* send outgoing data */ + d = au->au_pdata; + e = au->au_pend; + if (d != NULL && d <= e) { + vsaudio_codec_dwrite(sc, AM7930_DREG_BBTB, *d); + au->au_pdata++; + if (d == e) { + DPRINTFN(1, ("vsaudio_hwintr: swintr(p) requested")); + softint_schedule(sc->sc_sicookie); + } + } + mutex_spin_exit(&sc->sc_lock); +} + +void +vsaudio_swintr(void *v) +{ + struct vsaudio_softc *sc; + struct auio *au; + int dor, dow; + + sc = v; + au = &sc->sc_au; + + DPRINTFN(1, ("audiointr: sc=%p\n", sc)); + + dor = dow = 0; + mutex_spin_enter(&sc->sc_am7930.sc_intr_lock); + if (au->au_rdata > au->au_rend && sc->sc_rintr != NULL) + dor = 1; + if (au->au_pdata > au->au_pend && sc->sc_pintr != NULL) + dow = 1; + + if (dor != 0) + (*sc->sc_rintr)(sc->sc_rarg); + if (dow != 0) + (*sc->sc_pintr)(sc->sc_parg); + mutex_spin_exit(&sc->sc_am7930.sc_intr_lock); +} + + +/* indirect write */ +void +vsaudio_codec_iwrite(struct am7930_softc *sc, int reg, uint8_t val) +{ + struct vsaudio_softc *vssc = (struct vsaudio_softc *)sc; + + vsaudio_codec_dwrite(vssc, AM7930_DREG_CR, reg); + vsaudio_codec_dwrite(vssc, AM7930_DREG_DR, val); +} + +void +vsaudio_codec_iwrite16(struct am7930_softc *sc, int reg, uint16_t val) +{ + struct vsaudio_softc *vssc = (struct vsaudio_softc *)sc; + + vsaudio_codec_dwrite(vssc, AM7930_DREG_CR, reg); + vsaudio_codec_dwrite(vssc, AM7930_DREG_DR, val); + vsaudio_codec_dwrite(vssc, AM7930_DREG_DR, val >> 8); +} + +/* indirect read */ +uint8_t +vsaudio_codec_iread(struct am7930_softc *sc, int reg) +{ + struct vsaudio_softc *vssc = (struct vsaudio_softc *)sc; + + vsaudio_codec_dwrite(vssc, AM7930_DREG_CR, reg); + return vsaudio_codec_dread(vssc, AM7930_DREG_DR); +} + +uint16_t +vsaudio_codec_iread16(struct am7930_softc *sc, int reg) +{ + struct vsaudio_softc *vssc = (struct vsaudio_softc *)sc; + uint lo, hi; + + vsaudio_codec_dwrite(vssc, AM7930_DREG_CR, reg); + lo = vsaudio_codec_dread(vssc, AM7930_DREG_DR); + hi = vsaudio_codec_dread(vssc, AM7930_DREG_DR); + return (hi << 8) | lo; +} + +/* direct read */ +uint8_t +vsaudio_codec_dread(struct vsaudio_softc *sc, int reg) +{ + return bus_space_read_1(sc->sc_bt, sc->sc_bh, reg << 2); +} + +/* direct write */ +void +vsaudio_codec_dwrite(struct vsaudio_softc *sc, int reg, uint8_t val) +{ + bus_space_write_1(sc->sc_bt, sc->sc_bh, reg << 2, val); +} + +int +vsaudio_getdev(void *addr, struct audio_device *retp) +{ + *retp = vsaudio_device; + return 0; +} + +void +vsaudio_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread) +{ + struct vsaudio_softc *asc = opaque; + struct am7930_softc *sc = &asc->sc_am7930; + + *intr = &sc->sc_intr_lock; + *thread = &sc->sc_lock; +} + +/* +static stream_filter_t * +vsaudio_input_conv(struct audio_softc *sc, const audio_params_t *from, + const audio_params_t *to) +{ + return auconv_nocontext_filter_factory(vsaudio_input_conv_fetch_to); +} + +static int +vsaudio_input_conv_fetch_to(struct audio_softc *sc, stream_fetcher_t *self, + audio_stream_t *dst, int max_used) +{ + stream_filter_t *this; + int m, err; + + this = (stream_filter_t *)self; + if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used * 4))) + return err; + m = dst->end - dst->start; + m = min(m, max_used); + FILTER_LOOP_PROLOGUE(this->src, 4, dst, 1, m) { + *d = ((*(const uint32_t *)s) >> 16) & 0xff; + } FILTER_LOOP_EPILOGUE(this->src, dst); + return 0; +} + +static stream_filter_t * +vsaudio_output_conv(struct audio_softc *sc, const audio_params_t *from, + const audio_params_t *to) +{ + return auconv_nocontext_filter_factory(vsaudio_output_conv_fetch_to); +} + +static int +vsaudio_output_conv_fetch_to(struct audio_softc *sc, stream_fetcher_t *self, + audio_stream_t *dst, int max_used) +{ + stream_filter_t *this; + int m, err; + + this = (stream_filter_t *)self; + max_used = (max_used + 3) & ~3; + if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used / 4))) + return err; + m = (dst->end - dst->start) & ~3; + m = min(m, max_used); + FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) { + *(uint32_t *)d = (*s << 16); + } FILTER_LOOP_EPILOGUE(this->src, dst); + return 0; +} +*/ + +#endif /* NAUDIO > 0 */