- don't pretend to support 8bit stereo - the hardware can do it but not the
way we currently use it ( needs a 2nd pipe for each direction ) - 8bit mono a-law and u-law should work now - add support for audio input
This commit is contained in:
parent
425df11cce
commit
002ad49155
|
@ -1,10 +1,10 @@
|
|||
/* $NetBSD: dbri.c,v 1.13 2007/03/14 05:40:35 macallan Exp $ */
|
||||
/* $NetBSD: dbri.c,v 1.14 2007/07/12 22:58:50 macallan Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
|
||||
* Copyright (c) 1998, 1999 Brent Baccala (baccala@freesoft.org)
|
||||
* Copyright (c) 2001, 2002 Jared D. McNeill <jmcneill@netbsd.org>
|
||||
* Copyright (c) 2005 Michael Lorenz <macallan@netbsd.org>
|
||||
* Copyright (c) 2005, 2007 Michael Lorenz <macallan@netbsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This driver is losely based on a Linux driver written by Rudolf Koenig and
|
||||
|
@ -42,7 +42,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: dbri.c,v 1.13 2007/03/14 05:40:35 macallan Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: dbri.c,v 1.14 2007/07/12 22:58:50 macallan Exp $");
|
||||
|
||||
#include "audio.h"
|
||||
#if NAUDIO > 0
|
||||
|
@ -154,7 +154,9 @@ static int dbri_get_props(void *);
|
|||
static int dbri_open(void *, int);
|
||||
static void dbri_close(void *);
|
||||
|
||||
static void setup_ring(struct dbri_softc *, int, int, int, int,
|
||||
static void setup_ring_xmit(struct dbri_softc *, int, int, int, int,
|
||||
void (*)(void *), void *);
|
||||
static void setup_ring_recv(struct dbri_softc *, int, int, int, int,
|
||||
void (*)(void *), void *);
|
||||
|
||||
static int dbri_trigger_output(void *, void *, void *, int,
|
||||
|
@ -210,22 +212,29 @@ struct audio_hw_if dbri_hw_if = {
|
|||
CFATTACH_DECL(dbri, sizeof(struct dbri_softc),
|
||||
dbri_match_sbus, dbri_attach_sbus, NULL, NULL);
|
||||
|
||||
#define DBRI_NFORMATS 7
|
||||
#define DBRI_NFORMATS 4
|
||||
static const struct audio_format dbri_formats[DBRI_NFORMATS] = {
|
||||
{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_BE, 16, 16,
|
||||
2, AUFMT_STEREO, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100, 48000}},
|
||||
{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULAW, 8, 8,
|
||||
2, AUFMT_STEREO, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100, 48000}},
|
||||
2, AUFMT_STEREO, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100,
|
||||
48000}},
|
||||
/* {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULAW, 8, 8,
|
||||
2, AUFMT_STEREO, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100,
|
||||
48000}},
|
||||
{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ALAW, 8, 8,
|
||||
2, AUFMT_STEREO, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100, 48000}},
|
||||
2, AUFMT_STEREO, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100,
|
||||
48000}},
|
||||
{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR, 8, 8,
|
||||
2, AUFMT_STEREO, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100, 48000}},
|
||||
2, AUFMT_STEREO, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100,
|
||||
48000}},*/
|
||||
{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULAW, 8, 8,
|
||||
1, AUFMT_STEREO, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100, 48000}},
|
||||
1, AUFMT_MONAURAL, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100,
|
||||
48000}},
|
||||
{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ALAW, 8, 8,
|
||||
1, AUFMT_STEREO, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100, 48000}},
|
||||
1, AUFMT_MONAURAL, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100,
|
||||
48000}},
|
||||
{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR, 8, 8,
|
||||
1, AUFMT_STEREO, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100, 48000}},
|
||||
1, AUFMT_MONAURAL, 8, {8000, 9600, 11025, 16000, 22050, 32000, 44100,
|
||||
48000}},
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -317,7 +326,8 @@ dbri_attach_sbus(struct device *parent, struct device *self, void *aux)
|
|||
/* get a DMA handle */
|
||||
if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
|
||||
BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
|
||||
aprint_error("%s: DMA map create error %d\n", self->dv_xname, error);
|
||||
aprint_error("%s: DMA map create error %d\n", self->dv_xname,
|
||||
error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -364,8 +374,9 @@ dbri_attach_sbus(struct device *parent, struct device *self, void *aux)
|
|||
|
||||
sc->sc_locked = 0;
|
||||
sc->sc_desc_used = 0;
|
||||
sc->sc_open = 0;
|
||||
sc->sc_refcount = 0;
|
||||
sc->sc_playing = 0;
|
||||
sc->sc_recording = 0;
|
||||
sc->sc_pmgrstate = PWR_RESUME;
|
||||
config_interrupts(self, &dbri_config_interrupts);
|
||||
|
||||
|
@ -557,7 +568,8 @@ dbri_command_lock(struct dbri_softc *sc)
|
|||
{
|
||||
|
||||
if (sc->sc_locked)
|
||||
aprint_debug("%s: command buffer locked\n", sc->sc_dev.dv_xname);
|
||||
aprint_debug("%s: command buffer locked\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
|
||||
sc->sc_locked++;
|
||||
|
||||
|
@ -580,7 +592,8 @@ dbri_command_send(struct dbri_softc *sc, volatile u_int32_t *cmd)
|
|||
aprint_error("%s: command buffer improperly locked\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
} else if ((cmd - &sc->sc_dma->command[0]) >= DBRI_NUM_COMMANDS - 1) {
|
||||
aprint_error("%s: command buffer overflow\n", sc->sc_dev.dv_xname);
|
||||
aprint_error("%s: command buffer overflow\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
} else {
|
||||
*(cmd++) = DBRI_CMD(DBRI_COMMAND_PAUSE, 0, 0);
|
||||
*(cmd++) = DBRI_CMD(DBRI_COMMAND_WAIT, 1, 0);
|
||||
|
@ -595,7 +608,8 @@ dbri_command_send(struct dbri_softc *sc, volatile u_int32_t *cmd)
|
|||
}
|
||||
|
||||
if (maxloops == 0) {
|
||||
aprint_error("%s: chip never completed command buffer\n",
|
||||
aprint_error(
|
||||
"%s: chip never completed command buffer\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
} else {
|
||||
|
||||
|
@ -661,14 +675,18 @@ dbri_process_interrupt(struct dbri_softc *sc, int32_t i)
|
|||
td = sc->sc_pipe[channel].desc;
|
||||
dd = &sc->sc_desc[td];
|
||||
|
||||
if (dd->callback != NULL)
|
||||
if (dd->callback != NULL) {
|
||||
dd->callback(dd->callback_args);
|
||||
} else
|
||||
DPRINTF("!");
|
||||
break;
|
||||
}
|
||||
case DBRI_INTR_FXDT: /* fixed data change */
|
||||
DPRINTF("dbri_intr: Fixed data change (%d: %x)\n", channel,
|
||||
val);
|
||||
|
||||
#if 0
|
||||
printf("reg: %08x\n", sc->sc_mm.status);
|
||||
#endif
|
||||
if (sc->sc_pipe[channel].sdp & DBRI_SDP_MSB)
|
||||
val = reverse_bytes(val, sc->sc_pipe[channel].length);
|
||||
if (sc->sc_pipe[channel].prec)
|
||||
|
@ -683,24 +701,14 @@ dbri_process_interrupt(struct dbri_softc *sc, int32_t i)
|
|||
break;
|
||||
case DBRI_INTR_BRDY:
|
||||
{
|
||||
/* XXX no input (yet) */
|
||||
#if 0
|
||||
int rd = sc->sc_pipe[channel].desc;
|
||||
u_int32_t status;
|
||||
int td;
|
||||
struct dbri_desc *dd;
|
||||
|
||||
DPRINTF("dbri_intr: BRDY\n");
|
||||
if (rd < 0 || rd >= DBRI_NUM_DESCRIPTORS) {
|
||||
aprint_error("%s: invalid rd on pipe\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
break;
|
||||
}
|
||||
|
||||
sc->sc_desc[rd].busy = 0;
|
||||
sc->sc_pipe[channel].desc = sc->sc_desc[rd].next;
|
||||
status = sc->sc_dma->desc[rd].word1;
|
||||
#endif
|
||||
/* XXX: callback ??? */
|
||||
td = sc->sc_pipe[channel].desc;
|
||||
dd = &sc->sc_desc[td];
|
||||
|
||||
if (dd->callback != NULL)
|
||||
dd->callback(dd->callback_args);
|
||||
break;
|
||||
}
|
||||
case DBRI_INTR_UNDR:
|
||||
|
@ -710,7 +718,7 @@ dbri_process_interrupt(struct dbri_softc *sc, int32_t i)
|
|||
|
||||
DPRINTF("%s: DBRI_INTR_UNDR\n", sc->sc_dev.dv_xname);
|
||||
|
||||
sc->sc_dma->desc[td].status = 0;
|
||||
sc->sc_dma->xmit[td].status = 0;
|
||||
|
||||
cmd = dbri_command_lock(sc);
|
||||
*(cmd++) = DBRI_CMD(DBRI_COMMAND_SDP, 0,
|
||||
|
@ -718,15 +726,16 @@ dbri_process_interrupt(struct dbri_softc *sc, int32_t i)
|
|||
DBRI_SDP_VALID_POINTER |
|
||||
DBRI_SDP_CLEAR |
|
||||
DBRI_SDP_2SAME);
|
||||
*(cmd++) = sc->sc_dmabase + dbri_dma_off(desc, td);
|
||||
*(cmd++) = sc->sc_dmabase + dbri_dma_off(xmit, td);
|
||||
dbri_command_send(sc, cmd);
|
||||
break;
|
||||
}
|
||||
case DBRI_INTR_CMDI:
|
||||
DPRINTF("ok");
|
||||
break;
|
||||
default:
|
||||
|
||||
DPRINTF("%s: unknown interrupt code %d\n",
|
||||
aprint_error("%s: unknown interrupt code %d\n",
|
||||
sc->sc_dev.dv_xname, code);
|
||||
break;
|
||||
}
|
||||
|
@ -797,8 +806,8 @@ mmcodec_init(struct dbri_softc *sc)
|
|||
delay(10000);
|
||||
}
|
||||
|
||||
aprint_normal("%s: cs4215 ver %d found at offset %d\n",
|
||||
sc->sc_dev.dv_xname, sc->sc_version & 0xf, sc->sc_mm.offset);
|
||||
aprint_normal("%s: cs4215 rev %c found at offset %d\n",
|
||||
sc->sc_dev.dv_xname, 0x43 + (sc->sc_version & 0xf), sc->sc_mm.offset);
|
||||
|
||||
/* set some sane defaults for mmcodec_init_data */
|
||||
sc->sc_params.channels = 2;
|
||||
|
@ -831,10 +840,16 @@ mmcodec_init_data(struct dbri_softc *sc)
|
|||
chi_reset(sc, CHIslave, 128);
|
||||
|
||||
data_width = sc->sc_params.channels * sc->sc_params.precision;
|
||||
|
||||
if ((data_width != 32) && (data_width != 8))
|
||||
aprint_error("%s: data_width is %d\n", __func__, data_width);
|
||||
|
||||
pipe_ts_link(sc, 20, PIPEoutput, 16, 32, sc->sc_mm.offset + 32);
|
||||
pipe_ts_link(sc, 4, PIPEoutput, 16, data_width, sc->sc_mm.offset);
|
||||
pipe_ts_link(sc, 6, PIPEinput, 16, data_width, sc->sc_mm.offset);
|
||||
pipe_ts_link(sc, 21, PIPEinput, 16, 16, sc->sc_mm.offset + 40);
|
||||
pipe_ts_link(sc, 21, PIPEinput, 16, 32, sc->sc_mm.offset + 32);
|
||||
|
||||
pipe_receive_fixed(sc, 21, &sc->sc_mm.status);
|
||||
|
||||
mmcodec_setgain(sc, 0);
|
||||
|
||||
|
@ -876,7 +891,7 @@ mmcodec_default(struct dbri_softc *sc)
|
|||
*
|
||||
* data time slots 5-8
|
||||
* speaker, line and headphone enable. set gain to half.
|
||||
* input is mic
|
||||
* input is line
|
||||
*/
|
||||
mm->d.bdata[0] = sc->sc_latt = 0x20 | CS4215_HE | CS4215_LE;
|
||||
mm->d.bdata[1] = sc->sc_ratt = 0x20 | CS4215_SE;
|
||||
|
@ -1068,7 +1083,8 @@ chi_reset(struct dbri_softc *sc, enum ms ms, int bpf)
|
|||
DBRI_CHI_CHICM(divisor) | DBRI_CHI_FD | DBRI_CHI_BPF(bpf));
|
||||
break;
|
||||
default:
|
||||
aprint_error("%s: unknown value for ms!\n", sc->sc_dev.dv_xname);
|
||||
aprint_error("%s: unknown value for ms!\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1092,13 +1108,14 @@ pipe_setup(struct dbri_softc *sc, int pipe, int sdp)
|
|||
{
|
||||
DPRINTF("pipe setup: %d\n", pipe);
|
||||
if (pipe < 0 || pipe >= DBRI_PIPE_MAX) {
|
||||
aprint_error("%s: illegal pipe number %d\n", sc->sc_dev.dv_xname,
|
||||
pipe);
|
||||
aprint_error("%s: illegal pipe number %d\n",
|
||||
sc->sc_dev.dv_xname, pipe);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((sdp & 0xf800) != sdp)
|
||||
aprint_error("%s: strange SDP value %d\n", sc->sc_dev.dv_xname, sdp);
|
||||
aprint_error("%s: strange SDP value %d\n", sc->sc_dev.dv_xname,
|
||||
sdp);
|
||||
|
||||
if (DBRI_SDP_MODE(sdp) == DBRI_SDP_FIXED &&
|
||||
!(sdp & DBRI_SDP_TO_SER))
|
||||
|
@ -1123,8 +1140,8 @@ pipe_reset(struct dbri_softc *sc, int pipe)
|
|||
volatile u_int32_t *cmd;
|
||||
|
||||
if (pipe < 0 || pipe >= DBRI_PIPE_MAX) {
|
||||
aprint_error("%s: illegal pipe number %d\n", sc->sc_dev.dv_xname,
|
||||
pipe);
|
||||
aprint_error("%s: illegal pipe number %d\n",
|
||||
sc->sc_dev.dv_xname, pipe);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1226,7 +1243,7 @@ pipe_transmit_fixed(struct dbri_softc *sc, int pipe, u_int32_t data)
|
|||
}
|
||||
|
||||
static void
|
||||
setup_ring(struct dbri_softc *sc, int pipe, int which, int num, int blksz,
|
||||
setup_ring_xmit(struct dbri_softc *sc, int pipe, int which, int num, int blksz,
|
||||
void (*callback)(void *), void *callback_args)
|
||||
{
|
||||
volatile u_int32_t *cmd;
|
||||
|
@ -1236,48 +1253,46 @@ setup_ring(struct dbri_softc *sc, int pipe, int which, int num, int blksz,
|
|||
bus_addr_t dmabuf, dmabase;
|
||||
struct dbri_desc *dd = &sc->sc_desc[which];
|
||||
|
||||
switch (pipe) {
|
||||
case 4:
|
||||
/* output, offset 0 */
|
||||
break;
|
||||
default:
|
||||
aprint_error("%s: illegal pipe number (%d)\n",
|
||||
__func__, pipe);
|
||||
return;
|
||||
}
|
||||
|
||||
td = 0;
|
||||
td_first = td_last = -1;
|
||||
|
||||
if (pipe < 0 || pipe >= DBRI_PIPE_MAX / 2) {
|
||||
aprint_error("%s: illegal pipe number %d\n",
|
||||
sc->sc_dev.dv_xname, pipe);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc->sc_pipe[pipe].sdp == 0) {
|
||||
aprint_error("%s: uninitialized pipe %d\n",
|
||||
sc->sc_dev.dv_xname, pipe);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(sc->sc_pipe[pipe].sdp & DBRI_SDP_TO_SER)) {
|
||||
aprint_error("%s: called on receive pipe %d\n",
|
||||
sc->sc_dev.dv_xname, pipe);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
dmabuf = dd->dmabase;
|
||||
dmabase = sc->sc_dmabase;
|
||||
td = 0;
|
||||
|
||||
for (i = 0; i < (num-1); i++) {
|
||||
for (i = 0; i < (num - 1); i++) {
|
||||
|
||||
sc->sc_dma->desc[i].flags = TX_BCNT(blksz)
|
||||
sc->sc_dma->xmit[i].flags = TX_BCNT(blksz)
|
||||
| TX_EOF | TX_BINT;
|
||||
sc->sc_dma->desc[i].ba = dmabuf;
|
||||
sc->sc_dma->desc[i].nda = dmabase + dbri_dma_off(desc, i + 1);
|
||||
sc->sc_dma->desc[i].status = 0;
|
||||
sc->sc_dma->xmit[i].ba = dmabuf;
|
||||
sc->sc_dma->xmit[i].nda = dmabase + dbri_dma_off(xmit, i + 1);
|
||||
sc->sc_dma->xmit[i].status = 0;
|
||||
|
||||
td_last = td;
|
||||
dmabuf += blksz;
|
||||
}
|
||||
|
||||
sc->sc_dma->desc[i].flags = TX_BCNT(blksz) | TX_EOF | TX_BINT;
|
||||
sc->sc_dma->desc[i].ba = dmabuf;
|
||||
sc->sc_dma->desc[i].nda = dmabase + dbri_dma_off(desc, 0);
|
||||
sc->sc_dma->desc[i].status = 0;
|
||||
sc->sc_dma->xmit[i].flags = TX_BCNT(blksz) | TX_EOF | TX_BINT;
|
||||
|
||||
sc->sc_dma->xmit[i].ba = dmabuf;
|
||||
sc->sc_dma->xmit[i].nda = dmabase + dbri_dma_off(xmit, 0);
|
||||
sc->sc_dma->xmit[i].status = 0;
|
||||
|
||||
dd->callback = callback;
|
||||
dd->callback_args = callback_args;
|
||||
|
@ -1313,8 +1328,100 @@ setup_ring(struct dbri_softc *sc, int pipe, int which, int num, int blksz,
|
|||
DBRI_SDP_VALID_POINTER |
|
||||
DBRI_SDP_EVERY |
|
||||
DBRI_SDP_CLEAR);
|
||||
*(cmd++) = sc->sc_dmabase + dbri_dma_off(desc, 0);
|
||||
*(cmd++) = sc->sc_dmabase + dbri_dma_off(xmit, 0);
|
||||
dbri_command_send(sc, cmd);
|
||||
DPRINTF("%s: starting DMA\n", __func__);
|
||||
}
|
||||
|
||||
splx(x);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_ring_recv(struct dbri_softc *sc, int pipe, int which, int num, int blksz,
|
||||
void (*callback)(void *), void *callback_args)
|
||||
{
|
||||
volatile u_int32_t *cmd;
|
||||
int x, i;
|
||||
int td_first, td_last;
|
||||
bus_addr_t dmabuf, dmabase;
|
||||
struct dbri_desc *dd = &sc->sc_desc[which];
|
||||
|
||||
switch (pipe) {
|
||||
case 6:
|
||||
break;
|
||||
default:
|
||||
aprint_error("%s: illegal pipe number (%d)\n",
|
||||
__func__, pipe);
|
||||
return;
|
||||
}
|
||||
|
||||
td_first = td_last = -1;
|
||||
|
||||
if (sc->sc_pipe[pipe].sdp == 0) {
|
||||
aprint_error("%s: uninitialized pipe %d\n",
|
||||
sc->sc_dev.dv_xname, pipe);
|
||||
return;
|
||||
}
|
||||
|
||||
dmabuf = dd->dmabase;
|
||||
dmabase = sc->sc_dmabase;
|
||||
|
||||
for (i = 0; i < (num - 1); i++) {
|
||||
|
||||
sc->sc_dma->recv[i].flags = RX_BSIZE(blksz) | RX_FINAL;
|
||||
sc->sc_dma->recv[i].ba = dmabuf;
|
||||
sc->sc_dma->recv[i].nda = dmabase + dbri_dma_off(recv, i + 1);
|
||||
sc->sc_dma->recv[i].status = RX_EOF;
|
||||
|
||||
td_last = i;
|
||||
dmabuf += blksz;
|
||||
}
|
||||
|
||||
sc->sc_dma->recv[i].flags = RX_BSIZE(blksz) | RX_FINAL;
|
||||
|
||||
sc->sc_dma->recv[i].ba = dmabuf;
|
||||
sc->sc_dma->recv[i].nda = dmabase + dbri_dma_off(recv, 0);
|
||||
sc->sc_dma->recv[i].status = RX_EOF;
|
||||
|
||||
dd->callback = callback;
|
||||
dd->callback_args = callback_args;
|
||||
|
||||
x = splaudio();
|
||||
|
||||
/* the pipe shouldn't be active */
|
||||
if (pipe_active(sc, pipe)) {
|
||||
aprint_error("pipe active (CDP)\n");
|
||||
/* pipe is already active */
|
||||
#if 0
|
||||
td_last = sc->sc_pipe[pipe].desc;
|
||||
while (sc->sc_desc[td_last].next != -1)
|
||||
td_last = sc->sc_desc[td_last].next;
|
||||
|
||||
sc->sc_desc[td_last].next = td_first;
|
||||
sc->sc_dma->desc[td_last].nda =
|
||||
sc->sc_dmabase + dbri_dma_off(desc, td_first);
|
||||
|
||||
cmd = dbri_command_lock(sc);
|
||||
*(cmd++) = DBRI_CMD(DBRI_COMMAND_CDP, 0, pipe);
|
||||
dbri_command_send(sc, cmd);
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
* pipe isn't active - issue an SDP command to start our
|
||||
* chain of TDs running
|
||||
*/
|
||||
sc->sc_pipe[pipe].desc = which;
|
||||
cmd = dbri_command_lock(sc);
|
||||
*(cmd++) = DBRI_CMD(DBRI_COMMAND_SDP, 0,
|
||||
sc->sc_pipe[pipe].sdp |
|
||||
DBRI_SDP_VALID_POINTER |
|
||||
DBRI_SDP_EVERY |
|
||||
DBRI_SDP_CLEAR);
|
||||
*(cmd++) = sc->sc_dmabase + dbri_dma_off(recv, 0);
|
||||
dbri_command_send(sc, cmd);
|
||||
DPRINTF("%s: starting DMA\n", __func__);
|
||||
}
|
||||
|
||||
splx(x);
|
||||
|
@ -1330,6 +1437,7 @@ pipe_ts_link(struct dbri_softc *sc, int pipe, enum io dir, int basepipe,
|
|||
int prevpipe, nextpipe;
|
||||
int val;
|
||||
|
||||
DPRINTF("%s: %d\n", __func__, pipe);
|
||||
if (pipe < 0 || pipe >= DBRI_PIPE_MAX ||
|
||||
basepipe < 0 || basepipe >= DBRI_PIPE_MAX) {
|
||||
aprint_error("%s: illegal pipe numbers (%d, %d)\n",
|
||||
|
@ -1487,9 +1595,6 @@ dbri_query_encoding(void *hdl, struct audio_encoding *ae)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: recording isn't supported - jmcneill
|
||||
*/
|
||||
static int
|
||||
dbri_set_params(void *hdl, int setmode, int usemode,
|
||||
struct audio_params *play, struct audio_params *rec,
|
||||
|
@ -1529,11 +1634,11 @@ dbri_set_params(void *hdl, int setmode, int usemode,
|
|||
}
|
||||
|
||||
fil = mode == AUMODE_PLAY ? pfil : rfil;
|
||||
DPRINTF("enc: %d rate: %d prec: %d chan: %d\n", p->encoding,
|
||||
DPRINTF("requested enc: %d rate: %d prec: %d chan: %d\n", p->encoding,
|
||||
p->sample_rate, p->precision, p->channels);
|
||||
if (auconv_set_converter(dbri_formats, DBRI_NFORMATS,
|
||||
mode, p, true, fil) < 0) {
|
||||
DPRINTF("dbri_set_params: auconv_set_converter failed\n");
|
||||
aprint_error("dbri_set_params: auconv_set_converter failed\n");
|
||||
return EINVAL;
|
||||
}
|
||||
if (fil->req_size > 0)
|
||||
|
@ -1545,7 +1650,7 @@ dbri_set_params(void *hdl, int setmode, int usemode,
|
|||
return 0;
|
||||
}
|
||||
|
||||
DPRINTF("enc: %d rate: %d prec: %d chan: %d\n", p->encoding,
|
||||
DPRINTF("native enc: %d rate: %d prec: %d chan: %d\n", p->encoding,
|
||||
p->sample_rate, p->precision, p->channels);
|
||||
|
||||
for (rate = 0; CS4215_FREQ[rate].freq; rate++)
|
||||
|
@ -1602,7 +1707,7 @@ dbri_round_blocksize(void *hdl, int bs, int mode,
|
|||
const audio_params_t *param)
|
||||
{
|
||||
|
||||
/* DBRI DMA segment size, rounded town to 32bit alignment */
|
||||
/* DBRI DMA segment size, rounded down to 32bit alignment */
|
||||
return 0x1ffc;
|
||||
}
|
||||
|
||||
|
@ -1611,6 +1716,9 @@ dbri_halt_output(void *hdl)
|
|||
{
|
||||
struct dbri_softc *sc = hdl;
|
||||
|
||||
if (!sc->sc_playing)
|
||||
return 0;
|
||||
|
||||
sc->sc_playing = 0;
|
||||
pipe_reset(sc, 4);
|
||||
return (0);
|
||||
|
@ -1825,7 +1933,7 @@ static int
|
|||
dbri_get_props(void *hdl)
|
||||
{
|
||||
|
||||
return AUDIO_PROP_MMAP;
|
||||
return AUDIO_PROP_MMAP | AUDIO_PROP_FULLDUPLEX;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1834,7 +1942,10 @@ dbri_trigger_output(void *hdl, void *start, void *end, int blksize,
|
|||
const struct audio_params *param)
|
||||
{
|
||||
struct dbri_softc *sc = hdl;
|
||||
unsigned long count, current, num;
|
||||
unsigned long count, num;
|
||||
|
||||
if (sc->sc_playing)
|
||||
return 0;
|
||||
|
||||
count = (unsigned long)(((char *)end - (char *)start));
|
||||
num = count / blksize;
|
||||
|
@ -1845,24 +1956,32 @@ dbri_trigger_output(void *hdl, void *start, void *end, int blksize,
|
|||
|
||||
sc->sc_params = *param;
|
||||
|
||||
mmcodec_setcontrol(sc);
|
||||
mmcodec_init_data(sc);
|
||||
current = 0;
|
||||
while ((current < sc->sc_desc_used) &&
|
||||
(sc->sc_desc[current].buf != start))
|
||||
current++;
|
||||
|
||||
if (current < sc->sc_desc_used) {
|
||||
setup_ring(sc, 4, current, num, blksize, intr, intrarg);
|
||||
sc->sc_playing = 1;
|
||||
return 0;
|
||||
if (sc->sc_recording == 0) {
|
||||
/* do not muck with the codec when it's already in use */
|
||||
mmcodec_setcontrol(sc);
|
||||
mmcodec_init_data(sc);
|
||||
}
|
||||
return EINVAL;
|
||||
|
||||
/*
|
||||
* always use DMA descriptor 0 for output
|
||||
* no need to allocate them dynamically since we only ever have
|
||||
* exactly one input stream and exactly one output stream
|
||||
*/
|
||||
setup_ring_xmit(sc, 4, 0, num, blksize, intr, intrarg);
|
||||
sc->sc_playing = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dbri_halt_input(void *cookie)
|
||||
{
|
||||
struct dbri_softc *sc = cookie;
|
||||
|
||||
if (!sc->sc_recording)
|
||||
return 0;
|
||||
|
||||
sc->sc_recording = 0;
|
||||
pipe_reset(sc, 6);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1871,9 +1990,11 @@ dbri_trigger_input(void *hdl, void *start, void *end, int blksize,
|
|||
void (*intr)(void *), void *intrarg,
|
||||
const struct audio_params *param)
|
||||
{
|
||||
#if notyet
|
||||
struct dbri_softc *sc = hdl;
|
||||
unsigned long count, current, num;
|
||||
unsigned long count, num;
|
||||
|
||||
if (sc->sc_recording)
|
||||
return 0;
|
||||
|
||||
count = (unsigned long)(((char *)end - (char *)start));
|
||||
num = count / blksize;
|
||||
|
@ -1884,19 +2005,20 @@ dbri_trigger_input(void *hdl, void *start, void *end, int blksize,
|
|||
|
||||
sc->sc_params = *param;
|
||||
|
||||
mmcodec_setcontrol(sc);
|
||||
mmcodec_init_data(sc);
|
||||
current = 0;
|
||||
while ((current < sc->sc_desc_used) &&
|
||||
(sc->sc_desc[current].buf != start))
|
||||
current++;
|
||||
if (sc->sc_playing == 0) {
|
||||
|
||||
if (current < sc->sc_desc_used) {
|
||||
setup_ring(sc, 4, current, num, blksize, intr, intrarg);
|
||||
return 0;
|
||||
/*
|
||||
* we don't support different parameters for playing and
|
||||
* recording anyway so don't bother whacking the codec if
|
||||
* it's already set up
|
||||
*/
|
||||
mmcodec_setcontrol(sc);
|
||||
mmcodec_init_data(sc);
|
||||
}
|
||||
#endif
|
||||
return EINVAL;
|
||||
|
||||
sc->sc_recording = 1;
|
||||
setup_ring_recv(sc, 6, 1, num, blksize, intr, intrarg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1924,8 +2046,8 @@ reverse_bytes(u_int32_t b, int len)
|
|||
return (b);
|
||||
}
|
||||
|
||||
static void
|
||||
*dbri_malloc(void *v, int dir, size_t s, struct malloc_type *mt, int flags)
|
||||
static void *
|
||||
dbri_malloc(void *v, int dir, size_t s, struct malloc_type *mt, int flags)
|
||||
{
|
||||
struct dbri_softc *sc = v;
|
||||
struct dbri_desc *dd = &sc->sc_desc[sc->sc_desc_used];
|
||||
|
@ -1937,7 +2059,7 @@ static void
|
|||
1, &rseg, BUS_DMA_NOWAIT) == 0) {
|
||||
if (bus_dmamem_map(sc->sc_dmat, &dd->dmaseg, rseg, s,
|
||||
&dd->buf, BUS_DMA_NOWAIT|BUS_DMA_COHERENT) == 0) {
|
||||
if (dd->buf!=NULL) {
|
||||
if (dd->buf != NULL) {
|
||||
if (bus_dmamap_load(sc->sc_dmat,
|
||||
dd->dmamap, dd->buf, s, NULL,
|
||||
BUS_DMA_NOWAIT) == 0) {
|
||||
|
@ -1946,8 +2068,8 @@ static void
|
|||
dd->callback = NULL;
|
||||
dd->dmabase =
|
||||
dd->dmamap->dm_segs[0].ds_addr;
|
||||
DPRINTF("dbri_malloc: using buffer %d\n",
|
||||
sc->sc_desc_used);
|
||||
DPRINTF("dbri_malloc: using buffer %d %08x\n",
|
||||
sc->sc_desc_used, (uint32_t)dd->buf);
|
||||
sc->sc_desc_used++;
|
||||
return dd->buf;
|
||||
} else
|
||||
|
@ -1998,8 +2120,13 @@ dbri_open(void *cookie, int flags)
|
|||
{
|
||||
struct dbri_softc *sc = cookie;
|
||||
|
||||
dbri_bring_up(sc);
|
||||
sc->sc_open = 1;
|
||||
DPRINTF("%s: %d\n", __func__, sc->sc_refcount);
|
||||
|
||||
if (sc->sc_refcount == 0)
|
||||
dbri_bring_up(sc);
|
||||
|
||||
sc->sc_refcount++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2008,8 +2135,16 @@ dbri_close(void *cookie)
|
|||
{
|
||||
struct dbri_softc *sc = cookie;
|
||||
|
||||
sc->sc_open = 0;
|
||||
DPRINTF("%s: %d\n", __func__, sc->sc_refcount);
|
||||
|
||||
sc->sc_refcount--;
|
||||
KASSERT(sc->sc_refcount >= 0);
|
||||
if (sc->sc_refcount > 0)
|
||||
return;
|
||||
|
||||
dbri_set_power(sc, 0);
|
||||
sc->sc_playing = 0;
|
||||
sc->sc_recording = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2026,25 +2161,26 @@ dbri_powerhook(int why, void *cookie)
|
|||
dbri_set_power(sc, 0);
|
||||
break;
|
||||
case PWR_RESUME:
|
||||
DPRINTF("resume: %d\n", sc->sc_open);
|
||||
if (sc->sc_powerstate != 0)
|
||||
break;
|
||||
aprint_verbose("resume: %d\n", sc->sc_refcount);
|
||||
sc->sc_pmgrstate = PWR_RESUME;
|
||||
if (sc->sc_open == 1) {
|
||||
dbri_bring_up(sc);
|
||||
if (sc->sc_playing) {
|
||||
volatile u_int32_t *cmd;
|
||||
int s;
|
||||
dbri_bring_up(sc);
|
||||
if (sc->sc_playing) {
|
||||
volatile u_int32_t *cmd;
|
||||
int s;
|
||||
|
||||
s = splaudio();
|
||||
cmd = dbri_command_lock(sc);
|
||||
*(cmd++) = DBRI_CMD(DBRI_COMMAND_SDP,
|
||||
0, sc->sc_pipe[4].sdp |
|
||||
DBRI_SDP_VALID_POINTER |
|
||||
DBRI_SDP_EVERY | DBRI_SDP_CLEAR);
|
||||
*(cmd++) = sc->sc_dmabase +
|
||||
dbri_dma_off(desc, 0);
|
||||
dbri_command_send(sc, cmd);
|
||||
splx(s);
|
||||
}
|
||||
dbri_bring_up(sc);
|
||||
s = splaudio();
|
||||
cmd = dbri_command_lock(sc);
|
||||
*(cmd++) = DBRI_CMD(DBRI_COMMAND_SDP,
|
||||
0, sc->sc_pipe[4].sdp |
|
||||
DBRI_SDP_VALID_POINTER |
|
||||
DBRI_SDP_EVERY | DBRI_SDP_CLEAR);
|
||||
*(cmd++) = sc->sc_dmabase +
|
||||
dbri_dma_off(xmit, 0);
|
||||
dbri_command_send(sc, cmd);
|
||||
splx(s);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: dbrivar.h,v 1.6 2007/03/14 05:40:35 macallan Exp $ */
|
||||
/* $NetBSD: dbrivar.h,v 1.7 2007/07/12 22:58:50 macallan Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
|
||||
|
@ -45,7 +45,7 @@
|
|||
#define DBRI_VAR_H
|
||||
|
||||
#define DBRI_NUM_COMMANDS 64
|
||||
#define DBRI_NUM_DESCRIPTORS 64
|
||||
#define DBRI_NUM_DESCRIPTORS 32
|
||||
#define DBRI_INT_BLOCKS 64
|
||||
|
||||
#define DBRI_PIPE_MAX 32
|
||||
|
@ -56,7 +56,7 @@ enum direction {
|
|||
};
|
||||
|
||||
/* DBRI DMA transmit descriptor */
|
||||
struct dbri_mem {
|
||||
struct dbri_xmit {
|
||||
volatile uint32_t flags;
|
||||
#define TX_EOF 0x80000000 /* End of frame marker */
|
||||
#define TX_BCNT(x) ((x&0x3fff)<<16)
|
||||
|
@ -73,6 +73,23 @@ struct dbri_mem {
|
|||
#define TS_UNDERRUN 0x0008 /* DMA underrun */
|
||||
};
|
||||
|
||||
struct dbri_recv {
|
||||
volatile uint32_t status;
|
||||
#define RX_EOF 0x80000000
|
||||
#define RX_COMPLETED 0x40000000
|
||||
#define RX_BCNT(x) ((x & 0x3fff) << 16)
|
||||
#define RX_CRCERROR 0x00000080
|
||||
#define RX_BBC 0x00000040 /* bad byte count */
|
||||
#define RX_ABORT 0x00000020
|
||||
#define RX_OVERRUN 0x00000008
|
||||
volatile uint32_t ba;
|
||||
volatile uint32_t nda;
|
||||
volatile uint32_t flags;
|
||||
#define RX_BSIZE(x) (x & 0x3fff)
|
||||
#define RX_FINAL 0x00008000
|
||||
#define RX_MARKER 0x00004000
|
||||
};
|
||||
|
||||
struct dbri_pipe {
|
||||
uint32_t sdp; /* SDP command word */
|
||||
enum direction direction;
|
||||
|
@ -99,8 +116,8 @@ struct dbri_desc {
|
|||
struct dbri_dma {
|
||||
volatile uint32_t command[DBRI_NUM_COMMANDS];
|
||||
volatile int32_t intr[DBRI_INT_BLOCKS];
|
||||
struct dbri_mem desc[DBRI_NUM_DESCRIPTORS];
|
||||
bus_dmamap_t dmamap;
|
||||
struct dbri_xmit xmit[DBRI_NUM_DESCRIPTORS];
|
||||
struct dbri_recv recv[DBRI_NUM_DESCRIPTORS];
|
||||
};
|
||||
|
||||
struct dbri_softc {
|
||||
|
@ -109,6 +126,7 @@ struct dbri_softc {
|
|||
struct sbusdev sc_sd; /* sbus device */
|
||||
bus_space_handle_t sc_ioh;
|
||||
bus_space_tag_t sc_iot;
|
||||
/* DMA buffer for sending commands to the chip */
|
||||
bus_dma_tag_t sc_dmat;
|
||||
bus_dmamap_t sc_dmamap;
|
||||
bus_dma_segment_t sc_dmaseg;
|
||||
|
@ -126,8 +144,9 @@ struct dbri_softc {
|
|||
|
||||
int sc_waitseen;
|
||||
|
||||
int sc_open;
|
||||
int sc_refcount;
|
||||
int sc_playing;
|
||||
int sc_recording;
|
||||
|
||||
int sc_liu_state;
|
||||
void (*sc_liu)(void *);
|
||||
|
|
Loading…
Reference in New Issue