diff options
Diffstat (limited to 'sys/dev/sound/pci/csapcm.c')
-rw-r--r-- | sys/dev/sound/pci/csapcm.c | 333 |
1 files changed, 162 insertions, 171 deletions
diff --git a/sys/dev/sound/pci/csapcm.c b/sys/dev/sound/pci/csapcm.c index 1a5f807..c3ae93e 100644 --- a/sys/dev/sound/pci/csapcm.c +++ b/sys/dev/sound/pci/csapcm.c @@ -82,20 +82,6 @@ static int csa_startdsp(csa_res *resp); static int csa_allocres(struct csa_info *scp, device_t dev); static void csa_releaseres(struct csa_info *scp, device_t dev); -/* talk to the codec - called from ac97.c */ -static u_int32_t csa_rdcd(void *, int); -static void csa_wrcd(void *, int, u_int32_t); - -/* channel interface */ -static void *csachan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); -static int csachan_setdir(void *data, int dir); -static int csachan_setformat(void *data, u_int32_t format); -static int csachan_setspeed(void *data, u_int32_t speed); -static int csachan_setblocksize(void *data, u_int32_t blocksize); -static int csachan_trigger(void *data, int go); -static int csachan_getptr(void *data); -static pcmchan_caps *csachan_getcaps(void *data); - static u_int32_t csa_playfmt[] = { AFMT_U8, AFMT_STEREO | AFMT_U8, @@ -116,116 +102,37 @@ static u_int32_t csa_recfmt[] = { }; static pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0}; -static pcm_channel csa_chantemplate = { - csachan_init, - csachan_setdir, - csachan_setformat, - csachan_setspeed, - csachan_setblocksize, - csachan_trigger, - csachan_getptr, - csachan_getcaps, - NULL, /* free */ - NULL, /* nop1 */ - NULL, /* nop2 */ - NULL, /* nop3 */ - NULL, /* nop4 */ - NULL, /* nop5 */ - NULL, /* nop6 */ - NULL, /* nop7 */ -}; - /* -------------------------------------------------------------------- */ - -/* channel interface */ -static void * -csachan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) -{ - struct csa_info *csa = devinfo; - struct csa_chinfo *ch = (dir == PCMDIR_PLAY)? &csa->pch : &csa->rch; - - ch->parent = csa; - ch->channel = c; - ch->buffer = b; - ch->buffer->bufsize = CS461x_BUFFSIZE; - if (chn_allocbuf(ch->buffer, csa->parent_dmat) == -1) return NULL; - return ch; -} +/* ac97 codec */ static int -csachan_setdir(void *data, int dir) +csa_rdcd(kobj_t obj, void *devinfo, int regno) { - struct csa_chinfo *ch = data; - struct csa_info *csa = ch->parent; - csa_res *resp; + u_int32_t data; + struct csa_info *csa = (struct csa_info *)devinfo; - resp = &csa->res; + if (csa_readcodec(&csa->res, regno + BA0_AC97_RESET, &data)) + data = 0; - if (dir == PCMDIR_PLAY) - csa_writemem(resp, BA1_PBA, vtophys(ch->buffer->buf)); - else - csa_writemem(resp, BA1_CBA, vtophys(ch->buffer->buf)); - ch->dir = dir; - return 0; + return data; } static int -csachan_setformat(void *data, u_int32_t format) +csa_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) { - struct csa_chinfo *ch = data; - struct csa_info *csa = ch->parent; - u_long pdtc; - csa_res *resp; + struct csa_info *csa = (struct csa_info *)devinfo; - resp = &csa->res; + csa_writecodec(&csa->res, regno + BA0_AC97_RESET, data); - if (ch->dir == PCMDIR_REC) - csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); - else { - csa->pfie = csa_readmem(resp, BA1_PFIE) & ~0x0000f03f; - if (format & AFMT_U8 || format & AFMT_U16_LE || format & AFMT_U16_BE) - csa->pfie |= 0x8000; - if (format & AFMT_S16_BE || format & AFMT_U16_BE) - csa->pfie |= 0x4000; - if (!(format & AFMT_STEREO)) - csa->pfie |= 0x2000; - if (format & AFMT_U8 || format & AFMT_S8) - csa->pfie |= 0x1000; - csa_writemem(resp, BA1_PFIE, csa->pfie); - pdtc = csa_readmem(resp, BA1_PDTC) & ~0x000003ff; - if ((format & AFMT_S16_BE || format & AFMT_U16_BE || format & AFMT_S16_LE || format & AFMT_U16_LE) && (format & AFMT_STEREO)) - pdtc |= 0x00f; - else if ((format & AFMT_S16_BE || format & AFMT_U16_BE || format & AFMT_S16_LE || format & AFMT_U16_LE) || (format & AFMT_STEREO)) - pdtc |= 0x007; - else - pdtc |= 0x003; - csa_writemem(resp, BA1_PDTC, pdtc); - } - ch->fmt = format; return 0; } -static int -csachan_setspeed(void *data, u_int32_t speed) -{ - struct csa_chinfo *ch = data; - struct csa_info *csa = ch->parent; - csa_res *resp; - - resp = &csa->res; - - if (ch->dir == PCMDIR_PLAY) - csa_setplaysamplerate(resp, speed); - else if (ch->dir == PCMDIR_REC) - csa_setcapturesamplerate(resp, speed); - - /* rec/play speeds locked together - should indicate in flags */ -#if 0 - if (ch->direction == PCMDIR_PLAY) d->rec[0].speed = speed; - else d->play[0].speed = speed; -#endif - return speed; /* XXX calc real speed */ -} +static kobj_method_t csa_ac97_methods[] = { + KOBJMETHOD(ac97_read, csa_rdcd), + KOBJMETHOD(ac97_write, csa_wrcd), + { 0, 0 } +}; +AC97_DECLARE(csa_ac97); static void csa_setplaysamplerate(csa_res *resp, u_long ulInRate) @@ -387,40 +294,6 @@ csa_setcapturesamplerate(csa_res *resp, u_long ulOutRate) csa_writemem(resp, (BA1_CSPB + 4), 0x0000FFFF); } -static int -csachan_setblocksize(void *data, u_int32_t blocksize) -{ -#if notdef - return blocksize; -#else - struct csa_chinfo *ch = data; - return ch->buffer->bufsize / 2; -#endif /* notdef */ -} - -static int -csachan_trigger(void *data, int go) -{ - struct csa_chinfo *ch = data; - struct csa_info *csa = ch->parent; - - if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) - return 0; - - if (ch->dir == PCMDIR_PLAY) { - if (go == PCMTRIG_START) - csa_startplaydma(csa); - else - csa_stopplaydma(csa); - } else { - if (go == PCMTRIG_START) - csa_startcapturedma(csa); - else - csa_stopcapturedma(csa); - } - return 0; -} - static void csa_startplaydma(struct csa_info *csa) { @@ -638,8 +511,134 @@ csa_startdsp(csa_res *resp) return (0); } +/* -------------------------------------------------------------------- */ +/* channel interface */ + +static void * +csachan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) +{ + struct csa_info *csa = devinfo; + struct csa_chinfo *ch = (dir == PCMDIR_PLAY)? &csa->pch : &csa->rch; + + ch->parent = csa; + ch->channel = c; + ch->buffer = b; + ch->buffer->bufsize = CS461x_BUFFSIZE; + if (chn_allocbuf(ch->buffer, csa->parent_dmat) == -1) return NULL; + return ch; +} + +static int +csachan_setdir(kobj_t obj, void *data, int dir) +{ + struct csa_chinfo *ch = data; + struct csa_info *csa = ch->parent; + csa_res *resp; + + resp = &csa->res; + + if (dir == PCMDIR_PLAY) + csa_writemem(resp, BA1_PBA, vtophys(ch->buffer->buf)); + else + csa_writemem(resp, BA1_CBA, vtophys(ch->buffer->buf)); + ch->dir = dir; + return 0; +} + +static int +csachan_setformat(kobj_t obj, void *data, u_int32_t format) +{ + struct csa_chinfo *ch = data; + struct csa_info *csa = ch->parent; + u_long pdtc; + csa_res *resp; + + resp = &csa->res; + + if (ch->dir == PCMDIR_REC) + csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); + else { + csa->pfie = csa_readmem(resp, BA1_PFIE) & ~0x0000f03f; + if (format & AFMT_U8 || format & AFMT_U16_LE || format & AFMT_U16_BE) + csa->pfie |= 0x8000; + if (format & AFMT_S16_BE || format & AFMT_U16_BE) + csa->pfie |= 0x4000; + if (!(format & AFMT_STEREO)) + csa->pfie |= 0x2000; + if (format & AFMT_U8 || format & AFMT_S8) + csa->pfie |= 0x1000; + csa_writemem(resp, BA1_PFIE, csa->pfie); + pdtc = csa_readmem(resp, BA1_PDTC) & ~0x000003ff; + if ((format & AFMT_S16_BE || format & AFMT_U16_BE || format & AFMT_S16_LE || format & AFMT_U16_LE) && (format & AFMT_STEREO)) + pdtc |= 0x00f; + else if ((format & AFMT_S16_BE || format & AFMT_U16_BE || format & AFMT_S16_LE || format & AFMT_U16_LE) || (format & AFMT_STEREO)) + pdtc |= 0x007; + else + pdtc |= 0x003; + csa_writemem(resp, BA1_PDTC, pdtc); + } + ch->fmt = format; + return 0; +} + +static int +csachan_setspeed(kobj_t obj, void *data, u_int32_t speed) +{ + struct csa_chinfo *ch = data; + struct csa_info *csa = ch->parent; + csa_res *resp; + + resp = &csa->res; + + if (ch->dir == PCMDIR_PLAY) + csa_setplaysamplerate(resp, speed); + else if (ch->dir == PCMDIR_REC) + csa_setcapturesamplerate(resp, speed); + + /* rec/play speeds locked together - should indicate in flags */ +#if 0 + if (ch->direction == PCMDIR_PLAY) d->rec[0].speed = speed; + else d->play[0].speed = speed; +#endif + return speed; /* XXX calc real speed */ +} + static int -csachan_getptr(void *data) +csachan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) +{ +#if notdef + return blocksize; +#else + struct csa_chinfo *ch = data; + return ch->buffer->bufsize / 2; +#endif /* notdef */ +} + +static int +csachan_trigger(kobj_t obj, void *data, int go) +{ + struct csa_chinfo *ch = data; + struct csa_info *csa = ch->parent; + + if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) + return 0; + + if (ch->dir == PCMDIR_PLAY) { + if (go == PCMTRIG_START) + csa_startplaydma(csa); + else + csa_stopplaydma(csa); + } else { + if (go == PCMTRIG_START) + csa_startcapturedma(csa); + else + csa_stopcapturedma(csa); + } + return 0; +} + +static int +csachan_getptr(kobj_t obj, void *data) { struct csa_chinfo *ch = data; struct csa_info *csa = ch->parent; @@ -662,12 +661,26 @@ csachan_getptr(void *data) } static pcmchan_caps * -csachan_getcaps(void *data) +csachan_getcaps(kobj_t obj, void *data) { struct csa_chinfo *ch = data; return (ch->dir == PCMDIR_PLAY)? &csa_playcaps : &csa_reccaps; } +static kobj_method_t csachan_methods[] = { + KOBJMETHOD(channel_init, csachan_init), + KOBJMETHOD(channel_setdir, csachan_setdir), + KOBJMETHOD(channel_setformat, csachan_setformat), + KOBJMETHOD(channel_setspeed, csachan_setspeed), + KOBJMETHOD(channel_setblocksize, csachan_setblocksize), + KOBJMETHOD(channel_trigger, csachan_trigger), + KOBJMETHOD(channel_getptr, csachan_getptr), + KOBJMETHOD(channel_getcaps, csachan_getcaps), + { 0, 0 } +}; +CHANNEL_DECLARE(csachan); + +/* -------------------------------------------------------------------- */ /* The interrupt handler */ static void csa_intr (void *p) @@ -833,12 +846,12 @@ pcmcsa_attach(device_t dev) csa_releaseres(csa, dev); return (ENXIO); } - codec = ac97_create(dev, csa, NULL, csa_rdcd, csa_wrcd); + codec = AC97_CREATE(dev, csa, csa_ac97); if (codec == NULL) { csa_releaseres(csa, dev); return (ENXIO); } - if (mixer_init(dev, &ac97_mixer, codec) == -1) { + if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) { ac97_destroy(codec); csa_releaseres(csa, dev); return (ENXIO); @@ -860,8 +873,8 @@ pcmcsa_attach(device_t dev) csa_releaseres(csa, dev); return (ENXIO); } - pcm_addchan(dev, PCMDIR_REC, &csa_chantemplate, csa); - pcm_addchan(dev, PCMDIR_PLAY, &csa_chantemplate, csa); + pcm_addchan(dev, PCMDIR_REC, &csachan_class, csa); + pcm_addchan(dev, PCMDIR_PLAY, &csachan_class, csa); pcm_setstatus(dev, status); return (0); @@ -883,28 +896,6 @@ pcmcsa_detach(device_t dev) return 0; } -/* ac97 codec */ - -static u_int32_t -csa_rdcd(void *devinfo, int regno) -{ - u_int32_t data; - struct csa_info *csa = (struct csa_info *)devinfo; - - if (csa_readcodec(&csa->res, regno + BA0_AC97_RESET, &data)) - data = 0; - - return data; -} - -static void -csa_wrcd(void *devinfo, int regno, u_int32_t data) -{ - struct csa_info *csa = (struct csa_info *)devinfo; - - csa_writecodec(&csa->res, regno + BA0_AC97_RESET, data); -} - static device_method_t pcmcsa_methods[] = { /* Device interface */ DEVMETHOD(device_probe , pcmcsa_probe ), |