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 *);