t4dwave.c revision 126695
150724Scg/* 2119853Scg * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 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 */ 2650724Scg 2753465Scg#include <dev/sound/pcm/sound.h> 2853465Scg#include <dev/sound/pcm/ac97.h> 2953465Scg#include <dev/sound/pci/t4dwave.h> 3050724Scg 31119287Simp#include <dev/pci/pcireg.h> 32119287Simp#include <dev/pci/pcivar.h> 3350724Scg 3482180ScgSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/t4dwave.c 126695 2004-03-06 15:52:42Z matk $"); 3582180Scg 3650724Scg/* -------------------------------------------------------------------- */ 3750724Scg 3854459Scg#define TDX_PCI_ID 0x20001023 3954459Scg#define TNX_PCI_ID 0x20011023 4082490Sgreid#define ALI_PCI_ID 0x545110b9 4182363Sgreid#define SPA_PCI_ID 0x70181039 4254459Scg 4384658Scg#define TR_DEFAULT_BUFSZ 0x1000 4454459Scg#define TR_TIMEOUT_CDC 0xffff 4554459Scg#define TR_MAXPLAYCH 4 4654459Scg 4750724Scgstruct tr_info; 4850724Scg 4950724Scg/* channel registers */ 5050724Scgstruct tr_chinfo { 5150724Scg u_int32_t cso, alpha, fms, fmc, ec; 5250724Scg u_int32_t lba; 5350724Scg u_int32_t eso, delta; 5450724Scg u_int32_t rvol, cvol; 5550724Scg u_int32_t gvsel, pan, vol, ctrl; 5686870Siwasaki u_int32_t active:1, was_active:1; 5771503Scg int index, bufhalf; 5874763Scg struct snd_dbuf *buffer; 5974763Scg struct pcm_channel *channel; 6050724Scg struct tr_info *parent; 6150724Scg}; 6250724Scg 6370325Scgstruct tr_rchinfo { 6470325Scg u_int32_t delta; 6586870Siwasaki u_int32_t active:1, was_active:1; 6674763Scg struct snd_dbuf *buffer; 6774763Scg struct pcm_channel *channel; 6870325Scg struct tr_info *parent; 6970325Scg}; 7070325Scg 7150724Scg/* device private data */ 7250724Scgstruct tr_info { 7350724Scg u_int32_t type; 74105100Scognet u_int32_t rev; 7550724Scg 7650724Scg bus_space_tag_t st; 7750724Scg bus_space_handle_t sh; 7850724Scg bus_dma_tag_t parent_dmat; 7950724Scg 8050724Scg struct resource *reg, *irq; 8184658Scg int regtype, regid, irqid; 8284658Scg void *ih; 8350724Scg 84107285Scg struct mtx *lock; 8574763Scg 8650724Scg u_int32_t playchns; 8784658Scg unsigned int bufsz; 8884658Scg 8950724Scg struct tr_chinfo chinfo[TR_MAXPLAYCH]; 9070325Scg struct tr_rchinfo recchinfo; 9150724Scg}; 9250724Scg 9350724Scg/* -------------------------------------------------------------------- */ 9450724Scg 9564881Scgstatic u_int32_t tr_recfmt[] = { 9664881Scg AFMT_U8, 9764881Scg AFMT_STEREO | AFMT_U8, 9864881Scg AFMT_S8, 9964881Scg AFMT_STEREO | AFMT_S8, 10064881Scg AFMT_S16_LE, 10164881Scg AFMT_STEREO | AFMT_S16_LE, 10264881Scg AFMT_U16_LE, 10364881Scg AFMT_STEREO | AFMT_U16_LE, 10464881Scg 0 10550724Scg}; 10674763Scgstatic struct pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0}; 10750724Scg 10864881Scgstatic u_int32_t tr_playfmt[] = { 10964881Scg AFMT_U8, 11064881Scg AFMT_STEREO | AFMT_U8, 11164881Scg AFMT_S8, 11264881Scg AFMT_STEREO | AFMT_S8, 11364881Scg AFMT_S16_LE, 11464881Scg AFMT_STEREO | AFMT_S16_LE, 11564881Scg AFMT_U16_LE, 11664881Scg AFMT_STEREO | AFMT_U16_LE, 11764881Scg 0 11850724Scg}; 11974763Scgstatic struct pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0}; 12050724Scg 12150724Scg/* -------------------------------------------------------------------- */ 12250724Scg 12350724Scg/* Hardware */ 12450724Scg 12550724Scgstatic u_int32_t 12650724Scgtr_rd(struct tr_info *tr, int regno, int size) 12750724Scg{ 12850724Scg switch(size) { 12950724Scg case 1: 13050724Scg return bus_space_read_1(tr->st, tr->sh, regno); 13150724Scg case 2: 13250724Scg return bus_space_read_2(tr->st, tr->sh, regno); 13350724Scg case 4: 13450724Scg return bus_space_read_4(tr->st, tr->sh, regno); 13550724Scg default: 13650724Scg return 0xffffffff; 13750724Scg } 13850724Scg} 13950724Scg 14050724Scgstatic void 14150724Scgtr_wr(struct tr_info *tr, int regno, u_int32_t data, int size) 14250724Scg{ 14350724Scg switch(size) { 14450724Scg case 1: 14550724Scg bus_space_write_1(tr->st, tr->sh, regno, data); 14650724Scg break; 14750724Scg case 2: 14850724Scg bus_space_write_2(tr->st, tr->sh, regno, data); 14950724Scg break; 15050724Scg case 4: 15150724Scg bus_space_write_4(tr->st, tr->sh, regno, data); 15250724Scg break; 15350724Scg } 15450724Scg} 15550724Scg 15670134Scg/* -------------------------------------------------------------------- */ 15750724Scg/* ac97 codec */ 15850724Scg 15970134Scgstatic int 16070134Scgtr_rdcd(kobj_t obj, void *devinfo, int regno) 16150724Scg{ 16250724Scg struct tr_info *tr = (struct tr_info *)devinfo; 16350724Scg int i, j, treg, trw; 16450724Scg 16550724Scg switch (tr->type) { 16682363Sgreid case SPA_PCI_ID: 16782363Sgreid treg=SPA_REG_CODECRD; 16882363Sgreid trw=SPA_CDC_RWSTAT; 16982363Sgreid break; 17082490Sgreid case ALI_PCI_ID: 171105100Scognet if (tr->rev > 0x01) 172105100Scognet treg=TDX_REG_CODECWR; 173105100Scognet else 174105100Scognet treg=TDX_REG_CODECRD; 175105100Scognet trw=TDX_CDC_RWSTAT; 176105100Scognet break; 17750724Scg case TDX_PCI_ID: 17850724Scg treg=TDX_REG_CODECRD; 17950724Scg trw=TDX_CDC_RWSTAT; 18050724Scg break; 18150724Scg case TNX_PCI_ID: 18250724Scg treg=(regno & 0x100)? TNX_REG_CODEC2RD : TNX_REG_CODEC1RD; 18350724Scg trw=TNX_CDC_RWSTAT; 18450724Scg break; 18550724Scg default: 18650724Scg printf("!!! tr_rdcd defaulted !!!\n"); 18770134Scg return -1; 18850724Scg } 18950724Scg 190105308Smarcel i = j = 0; 191105308Smarcel 19250724Scg regno &= 0x7f; 19374763Scg snd_mtxlock(tr->lock); 194105100Scognet if (tr->type == ALI_PCI_ID) { 195105100Scognet u_int32_t chk1, chk2; 196105100Scognet j = trw; 197105100Scognet for (i = TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) 198105100Scognet j = tr_rd(tr, treg, 4); 199105100Scognet if (i > 0) { 200105100Scognet chk1 = tr_rd(tr, 0xc8, 4); 201105100Scognet chk2 = tr_rd(tr, 0xc8, 4); 202105100Scognet for (i = TR_TIMEOUT_CDC; (i > 0) && (chk1 == chk2); 203105100Scognet i--) 204105100Scognet chk2 = tr_rd(tr, 0xc8, 4); 205105100Scognet } 206105100Scognet } 207105100Scognet if (tr->type != ALI_PCI_ID || i > 0) { 208105100Scognet tr_wr(tr, treg, regno | trw, 4); 209105100Scognet j=trw; 210105100Scognet for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) 211105100Scognet j=tr_rd(tr, treg, 4); 212105100Scognet } 21374763Scg snd_mtxunlock(tr->lock); 21450724Scg if (i == 0) printf("codec timeout during read of register %x\n", regno); 21550724Scg return (j >> TR_CDC_DATA) & 0xffff; 21650724Scg} 21750724Scg 21870134Scgstatic int 21970134Scgtr_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) 22050724Scg{ 22150724Scg struct tr_info *tr = (struct tr_info *)devinfo; 22250724Scg int i, j, treg, trw; 22350724Scg 22450724Scg switch (tr->type) { 22582363Sgreid case SPA_PCI_ID: 22682363Sgreid treg=SPA_REG_CODECWR; 22782363Sgreid trw=SPA_CDC_RWSTAT; 22882363Sgreid break; 22982490Sgreid case ALI_PCI_ID: 23050724Scg case TDX_PCI_ID: 23150724Scg treg=TDX_REG_CODECWR; 23250724Scg trw=TDX_CDC_RWSTAT; 23350724Scg break; 23450724Scg case TNX_PCI_ID: 23550724Scg treg=TNX_REG_CODECWR; 23650724Scg trw=TNX_CDC_RWSTAT | ((regno & 0x100)? TNX_CDC_SEC : 0); 23750724Scg break; 23850724Scg default: 23950724Scg printf("!!! tr_wrcd defaulted !!!"); 24070134Scg return -1; 24150724Scg } 24250724Scg 243105308Smarcel i = 0; 244105308Smarcel 24550724Scg regno &= 0x7f; 24650724Scg#if 0 24750724Scg printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno)); 24850724Scg#endif 24950724Scg j=trw; 25074763Scg snd_mtxlock(tr->lock); 251105100Scognet if (tr->type == ALI_PCI_ID) { 252105100Scognet j = trw; 253105100Scognet for (i = TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) 254105100Scognet j = tr_rd(tr, treg, 4); 255105100Scognet if (i > 0) { 256105100Scognet u_int32_t chk1, chk2; 257105100Scognet chk1 = tr_rd(tr, 0xc8, 4); 258105100Scognet chk2 = tr_rd(tr, 0xc8, 4); 259105100Scognet for (i = TR_TIMEOUT_CDC; (i > 0) && (chk1 == chk2); 260105100Scognet i--) 261105100Scognet chk2 = tr_rd(tr, 0xc8, 4); 262105100Scognet } 263105100Scognet } 264105100Scognet if (tr->type != ALI_PCI_ID || i > 0) { 265107285Scg for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) 266105100Scognet j=tr_rd(tr, treg, 4); 267105100Scognet if (tr->type == ALI_PCI_ID && tr->rev > 0x01) 268105100Scognet trw |= 0x0100; 269105100Scognet tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4); 270105100Scognet } 27150724Scg#if 0 27250724Scg printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno)); 27350724Scg#endif 27474763Scg snd_mtxunlock(tr->lock); 27550724Scg if (i==0) printf("codec timeout writing %x, data %x\n", regno, data); 27670134Scg return (i > 0)? 0 : -1; 27750724Scg} 27850724Scg 27970134Scgstatic kobj_method_t tr_ac97_methods[] = { 28070134Scg KOBJMETHOD(ac97_read, tr_rdcd), 28170134Scg KOBJMETHOD(ac97_write, tr_wrcd), 28270134Scg { 0, 0 } 28370134Scg}; 28470134ScgAC97_DECLARE(tr_ac97); 28570134Scg 28670134Scg/* -------------------------------------------------------------------- */ 28750724Scg/* playback channel interrupts */ 28850724Scg 28971503Scg#if 0 29050724Scgstatic u_int32_t 29170325Scgtr_testint(struct tr_chinfo *ch) 29250724Scg{ 29370325Scg struct tr_info *tr = ch->parent; 29470325Scg int bank, chan; 29570325Scg 29670325Scg bank = (ch->index & 0x20) ? 1 : 0; 29770325Scg chan = ch->index & 0x1f; 29870325Scg return tr_rd(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 4) & (1 << chan); 29950724Scg} 30071503Scg#endif 30150724Scg 30250724Scgstatic void 30370325Scgtr_clrint(struct tr_chinfo *ch) 30450724Scg{ 30570325Scg struct tr_info *tr = ch->parent; 30670325Scg int bank, chan; 30770325Scg 30870325Scg bank = (ch->index & 0x20) ? 1 : 0; 30970325Scg chan = ch->index & 0x1f; 31070325Scg tr_wr(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 1 << chan, 4); 31150724Scg} 31250724Scg 31350724Scgstatic void 31470325Scgtr_enaint(struct tr_chinfo *ch, int enable) 31550724Scg{ 31670325Scg struct tr_info *tr = ch->parent; 31770325Scg u_int32_t i, reg; 31870325Scg int bank, chan; 31970325Scg 32074763Scg snd_mtxlock(tr->lock); 32170325Scg bank = (ch->index & 0x20) ? 1 : 0; 32270325Scg chan = ch->index & 0x1f; 32370325Scg reg = bank? TR_REG_INTENB : TR_REG_INTENA; 32470325Scg 32570325Scg i = tr_rd(tr, reg, 4); 32670325Scg i &= ~(1 << chan); 32770325Scg i |= (enable? 1 : 0) << chan; 32870325Scg 32970325Scg tr_clrint(ch); 33050724Scg tr_wr(tr, reg, i, 4); 33174763Scg snd_mtxunlock(tr->lock); 33250724Scg} 33350724Scg 33450724Scg/* playback channels */ 33550724Scg 33650724Scgstatic void 33770325Scgtr_selch(struct tr_chinfo *ch) 33850724Scg{ 33970325Scg struct tr_info *tr = ch->parent; 34070325Scg int i; 34170325Scg 34270325Scg i = tr_rd(tr, TR_REG_CIR, 4); 34350724Scg i &= ~TR_CIR_MASK; 34470325Scg i |= ch->index & 0x3f; 34550724Scg tr_wr(tr, TR_REG_CIR, i, 4); 34650724Scg} 34750724Scg 34850724Scgstatic void 34970325Scgtr_startch(struct tr_chinfo *ch) 35050724Scg{ 35170325Scg struct tr_info *tr = ch->parent; 35270325Scg int bank, chan; 35370325Scg 35470325Scg bank = (ch->index & 0x20) ? 1 : 0; 35570325Scg chan = ch->index & 0x1f; 35670325Scg tr_wr(tr, bank? TR_REG_STARTB : TR_REG_STARTA, 1 << chan, 4); 35750724Scg} 35850724Scg 35950724Scgstatic void 36070325Scgtr_stopch(struct tr_chinfo *ch) 36150724Scg{ 36270325Scg struct tr_info *tr = ch->parent; 36370325Scg int bank, chan; 36470325Scg 36570325Scg bank = (ch->index & 0x20) ? 1 : 0; 36670325Scg chan = ch->index & 0x1f; 36770325Scg tr_wr(tr, bank? TR_REG_STOPB : TR_REG_STOPA, 1 << chan, 4); 36850724Scg} 36950724Scg 37050724Scgstatic void 37170325Scgtr_wrch(struct tr_chinfo *ch) 37250724Scg{ 37370325Scg struct tr_info *tr = ch->parent; 37450724Scg u_int32_t cr[TR_CHN_REGS], i; 37550724Scg 37650724Scg ch->gvsel &= 0x00000001; 37750724Scg ch->fmc &= 0x00000003; 37850724Scg ch->fms &= 0x0000000f; 37950724Scg ch->ctrl &= 0x0000000f; 38050724Scg ch->pan &= 0x0000007f; 38150724Scg ch->rvol &= 0x0000007f; 38250724Scg ch->cvol &= 0x0000007f; 38350724Scg ch->vol &= 0x000000ff; 38450724Scg ch->ec &= 0x00000fff; 38550724Scg ch->alpha &= 0x00000fff; 38650724Scg ch->delta &= 0x0000ffff; 38750724Scg ch->lba &= 0x3fffffff; 38850724Scg 38950724Scg cr[1]=ch->lba; 39071503Scg cr[3]=(ch->fmc<<14) | (ch->rvol<<7) | (ch->cvol); 39171503Scg cr[4]=(ch->gvsel<<31) | (ch->pan<<24) | (ch->vol<<16) | (ch->ctrl<<12) | (ch->ec); 39250724Scg 39350724Scg switch (tr->type) { 39482363Sgreid case SPA_PCI_ID: 39582490Sgreid case ALI_PCI_ID: 39650724Scg case TDX_PCI_ID: 39750724Scg ch->cso &= 0x0000ffff; 39850724Scg ch->eso &= 0x0000ffff; 39950724Scg cr[0]=(ch->cso<<16) | (ch->alpha<<4) | (ch->fms); 40050724Scg cr[2]=(ch->eso<<16) | (ch->delta); 40150724Scg break; 40250724Scg case TNX_PCI_ID: 40350724Scg ch->cso &= 0x00ffffff; 40450724Scg ch->eso &= 0x00ffffff; 40550724Scg cr[0]=((ch->delta & 0xff)<<24) | (ch->cso); 40682183Scg cr[2]=((ch->delta>>8)<<24) | (ch->eso); 40750724Scg cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14); 40850724Scg break; 40950724Scg } 41074763Scg snd_mtxlock(tr->lock); 41170325Scg tr_selch(ch); 41250724Scg for (i=0; i<TR_CHN_REGS; i++) 41350724Scg tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4); 41474763Scg snd_mtxunlock(tr->lock); 41550724Scg} 41650724Scg 41750724Scgstatic void 41870325Scgtr_rdch(struct tr_chinfo *ch) 41950724Scg{ 42070325Scg struct tr_info *tr = ch->parent; 42150724Scg u_int32_t cr[5], i; 42270325Scg 42374763Scg snd_mtxlock(tr->lock); 42470325Scg tr_selch(ch); 42570325Scg for (i=0; i<5; i++) 42670325Scg cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4); 42774763Scg snd_mtxunlock(tr->lock); 42870325Scg 42970325Scg 43050724Scg ch->lba= (cr[1] & 0x3fffffff); 43150724Scg ch->fmc= (cr[3] & 0x0000c000) >> 14; 43250724Scg ch->rvol= (cr[3] & 0x00003f80) >> 7; 43350724Scg ch->cvol= (cr[3] & 0x0000007f); 43450724Scg ch->gvsel= (cr[4] & 0x80000000) >> 31; 43550724Scg ch->pan= (cr[4] & 0x7f000000) >> 24; 43650724Scg ch->vol= (cr[4] & 0x00ff0000) >> 16; 43750724Scg ch->ctrl= (cr[4] & 0x0000f000) >> 12; 43850724Scg ch->ec= (cr[4] & 0x00000fff); 43950724Scg switch(tr->type) { 44082363Sgreid case SPA_PCI_ID: 44182490Sgreid case ALI_PCI_ID: 44250724Scg case TDX_PCI_ID: 44350724Scg ch->cso= (cr[0] & 0xffff0000) >> 16; 44450724Scg ch->alpha= (cr[0] & 0x0000fff0) >> 4; 44550724Scg ch->fms= (cr[0] & 0x0000000f); 44650724Scg ch->eso= (cr[2] & 0xffff0000) >> 16; 44750724Scg ch->delta= (cr[2] & 0x0000ffff); 44850724Scg break; 44950724Scg case TNX_PCI_ID: 45050724Scg ch->cso= (cr[0] & 0x00ffffff); 45150724Scg ch->eso= (cr[2] & 0x00ffffff); 45270325Scg ch->delta= ((cr[2] & 0xff000000) >> 16) | ((cr[0] & 0xff000000) >> 24); 45350724Scg ch->alpha= (cr[3] & 0xfff00000) >> 20; 45450724Scg ch->fms= (cr[3] & 0x000f0000) >> 16; 45550724Scg break; 45650724Scg } 45750724Scg} 45850724Scg 45971503Scgstatic u_int32_t 46071503Scgtr_fmttobits(u_int32_t fmt) 46171503Scg{ 46271503Scg u_int32_t bits; 46371503Scg 46471503Scg bits = 0; 46571503Scg bits |= (fmt & AFMT_SIGNED)? 0x2 : 0; 46671503Scg bits |= (fmt & AFMT_STEREO)? 0x4 : 0; 46771503Scg bits |= (fmt & AFMT_16BIT)? 0x8 : 0; 46871503Scg 46971503Scg return bits; 47071503Scg} 47171503Scg 47270134Scg/* -------------------------------------------------------------------- */ 47350724Scg/* channel interface */ 47450724Scg 47570134Scgstatic void * 47674763Scgtrpchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 47750724Scg{ 47850724Scg struct tr_info *tr = devinfo; 47950724Scg struct tr_chinfo *ch; 48070325Scg 48170325Scg KASSERT(dir == PCMDIR_PLAY, ("trpchan_init: bad direction")); 48270325Scg ch = &tr->chinfo[tr->playchns]; 48370325Scg ch->index = tr->playchns++; 48450724Scg ch->buffer = b; 48550724Scg ch->parent = tr; 48650724Scg ch->channel = c; 48784658Scg if (sndbuf_alloc(ch->buffer, tr->parent_dmat, tr->bufsz) == -1) 48870325Scg return NULL; 48970325Scg 49070325Scg return ch; 49150724Scg} 49250724Scg 49350724Scgstatic int 49470325Scgtrpchan_setformat(kobj_t obj, void *data, u_int32_t format) 49550724Scg{ 49650724Scg struct tr_chinfo *ch = data; 49770325Scg 49870325Scg ch->ctrl = tr_fmttobits(format) | 0x01; 49970325Scg 50070325Scg return 0; 50170325Scg} 50270325Scg 50370325Scgstatic int 50470325Scgtrpchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 50570325Scg{ 50670325Scg struct tr_chinfo *ch = data; 50770325Scg 50870325Scg ch->delta = (speed << 12) / 48000; 50970325Scg return (ch->delta * 48000) >> 12; 51070325Scg} 51170325Scg 51270325Scgstatic int 51370325Scgtrpchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 51470325Scg{ 51570325Scg struct tr_chinfo *ch = data; 51670325Scg 51770325Scg sndbuf_resize(ch->buffer, 2, blocksize); 51870325Scg return blocksize; 51970325Scg} 52070325Scg 52170325Scgstatic int 52270325Scgtrpchan_trigger(kobj_t obj, void *data, int go) 52370325Scg{ 52470325Scg struct tr_chinfo *ch = data; 52570325Scg 52670325Scg if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 52770325Scg return 0; 52870325Scg 52970325Scg if (go == PCMTRIG_START) { 53071503Scg ch->fmc = 3; 53171503Scg ch->fms = 0; 53271503Scg ch->ec = 0; 53371503Scg ch->alpha = 0; 534111183Scognet ch->lba = sndbuf_getbufaddr(ch->buffer); 53550724Scg ch->cso = 0; 53670325Scg ch->eso = (sndbuf_getsize(ch->buffer) / sndbuf_getbps(ch->buffer)) - 1; 53771503Scg ch->rvol = ch->cvol = 0x7f; 53850724Scg ch->gvsel = 0; 53950724Scg ch->pan = 0; 54050724Scg ch->vol = 0; 54171503Scg ch->bufhalf = 0; 54270325Scg tr_wrch(ch); 54370325Scg tr_enaint(ch, 1); 54470325Scg tr_startch(ch); 54586870Siwasaki ch->active = 1; 54686870Siwasaki } else { 54770325Scg tr_stopch(ch); 54886870Siwasaki ch->active = 0; 54986870Siwasaki } 55070325Scg 55150724Scg return 0; 55250724Scg} 55350724Scg 55450724Scgstatic int 55570325Scgtrpchan_getptr(kobj_t obj, void *data) 55650724Scg{ 55750724Scg struct tr_chinfo *ch = data; 55870325Scg 55970325Scg tr_rdch(ch); 56070325Scg return ch->cso * sndbuf_getbps(ch->buffer); 56170325Scg} 56270325Scg 56374763Scgstatic struct pcmchan_caps * 56470325Scgtrpchan_getcaps(kobj_t obj, void *data) 56570325Scg{ 56670325Scg return &tr_playcaps; 56770325Scg} 56870325Scg 56970325Scgstatic kobj_method_t trpchan_methods[] = { 57070325Scg KOBJMETHOD(channel_init, trpchan_init), 57170325Scg KOBJMETHOD(channel_setformat, trpchan_setformat), 57270325Scg KOBJMETHOD(channel_setspeed, trpchan_setspeed), 57370325Scg KOBJMETHOD(channel_setblocksize, trpchan_setblocksize), 57470325Scg KOBJMETHOD(channel_trigger, trpchan_trigger), 57570325Scg KOBJMETHOD(channel_getptr, trpchan_getptr), 57670325Scg KOBJMETHOD(channel_getcaps, trpchan_getcaps), 57770325Scg { 0, 0 } 57870325Scg}; 57970325ScgCHANNEL_DECLARE(trpchan); 58070325Scg 58170325Scg/* -------------------------------------------------------------------- */ 58270325Scg/* rec channel interface */ 58370325Scg 58470325Scgstatic void * 58574763Scgtrrchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 58670325Scg{ 58770325Scg struct tr_info *tr = devinfo; 58870325Scg struct tr_rchinfo *ch; 58970325Scg 59070325Scg KASSERT(dir == PCMDIR_REC, ("trrchan_init: bad direction")); 59170325Scg ch = &tr->recchinfo; 59270325Scg ch->buffer = b; 59370325Scg ch->parent = tr; 59470325Scg ch->channel = c; 59584658Scg if (sndbuf_alloc(ch->buffer, tr->parent_dmat, tr->bufsz) == -1) 59670325Scg return NULL; 59770325Scg 59870325Scg return ch; 59970325Scg} 60070325Scg 60170325Scgstatic int 60270325Scgtrrchan_setformat(kobj_t obj, void *data, u_int32_t format) 60370325Scg{ 60470325Scg struct tr_rchinfo *ch = data; 60550724Scg struct tr_info *tr = ch->parent; 60670325Scg u_int32_t i, bits; 60750724Scg 60870325Scg bits = tr_fmttobits(format); 60970325Scg /* set # of samples between interrupts */ 61071503Scg i = (sndbuf_runsz(ch->buffer) >> ((bits & 0x08)? 1 : 0)) - 1; 61170325Scg tr_wr(tr, TR_REG_SBBL, i | (i << 16), 4); 61270325Scg /* set sample format */ 61370325Scg i = 0x18 | (bits << 4); 61470325Scg tr_wr(tr, TR_REG_SBCTRL, i, 1); 61570325Scg 61650724Scg return 0; 61770325Scg 61850724Scg} 61950724Scg 62050724Scgstatic int 62170325Scgtrrchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 62250724Scg{ 62370325Scg struct tr_rchinfo *ch = data; 62450724Scg struct tr_info *tr = ch->parent; 62550724Scg 62670325Scg /* setup speed */ 62770325Scg ch->delta = (48000 << 12) / speed; 62870325Scg tr_wr(tr, TR_REG_SBDELTA, ch->delta, 2); 62970325Scg 63070325Scg /* return closest possible speed */ 63170325Scg return (48000 << 12) / ch->delta; 63250724Scg} 63350724Scg 63450724Scgstatic int 63570325Scgtrrchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 63650724Scg{ 63770325Scg struct tr_rchinfo *ch = data; 63870325Scg 63970325Scg sndbuf_resize(ch->buffer, 2, blocksize); 64070325Scg 64170325Scg return blocksize; 64250724Scg} 64350724Scg 64450724Scgstatic int 64570325Scgtrrchan_trigger(kobj_t obj, void *data, int go) 64650724Scg{ 64770325Scg struct tr_rchinfo *ch = data; 64850724Scg struct tr_info *tr = ch->parent; 64970325Scg u_int32_t i; 65059323Scg 65160958Scg if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 65260958Scg return 0; 65360958Scg 65470325Scg if (go == PCMTRIG_START) { 65570325Scg /* set up dma mode regs */ 65670325Scg tr_wr(tr, TR_REG_DMAR15, 0, 1); 65770325Scg i = tr_rd(tr, TR_REG_DMAR11, 1) & 0x03; 65870325Scg tr_wr(tr, TR_REG_DMAR11, i | 0x54, 1); 65970325Scg /* set up base address */ 660111183Scognet tr_wr(tr, TR_REG_DMAR0, sndbuf_getbufaddr(ch->buffer), 4); 66170325Scg /* set up buffer size */ 66270325Scg i = tr_rd(tr, TR_REG_DMAR4, 4) & ~0x00ffffff; 66370325Scg tr_wr(tr, TR_REG_DMAR4, i | (sndbuf_runsz(ch->buffer) - 1), 4); 66470325Scg /* start */ 66570325Scg tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) | 1, 1); 66686870Siwasaki ch->active = 1; 66786870Siwasaki } else { 66870325Scg tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) & ~7, 1); 66986870Siwasaki ch->active = 0; 67086870Siwasaki } 67170325Scg 67270325Scg /* return 0 if ok */ 67350724Scg return 0; 67450724Scg} 67550724Scg 67650724Scgstatic int 67770325Scgtrrchan_getptr(kobj_t obj, void *data) 67850724Scg{ 67970325Scg struct tr_rchinfo *ch = data; 68050724Scg struct tr_info *tr = ch->parent; 68160958Scg 68270325Scg /* return current byte offset of channel */ 683111183Scognet return tr_rd(tr, TR_REG_DMAR0, 4) - sndbuf_getbufaddr(ch->buffer); 68450724Scg} 68550724Scg 68674763Scgstatic struct pcmchan_caps * 68770325Scgtrrchan_getcaps(kobj_t obj, void *data) 68850724Scg{ 68970325Scg return &tr_reccaps; 69050724Scg} 69150724Scg 69270325Scgstatic kobj_method_t trrchan_methods[] = { 69370325Scg KOBJMETHOD(channel_init, trrchan_init), 69470325Scg KOBJMETHOD(channel_setformat, trrchan_setformat), 69570325Scg KOBJMETHOD(channel_setspeed, trrchan_setspeed), 69670325Scg KOBJMETHOD(channel_setblocksize, trrchan_setblocksize), 69770325Scg KOBJMETHOD(channel_trigger, trrchan_trigger), 69870325Scg KOBJMETHOD(channel_getptr, trrchan_getptr), 69970325Scg KOBJMETHOD(channel_getcaps, trrchan_getcaps), 70070134Scg { 0, 0 } 70170134Scg}; 70270325ScgCHANNEL_DECLARE(trrchan); 70370134Scg 70470134Scg/* -------------------------------------------------------------------- */ 70550724Scg/* The interrupt handler */ 70650724Scg 70750724Scgstatic void 70850724Scgtr_intr(void *p) 70950724Scg{ 71050724Scg struct tr_info *tr = (struct tr_info *)p; 71170325Scg struct tr_chinfo *ch; 71271503Scg u_int32_t active, mask, bufhalf, chnum, intsrc; 71371503Scg int tmp; 71450724Scg 71570325Scg intsrc = tr_rd(tr, TR_REG_MISCINT, 4); 71650724Scg if (intsrc & TR_INT_ADDR) { 71771503Scg chnum = 0; 71871503Scg while (chnum < 64) { 71971503Scg mask = 0x00000001; 72071503Scg active = tr_rd(tr, (chnum < 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, 4); 72171503Scg bufhalf = tr_rd(tr, (chnum < 32)? TR_REG_CSPF_A : TR_REG_CSPF_B, 4); 72271503Scg if (active) { 72371503Scg do { 72471503Scg if (active & mask) { 72571503Scg tmp = (bufhalf & mask)? 1 : 0; 72671503Scg if (chnum < tr->playchns) { 72771503Scg ch = &tr->chinfo[chnum]; 72871503Scg /* printf("%d @ %d, ", chnum, trpchan_getptr(NULL, ch)); */ 72971503Scg if (ch->bufhalf != tmp) { 73071503Scg chn_intr(ch->channel); 73171503Scg ch->bufhalf = tmp; 73274763Scg } 73371503Scg } 73471503Scg } 73571503Scg chnum++; 73671503Scg mask <<= 1; 73771503Scg } while (chnum & 31); 73871503Scg } else 73971503Scg chnum += 32; 74071503Scg 74171503Scg tr_wr(tr, (chnum <= 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, active, 4); 74250724Scg } 74350724Scg } 74450724Scg if (intsrc & TR_INT_SB) { 74550724Scg chn_intr(tr->recchinfo.channel); 74650724Scg tr_rd(tr, TR_REG_SBR9, 1); 74750724Scg tr_rd(tr, TR_REG_SBR10, 1); 74850724Scg } 74950724Scg} 75050724Scg 75150724Scg/* -------------------------------------------------------------------- */ 75250724Scg 75350724Scg/* 75450724Scg * Probe and attach the card 75550724Scg */ 75650724Scg 75750724Scgstatic int 75850724Scgtr_init(struct tr_info *tr) 75950724Scg{ 76082363Sgreid switch (tr->type) { 76182363Sgreid case SPA_PCI_ID: 76282363Sgreid tr_wr(tr, SPA_REG_GPIO, 0, 4); 76382363Sgreid tr_wr(tr, SPA_REG_CODECST, SPA_RST_OFF, 4); 76482363Sgreid break; 76582363Sgreid case TDX_PCI_ID: 76650724Scg tr_wr(tr, TDX_REG_CODECST, TDX_CDC_ON, 4); 76782363Sgreid break; 76882363Sgreid case TNX_PCI_ID: 76982363Sgreid tr_wr(tr, TNX_REG_CODECST, TNX_CDC_ON, 4); 77082363Sgreid break; 77182363Sgreid } 77250724Scg 77350724Scg tr_wr(tr, TR_REG_CIR, TR_CIR_MIDENA | TR_CIR_ADDRENA, 4); 77450724Scg return 0; 77550724Scg} 77650724Scg 77750724Scgstatic int 77850724Scgtr_pci_probe(device_t dev) 77950724Scg{ 78082363Sgreid switch (pci_get_devid(dev)) { 78182363Sgreid case SPA_PCI_ID: 78282363Sgreid device_set_desc(dev, "SiS 7018"); 78382363Sgreid return 0; 78482490Sgreid case ALI_PCI_ID: 78582490Sgreid device_set_desc(dev, "Acer Labs M5451"); 78682490Sgreid return 0; 78782363Sgreid case TDX_PCI_ID: 78882363Sgreid device_set_desc(dev, "Trident 4DWave DX"); 78982363Sgreid return 0; 79082363Sgreid case TNX_PCI_ID: 79182363Sgreid device_set_desc(dev, "Trident 4DWave NX"); 79282363Sgreid return 0; 79350724Scg } 79450724Scg 79550724Scg return ENXIO; 79650724Scg} 79750724Scg 79850724Scgstatic int 79950724Scgtr_pci_attach(device_t dev) 80050724Scg{ 80150724Scg u_int32_t data; 80250724Scg struct tr_info *tr; 80366012Scg struct ac97_info *codec = 0; 80450724Scg int i; 80550724Scg char status[SND_STATUSLEN]; 80650724Scg 80778564Sgreid if ((tr = malloc(sizeof(*tr), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 80850724Scg device_printf(dev, "cannot allocate softc\n"); 80950724Scg return ENXIO; 81050724Scg } 81150724Scg 81250724Scg tr->type = pci_get_devid(dev); 813105100Scognet tr->rev = pci_get_revid(dev); 81493816Sjhb tr->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); 81550724Scg 81650724Scg data = pci_read_config(dev, PCIR_COMMAND, 2); 81750724Scg data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 81850724Scg pci_write_config(dev, PCIR_COMMAND, data, 2); 81950724Scg data = pci_read_config(dev, PCIR_COMMAND, 2); 82050724Scg 821119690Sjhb tr->regid = PCIR_BAR(0); 82270325Scg tr->regtype = SYS_RES_IOPORT; 82370325Scg tr->reg = bus_alloc_resource(dev, tr->regtype, &tr->regid, 0, ~0, 1, RF_ACTIVE); 82470325Scg if (tr->reg) { 82570325Scg tr->st = rman_get_bustag(tr->reg); 82670325Scg tr->sh = rman_get_bushandle(tr->reg); 82770325Scg } else { 82850724Scg device_printf(dev, "unable to map register space\n"); 82950724Scg goto bad; 83050724Scg } 83150724Scg 83284658Scg tr->bufsz = pcm_getbuffersize(dev, 4096, TR_DEFAULT_BUFSZ, 65536); 83384658Scg 83450724Scg if (tr_init(tr) == -1) { 83550724Scg device_printf(dev, "unable to initialize the card\n"); 83650724Scg goto bad; 83750724Scg } 83886870Siwasaki tr->playchns = 0; 83950724Scg 84070134Scg codec = AC97_CREATE(dev, tr, tr_ac97); 84150724Scg if (codec == NULL) goto bad; 84270134Scg if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad; 84350724Scg 84450724Scg tr->irqid = 0; 84550724Scg tr->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &tr->irqid, 84650724Scg 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 84774763Scg if (!tr->irq || snd_setup_intr(dev, tr->irq, INTR_MPSAFE, tr_intr, tr, &tr->ih)) { 84850724Scg device_printf(dev, "unable to map interrupt\n"); 84950724Scg goto bad; 85050724Scg } 85150724Scg 85250724Scg if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 85350724Scg /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 85450724Scg /*highaddr*/BUS_SPACE_MAXADDR, 85550724Scg /*filter*/NULL, /*filterarg*/NULL, 85684658Scg /*maxsize*/tr->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, 857117126Sscottl /*flags*/0, /*lockfunc*/busdma_lock_mutex, 858117126Sscottl /*lockarg*/&Giant, &tr->parent_dmat) != 0) { 85950724Scg device_printf(dev, "unable to create dma tag\n"); 86050724Scg goto bad; 86150724Scg } 86250724Scg 863126695Smatk snprintf(status, 64, "at io 0x%lx irq %ld %s", 864126695Smatk rman_get_start(tr->reg), rman_get_start(tr->irq),PCM_KLDSTRING(snd_t4dwave)); 86550724Scg 86650724Scg if (pcm_register(dev, tr, TR_MAXPLAYCH, 1)) goto bad; 86770325Scg pcm_addchan(dev, PCMDIR_REC, &trrchan_class, tr); 86850724Scg for (i = 0; i < TR_MAXPLAYCH; i++) 86970325Scg pcm_addchan(dev, PCMDIR_PLAY, &trpchan_class, tr); 87050724Scg pcm_setstatus(dev, status); 87150724Scg 87250724Scg return 0; 87350724Scg 87450724Scgbad: 87565644Scg if (codec) ac97_destroy(codec); 87650724Scg if (tr->reg) bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 87750724Scg if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih); 87850724Scg if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 87965644Scg if (tr->parent_dmat) bus_dma_tag_destroy(tr->parent_dmat); 88074763Scg if (tr->lock) snd_mtxfree(tr->lock); 88150724Scg free(tr, M_DEVBUF); 88250724Scg return ENXIO; 88350724Scg} 88450724Scg 88565644Scgstatic int 88665644Scgtr_pci_detach(device_t dev) 88765644Scg{ 88865644Scg int r; 88965644Scg struct tr_info *tr; 89065644Scg 89165644Scg r = pcm_unregister(dev); 89265644Scg if (r) 89365644Scg return r; 89465644Scg 89565644Scg tr = pcm_getdevinfo(dev); 89665644Scg bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 89765644Scg bus_teardown_intr(dev, tr->irq, tr->ih); 89865644Scg bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 89965644Scg bus_dma_tag_destroy(tr->parent_dmat); 90074763Scg snd_mtxfree(tr->lock); 90165644Scg free(tr, M_DEVBUF); 90265644Scg 90365644Scg return 0; 90465644Scg} 90565644Scg 90686870Siwasakistatic int 90786870Siwasakitr_pci_suspend(device_t dev) 90886870Siwasaki{ 90986870Siwasaki int i; 91086870Siwasaki struct tr_info *tr; 91186870Siwasaki 91286870Siwasaki tr = pcm_getdevinfo(dev); 91386870Siwasaki 91486870Siwasaki for (i = 0; i < tr->playchns; i++) { 91586870Siwasaki tr->chinfo[i].was_active = tr->chinfo[i].active; 91686870Siwasaki if (tr->chinfo[i].active) { 91786870Siwasaki trpchan_trigger(NULL, &tr->chinfo[i], PCMTRIG_STOP); 91886870Siwasaki } 91986870Siwasaki } 92086870Siwasaki 92186870Siwasaki tr->recchinfo.was_active = tr->recchinfo.active; 92286870Siwasaki if (tr->recchinfo.active) { 92386870Siwasaki trrchan_trigger(NULL, &tr->recchinfo, PCMTRIG_STOP); 92486870Siwasaki } 92586870Siwasaki 92686870Siwasaki return 0; 92786870Siwasaki} 92886870Siwasaki 92986870Siwasakistatic int 93086870Siwasakitr_pci_resume(device_t dev) 93186870Siwasaki{ 93286870Siwasaki int i; 93386870Siwasaki struct tr_info *tr; 93486870Siwasaki 93586870Siwasaki tr = pcm_getdevinfo(dev); 93686870Siwasaki 93786870Siwasaki if (tr_init(tr) == -1) { 93886870Siwasaki device_printf(dev, "unable to initialize the card\n"); 93986870Siwasaki return ENXIO; 94086870Siwasaki } 94186870Siwasaki 94286870Siwasaki if (mixer_reinit(dev) == -1) { 94386870Siwasaki device_printf(dev, "unable to initialize the mixer\n"); 94486870Siwasaki return ENXIO; 94586870Siwasaki } 94686870Siwasaki 94786870Siwasaki for (i = 0; i < tr->playchns; i++) { 94886870Siwasaki if (tr->chinfo[i].was_active) { 94986870Siwasaki trpchan_trigger(NULL, &tr->chinfo[i], PCMTRIG_START); 95086870Siwasaki } 95186870Siwasaki } 95286870Siwasaki 95386870Siwasaki if (tr->recchinfo.was_active) { 95486870Siwasaki trrchan_trigger(NULL, &tr->recchinfo, PCMTRIG_START); 95586870Siwasaki } 95686870Siwasaki 95786870Siwasaki return 0; 95886870Siwasaki} 95986870Siwasaki 96050724Scgstatic device_method_t tr_methods[] = { 96150724Scg /* Device interface */ 96250724Scg DEVMETHOD(device_probe, tr_pci_probe), 96350724Scg DEVMETHOD(device_attach, tr_pci_attach), 96465644Scg DEVMETHOD(device_detach, tr_pci_detach), 96586870Siwasaki DEVMETHOD(device_suspend, tr_pci_suspend), 96686870Siwasaki DEVMETHOD(device_resume, tr_pci_resume), 96750724Scg { 0, 0 } 96850724Scg}; 96950724Scg 97050724Scgstatic driver_t tr_driver = { 97150724Scg "pcm", 97250724Scg tr_methods, 97382180Scg PCM_SOFTC_SIZE, 97450724Scg}; 97550724Scg 97662483ScgDRIVER_MODULE(snd_t4dwave, pci, tr_driver, pcm_devclass, 0, 0); 97762483ScgMODULE_DEPEND(snd_t4dwave, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 97862483ScgMODULE_VERSION(snd_t4dwave, 1); 979