diff options
Diffstat (limited to 'sys/dev/sound/isa/ess.c')
-rw-r--r-- | sys/dev/sound/isa/ess.c | 262 |
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; |