Module Name: src Committed By: isaki Date: Sat Aug 5 05:53:27 UTC 2017
Modified Files: src/sys/arch/x68k/dev: vs.c vsvar.h src/sys/dev/ic: msm6258.c msm6258var.h Log Message: vs(4) became to able to play audio again. At the moment the encoding conversion using set_params() does not seem to work for me. So vs(4) uses local conversion to/from ADPCM instead of it. But this should be a temporary work. XXX The playback quality is very poor compared to before... XXX Recording is not tested. To generate a diff of this commit: cvs rdiff -u -r1.42 -r1.43 src/sys/arch/x68k/dev/vs.c cvs rdiff -u -r1.12 -r1.13 src/sys/arch/x68k/dev/vsvar.h cvs rdiff -u -r1.22 -r1.23 src/sys/dev/ic/msm6258.c cvs rdiff -u -r1.8 -r1.9 src/sys/dev/ic/msm6258var.h 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/x68k/dev/vs.c diff -u src/sys/arch/x68k/dev/vs.c:1.42 src/sys/arch/x68k/dev/vs.c:1.43 --- src/sys/arch/x68k/dev/vs.c:1.42 Sat Aug 5 05:22:55 2017 +++ src/sys/arch/x68k/dev/vs.c Sat Aug 5 05:53:27 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: vs.c,v 1.42 2017/08/05 05:22:55 isaki Exp $ */ +/* $NetBSD: vs.c,v 1.43 2017/08/05 05:53:27 isaki Exp $ */ /* * Copyright (c) 2001 Tetsuya Isaki. All rights reserved. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vs.c,v 1.42 2017/08/05 05:22:55 isaki Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vs.c,v 1.43 2017/08/05 05:53:27 isaki Exp $"); #include "audio.h" #include "vs.h" @@ -78,10 +78,10 @@ static void vs_close(void *); static int vs_query_encoding(void *, struct audio_encoding *); static int vs_set_params(void *, int, int, audio_params_t *, audio_params_t *, stream_filter_list_t *, stream_filter_list_t *); -static int vs_trigger_output(void *, void *, void *, int, - void (*)(void *), void *, const audio_params_t *); -static int vs_trigger_input(void *, void *, void *, int, - void (*)(void *), void *, const audio_params_t *); +static int vs_init_output(void *, void *, int); +static int vs_init_input(void *, void *, int); +static int vs_start_input(void *, void *, int, void (*)(void *), void *); +static int vs_start_output(void *, void *, int, void (*)(void *), void *); static int vs_halt_output(void *); static int vs_halt_input(void *); static int vs_allocmem(struct vs_softc *, size_t, size_t, size_t, @@ -101,6 +101,7 @@ static void vs_get_locks(void *, kmutex_ static int vs_round_sr(u_long); static void vs_set_sr(struct vs_softc *, int); static inline void vs_set_po(struct vs_softc *, u_long); +static void *vs_realloc_hwbuf(struct vs_softc *, int); extern struct cfdriver vs_cd; @@ -117,10 +118,10 @@ static const struct audio_hw_if vs_hw_if vs_set_params, NULL, /* round_blocksize */ NULL, /* commit_settings */ - NULL, /* init_output */ - NULL, /* init_input */ - NULL, /* start_output */ - NULL, /* start_input */ + vs_init_output, + vs_init_input, + vs_start_output, + vs_start_input, vs_halt_output, vs_halt_input, NULL, /* speaker_ctl */ @@ -129,13 +130,13 @@ static const struct audio_hw_if vs_hw_if vs_set_port, vs_get_port, vs_query_devinfo, - vs_allocm, - vs_freem, + NULL, /* allocm */ + NULL, /* freem */ vs_round_buffersize, NULL, /* mappage */ vs_get_props, - vs_trigger_output, - vs_trigger_input, + NULL, /* trigger_output */ + NULL, /* trigger_input */ NULL, vs_get_locks, }; @@ -160,8 +161,6 @@ struct { #define NUM_RATE (sizeof(vs_l2r)/sizeof(vs_l2r[0])) -extern stream_filter_factory_t null_filter; - static int vs_match(device_t parent, cfdata_t cf, void *aux) { @@ -222,6 +221,9 @@ vs_attach(device_t parent, device_t self sc->sc_addr = (void *) ia->ia_addr; sc->sc_dmas = NULL; sc->sc_active = 0; + sc->sc_hwbuf = NULL; + sc->sc_hwbufsize = 0; + sc->sc_codec = vs_alloc_msm6258codec(); mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); @@ -253,27 +255,13 @@ vs_dmaintr(void *hdl) mutex_spin_enter(&sc->sc_intr_lock); + sc->sc_active = 0; if (sc->sc_pintr) { - /* start next transfer */ - sc->sc_current.dmap += sc->sc_current.blksize; - if (sc->sc_current.dmap + sc->sc_current.blksize - > sc->sc_current.bufsize) - sc->sc_current.dmap -= sc->sc_current.bufsize; - dmac_start_xfer_offset(sc->sc_dma_ch->ch_softc, - sc->sc_current.xfer, - sc->sc_current.dmap, - sc->sc_current.blksize); sc->sc_pintr(sc->sc_parg); } else if (sc->sc_rintr) { - /* start next transfer */ - sc->sc_current.dmap += sc->sc_current.blksize; - if (sc->sc_current.dmap + sc->sc_current.blksize - > sc->sc_current.bufsize) - sc->sc_current.dmap -= sc->sc_current.bufsize; - dmac_start_xfer_offset(sc->sc_dma_ch->ch_softc, - sc->sc_current.xfer, - sc->sc_current.dmap, - sc->sc_current.blksize); + /* convert ADPCM to slinear */ + sc->sc_rconv(sc->sc_codec, sc->sc_current.rblock, + sc->sc_current.blksize, sc->sc_hwbuf); sc->sc_rintr(sc->sc_rarg); } else { printf("vs_dmaintr: spurious interrupt\n"); @@ -379,8 +367,6 @@ vs_set_params(void *hdl, int setmode, in stream_filter_list_t *pfil, stream_filter_list_t *rfil) { struct vs_softc *sc; - stream_filter_factory_t *pconv; - stream_filter_factory_t *rconv; int rate; sc = hdl; @@ -403,12 +389,16 @@ vs_set_params(void *hdl, int setmode, in } if (play->precision == 8 && play->encoding == AUDIO_ENCODING_SLINEAR) { - pconv = msm6258_linear8_to_adpcm; - rconv = msm6258_adpcm_to_linear8; + sc->sc_current.precision = 8; + sc->sc_pconv = vs_slinear8_to_adpcm; + sc->sc_rconv = vs_adpcm_to_slinear8; + } else if (play->precision == 16 && play->encoding == AUDIO_ENCODING_SLINEAR_BE) { - pconv = msm6258_slinear16_to_adpcm; - rconv = msm6258_adpcm_to_slinear16; + sc->sc_current.precision = 16; + sc->sc_pconv = vs_slinear16be_to_adpcm; + sc->sc_rconv = vs_adpcm_to_slinear16be; + } else { DPRINTF(1, ("prec/enc not matched\n")); return EINVAL; @@ -419,20 +409,11 @@ vs_set_params(void *hdl, int setmode, in /* pfil and rfil are independent even if !AUDIO_PROP_INDEPENDENT */ - if ((setmode & AUMODE_PLAY) != 0) { - pfil->append(pfil, null_filter, play); - play->encoding = AUDIO_ENCODING_ADPCM; - play->validbits = 4; - play->precision = 4; - pfil->append(pfil, pconv, play); - } - if ((setmode & AUMODE_RECORD) != 0) { - rfil->append(rfil, null_filter, rec); - rec->encoding = AUDIO_ENCODING_ADPCM; - rec->validbits = 4; - rec->precision = 4; - rfil->append(rfil, rconv, rec); - } + /* + * XXX MI audio(4) layer does not seem to support non SLINEAR devices. + * So vs(4) behaves as SLINEAR device completely against MI layer + * and converts SLINEAR <-> ADPCM by myself. + */ DPRINTF(1, ("accepted\n")); return 0; @@ -460,38 +441,84 @@ vs_set_po(struct vs_softc *sc, u_long po } static int -vs_trigger_output(void *hdl, void *start, void *end, int bsize, - void (*intr)(void *), void *arg, - const audio_params_t *p) +vs_init_output(void *hdl, void *buffer, int size) +{ + struct vs_softc *sc; + + DPRINTF(1, ("%s\n", __func__)); + sc = hdl; + + /* Set rate and pan */ + vs_set_sr(sc, sc->sc_current.prate); + vs_set_po(sc, VS_PANOUT_LR); + + return 0; +} + +static int +vs_init_input(void *hdl, void *buffer, int size) +{ + struct vs_softc *sc; + + DPRINTF(1, ("%s\n", __func__)); + sc = hdl; + + /* Set rate */ + vs_set_sr(sc, sc->sc_current.rrate); + + return 0; +} + +/* (re)allocate sc_hwbuf with hwbufsize */ +static void * +vs_realloc_hwbuf(struct vs_softc *sc, int hwbufsize) +{ + if (sc->sc_hwbuf != NULL) { + vs_freem(sc, sc->sc_hwbuf, sc->sc_hwbufsize); + } + sc->sc_hwbufsize = hwbufsize; + sc->sc_hwbuf = vs_allocm(sc, 0, sc->sc_hwbufsize); + if (sc->sc_hwbuf == NULL) { + sc->sc_hwbufsize = 0; + return NULL; + } + return sc->sc_hwbuf; +} + +static int +vs_start_output(void *hdl, void *block, int blksize, void (*intr)(void *), + void *arg) { struct vs_softc *sc; struct vs_dma *vd; struct dmac_dma_xfer *xf; struct dmac_channel_stat *chan; + int hwblksize; - DPRINTF(2, ("vs_trigger_output: start=%p, bsize=%d, intr=%p, arg=%p\n", - start, bsize, intr, arg)); + DPRINTF(2, ("%s: block=%p blksize=%d\n", __func__, block, blksize)); sc = hdl; - chan = sc->sc_dma_ch; + + hwblksize = blksize / (sc->sc_current.precision / 4); + if (hwblksize > sc->sc_hwbufsize) { + if (vs_realloc_hwbuf(sc, hwblksize) == NULL) { + DPRINTF(1, ("%s: alloc hwbuf failed\n", __func__)); + return ENOMEM; + } + } + + /* Convert slinear to ADPCM */ + sc->sc_pconv(sc->sc_codec, sc->sc_hwbuf, block, blksize); + sc->sc_pintr = intr; sc->sc_parg = arg; - sc->sc_current.blksize = bsize; - sc->sc_current.bufsize = (char *)end - (char *)start; + sc->sc_current.blksize = hwblksize; + sc->sc_current.bufsize = hwblksize; sc->sc_current.dmap = 0; - /* Find DMA buffer. */ - for (vd = sc->sc_dmas; vd != NULL && KVADDR(vd) != start; - vd = vd->vd_next) - continue; - if (vd == NULL) { - printf("%s: trigger_output: bad addr %p\n", - device_xname(sc->sc_dev), start); - return EINVAL; - } - - vs_set_sr(sc, sc->sc_current.prate); - vs_set_po(sc, VS_PANOUT_LR); + /* vd is always first of sc_dmas */ + vd = sc->sc_dmas; + chan = sc->sc_dma_ch; xf = dmac_alloc_xfer(chan, sc->sc_dmat, vd->vd_map); sc->sc_current.xfer = xf; chan->ch_dcr = (DMAC_DCR_XRM_CSWOH | DMAC_DCR_OTYP_EASYNC | @@ -499,7 +526,7 @@ vs_trigger_output(void *hdl, void *start chan->ch_ocr = DMAC_OCR_REQG_EXTERNAL; xf->dx_ocr = DMAC_OCR_DIR_MTD; xf->dx_scr = DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT; - xf->dx_device = sc->sc_addr + MSM6258_DATA*2 + 1; + xf->dx_device = sc->sc_addr + MSM6258_DATA * 2 + 1; dmac_load_xfer(chan->ch_softc, xf); dmac_start_xfer_offset(chan->ch_softc, xf, 0, sc->sc_current.blksize); @@ -510,36 +537,37 @@ vs_trigger_output(void *hdl, void *start } static int -vs_trigger_input(void *hdl, void *start, void *end, int bsize, - void (*intr)(void *), void *arg, - const audio_params_t *p) +vs_start_input(void *hdl, void *block, int blksize, void (*intr)(void *), + void *arg) { struct vs_softc *sc; struct vs_dma *vd; struct dmac_dma_xfer *xf; struct dmac_channel_stat *chan; + int hwblksize; - DPRINTF(2, ("vs_trigger_input: start=%p, bsize=%d, intr=%p, arg=%p\n", - start, bsize, intr, arg)); + DPRINTF(2, ("%s: block=%p blksize=%d\n", __func__, block, blksize)); sc = hdl; - chan = sc->sc_dma_ch; + + hwblksize = blksize / (sc->sc_current.precision / 4); + if (hwblksize > sc->sc_hwbufsize) { + if (vs_realloc_hwbuf(sc, hwblksize) == NULL) { + DPRINTF(1, ("%s: alloc hwbuf failed\n", __func__)); + return ENOMEM; + } + } + sc->sc_rintr = intr; sc->sc_rarg = arg; - sc->sc_current.blksize = bsize; - sc->sc_current.bufsize = (char *)end - (char *)start; + sc->sc_current.rblock = block; + sc->sc_current.blksize = hwblksize; + sc->sc_current.bufsize = hwblksize; sc->sc_current.dmap = 0; - /* Find DMA buffer. */ - for (vd = sc->sc_dmas; vd != NULL && KVADDR(vd) != start; - vd = vd->vd_next) - continue; - if (vd == NULL) { - printf("%s: trigger_output: bad addr %p\n", - device_xname(sc->sc_dev), start); - return EINVAL; - } + /* vd is always first of sc_dmas */ + vd = sc->sc_dmas; - vs_set_sr(sc, sc->sc_current.rrate); + chan = sc->sc_dma_ch; xf = dmac_alloc_xfer(chan, sc->sc_dmat, vd->vd_map); sc->sc_current.xfer = xf; chan->ch_dcr = (DMAC_DCR_XRM_CSWOH | DMAC_DCR_OTYP_EASYNC | @@ -547,7 +575,7 @@ vs_trigger_input(void *hdl, void *start, chan->ch_ocr = DMAC_OCR_REQG_EXTERNAL; xf->dx_ocr = DMAC_OCR_DIR_DTM; xf->dx_scr = DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT; - xf->dx_device = sc->sc_addr + MSM6258_DATA*2 + 1; + xf->dx_device = sc->sc_addr + MSM6258_DATA * 2 + 1; dmac_load_xfer(chan->ch_softc, xf); dmac_start_xfer_offset(chan->ch_softc, xf, 0, sc->sc_current.blksize); @@ -570,6 +598,9 @@ vs_halt_output(void *hdl) bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 1); sc->sc_active = 0; } + vs_freem(sc, sc->sc_hwbuf, sc->sc_hwbufsize); + sc->sc_hwbuf = NULL; + sc->sc_hwbufsize = 0; return 0; } @@ -587,6 +618,9 @@ vs_halt_input(void *hdl) bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 1); sc->sc_active = 0; } + vs_freem(sc, sc->sc_hwbuf, sc->sc_hwbufsize); + sc->sc_hwbuf = NULL; + sc->sc_hwbufsize = 0; return 0; } Index: src/sys/arch/x68k/dev/vsvar.h diff -u src/sys/arch/x68k/dev/vsvar.h:1.12 src/sys/arch/x68k/dev/vsvar.h:1.13 --- src/sys/arch/x68k/dev/vsvar.h:1.12 Sun Jun 25 06:26:40 2017 +++ src/sys/arch/x68k/dev/vsvar.h Sat Aug 5 05:53:27 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: vsvar.h,v 1.12 2017/06/25 06:26:40 isaki Exp $ */ +/* $NetBSD: vsvar.h,v 1.13 2017/08/05 05:53:27 isaki Exp $ */ /* * Copyright (c) 2001 Tetsuya Isaki. All rights reserved. @@ -91,8 +91,10 @@ struct vs_softc { struct { struct dmac_dma_xfer *xfer; int prate, rrate; + int precision; int bufsize, blksize; int dmap; + void *rblock; /* block specified by start_input() */ } sc_current; int sc_active; @@ -102,4 +104,11 @@ struct vs_softc { void (*sc_rintr)(void *); void *sc_parg; void *sc_rarg; + + /* local conversion */ + void (*sc_pconv)(void *, void *, const void *, int); + void (*sc_rconv)(void *, void *, int, const void *); + void *sc_hwbuf; /* ADPCM buffer */ + int sc_hwbufsize; /* buffer size */ + void *sc_codec; /* msm6258codecvar */ }; Index: src/sys/dev/ic/msm6258.c diff -u src/sys/dev/ic/msm6258.c:1.22 src/sys/dev/ic/msm6258.c:1.23 --- src/sys/dev/ic/msm6258.c:1.22 Sat Aug 5 05:04:30 2017 +++ src/sys/dev/ic/msm6258.c Sat Aug 5 05:53:26 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: msm6258.c,v 1.22 2017/08/05 05:04:30 isaki Exp $ */ +/* $NetBSD: msm6258.c,v 1.23 2017/08/05 05:53:26 isaki Exp $ */ /* * Copyright (c) 2001 Tetsuya Isaki. All rights reserved. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: msm6258.c,v 1.22 2017/08/05 05:04:30 isaki Exp $"); +__KERNEL_RCSID(0, "$NetBSD: msm6258.c,v 1.23 2017/08/05 05:53:26 isaki Exp $"); #include <sys/systm.h> #include <sys/device.h> @@ -412,3 +412,111 @@ DEFINE_FILTER(msm6258_adpcm_to_linear8) this->src->outp = s; return 0; } + + +/* + * XXX MI audio(4) layer does not seem to support non SLINEAR devices. + * XXX So vs(4) converts SLINEAR <-> ADPCM itself. + * XXX This is temporary way, of course. + */ + +void * +vs_alloc_msm6258codec(void) +{ + return (void *)msm6258_factory(NULL, NULL); +} + +void +vs_free_msm6258codec(void *arg) +{ + stream_filter_t *filter = (stream_filter_t *)arg; + if (filter != NULL) { + filter->dtor(filter); + } +} + +void +vs_slinear16be_to_adpcm(void *arg, void *dst, const void *src, int srclen) +{ + struct msm6258_codecvar *mc = (struct msm6258_codecvar *)arg; + const int16_t *s, *end; + uint8_t *d; + + s = (const int16_t *)src; + d = (uint8_t *)dst; + end = (const int16_t *)((const int8_t *)src + srclen); + while (s < end) { + uint8_t f; + int16_t ss; + ss = be16toh(*s++); + f = pcm2adpcm_step(mc, ss); + ss = be16toh(*s++); + f |= pcm2adpcm_step(mc, ss) << 4; + *d++ = f; + } +} + +void +vs_slinear8_to_adpcm(void *arg, void *dst, const void *src, int srclen) +{ + struct msm6258_codecvar *mc = (struct msm6258_codecvar *)arg; + const int8_t *s, *end; + uint8_t *d; + + s = (const int8_t *)src; + d = (uint8_t *)dst; + end = (const int8_t *)src + srclen; + while (s < end) { + uint8_t f; + int16_t ss; + ss = ((int16_t)*s) * 256; + s++; + f = pcm2adpcm_step(mc, ss); + ss = ((int16_t)*s) * 256; + s++; + f |= pcm2adpcm_step(mc, ss) << 4; + *d++ = f; + } +} + +void +vs_adpcm_to_slinear16be(void *arg, void *dst, int dstlen, const void *src) +{ + struct msm6258_codecvar *mc = (struct msm6258_codecvar *)arg; + const uint8_t *s, *end; + int16_t *d; + + s = (const int8_t *)src; + d = (int16_t *)dst; + end = s + (dstlen / 4); + while (s < end) { + uint8_t a; + int16_t s1, s2; + a = *s++; + s1 = adpcm2pcm_step(mc, a & 0x0f); + s2 = adpcm2pcm_step(mc, a >> 4); + *d++ = s1; + *d++ = s2; + } +} + +void +vs_adpcm_to_slinear8(void *arg, void *dst, int dstlen, const void *src) +{ + struct msm6258_codecvar *mc = (struct msm6258_codecvar *)arg; + const uint8_t *s, *end; + int8_t *d; + + s = (const int8_t *)src; + d = (int8_t *)dst; + end = s + (dstlen / 2); + while (s < end) { + uint8_t a; + int16_t s1, s2; + a = *s++; + s1 = adpcm2pcm_step(mc, a & 0x0f); + s2 = adpcm2pcm_step(mc, a >> 4); + *d++ = s1 / 256; + *d++ = s2 / 256; + } +} Index: src/sys/dev/ic/msm6258var.h diff -u src/sys/dev/ic/msm6258var.h:1.8 src/sys/dev/ic/msm6258var.h:1.9 --- src/sys/dev/ic/msm6258var.h:1.8 Sun Oct 16 03:10:18 2011 +++ src/sys/dev/ic/msm6258var.h Sat Aug 5 05:53:26 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: msm6258var.h,v 1.8 2011/10/16 03:10:18 isaki Exp $ */ +/* $NetBSD: msm6258var.h,v 1.9 2017/08/05 05:53:26 isaki Exp $ */ /* * Copyright (c) 2001 Tetsuya Isaki. All rights reserved. @@ -32,3 +32,11 @@ extern stream_filter_factory_t msm6258_s extern stream_filter_factory_t msm6258_linear8_to_adpcm; extern stream_filter_factory_t msm6258_adpcm_to_slinear16; extern stream_filter_factory_t msm6258_adpcm_to_linear8; + +/* XXX */ +extern void *vs_alloc_msm6258codec(void); +extern void vs_free_msm6258codec(void *); +extern void vs_slinear16be_to_adpcm(void *, void *, const void *, int); +extern void vs_slinear8_to_adpcm(void *, void *, const void *, int); +extern void vs_adpcm_to_slinear16be(void *, void *, int, const void *); +extern void vs_adpcm_to_slinear8(void *, void *, int, const void *);