summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/isa/ess.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sound/isa/ess.c')
-rw-r--r--sys/dev/sound/isa/ess.c262
1 files changed, 124 insertions, 138 deletions
diff --git a/sys/dev/sound/isa/ess.c b/sys/dev/sound/isa/ess.c
index 7841e35..f353289 100644
--- a/sys/dev/sound/isa/ess.c
+++ b/sys/dev/sound/isa/ess.c
@@ -36,6 +36,8 @@
#include <dev/sound/isa/sb.h>
#include <dev/sound/chip.h>
+#include "mixer_if.h"
+
#define ESS_BUFFSIZE (4096)
#define ABS(x) (((x) < 0)? -(x) : (x))
@@ -45,15 +47,6 @@
/* more accurate clocks and split audio1/audio2 rates */
#define ESS18XX_NEWSPEED
-/* channel interface for ESS */
-static void *esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
-static int esschan_setformat(void *data, u_int32_t format);
-static int esschan_setspeed(void *data, u_int32_t speed);
-static int esschan_setblocksize(void *data, u_int32_t blocksize);
-static int esschan_trigger(void *data, int go);
-static int esschan_getptr(void *data);
-static pcmchan_caps *esschan_getcaps(void *data);
-
static u_int32_t ess_pfmt[] = {
AFMT_U8,
AFMT_STEREO | AFMT_U8,
@@ -82,32 +75,13 @@ static u_int32_t ess_rfmt[] = {
static pcmchan_caps ess_reccaps = {5000, 49000, ess_rfmt, 0};
-static pcm_channel ess_chantemplate = {
- esschan_init,
- NULL, /* setdir */
- esschan_setformat,
- esschan_setspeed,
- esschan_setblocksize,
- esschan_trigger,
- esschan_getptr,
- esschan_getcaps,
- NULL, /* free */
- NULL, /* nop1 */
- NULL, /* nop2 */
- NULL, /* nop3 */
- NULL, /* nop4 */
- NULL, /* nop5 */
- NULL, /* nop6 */
- NULL, /* nop7 */
-};
-
struct ess_info;
struct ess_chinfo {
struct ess_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
- int dir, hwch, stopping;
+ int dir, hwch, stopping, run;
u_int32_t fmt, spd;
};
@@ -142,19 +116,6 @@ static int ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t
static int ess_start(struct ess_chinfo *ch);
static int ess_stop(struct ess_chinfo *ch);
-static int essmix_init(snd_mixer *m);
-static int essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right);
-static int essmix_setrecsrc(snd_mixer *m, u_int32_t src);
-
-static snd_mixer ess_mixer = {
- "ESS mixer",
- essmix_init,
- NULL,
- NULL,
- essmix_set,
- essmix_setrecsrc,
-};
-
static devclass_t pcm_devclass;
/*
@@ -377,94 +338,6 @@ ess_alloc_resources(struct ess_info *sc, device_t dev)
} else return ENXIO;
}
-static int
-ess_doattach(device_t dev, struct ess_info *sc)
-{
- char status[SND_STATUSLEN], buf[64];
- int ver;
-
- if (ess_alloc_resources(sc, dev))
- goto no;
- if (ess_reset_dsp(sc))
- goto no;
- mixer_init(dev, &ess_mixer, sc);
-
- sc->duplex = 0;
- sc->newspeed = 0;
- ver = (ess_getmixer(sc, 0x40) << 8) | ess_rd(sc, SB_MIX_DATA);
- snprintf(buf, sizeof buf, "ESS %x DSP", ver);
- device_set_desc_copy(dev, buf);
- if (bootverbose)
- device_printf(dev, "ESS%x detected", ver);
-
- switch (ver) {
- case 0x1869:
- case 0x1879:
-#ifdef ESS18XX_DUPLEX
- sc->duplex = sc->drq2? 1 : 0;
-#endif
-#ifdef ESS18XX_NEWSPEED
- sc->newspeed = 1;
-#endif
- break;
- }
- if (bootverbose)
- printf("%s%s\n", sc->duplex? ", duplex" : "",
- sc->newspeed? ", newspeed" : "");
-
- if (sc->newspeed)
- ess_setmixer(sc, 0x71, 0x22);
-
- bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ess_intr, sc, &sc->ih);
- if (!sc->duplex)
- pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
-
- if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
- /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
- /*highaddr*/BUS_SPACE_MAXADDR,
- /*filter*/NULL, /*filterarg*/NULL,
- /*maxsize*/ESS_BUFFSIZE, /*nsegments*/1,
- /*maxsegz*/0x3ffff,
- /*flags*/0, &sc->parent_dmat) != 0) {
- device_printf(dev, "unable to create dma tag\n");
- goto no;
- }
-
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
- rman_get_start(sc->io_base), rman_get_start(sc->irq),
- rman_get_start(sc->drq1));
- if (sc->drq2)
- snprintf(status + strlen(status), SND_STATUSLEN - strlen(status),
- ":%ld", rman_get_start(sc->drq2));
-
- if (pcm_register(dev, sc, 1, 1))
- goto no;
- pcm_addchan(dev, PCMDIR_REC, &ess_chantemplate, sc);
- pcm_addchan(dev, PCMDIR_PLAY, &ess_chantemplate, sc);
- pcm_setstatus(dev, status);
-
- return 0;
-
-no:
- ess_release_resources(sc, dev);
- return ENXIO;
-}
-
-static int
-ess_detach(device_t dev)
-{
- int r;
- struct ess_info *sc;
-
- r = pcm_unregister(dev);
- if (r)
- return r;
-
- sc = pcm_getdevinfo(dev);
- ess_release_resources(sc, dev);
- return 0;
-}
-
static void
ess_intr(void *arg)
{
@@ -481,7 +354,10 @@ ess_intr(void *arg)
rirq = (src & sc->rch.hwch)? 1 : 0;
if (pirq) {
+ if (!sc->pch.run)
+ printf("ess: play intr while not running\n");
if (sc->pch.stopping) {
+ sc->pch.run = 0;
buf_isadma(sc->pch.buffer, PCMTRIG_STOP);
sc->pch.stopping = 0;
if (sc->pch.hwch == 1)
@@ -493,7 +369,10 @@ ess_intr(void *arg)
}
if (rirq) {
+ if (!sc->rch.run)
+ printf("ess: record intr while not running\n");
if (sc->rch.stopping) {
+ sc->rch.run = 0;
buf_isadma(sc->rch.buffer, PCMTRIG_STOP);
sc->rch.stopping = 0;
/* XXX: will this stop audio2? */
@@ -657,9 +536,10 @@ ess_stop(struct ess_chinfo *ch)
return 0;
}
+/* -------------------------------------------------------------------- */
/* channel interface for ESS18xx */
static void *
-esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
+esschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
{
struct ess_info *sc = devinfo;
struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;
@@ -679,7 +559,7 @@ esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
}
static int
-esschan_setformat(void *data, u_int32_t format)
+esschan_setformat(kobj_t obj, void *data, u_int32_t format)
{
struct ess_chinfo *ch = data;
@@ -688,7 +568,7 @@ esschan_setformat(void *data, u_int32_t format)
}
static int
-esschan_setspeed(void *data, u_int32_t speed)
+esschan_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
struct ess_chinfo *ch = data;
struct ess_info *sc = ch->parent;
@@ -702,13 +582,13 @@ esschan_setspeed(void *data, u_int32_t speed)
}
static int
-esschan_setblocksize(void *data, u_int32_t blocksize)
+esschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
return blocksize;
}
static int
-esschan_trigger(void *data, int go)
+esschan_trigger(kobj_t obj, void *data, int go)
{
struct ess_chinfo *ch = data;
@@ -717,6 +597,7 @@ esschan_trigger(void *data, int go)
switch (go) {
case PCMTRIG_START:
+ ch->run = 1;
buf_isadma(ch->buffer, go);
ess_start(ch);
break;
@@ -731,7 +612,7 @@ esschan_trigger(void *data, int go)
}
static int
-esschan_getptr(void *data)
+esschan_getptr(kobj_t obj, void *data)
{
struct ess_chinfo *ch = data;
@@ -739,13 +620,25 @@ esschan_getptr(void *data)
}
static pcmchan_caps *
-esschan_getcaps(void *data)
+esschan_getcaps(kobj_t obj, void *data)
{
struct ess_chinfo *ch = data;
return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps;
}
+static kobj_method_t esschan_methods[] = {
+ KOBJMETHOD(channel_init, esschan_init),
+ KOBJMETHOD(channel_setformat, esschan_setformat),
+ KOBJMETHOD(channel_setspeed, esschan_setspeed),
+ KOBJMETHOD(channel_setblocksize, esschan_setblocksize),
+ KOBJMETHOD(channel_trigger, esschan_trigger),
+ KOBJMETHOD(channel_getptr, esschan_getptr),
+ KOBJMETHOD(channel_getcaps, esschan_getcaps),
+ { 0, 0 }
+};
+CHANNEL_DECLARE(esschan);
+
/************************************************************/
static int
@@ -856,6 +749,16 @@ essmix_setrecsrc(snd_mixer *m, u_int32_t src)
return src;
}
+static kobj_method_t essmixer_methods[] = {
+ KOBJMETHOD(mixer_init, essmix_init),
+ KOBJMETHOD(mixer_set, essmix_set),
+ KOBJMETHOD(mixer_setrecsrc, essmix_setrecsrc),
+ { 0, 0 }
+};
+MIXER_DECLARE(essmixer);
+
+/************************************************************/
+
static int
ess_probe(device_t dev)
{
@@ -880,13 +783,95 @@ static int
ess_attach(device_t dev)
{
struct ess_info *sc;
+ char status[SND_STATUSLEN], buf[64];
+ int ver;
sc = (struct ess_info *)malloc(sizeof *sc, M_DEVBUF, M_NOWAIT);
if (!sc)
return ENXIO;
bzero(sc, sizeof *sc);
- return ess_doattach(dev, sc);
+ if (ess_alloc_resources(sc, dev))
+ goto no;
+ if (ess_reset_dsp(sc))
+ goto no;
+ if (mixer_init(dev, &essmixer_class, sc))
+ goto no;
+
+ sc->duplex = 0;
+ sc->newspeed = 0;
+ ver = (ess_getmixer(sc, 0x40) << 8) | ess_rd(sc, SB_MIX_DATA);
+ snprintf(buf, sizeof buf, "ESS %x DSP", ver);
+ device_set_desc_copy(dev, buf);
+ if (bootverbose)
+ device_printf(dev, "ESS%x detected", ver);
+
+ switch (ver) {
+ case 0x1869:
+ case 0x1879:
+#ifdef ESS18XX_DUPLEX
+ sc->duplex = sc->drq2? 1 : 0;
+#endif
+#ifdef ESS18XX_NEWSPEED
+ sc->newspeed = 1;
+#endif
+ break;
+ }
+ if (bootverbose)
+ printf("%s%s\n", sc->duplex? ", duplex" : "",
+ sc->newspeed? ", newspeed" : "");
+
+ if (sc->newspeed)
+ ess_setmixer(sc, 0x71, 0x22);
+
+ bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ess_intr, sc, &sc->ih);
+ if (!sc->duplex)
+ pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
+
+ if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
+ /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
+ /*highaddr*/BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ /*maxsize*/ESS_BUFFSIZE, /*nsegments*/1,
+ /*maxsegz*/0x3ffff,
+ /*flags*/0, &sc->parent_dmat) != 0) {
+ device_printf(dev, "unable to create dma tag\n");
+ goto no;
+ }
+
+ snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
+ rman_get_start(sc->io_base), rman_get_start(sc->irq),
+ rman_get_start(sc->drq1));
+ if (sc->drq2)
+ snprintf(status + strlen(status), SND_STATUSLEN - strlen(status),
+ ":%ld", rman_get_start(sc->drq2));
+
+ if (pcm_register(dev, sc, 1, 1))
+ goto no;
+ pcm_addchan(dev, PCMDIR_REC, &esschan_class, sc);
+ pcm_addchan(dev, PCMDIR_PLAY, &esschan_class, sc);
+ pcm_setstatus(dev, status);
+
+ return 0;
+
+no:
+ ess_release_resources(sc, dev);
+ return ENXIO;
+}
+
+static int
+ess_detach(device_t dev)
+{
+ int r;
+ struct ess_info *sc;
+
+ r = pcm_unregister(dev);
+ if (r)
+ return r;
+
+ sc = pcm_getdevinfo(dev);
+ ess_release_resources(sc, dev);
+ return 0;
}
static device_method_t ess_methods[] = {
@@ -908,6 +893,7 @@ DRIVER_MODULE(snd_ess, sbc, ess_driver, pcm_devclass, 0, 0);
MODULE_DEPEND(snd_ess, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
MODULE_VERSION(snd_ess, 1);
+/************************************************************/
static devclass_t esscontrol_devclass;
OpenPOWER on IntegriCloud