t4dwave.c revision 50733
150724Scg/* 250724Scg * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 350724Scg * All rights reserved. 450724Scg * 550724Scg * Redistribution and use in source and binary forms, with or without 650724Scg * modification, are permitted provided that the following conditions 750724Scg * are met: 850724Scg * 1. Redistributions of source code must retain the above copyright 950724Scg * notice, this list of conditions and the following disclaimer. 1050724Scg * 2. Redistributions in binary form must reproduce the above copyright 1150724Scg * notice, this list of conditions and the following disclaimer in the 1250724Scg * documentation and/or other materials provided with the distribution. 1350724Scg * 1450724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1550724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1650724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1750724Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1850724Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1950724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2050724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2150724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 2250724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2350724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 2450724Scg * SUCH DAMAGE. 2550724Scg * 2650733Speter * $FreeBSD: head/sys/dev/sound/pci/t4dwave.c 50733 1999-09-01 06:58:27Z peter $ 2750724Scg */ 2850724Scg 2950724Scg#include "pci.h" 3050724Scg#include "pcm.h" 3150724Scg 3250724Scg#include <dev/pcm/sound.h> 3350724Scg#include <dev/pcm/ac97.h> 3450724Scg#include <dev/pcm/pci/t4dwave.h> 3550724Scg 3650724Scg#include <pci/pcireg.h> 3750724Scg#include <pci/pcivar.h> 3850724Scg 3950724Scg#if NPCI != 0 4050724Scg 4150724Scg/* -------------------------------------------------------------------- */ 4250724Scg 4350724Scgstruct tr_info; 4450724Scg 4550724Scg/* channel registers */ 4650724Scgstruct tr_chinfo { 4750724Scg u_int32_t cso, alpha, fms, fmc, ec; 4850724Scg u_int32_t lba; 4950724Scg u_int32_t eso, delta; 5050724Scg u_int32_t rvol, cvol; 5150724Scg u_int32_t gvsel, pan, vol, ctrl; 5250724Scg int index; 5350724Scg snd_dbuf *buffer; 5450724Scg pcm_channel *channel; 5550724Scg struct tr_info *parent; 5650724Scg}; 5750724Scg 5850724Scg/* device private data */ 5950724Scgstruct tr_info { 6050724Scg u_int32_t type; 6150724Scg 6250724Scg bus_space_tag_t st; 6350724Scg bus_space_handle_t sh; 6450724Scg bus_dma_tag_t parent_dmat; 6550724Scg 6650724Scg struct resource *reg, *irq; 6750724Scg int regtype, regid, irqid; 6850724Scg void *ih; 6950724Scg 7050724Scg u_int32_t playchns; 7150724Scg struct tr_chinfo chinfo[TR_MAXPLAYCH]; 7250724Scg struct tr_chinfo recchinfo; 7350724Scg}; 7450724Scg 7550724Scg/* -------------------------------------------------------------------- */ 7650724Scg 7750724Scg/* 7850724Scg * prototypes 7950724Scg */ 8050724Scg 8150724Scg/* channel interface */ 8250724Scgstatic void *trchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); 8350724Scgstatic int trchan_setdir(void *data, int dir); 8450724Scgstatic int trchan_setformat(void *data, u_int32_t format); 8550724Scgstatic int trchan_setspeed(void *data, u_int32_t speed); 8650724Scgstatic int trchan_setblocksize(void *data, u_int32_t blocksize); 8750724Scgstatic int trchan_trigger(void *data, int go); 8850724Scgstatic int trchan_getptr(void *data); 8950724Scgstatic pcmchan_caps *trchan_getcaps(void *data); 9050724Scg 9150724Scg/* talk to the codec - called from ac97.c */ 9250724Scgstatic u_int32_t tr_rdcd(void *, int); 9350724Scgstatic void tr_wrcd(void *, int, u_int32_t); 9450724Scg 9550724Scg/* stuff */ 9650724Scgstatic int tr_init(struct tr_info *); 9750724Scgstatic void tr_intr(void *); 9850724Scg 9950724Scg/* talk to the card */ 10050724Scgstatic u_int32_t tr_rd(struct tr_info *, int, int); 10150724Scgstatic void tr_wr(struct tr_info *, int, u_int32_t, int); 10250724Scg 10350724Scg/* manipulate playback channels */ 10450724Scgstatic void tr_clrint(struct tr_info *, char); 10550724Scgstatic void tr_enaint(struct tr_info *, char, int); 10650724Scgstatic u_int32_t tr_testint(struct tr_info *, char); 10750724Scgstatic void tr_rdch(struct tr_info *, char, struct tr_chinfo *); 10850724Scgstatic void tr_wrch(struct tr_info *, char, struct tr_chinfo *); 10950724Scgstatic void tr_selch(struct tr_info *, char); 11050724Scgstatic void tr_startch(struct tr_info *, char); 11150724Scgstatic void tr_stopch(struct tr_info *, char); 11250724Scg 11350724Scg/* -------------------------------------------------------------------- */ 11450724Scg 11550724Scgstatic pcmchan_caps tr_reccaps = { 11650724Scg 4000, 48000, 11750724Scg AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_U16_LE, 11850724Scg AFMT_STEREO | AFMT_S16_LE 11950724Scg}; 12050724Scg 12150724Scgstatic pcmchan_caps tr_playcaps = { 12250724Scg 4000, 48000, 12350724Scg AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_U16_LE, 12450724Scg AFMT_U16_LE 12550724Scg}; 12650724Scg 12750724Scgstatic pcm_channel tr_chantemplate = { 12850724Scg trchan_init, 12950724Scg trchan_setdir, 13050724Scg trchan_setformat, 13150724Scg trchan_setspeed, 13250724Scg trchan_setblocksize, 13350724Scg trchan_trigger, 13450724Scg trchan_getptr, 13550724Scg trchan_getcaps, 13650724Scg}; 13750724Scg 13850724Scg/* -------------------------------------------------------------------- */ 13950724Scg 14050724Scgstatic u_int32_t 14150724Scgtr_fmttobits(u_int32_t fmt) 14250724Scg{ 14350724Scg u_int32_t bits = 0; 14450724Scg bits |= (fmt & AFMT_STEREO)? 0x4 : 0; 14550724Scg bits |= (fmt & (AFMT_S8 | AFMT_S16_LE))? 0x2 : 0; 14650724Scg bits |= (fmt & (AFMT_S16_LE | AFMT_U16_LE))? 0x8 : 0; 14750724Scg return bits; 14850724Scg} 14950724Scg 15050724Scg/* Hardware */ 15150724Scg 15250724Scgstatic u_int32_t 15350724Scgtr_rd(struct tr_info *tr, int regno, int size) 15450724Scg{ 15550724Scg switch(size) { 15650724Scg case 1: 15750724Scg return bus_space_read_1(tr->st, tr->sh, regno); 15850724Scg case 2: 15950724Scg return bus_space_read_2(tr->st, tr->sh, regno); 16050724Scg case 4: 16150724Scg return bus_space_read_4(tr->st, tr->sh, regno); 16250724Scg default: 16350724Scg return 0xffffffff; 16450724Scg } 16550724Scg} 16650724Scg 16750724Scgstatic void 16850724Scgtr_wr(struct tr_info *tr, int regno, u_int32_t data, int size) 16950724Scg{ 17050724Scg switch(size) { 17150724Scg case 1: 17250724Scg bus_space_write_1(tr->st, tr->sh, regno, data); 17350724Scg break; 17450724Scg case 2: 17550724Scg bus_space_write_2(tr->st, tr->sh, regno, data); 17650724Scg break; 17750724Scg case 4: 17850724Scg bus_space_write_4(tr->st, tr->sh, regno, data); 17950724Scg break; 18050724Scg } 18150724Scg} 18250724Scg 18350724Scg/* ac97 codec */ 18450724Scg 18550724Scgstatic u_int32_t 18650724Scgtr_rdcd(void *devinfo, int regno) 18750724Scg{ 18850724Scg struct tr_info *tr = (struct tr_info *)devinfo; 18950724Scg int i, j, treg, trw; 19050724Scg 19150724Scg switch (tr->type) { 19250724Scg case TDX_PCI_ID: 19350724Scg treg=TDX_REG_CODECRD; 19450724Scg trw=TDX_CDC_RWSTAT; 19550724Scg break; 19650724Scg case TNX_PCI_ID: 19750724Scg treg=(regno & 0x100)? TNX_REG_CODEC2RD : TNX_REG_CODEC1RD; 19850724Scg trw=TNX_CDC_RWSTAT; 19950724Scg break; 20050724Scg default: 20150724Scg printf("!!! tr_rdcd defaulted !!!\n"); 20250724Scg return 0xffffffff; 20350724Scg } 20450724Scg 20550724Scg regno &= 0x7f; 20650724Scg tr_wr(tr, treg, regno | trw, 4); 20750724Scg j=trw; 20850724Scg for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) j=tr_rd(tr, treg, 4); 20950724Scg if (i == 0) printf("codec timeout during read of register %x\n", regno); 21050724Scg return (j >> TR_CDC_DATA) & 0xffff; 21150724Scg} 21250724Scg 21350724Scgstatic void 21450724Scgtr_wrcd(void *devinfo, int regno, u_int32_t data) 21550724Scg{ 21650724Scg struct tr_info *tr = (struct tr_info *)devinfo; 21750724Scg int i, j, treg, trw; 21850724Scg 21950724Scg switch (tr->type) { 22050724Scg case TDX_PCI_ID: 22150724Scg treg=TDX_REG_CODECWR; 22250724Scg trw=TDX_CDC_RWSTAT; 22350724Scg break; 22450724Scg case TNX_PCI_ID: 22550724Scg treg=TNX_REG_CODECWR; 22650724Scg trw=TNX_CDC_RWSTAT | ((regno & 0x100)? TNX_CDC_SEC : 0); 22750724Scg break; 22850724Scg default: 22950724Scg printf("!!! tr_wrcd defaulted !!!"); 23050724Scg return; 23150724Scg } 23250724Scg 23350724Scg regno &= 0x7f; 23450724Scg#if 0 23550724Scg printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno)); 23650724Scg#endif 23750724Scg j=trw; 23850724Scg for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) j=tr_rd(tr, treg, 4); 23950724Scg tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4); 24050724Scg#if 0 24150724Scg printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno)); 24250724Scg#endif 24350724Scg if (i==0) printf("codec timeout writing %x, data %x\n", regno, data); 24450724Scg} 24550724Scg 24650724Scg/* playback channel interrupts */ 24750724Scg 24850724Scgstatic u_int32_t 24950724Scgtr_testint(struct tr_info *tr, char channel) 25050724Scg{ 25150724Scg return tr_rd(tr, (channel & 0x20)? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 25250724Scg 4) & (1<<(channel & 0x1f)); 25350724Scg} 25450724Scg 25550724Scgstatic void 25650724Scgtr_clrint(struct tr_info *tr, char channel) 25750724Scg{ 25850724Scg tr_wr(tr, (channel & 0x20)? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 25950724Scg 1<<(channel & 0x1f), 4); 26050724Scg} 26150724Scg 26250724Scgstatic void 26350724Scgtr_enaint(struct tr_info *tr, char channel, int enable) 26450724Scg{ 26550724Scg u_int32_t reg = (channel & 0x20)? TR_REG_INTENB : TR_REG_INTENA; 26650724Scg u_int32_t i = tr_rd(tr, reg, 4); 26750724Scg channel &= 0x1f; 26850724Scg i &= ~(1 << channel); 26950724Scg i |= (enable? 1 : 0) << channel; 27050724Scg tr_clrint(tr, channel); 27150724Scg tr_wr(tr, reg, i, 4); 27250724Scg} 27350724Scg 27450724Scg/* playback channels */ 27550724Scg 27650724Scgstatic void 27750724Scgtr_selch(struct tr_info *tr, char channel) 27850724Scg{ 27950724Scg int i=tr_rd(tr, TR_REG_CIR, 4); 28050724Scg i &= ~TR_CIR_MASK; 28150724Scg i |= channel & 0x3f; 28250724Scg tr_wr(tr, TR_REG_CIR, i, 4); 28350724Scg} 28450724Scg 28550724Scgstatic void 28650724Scgtr_startch(struct tr_info *tr, char channel) 28750724Scg{ 28850724Scg tr_wr(tr, (channel & 0x20)? TR_REG_STARTB : TR_REG_STARTA, 28950724Scg 1<<(channel & 0x1f), 4); 29050724Scg} 29150724Scg 29250724Scgstatic void 29350724Scgtr_stopch(struct tr_info *tr, char channel) 29450724Scg{ 29550724Scg tr_wr(tr, (channel & 0x20)? TR_REG_STOPB : TR_REG_STOPA, 29650724Scg 1<<(channel & 0x1f), 4); 29750724Scg} 29850724Scg 29950724Scgstatic void 30050724Scgtr_wrch(struct tr_info *tr, char channel, struct tr_chinfo *ch) 30150724Scg{ 30250724Scg u_int32_t cr[TR_CHN_REGS], i; 30350724Scg 30450724Scg ch->gvsel &= 0x00000001; 30550724Scg ch->fmc &= 0x00000003; 30650724Scg ch->fms &= 0x0000000f; 30750724Scg ch->ctrl &= 0x0000000f; 30850724Scg ch->pan &= 0x0000007f; 30950724Scg ch->rvol &= 0x0000007f; 31050724Scg ch->cvol &= 0x0000007f; 31150724Scg ch->vol &= 0x000000ff; 31250724Scg ch->ec &= 0x00000fff; 31350724Scg ch->alpha &= 0x00000fff; 31450724Scg ch->delta &= 0x0000ffff; 31550724Scg ch->lba &= 0x3fffffff; 31650724Scg 31750724Scg cr[1]=ch->lba; 31850724Scg cr[3]=(ch->rvol<<7) | (ch->cvol); 31950724Scg cr[4]=(ch->gvsel<<31)|(ch->pan<<24)|(ch->vol<<16)|(ch->ctrl<<12)|(ch->ec); 32050724Scg 32150724Scg switch (tr->type) { 32250724Scg case TDX_PCI_ID: 32350724Scg ch->cso &= 0x0000ffff; 32450724Scg ch->eso &= 0x0000ffff; 32550724Scg cr[0]=(ch->cso<<16) | (ch->alpha<<4) | (ch->fms); 32650724Scg cr[2]=(ch->eso<<16) | (ch->delta); 32750724Scg cr[3]|=0x0000c000; 32850724Scg break; 32950724Scg case TNX_PCI_ID: 33050724Scg ch->cso &= 0x00ffffff; 33150724Scg ch->eso &= 0x00ffffff; 33250724Scg cr[0]=((ch->delta & 0xff)<<24) | (ch->cso); 33350724Scg cr[2]=((ch->delta>>16)<<24) | (ch->eso); 33450724Scg cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14); 33550724Scg break; 33650724Scg } 33750724Scg tr_selch(tr, channel); 33850724Scg for (i=0; i<TR_CHN_REGS; i++) 33950724Scg tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4); 34050724Scg} 34150724Scg 34250724Scgstatic void 34350724Scgtr_rdch(struct tr_info *tr, char channel, struct tr_chinfo *ch) 34450724Scg{ 34550724Scg u_int32_t cr[5], i; 34650724Scg tr_selch(tr, channel); 34750724Scg for (i=0; i<5; i++) cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4); 34850724Scg ch->lba= (cr[1] & 0x3fffffff); 34950724Scg ch->fmc= (cr[3] & 0x0000c000) >> 14; 35050724Scg ch->rvol= (cr[3] & 0x00003f80) >> 7; 35150724Scg ch->cvol= (cr[3] & 0x0000007f); 35250724Scg ch->gvsel= (cr[4] & 0x80000000) >> 31; 35350724Scg ch->pan= (cr[4] & 0x7f000000) >> 24; 35450724Scg ch->vol= (cr[4] & 0x00ff0000) >> 16; 35550724Scg ch->ctrl= (cr[4] & 0x0000f000) >> 12; 35650724Scg ch->ec= (cr[4] & 0x00000fff); 35750724Scg switch(tr->type) { 35850724Scg case TDX_PCI_ID: 35950724Scg ch->cso= (cr[0] & 0xffff0000) >> 16; 36050724Scg ch->alpha= (cr[0] & 0x0000fff0) >> 4; 36150724Scg ch->fms= (cr[0] & 0x0000000f); 36250724Scg ch->eso= (cr[2] & 0xffff0000) >> 16; 36350724Scg ch->delta= (cr[2] & 0x0000ffff); 36450724Scg break; 36550724Scg case TNX_PCI_ID: 36650724Scg ch->cso= (cr[0] & 0x00ffffff); 36750724Scg ch->eso= (cr[2] & 0x00ffffff); 36850724Scg ch->delta= ((cr[2] & 0xff000000) >> 16) | 36950724Scg ((cr[0] & 0xff000000) >> 24); 37050724Scg ch->alpha= (cr[3] & 0xfff00000) >> 20; 37150724Scg ch->fms= (cr[3] & 0x000f0000) >> 16; 37250724Scg break; 37350724Scg } 37450724Scg} 37550724Scg 37650724Scg/* channel interface */ 37750724Scg 37850724Scgvoid * 37950724Scgtrchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 38050724Scg{ 38150724Scg struct tr_info *tr = devinfo; 38250724Scg struct tr_chinfo *ch; 38350724Scg if (dir == PCMDIR_PLAY) { 38450724Scg ch = &tr->chinfo[tr->playchns]; 38550724Scg ch->index = tr->playchns++; 38650724Scg } else { 38750724Scg ch = &tr->recchinfo; 38850724Scg ch->index = -1; 38950724Scg } 39050724Scg ch->buffer = b; 39150724Scg ch->buffer->bufsize = TR_BUFFSIZE; 39250724Scg ch->parent = tr; 39350724Scg ch->channel = c; 39450724Scg if (chn_allocbuf(ch->buffer, tr->parent_dmat) == -1) return NULL; 39550724Scg else return ch; 39650724Scg} 39750724Scg 39850724Scgstatic int 39950724Scgtrchan_setdir(void *data, int dir) 40050724Scg{ 40150724Scg struct tr_chinfo *ch = data; 40250724Scg struct tr_info *tr = ch->parent; 40350724Scg if (dir == PCMDIR_PLAY && ch->index >= 0) { 40450724Scg ch->fmc = ch->fms = ch->ec = ch->alpha = 0; 40550724Scg ch->lba = vtophys(ch->buffer->buf); 40650724Scg ch->cso = 0; 40750724Scg ch->eso = ch->buffer->bufsize - 1; 40850724Scg ch->rvol = ch->cvol = 0; 40950724Scg ch->gvsel = 0; 41050724Scg ch->pan = 0; 41150724Scg ch->vol = 0; 41250724Scg ch->ctrl = 0x01; 41350724Scg ch->delta = 0; 41450724Scg tr_wrch(tr, ch->index, ch); 41550724Scg tr_enaint(tr, ch->index, 1); 41650724Scg } else if (dir == PCMDIR_REC && ch->index == -1) { 41750724Scg /* set up dma mode regs */ 41850724Scg u_int32_t i; 41950724Scg tr_wr(tr, TR_REG_DMAR15, 0, 1); 42050724Scg i = tr_rd(tr, TR_REG_DMAR11, 1) & 0x03; 42150724Scg tr_wr(tr, TR_REG_DMAR11, i | 0x54, 1); 42250724Scg /* set up base address */ 42350724Scg tr_wr(tr, TR_REG_DMAR0, vtophys(ch->buffer->buf), 4); 42450724Scg /* set up buffer size */ 42550724Scg i = tr_rd(tr, TR_REG_DMAR4, 4) & ~0x00ffffff; 42650724Scg tr_wr(tr, TR_REG_DMAR4, i | (ch->buffer->bufsize - 1), 4); 42750724Scg } else return -1; 42850724Scg return 0; 42950724Scg} 43050724Scg 43150724Scgstatic int 43250724Scgtrchan_setformat(void *data, u_int32_t format) 43350724Scg{ 43450724Scg struct tr_chinfo *ch = data; 43550724Scg struct tr_info *tr = ch->parent; 43650724Scg u_int32_t bits = tr_fmttobits(format); 43750724Scg 43850724Scg if (ch->index >= 0) { 43950724Scg tr_rdch(tr, ch->index, ch); 44050724Scg ch->eso = (ch->buffer->bufsize / ch->buffer->sample_size) - 1; 44150724Scg ch->ctrl = bits | 0x01; 44250724Scg tr_wrch(tr, ch->index, ch); 44350724Scg } else { 44450724Scg u_int32_t i; 44550724Scg /* set # of samples between interrupts */ 44650724Scg i = (TR_INTSAMPLES >> ((bits & 0x08)? 1 : 0)) - 1; 44750724Scg tr_wr(tr, TR_REG_SBBL, i | (i << 16), 4); 44850724Scg /* set sample format */ 44950724Scg i = 0x18 | (bits << 4); 45050724Scg tr_wr(tr, TR_REG_SBCTRL, i, 1); 45150724Scg } 45250724Scg return 0; 45350724Scg} 45450724Scg 45550724Scgstatic int 45650724Scgtrchan_setspeed(void *data, u_int32_t speed) 45750724Scg{ 45850724Scg struct tr_chinfo *ch = data; 45950724Scg struct tr_info *tr = ch->parent; 46050724Scg 46150724Scg if (ch->index >= 0) { 46250724Scg tr_rdch(tr, ch->index, ch); 46350724Scg ch->delta = (speed << 12) / 48000; 46450724Scg tr_wrch(tr, ch->index, ch); 46550724Scg return (ch->delta * 48000) >> 12; 46650724Scg } else { 46750724Scg /* setup speed */ 46850724Scg ch->delta = (48000 << 12) / speed; 46950724Scg tr_wr(tr, TR_REG_SBDELTA, ch->delta, 2); 47050724Scg return (48000 << 12) / ch->delta; 47150724Scg } 47250724Scg return 0; 47350724Scg} 47450724Scg 47550724Scgstatic int 47650724Scgtrchan_setblocksize(void *data, u_int32_t blocksize) 47750724Scg{ 47850724Scg struct tr_chinfo *ch = data; 47950724Scg return ch->buffer->bufsize / 2; 48050724Scg} 48150724Scg 48250724Scgstatic int 48350724Scgtrchan_trigger(void *data, int go) 48450724Scg{ 48550724Scg struct tr_chinfo *ch = data; 48650724Scg struct tr_info *tr = ch->parent; 48750724Scg if (ch->index >= 0) { 48850724Scg if (go == PCMTRIG_START) tr_startch(tr, ch->index); 48950724Scg else tr_stopch(tr, ch->index); 49050724Scg } else { 49150724Scg u_int32_t i = tr_rd(tr, TR_REG_SBCTRL, 1) & ~7; 49250724Scg tr_wr(tr, TR_REG_SBCTRL, i | (go == PCMTRIG_START)? 1 : 0, 1); 49350724Scg } 49450724Scg return 0; 49550724Scg} 49650724Scg 49750724Scgstatic int 49850724Scgtrchan_getptr(void *data) 49950724Scg{ 50050724Scg struct tr_chinfo *ch = data; 50150724Scg struct tr_info *tr = ch->parent; 50250724Scg if (ch->index >= 0) { 50350724Scg tr_rdch(tr, ch->index, ch); 50450724Scg return ch->cso * ch->buffer->sample_size; 50550724Scg } else return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(ch->buffer->buf); 50650724Scg} 50750724Scg 50850724Scgstatic pcmchan_caps * 50950724Scgtrchan_getcaps(void *data) 51050724Scg{ 51150724Scg struct tr_chinfo *ch = data; 51250724Scg return (ch->index >= 0)? &tr_playcaps : &tr_reccaps; 51350724Scg} 51450724Scg 51550724Scg/* The interrupt handler */ 51650724Scg 51750724Scgstatic void 51850724Scgtr_intr(void *p) 51950724Scg{ 52050724Scg struct tr_info *tr = (struct tr_info *)p; 52150724Scg u_int32_t intsrc = tr_rd(tr, TR_REG_MISCINT, 4); 52250724Scg 52350724Scg if (intsrc & TR_INT_ADDR) { 52450724Scg int i; 52550724Scg for (i = 0; i < tr->playchns; i++) { 52650724Scg if (tr_testint(tr, i)) { 52750724Scg chn_intr(tr->chinfo[i].channel); 52850724Scg tr_clrint(tr, i); 52950724Scg } 53050724Scg } 53150724Scg } 53250724Scg if (intsrc & TR_INT_SB) { 53350724Scg chn_intr(tr->recchinfo.channel); 53450724Scg tr_rd(tr, TR_REG_SBR9, 1); 53550724Scg tr_rd(tr, TR_REG_SBR10, 1); 53650724Scg } 53750724Scg} 53850724Scg 53950724Scg/* -------------------------------------------------------------------- */ 54050724Scg 54150724Scg/* 54250724Scg * Probe and attach the card 54350724Scg */ 54450724Scg 54550724Scgstatic int 54650724Scgtr_init(struct tr_info *tr) 54750724Scg{ 54850724Scg if (tr->type == TDX_PCI_ID) { 54950724Scg tr_wr(tr, TDX_REG_CODECST, TDX_CDC_ON, 4); 55050724Scg } else tr_wr(tr, TNX_REG_CODECST, TNX_CDC_ON, 4); 55150724Scg 55250724Scg tr_wr(tr, TR_REG_CIR, TR_CIR_MIDENA | TR_CIR_ADDRENA, 4); 55350724Scg tr->playchns = 0; 55450724Scg return 0; 55550724Scg} 55650724Scg 55750724Scgstatic int 55850724Scgtr_pci_probe(device_t dev) 55950724Scg{ 56050724Scg if (pci_get_devid(dev) == TDX_PCI_ID) { 56150724Scg device_set_desc(dev, "Trident 4DWave DX"); 56250724Scg return 0; 56350724Scg } 56450724Scg if (pci_get_devid(dev) == TNX_PCI_ID) { 56550724Scg device_set_desc(dev, "Trident 4DWave NX"); 56650724Scg return 0; 56750724Scg } 56850724Scg 56950724Scg return ENXIO; 57050724Scg} 57150724Scg 57250724Scgstatic int 57350724Scgtr_pci_attach(device_t dev) 57450724Scg{ 57550724Scg snddev_info *d; 57650724Scg u_int32_t data; 57750724Scg struct tr_info *tr; 57850724Scg struct ac97_info *codec; 57950724Scg int i; 58050724Scg int mapped; 58150724Scg char status[SND_STATUSLEN]; 58250724Scg 58350724Scg d = device_get_softc(dev); 58450724Scg if ((tr = malloc(sizeof(*tr), M_DEVBUF, M_NOWAIT)) == NULL) { 58550724Scg device_printf(dev, "cannot allocate softc\n"); 58650724Scg return ENXIO; 58750724Scg } 58850724Scg 58950724Scg bzero(tr, sizeof(*tr)); 59050724Scg tr->type = pci_get_devid(dev); 59150724Scg 59250724Scg data = pci_read_config(dev, PCIR_COMMAND, 2); 59350724Scg data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 59450724Scg pci_write_config(dev, PCIR_COMMAND, data, 2); 59550724Scg data = pci_read_config(dev, PCIR_COMMAND, 2); 59650724Scg 59750724Scg mapped = 0; 59850724Scg /* XXX dfr: is this strictly necessary? */ 59950724Scg for (i = 0; (mapped == 0) && (i < PCI_MAXMAPS_0); i++) { 60050724Scg tr->regid = PCIR_MAPS + i*4; 60150724Scg tr->regtype = SYS_RES_MEMORY; 60250724Scg tr->reg = bus_alloc_resource(dev, tr->regtype, &tr->regid, 60350724Scg 0, ~0, 1, RF_ACTIVE); 60450724Scg if (!tr->reg) { 60550724Scg tr->regtype = SYS_RES_IOPORT; 60650724Scg tr->reg = bus_alloc_resource(dev, tr->regtype, 60750724Scg &tr->regid, 0, ~0, 1, 60850724Scg RF_ACTIVE); 60950724Scg } 61050724Scg if (tr->reg) { 61150724Scg tr->st = rman_get_bustag(tr->reg); 61250724Scg tr->sh = rman_get_bushandle(tr->reg); 61350724Scg mapped++; 61450724Scg } 61550724Scg } 61650724Scg 61750724Scg if (mapped == 0) { 61850724Scg device_printf(dev, "unable to map register space\n"); 61950724Scg goto bad; 62050724Scg } 62150724Scg 62250724Scg if (tr_init(tr) == -1) { 62350724Scg device_printf(dev, "unable to initialize the card\n"); 62450724Scg goto bad; 62550724Scg } 62650724Scg 62750724Scg codec = ac97_create(tr, tr_rdcd, tr_wrcd); 62850724Scg if (codec == NULL) goto bad; 62950724Scg mixer_init(d, &ac97_mixer, codec); 63050724Scg 63150724Scg tr->irqid = 0; 63250724Scg tr->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &tr->irqid, 63350724Scg 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 63450724Scg if (!tr->irq || 63550724Scg bus_setup_intr(dev, tr->irq, INTR_TYPE_TTY, tr_intr, tr, &tr->ih)) { 63650724Scg device_printf(dev, "unable to map interrupt\n"); 63750724Scg goto bad; 63850724Scg } 63950724Scg 64050724Scg if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 64150724Scg /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 64250724Scg /*highaddr*/BUS_SPACE_MAXADDR, 64350724Scg /*filter*/NULL, /*filterarg*/NULL, 64450724Scg /*maxsize*/TR_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, 64550724Scg /*flags*/0, &tr->parent_dmat) != 0) { 64650724Scg device_printf(dev, "unable to create dma tag\n"); 64750724Scg goto bad; 64850724Scg } 64950724Scg 65050724Scg snprintf(status, 64, "at %s 0x%lx irq %ld", 65150724Scg (tr->regtype == SYS_RES_IOPORT)? "io" : "memory", 65250724Scg rman_get_start(tr->reg), rman_get_start(tr->irq)); 65350724Scg 65450724Scg if (pcm_register(dev, tr, TR_MAXPLAYCH, 1)) goto bad; 65550724Scg pcm_addchan(dev, PCMDIR_REC, &tr_chantemplate, tr); 65650724Scg for (i = 0; i < TR_MAXPLAYCH; i++) 65750724Scg pcm_addchan(dev, PCMDIR_PLAY, &tr_chantemplate, tr); 65850724Scg pcm_setstatus(dev, status); 65950724Scg 66050724Scg return 0; 66150724Scg 66250724Scgbad: 66350724Scg if (tr->reg) bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 66450724Scg if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih); 66550724Scg if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 66650724Scg free(tr, M_DEVBUF); 66750724Scg return ENXIO; 66850724Scg} 66950724Scg 67050724Scgstatic device_method_t tr_methods[] = { 67150724Scg /* Device interface */ 67250724Scg DEVMETHOD(device_probe, tr_pci_probe), 67350724Scg DEVMETHOD(device_attach, tr_pci_attach), 67450724Scg 67550724Scg { 0, 0 } 67650724Scg}; 67750724Scg 67850724Scgstatic driver_t tr_driver = { 67950724Scg "pcm", 68050724Scg tr_methods, 68150724Scg sizeof(snddev_info), 68250724Scg}; 68350724Scg 68450724Scgstatic devclass_t pcm_devclass; 68550724Scg 68650724ScgDRIVER_MODULE(tr, pci, tr_driver, pcm_devclass, 0, 0); 68750724Scg 68850724Scg#endif /* NPCI != 0 */ 689