1139749Simp/*- 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 27193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 28193640Sariff#include "opt_snd.h" 29193640Sariff#endif 30193640Sariff 3153465Scg#include <dev/sound/pcm/sound.h> 3253465Scg#include <dev/sound/pcm/ac97.h> 3353465Scg#include <dev/sound/pci/t4dwave.h> 3450724Scg 35119287Simp#include <dev/pci/pcireg.h> 36119287Simp#include <dev/pci/pcivar.h> 3750724Scg 3882180ScgSND_DECLARE_FILE("$FreeBSD$"); 3982180Scg 4050724Scg/* -------------------------------------------------------------------- */ 4150724Scg 4254459Scg#define TDX_PCI_ID 0x20001023 4354459Scg#define TNX_PCI_ID 0x20011023 4482490Sgreid#define ALI_PCI_ID 0x545110b9 4582363Sgreid#define SPA_PCI_ID 0x70181039 4654459Scg 4784658Scg#define TR_DEFAULT_BUFSZ 0x1000 48197401Smarius/* For ALi M5451 the DMA transfer size appears to be fixed to 64k. */ 49197401Smarius#define ALI_BUFSZ 0x10000 50197401Smarius#define TR_BUFALGN 0x8 5154459Scg#define TR_TIMEOUT_CDC 0xffff 52197401Smarius#define TR_MAXHWCH 64 53197401Smarius#define ALI_MAXHWCH 32 5454459Scg#define TR_MAXPLAYCH 4 55197401Smarius#define ALI_MAXPLAYCH 1 56136470Syongari/* 57197401Smarius * Though, it's not clearly documented in the 4DWAVE datasheet, the 58197401Smarius * DX and NX chips can't handle DMA addresses located above 1GB as the 59197401Smarius * LBA (loop begin address) register which holds the DMA base address 60197401Smarius * is 32-bit, but the two MSBs are used for other purposes. 61136470Syongari */ 62197401Smarius#define TR_MAXADDR ((1U << 30) - 1) 63197401Smarius#define ALI_MAXADDR ((1U << 31) - 1) 6454459Scg 6550724Scgstruct tr_info; 6650724Scg 6750724Scg/* channel registers */ 6850724Scgstruct tr_chinfo { 6950724Scg u_int32_t cso, alpha, fms, fmc, ec; 7050724Scg u_int32_t lba; 7150724Scg u_int32_t eso, delta; 7250724Scg u_int32_t rvol, cvol; 7350724Scg u_int32_t gvsel, pan, vol, ctrl; 7486870Siwasaki u_int32_t active:1, was_active:1; 7571503Scg int index, bufhalf; 7674763Scg struct snd_dbuf *buffer; 7774763Scg struct pcm_channel *channel; 7850724Scg struct tr_info *parent; 7950724Scg}; 8050724Scg 8170325Scgstruct tr_rchinfo { 8270325Scg u_int32_t delta; 8386870Siwasaki u_int32_t active:1, was_active:1; 8474763Scg struct snd_dbuf *buffer; 8574763Scg struct pcm_channel *channel; 8670325Scg struct tr_info *parent; 8770325Scg}; 8870325Scg 8950724Scg/* device private data */ 9050724Scgstruct tr_info { 9150724Scg u_int32_t type; 92105100Scognet u_int32_t rev; 9350724Scg 9450724Scg bus_space_tag_t st; 9550724Scg bus_space_handle_t sh; 9650724Scg bus_dma_tag_t parent_dmat; 9750724Scg 9850724Scg struct resource *reg, *irq; 9984658Scg int regtype, regid, irqid; 10084658Scg void *ih; 10150724Scg 102107285Scg struct mtx *lock; 10374763Scg 104197401Smarius u_int32_t hwchns; 10550724Scg u_int32_t playchns; 10684658Scg unsigned int bufsz; 10784658Scg 10850724Scg struct tr_chinfo chinfo[TR_MAXPLAYCH]; 10970325Scg struct tr_rchinfo recchinfo; 11050724Scg}; 11150724Scg 11250724Scg/* -------------------------------------------------------------------- */ 11350724Scg 11464881Scgstatic u_int32_t tr_recfmt[] = { 115193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 116193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 117193640Sariff SND_FORMAT(AFMT_S8, 1, 0), 118193640Sariff SND_FORMAT(AFMT_S8, 2, 0), 119193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 120193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 121193640Sariff SND_FORMAT(AFMT_U16_LE, 1, 0), 122193640Sariff SND_FORMAT(AFMT_U16_LE, 2, 0), 12364881Scg 0 12450724Scg}; 12574763Scgstatic struct pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0}; 12650724Scg 12764881Scgstatic u_int32_t tr_playfmt[] = { 128193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 129193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 130193640Sariff SND_FORMAT(AFMT_S8, 1, 0), 131193640Sariff SND_FORMAT(AFMT_S8, 2, 0), 132193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 133193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 134193640Sariff SND_FORMAT(AFMT_U16_LE, 1, 0), 135193640Sariff SND_FORMAT(AFMT_U16_LE, 2, 0), 13664881Scg 0 13750724Scg}; 13874763Scgstatic struct pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0}; 13950724Scg 14050724Scg/* -------------------------------------------------------------------- */ 14150724Scg 14250724Scg/* Hardware */ 14350724Scg 14450724Scgstatic u_int32_t 14550724Scgtr_rd(struct tr_info *tr, int regno, int size) 14650724Scg{ 14750724Scg switch(size) { 14850724Scg case 1: 14950724Scg return bus_space_read_1(tr->st, tr->sh, regno); 15050724Scg case 2: 15150724Scg return bus_space_read_2(tr->st, tr->sh, regno); 15250724Scg case 4: 15350724Scg return bus_space_read_4(tr->st, tr->sh, regno); 15450724Scg default: 15550724Scg return 0xffffffff; 15650724Scg } 15750724Scg} 15850724Scg 15950724Scgstatic void 16050724Scgtr_wr(struct tr_info *tr, int regno, u_int32_t data, int size) 16150724Scg{ 16250724Scg switch(size) { 16350724Scg case 1: 16450724Scg bus_space_write_1(tr->st, tr->sh, regno, data); 16550724Scg break; 16650724Scg case 2: 16750724Scg bus_space_write_2(tr->st, tr->sh, regno, data); 16850724Scg break; 16950724Scg case 4: 17050724Scg bus_space_write_4(tr->st, tr->sh, regno, data); 17150724Scg break; 17250724Scg } 17350724Scg} 17450724Scg 17570134Scg/* -------------------------------------------------------------------- */ 17650724Scg/* ac97 codec */ 17750724Scg 17870134Scgstatic int 17970134Scgtr_rdcd(kobj_t obj, void *devinfo, int regno) 18050724Scg{ 18150724Scg struct tr_info *tr = (struct tr_info *)devinfo; 18250724Scg int i, j, treg, trw; 18350724Scg 18450724Scg switch (tr->type) { 18582363Sgreid case SPA_PCI_ID: 18682363Sgreid treg=SPA_REG_CODECRD; 18782363Sgreid trw=SPA_CDC_RWSTAT; 18882363Sgreid break; 18982490Sgreid case ALI_PCI_ID: 190105100Scognet if (tr->rev > 0x01) 191105100Scognet treg=TDX_REG_CODECWR; 192105100Scognet else 193105100Scognet treg=TDX_REG_CODECRD; 194105100Scognet trw=TDX_CDC_RWSTAT; 195105100Scognet break; 19650724Scg case TDX_PCI_ID: 19750724Scg treg=TDX_REG_CODECRD; 19850724Scg trw=TDX_CDC_RWSTAT; 19950724Scg break; 20050724Scg case TNX_PCI_ID: 20150724Scg treg=(regno & 0x100)? TNX_REG_CODEC2RD : TNX_REG_CODEC1RD; 20250724Scg trw=TNX_CDC_RWSTAT; 20350724Scg break; 20450724Scg default: 20550724Scg printf("!!! tr_rdcd defaulted !!!\n"); 20670134Scg return -1; 20750724Scg } 20850724Scg 209105308Smarcel i = j = 0; 210105308Smarcel 21150724Scg regno &= 0x7f; 21274763Scg snd_mtxlock(tr->lock); 213105100Scognet if (tr->type == ALI_PCI_ID) { 214105100Scognet u_int32_t chk1, chk2; 215105100Scognet j = trw; 216105100Scognet for (i = TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) 217105100Scognet j = tr_rd(tr, treg, 4); 218105100Scognet if (i > 0) { 219105100Scognet chk1 = tr_rd(tr, 0xc8, 4); 220105100Scognet chk2 = tr_rd(tr, 0xc8, 4); 221105100Scognet for (i = TR_TIMEOUT_CDC; (i > 0) && (chk1 == chk2); 222105100Scognet i--) 223105100Scognet chk2 = tr_rd(tr, 0xc8, 4); 224105100Scognet } 225105100Scognet } 226105100Scognet if (tr->type != ALI_PCI_ID || i > 0) { 227105100Scognet tr_wr(tr, treg, regno | trw, 4); 228105100Scognet j=trw; 229105100Scognet for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) 230105100Scognet j=tr_rd(tr, treg, 4); 231105100Scognet } 23274763Scg snd_mtxunlock(tr->lock); 23350724Scg if (i == 0) printf("codec timeout during read of register %x\n", regno); 23450724Scg return (j >> TR_CDC_DATA) & 0xffff; 23550724Scg} 23650724Scg 23770134Scgstatic int 23870134Scgtr_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) 23950724Scg{ 24050724Scg struct tr_info *tr = (struct tr_info *)devinfo; 24150724Scg int i, j, treg, trw; 24250724Scg 24350724Scg switch (tr->type) { 24482363Sgreid case SPA_PCI_ID: 24582363Sgreid treg=SPA_REG_CODECWR; 24682363Sgreid trw=SPA_CDC_RWSTAT; 24782363Sgreid break; 24882490Sgreid case ALI_PCI_ID: 24950724Scg case TDX_PCI_ID: 25050724Scg treg=TDX_REG_CODECWR; 25150724Scg trw=TDX_CDC_RWSTAT; 25250724Scg break; 25350724Scg case TNX_PCI_ID: 25450724Scg treg=TNX_REG_CODECWR; 25550724Scg trw=TNX_CDC_RWSTAT | ((regno & 0x100)? TNX_CDC_SEC : 0); 25650724Scg break; 25750724Scg default: 25850724Scg printf("!!! tr_wrcd defaulted !!!"); 25970134Scg return -1; 26050724Scg } 26150724Scg 262105308Smarcel i = 0; 263105308Smarcel 26450724Scg regno &= 0x7f; 26550724Scg#if 0 26650724Scg printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno)); 26750724Scg#endif 26850724Scg j=trw; 26974763Scg snd_mtxlock(tr->lock); 270105100Scognet if (tr->type == ALI_PCI_ID) { 271105100Scognet j = trw; 272105100Scognet for (i = TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) 273105100Scognet j = tr_rd(tr, treg, 4); 274105100Scognet if (i > 0) { 275105100Scognet u_int32_t chk1, chk2; 276105100Scognet chk1 = tr_rd(tr, 0xc8, 4); 277105100Scognet chk2 = tr_rd(tr, 0xc8, 4); 278105100Scognet for (i = TR_TIMEOUT_CDC; (i > 0) && (chk1 == chk2); 279105100Scognet i--) 280105100Scognet chk2 = tr_rd(tr, 0xc8, 4); 281105100Scognet } 282105100Scognet } 283105100Scognet if (tr->type != ALI_PCI_ID || i > 0) { 284107285Scg for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) 285105100Scognet j=tr_rd(tr, treg, 4); 286105100Scognet if (tr->type == ALI_PCI_ID && tr->rev > 0x01) 287105100Scognet trw |= 0x0100; 288105100Scognet tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4); 289105100Scognet } 29050724Scg#if 0 29150724Scg printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno)); 29250724Scg#endif 29374763Scg snd_mtxunlock(tr->lock); 29450724Scg if (i==0) printf("codec timeout writing %x, data %x\n", regno, data); 29570134Scg return (i > 0)? 0 : -1; 29650724Scg} 29750724Scg 29870134Scgstatic kobj_method_t tr_ac97_methods[] = { 29970134Scg KOBJMETHOD(ac97_read, tr_rdcd), 30070134Scg KOBJMETHOD(ac97_write, tr_wrcd), 301193640Sariff KOBJMETHOD_END 30270134Scg}; 30370134ScgAC97_DECLARE(tr_ac97); 30470134Scg 30570134Scg/* -------------------------------------------------------------------- */ 30650724Scg/* playback channel interrupts */ 30750724Scg 30871503Scg#if 0 30950724Scgstatic u_int32_t 31070325Scgtr_testint(struct tr_chinfo *ch) 31150724Scg{ 31270325Scg struct tr_info *tr = ch->parent; 31370325Scg int bank, chan; 31470325Scg 31570325Scg bank = (ch->index & 0x20) ? 1 : 0; 31670325Scg chan = ch->index & 0x1f; 31770325Scg return tr_rd(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 4) & (1 << chan); 31850724Scg} 31971503Scg#endif 32050724Scg 32150724Scgstatic void 32270325Scgtr_clrint(struct tr_chinfo *ch) 32350724Scg{ 32470325Scg struct tr_info *tr = ch->parent; 32570325Scg int bank, chan; 32670325Scg 32770325Scg bank = (ch->index & 0x20) ? 1 : 0; 32870325Scg chan = ch->index & 0x1f; 32970325Scg tr_wr(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 1 << chan, 4); 33050724Scg} 33150724Scg 33250724Scgstatic void 33370325Scgtr_enaint(struct tr_chinfo *ch, int enable) 33450724Scg{ 33570325Scg struct tr_info *tr = ch->parent; 33670325Scg u_int32_t i, reg; 33770325Scg int bank, chan; 33870325Scg 33974763Scg snd_mtxlock(tr->lock); 34070325Scg bank = (ch->index & 0x20) ? 1 : 0; 34170325Scg chan = ch->index & 0x1f; 34270325Scg reg = bank? TR_REG_INTENB : TR_REG_INTENA; 34370325Scg 34470325Scg i = tr_rd(tr, reg, 4); 34570325Scg i &= ~(1 << chan); 34670325Scg i |= (enable? 1 : 0) << chan; 34770325Scg 34870325Scg tr_clrint(ch); 34950724Scg tr_wr(tr, reg, i, 4); 35074763Scg snd_mtxunlock(tr->lock); 35150724Scg} 35250724Scg 35350724Scg/* playback channels */ 35450724Scg 35550724Scgstatic void 35670325Scgtr_selch(struct tr_chinfo *ch) 35750724Scg{ 35870325Scg struct tr_info *tr = ch->parent; 35970325Scg int i; 36070325Scg 36170325Scg i = tr_rd(tr, TR_REG_CIR, 4); 36250724Scg i &= ~TR_CIR_MASK; 36370325Scg i |= ch->index & 0x3f; 36450724Scg tr_wr(tr, TR_REG_CIR, i, 4); 36550724Scg} 36650724Scg 36750724Scgstatic void 36870325Scgtr_startch(struct tr_chinfo *ch) 36950724Scg{ 37070325Scg struct tr_info *tr = ch->parent; 37170325Scg int bank, chan; 37270325Scg 37370325Scg bank = (ch->index & 0x20) ? 1 : 0; 37470325Scg chan = ch->index & 0x1f; 37570325Scg tr_wr(tr, bank? TR_REG_STARTB : TR_REG_STARTA, 1 << chan, 4); 37650724Scg} 37750724Scg 37850724Scgstatic void 37970325Scgtr_stopch(struct tr_chinfo *ch) 38050724Scg{ 38170325Scg struct tr_info *tr = ch->parent; 38270325Scg int bank, chan; 38370325Scg 38470325Scg bank = (ch->index & 0x20) ? 1 : 0; 38570325Scg chan = ch->index & 0x1f; 38670325Scg tr_wr(tr, bank? TR_REG_STOPB : TR_REG_STOPA, 1 << chan, 4); 38750724Scg} 38850724Scg 38950724Scgstatic void 39070325Scgtr_wrch(struct tr_chinfo *ch) 39150724Scg{ 39270325Scg struct tr_info *tr = ch->parent; 39350724Scg u_int32_t cr[TR_CHN_REGS], i; 39450724Scg 39550724Scg ch->gvsel &= 0x00000001; 39650724Scg ch->fmc &= 0x00000003; 39750724Scg ch->fms &= 0x0000000f; 39850724Scg ch->ctrl &= 0x0000000f; 39950724Scg ch->pan &= 0x0000007f; 40050724Scg ch->rvol &= 0x0000007f; 40150724Scg ch->cvol &= 0x0000007f; 40250724Scg ch->vol &= 0x000000ff; 40350724Scg ch->ec &= 0x00000fff; 40450724Scg ch->alpha &= 0x00000fff; 40550724Scg ch->delta &= 0x0000ffff; 406197401Smarius if (tr->type == ALI_PCI_ID) 407197401Smarius ch->lba &= ALI_MAXADDR; 408197401Smarius else 409197401Smarius ch->lba &= TR_MAXADDR; 41050724Scg 41150724Scg cr[1]=ch->lba; 41271503Scg cr[3]=(ch->fmc<<14) | (ch->rvol<<7) | (ch->cvol); 41371503Scg cr[4]=(ch->gvsel<<31) | (ch->pan<<24) | (ch->vol<<16) | (ch->ctrl<<12) | (ch->ec); 41450724Scg 41550724Scg switch (tr->type) { 41682363Sgreid case SPA_PCI_ID: 41782490Sgreid case ALI_PCI_ID: 41850724Scg case TDX_PCI_ID: 41950724Scg ch->cso &= 0x0000ffff; 42050724Scg ch->eso &= 0x0000ffff; 42150724Scg cr[0]=(ch->cso<<16) | (ch->alpha<<4) | (ch->fms); 42250724Scg cr[2]=(ch->eso<<16) | (ch->delta); 42350724Scg break; 42450724Scg case TNX_PCI_ID: 42550724Scg ch->cso &= 0x00ffffff; 42650724Scg ch->eso &= 0x00ffffff; 42750724Scg cr[0]=((ch->delta & 0xff)<<24) | (ch->cso); 42882183Scg cr[2]=((ch->delta>>8)<<24) | (ch->eso); 42950724Scg cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14); 43050724Scg break; 43150724Scg } 43274763Scg snd_mtxlock(tr->lock); 43370325Scg tr_selch(ch); 43450724Scg for (i=0; i<TR_CHN_REGS; i++) 43550724Scg tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4); 43674763Scg snd_mtxunlock(tr->lock); 43750724Scg} 43850724Scg 43950724Scgstatic void 44070325Scgtr_rdch(struct tr_chinfo *ch) 44150724Scg{ 44270325Scg struct tr_info *tr = ch->parent; 44350724Scg u_int32_t cr[5], i; 44470325Scg 44574763Scg snd_mtxlock(tr->lock); 44670325Scg tr_selch(ch); 44770325Scg for (i=0; i<5; i++) 44870325Scg cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4); 44974763Scg snd_mtxunlock(tr->lock); 45070325Scg 45170325Scg 452197401Smarius if (tr->type == ALI_PCI_ID) 453197401Smarius ch->lba=(cr[1] & ALI_MAXADDR); 454197401Smarius else 455197401Smarius ch->lba=(cr[1] & TR_MAXADDR); 45650724Scg ch->fmc= (cr[3] & 0x0000c000) >> 14; 45750724Scg ch->rvol= (cr[3] & 0x00003f80) >> 7; 45850724Scg ch->cvol= (cr[3] & 0x0000007f); 45950724Scg ch->gvsel= (cr[4] & 0x80000000) >> 31; 46050724Scg ch->pan= (cr[4] & 0x7f000000) >> 24; 46150724Scg ch->vol= (cr[4] & 0x00ff0000) >> 16; 46250724Scg ch->ctrl= (cr[4] & 0x0000f000) >> 12; 46350724Scg ch->ec= (cr[4] & 0x00000fff); 46450724Scg switch(tr->type) { 46582363Sgreid case SPA_PCI_ID: 46682490Sgreid case ALI_PCI_ID: 46750724Scg case TDX_PCI_ID: 46850724Scg ch->cso= (cr[0] & 0xffff0000) >> 16; 46950724Scg ch->alpha= (cr[0] & 0x0000fff0) >> 4; 47050724Scg ch->fms= (cr[0] & 0x0000000f); 47150724Scg ch->eso= (cr[2] & 0xffff0000) >> 16; 47250724Scg ch->delta= (cr[2] & 0x0000ffff); 47350724Scg break; 47450724Scg case TNX_PCI_ID: 47550724Scg ch->cso= (cr[0] & 0x00ffffff); 47650724Scg ch->eso= (cr[2] & 0x00ffffff); 47770325Scg ch->delta= ((cr[2] & 0xff000000) >> 16) | ((cr[0] & 0xff000000) >> 24); 47850724Scg ch->alpha= (cr[3] & 0xfff00000) >> 20; 47950724Scg ch->fms= (cr[3] & 0x000f0000) >> 16; 48050724Scg break; 48150724Scg } 48250724Scg} 48350724Scg 48471503Scgstatic u_int32_t 48571503Scgtr_fmttobits(u_int32_t fmt) 48671503Scg{ 48771503Scg u_int32_t bits; 48871503Scg 48971503Scg bits = 0; 49071503Scg bits |= (fmt & AFMT_SIGNED)? 0x2 : 0; 491193640Sariff bits |= (AFMT_CHANNEL(fmt) > 1)? 0x4 : 0; 49271503Scg bits |= (fmt & AFMT_16BIT)? 0x8 : 0; 49371503Scg 49471503Scg return bits; 49571503Scg} 49671503Scg 49770134Scg/* -------------------------------------------------------------------- */ 49850724Scg/* channel interface */ 49950724Scg 50070134Scgstatic void * 50174763Scgtrpchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 50250724Scg{ 50350724Scg struct tr_info *tr = devinfo; 50450724Scg struct tr_chinfo *ch; 50570325Scg 50670325Scg KASSERT(dir == PCMDIR_PLAY, ("trpchan_init: bad direction")); 50770325Scg ch = &tr->chinfo[tr->playchns]; 50870325Scg ch->index = tr->playchns++; 50950724Scg ch->buffer = b; 51050724Scg ch->parent = tr; 51150724Scg ch->channel = c; 512168847Sariff if (sndbuf_alloc(ch->buffer, tr->parent_dmat, 0, tr->bufsz) != 0) 51370325Scg return NULL; 51470325Scg 51570325Scg return ch; 51650724Scg} 51750724Scg 51850724Scgstatic int 51970325Scgtrpchan_setformat(kobj_t obj, void *data, u_int32_t format) 52050724Scg{ 52150724Scg struct tr_chinfo *ch = data; 52270325Scg 52370325Scg ch->ctrl = tr_fmttobits(format) | 0x01; 52470325Scg 52570325Scg return 0; 52670325Scg} 52770325Scg 528193640Sariffstatic u_int32_t 52970325Scgtrpchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 53070325Scg{ 53170325Scg struct tr_chinfo *ch = data; 53270325Scg 53370325Scg ch->delta = (speed << 12) / 48000; 53470325Scg return (ch->delta * 48000) >> 12; 53570325Scg} 53670325Scg 537193640Sariffstatic u_int32_t 53870325Scgtrpchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 53970325Scg{ 54070325Scg struct tr_chinfo *ch = data; 54170325Scg 54270325Scg sndbuf_resize(ch->buffer, 2, blocksize); 54370325Scg return blocksize; 54470325Scg} 54570325Scg 54670325Scgstatic int 54770325Scgtrpchan_trigger(kobj_t obj, void *data, int go) 54870325Scg{ 54970325Scg struct tr_chinfo *ch = data; 55070325Scg 551170521Sariff if (!PCMTRIG_COMMON(go)) 55270325Scg return 0; 55370325Scg 55470325Scg if (go == PCMTRIG_START) { 55571503Scg ch->fmc = 3; 55671503Scg ch->fms = 0; 55771503Scg ch->ec = 0; 55871503Scg ch->alpha = 0; 559111183Scognet ch->lba = sndbuf_getbufaddr(ch->buffer); 56050724Scg ch->cso = 0; 561193640Sariff ch->eso = (sndbuf_getsize(ch->buffer) / sndbuf_getalign(ch->buffer)) - 1; 56271503Scg ch->rvol = ch->cvol = 0x7f; 56350724Scg ch->gvsel = 0; 56450724Scg ch->pan = 0; 56550724Scg ch->vol = 0; 56671503Scg ch->bufhalf = 0; 56770325Scg tr_wrch(ch); 56870325Scg tr_enaint(ch, 1); 56970325Scg tr_startch(ch); 57086870Siwasaki ch->active = 1; 57186870Siwasaki } else { 57270325Scg tr_stopch(ch); 57386870Siwasaki ch->active = 0; 57486870Siwasaki } 57570325Scg 57650724Scg return 0; 57750724Scg} 57850724Scg 579193640Sariffstatic u_int32_t 58070325Scgtrpchan_getptr(kobj_t obj, void *data) 58150724Scg{ 58250724Scg struct tr_chinfo *ch = data; 58370325Scg 58470325Scg tr_rdch(ch); 585193640Sariff return ch->cso * sndbuf_getalign(ch->buffer); 58670325Scg} 58770325Scg 58874763Scgstatic struct pcmchan_caps * 58970325Scgtrpchan_getcaps(kobj_t obj, void *data) 59070325Scg{ 59170325Scg return &tr_playcaps; 59270325Scg} 59370325Scg 59470325Scgstatic kobj_method_t trpchan_methods[] = { 59570325Scg KOBJMETHOD(channel_init, trpchan_init), 59670325Scg KOBJMETHOD(channel_setformat, trpchan_setformat), 59770325Scg KOBJMETHOD(channel_setspeed, trpchan_setspeed), 59870325Scg KOBJMETHOD(channel_setblocksize, trpchan_setblocksize), 59970325Scg KOBJMETHOD(channel_trigger, trpchan_trigger), 60070325Scg KOBJMETHOD(channel_getptr, trpchan_getptr), 60170325Scg KOBJMETHOD(channel_getcaps, trpchan_getcaps), 602193640Sariff KOBJMETHOD_END 60370325Scg}; 60470325ScgCHANNEL_DECLARE(trpchan); 60570325Scg 60670325Scg/* -------------------------------------------------------------------- */ 60770325Scg/* rec channel interface */ 60870325Scg 60970325Scgstatic void * 61074763Scgtrrchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 61170325Scg{ 61270325Scg struct tr_info *tr = devinfo; 61370325Scg struct tr_rchinfo *ch; 61470325Scg 61570325Scg KASSERT(dir == PCMDIR_REC, ("trrchan_init: bad direction")); 61670325Scg ch = &tr->recchinfo; 61770325Scg ch->buffer = b; 61870325Scg ch->parent = tr; 61970325Scg ch->channel = c; 620168847Sariff if (sndbuf_alloc(ch->buffer, tr->parent_dmat, 0, tr->bufsz) != 0) 62170325Scg return NULL; 62270325Scg 62370325Scg return ch; 62470325Scg} 62570325Scg 62670325Scgstatic int 62770325Scgtrrchan_setformat(kobj_t obj, void *data, u_int32_t format) 62870325Scg{ 62970325Scg struct tr_rchinfo *ch = data; 63050724Scg struct tr_info *tr = ch->parent; 63170325Scg u_int32_t i, bits; 63250724Scg 63370325Scg bits = tr_fmttobits(format); 63470325Scg /* set # of samples between interrupts */ 63571503Scg i = (sndbuf_runsz(ch->buffer) >> ((bits & 0x08)? 1 : 0)) - 1; 63670325Scg tr_wr(tr, TR_REG_SBBL, i | (i << 16), 4); 63770325Scg /* set sample format */ 63870325Scg i = 0x18 | (bits << 4); 63970325Scg tr_wr(tr, TR_REG_SBCTRL, i, 1); 64070325Scg 64150724Scg return 0; 64250724Scg} 64350724Scg 644193640Sariffstatic u_int32_t 64570325Scgtrrchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 64650724Scg{ 64770325Scg struct tr_rchinfo *ch = data; 64850724Scg struct tr_info *tr = ch->parent; 64950724Scg 65070325Scg /* setup speed */ 65170325Scg ch->delta = (48000 << 12) / speed; 65270325Scg tr_wr(tr, TR_REG_SBDELTA, ch->delta, 2); 65370325Scg 65470325Scg /* return closest possible speed */ 65570325Scg return (48000 << 12) / ch->delta; 65650724Scg} 65750724Scg 658193640Sariffstatic u_int32_t 65970325Scgtrrchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 66050724Scg{ 66170325Scg struct tr_rchinfo *ch = data; 66270325Scg 66370325Scg sndbuf_resize(ch->buffer, 2, blocksize); 66470325Scg 66570325Scg return blocksize; 66650724Scg} 66750724Scg 66850724Scgstatic int 66970325Scgtrrchan_trigger(kobj_t obj, void *data, int go) 67050724Scg{ 67170325Scg struct tr_rchinfo *ch = data; 67250724Scg struct tr_info *tr = ch->parent; 67370325Scg u_int32_t i; 67459323Scg 675170521Sariff if (!PCMTRIG_COMMON(go)) 67660958Scg return 0; 67760958Scg 67870325Scg if (go == PCMTRIG_START) { 67970325Scg /* set up dma mode regs */ 68070325Scg tr_wr(tr, TR_REG_DMAR15, 0, 1); 68170325Scg i = tr_rd(tr, TR_REG_DMAR11, 1) & 0x03; 68270325Scg tr_wr(tr, TR_REG_DMAR11, i | 0x54, 1); 68370325Scg /* set up base address */ 684111183Scognet tr_wr(tr, TR_REG_DMAR0, sndbuf_getbufaddr(ch->buffer), 4); 68570325Scg /* set up buffer size */ 68670325Scg i = tr_rd(tr, TR_REG_DMAR4, 4) & ~0x00ffffff; 68770325Scg tr_wr(tr, TR_REG_DMAR4, i | (sndbuf_runsz(ch->buffer) - 1), 4); 68870325Scg /* start */ 68970325Scg tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) | 1, 1); 69086870Siwasaki ch->active = 1; 69186870Siwasaki } else { 69270325Scg tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) & ~7, 1); 69386870Siwasaki ch->active = 0; 69486870Siwasaki } 69570325Scg 69670325Scg /* return 0 if ok */ 69750724Scg return 0; 69850724Scg} 69950724Scg 700193640Sariffstatic u_int32_t 70170325Scgtrrchan_getptr(kobj_t obj, void *data) 70250724Scg{ 70370325Scg struct tr_rchinfo *ch = data; 70450724Scg struct tr_info *tr = ch->parent; 70560958Scg 70670325Scg /* return current byte offset of channel */ 707111183Scognet return tr_rd(tr, TR_REG_DMAR0, 4) - sndbuf_getbufaddr(ch->buffer); 70850724Scg} 70950724Scg 71074763Scgstatic struct pcmchan_caps * 71170325Scgtrrchan_getcaps(kobj_t obj, void *data) 71250724Scg{ 71370325Scg return &tr_reccaps; 71450724Scg} 71550724Scg 71670325Scgstatic kobj_method_t trrchan_methods[] = { 71770325Scg KOBJMETHOD(channel_init, trrchan_init), 71870325Scg KOBJMETHOD(channel_setformat, trrchan_setformat), 71970325Scg KOBJMETHOD(channel_setspeed, trrchan_setspeed), 72070325Scg KOBJMETHOD(channel_setblocksize, trrchan_setblocksize), 72170325Scg KOBJMETHOD(channel_trigger, trrchan_trigger), 72270325Scg KOBJMETHOD(channel_getptr, trrchan_getptr), 72370325Scg KOBJMETHOD(channel_getcaps, trrchan_getcaps), 724193640Sariff KOBJMETHOD_END 72570134Scg}; 72670325ScgCHANNEL_DECLARE(trrchan); 72770134Scg 72870134Scg/* -------------------------------------------------------------------- */ 72950724Scg/* The interrupt handler */ 73050724Scg 73150724Scgstatic void 73250724Scgtr_intr(void *p) 73350724Scg{ 73450724Scg struct tr_info *tr = (struct tr_info *)p; 73570325Scg struct tr_chinfo *ch; 73671503Scg u_int32_t active, mask, bufhalf, chnum, intsrc; 73771503Scg int tmp; 73850724Scg 73970325Scg intsrc = tr_rd(tr, TR_REG_MISCINT, 4); 74050724Scg if (intsrc & TR_INT_ADDR) { 74171503Scg chnum = 0; 742197401Smarius while (chnum < tr->hwchns) { 74371503Scg mask = 0x00000001; 74471503Scg active = tr_rd(tr, (chnum < 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, 4); 74571503Scg bufhalf = tr_rd(tr, (chnum < 32)? TR_REG_CSPF_A : TR_REG_CSPF_B, 4); 74671503Scg if (active) { 74771503Scg do { 74871503Scg if (active & mask) { 74971503Scg tmp = (bufhalf & mask)? 1 : 0; 75071503Scg if (chnum < tr->playchns) { 75171503Scg ch = &tr->chinfo[chnum]; 75271503Scg /* printf("%d @ %d, ", chnum, trpchan_getptr(NULL, ch)); */ 75371503Scg if (ch->bufhalf != tmp) { 75471503Scg chn_intr(ch->channel); 75571503Scg ch->bufhalf = tmp; 75674763Scg } 75771503Scg } 75871503Scg } 75971503Scg chnum++; 76071503Scg mask <<= 1; 76171503Scg } while (chnum & 31); 76271503Scg } else 76371503Scg chnum += 32; 76471503Scg 76571503Scg tr_wr(tr, (chnum <= 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, active, 4); 76650724Scg } 76750724Scg } 76850724Scg if (intsrc & TR_INT_SB) { 76950724Scg chn_intr(tr->recchinfo.channel); 77050724Scg tr_rd(tr, TR_REG_SBR9, 1); 77150724Scg tr_rd(tr, TR_REG_SBR10, 1); 77250724Scg } 77350724Scg} 77450724Scg 77550724Scg/* -------------------------------------------------------------------- */ 77650724Scg 77750724Scg/* 77850724Scg * Probe and attach the card 77950724Scg */ 78050724Scg 78150724Scgstatic int 78250724Scgtr_init(struct tr_info *tr) 78350724Scg{ 78482363Sgreid switch (tr->type) { 78582363Sgreid case SPA_PCI_ID: 78682363Sgreid tr_wr(tr, SPA_REG_GPIO, 0, 4); 78782363Sgreid tr_wr(tr, SPA_REG_CODECST, SPA_RST_OFF, 4); 78882363Sgreid break; 78982363Sgreid case TDX_PCI_ID: 79050724Scg tr_wr(tr, TDX_REG_CODECST, TDX_CDC_ON, 4); 79182363Sgreid break; 79282363Sgreid case TNX_PCI_ID: 79382363Sgreid tr_wr(tr, TNX_REG_CODECST, TNX_CDC_ON, 4); 79482363Sgreid break; 79582363Sgreid } 79650724Scg 79750724Scg tr_wr(tr, TR_REG_CIR, TR_CIR_MIDENA | TR_CIR_ADDRENA, 4); 79850724Scg return 0; 79950724Scg} 80050724Scg 80150724Scgstatic int 80250724Scgtr_pci_probe(device_t dev) 80350724Scg{ 80482363Sgreid switch (pci_get_devid(dev)) { 80582363Sgreid case SPA_PCI_ID: 80682363Sgreid device_set_desc(dev, "SiS 7018"); 807142890Simp return BUS_PROBE_DEFAULT; 80882490Sgreid case ALI_PCI_ID: 80982490Sgreid device_set_desc(dev, "Acer Labs M5451"); 810142890Simp return BUS_PROBE_DEFAULT; 81182363Sgreid case TDX_PCI_ID: 81282363Sgreid device_set_desc(dev, "Trident 4DWave DX"); 813142890Simp return BUS_PROBE_DEFAULT; 81482363Sgreid case TNX_PCI_ID: 81582363Sgreid device_set_desc(dev, "Trident 4DWave NX"); 816142890Simp return BUS_PROBE_DEFAULT; 81750724Scg } 81850724Scg 81950724Scg return ENXIO; 82050724Scg} 82150724Scg 82250724Scgstatic int 82350724Scgtr_pci_attach(device_t dev) 82450724Scg{ 82550724Scg struct tr_info *tr; 82666012Scg struct ac97_info *codec = 0; 827197401Smarius bus_addr_t lowaddr; 828173511Sariff int i, dacn; 82950724Scg char status[SND_STATUSLEN]; 830197401Smarius#ifdef __sparc64__ 831197401Smarius device_t *children; 832197401Smarius int nchildren; 833254263Sscottl u_int32_t data; 834197401Smarius#endif 83550724Scg 836170873Sariff tr = malloc(sizeof(*tr), M_DEVBUF, M_WAITOK | M_ZERO); 83750724Scg tr->type = pci_get_devid(dev); 838105100Scognet tr->rev = pci_get_revid(dev); 839167608Sariff tr->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_t4dwave softc"); 84050724Scg 841173511Sariff if (resource_int_value(device_get_name(dev), device_get_unit(dev), 842173511Sariff "dac", &i) == 0) { 843173511Sariff if (i < 1) 844173511Sariff dacn = 1; 845173511Sariff else if (i > TR_MAXPLAYCH) 846173511Sariff dacn = TR_MAXPLAYCH; 847173511Sariff else 848173511Sariff dacn = i; 849173511Sariff } else { 850173511Sariff switch (tr->type) { 851173511Sariff case ALI_PCI_ID: 852197401Smarius dacn = ALI_MAXPLAYCH; 853173511Sariff break; 854173511Sariff default: 855173511Sariff dacn = TR_MAXPLAYCH; 856173511Sariff break; 857173511Sariff } 858173511Sariff } 859173511Sariff 860254263Sscottl pci_enable_busmaster(dev); 86150724Scg 862119690Sjhb tr->regid = PCIR_BAR(0); 86370325Scg tr->regtype = SYS_RES_IOPORT; 864127135Snjl tr->reg = bus_alloc_resource_any(dev, tr->regtype, &tr->regid, 865127135Snjl RF_ACTIVE); 86670325Scg if (tr->reg) { 86770325Scg tr->st = rman_get_bustag(tr->reg); 86870325Scg tr->sh = rman_get_bushandle(tr->reg); 86970325Scg } else { 87050724Scg device_printf(dev, "unable to map register space\n"); 87150724Scg goto bad; 87250724Scg } 87350724Scg 87450724Scg if (tr_init(tr) == -1) { 87550724Scg device_printf(dev, "unable to initialize the card\n"); 87650724Scg goto bad; 87750724Scg } 87886870Siwasaki tr->playchns = 0; 87950724Scg 88070134Scg codec = AC97_CREATE(dev, tr, tr_ac97); 88150724Scg if (codec == NULL) goto bad; 88270134Scg if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad; 88350724Scg 88450724Scg tr->irqid = 0; 885127135Snjl tr->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &tr->irqid, 886127135Snjl RF_ACTIVE | RF_SHAREABLE); 887128232Sgreen if (!tr->irq || snd_setup_intr(dev, tr->irq, 0, tr_intr, tr, &tr->ih)) { 88850724Scg device_printf(dev, "unable to map interrupt\n"); 88950724Scg goto bad; 89050724Scg } 89150724Scg 892197401Smarius if (tr->type == ALI_PCI_ID) { 893197401Smarius /* 894197401Smarius * The M5451 generates 31 bit of DMA and in order to do 895197401Smarius * 32-bit DMA, the 31st bit can be set via its accompanying 896197401Smarius * ISA bridge. Note that we can't predict whether bus_dma(9) 897197401Smarius * will actually supply us with a 32-bit buffer and even when 898197401Smarius * using a low address of BUS_SPACE_MAXADDR_32BIT for both 899197401Smarius * we might end up with the play buffer being in the 32-bit 900197401Smarius * range while the record buffer isn't or vice versa. So we 901197401Smarius * limit enabling the 31st bit to sparc64, where the IOMMU 902197401Smarius * guarantees that we're using a 32-bit address (and in turn 903197401Smarius * requires it). 904197401Smarius */ 905197401Smarius lowaddr = ALI_MAXADDR; 906197401Smarius#ifdef __sparc64__ 907197401Smarius if (device_get_children(device_get_parent(dev), &children, 908197401Smarius &nchildren) == 0) { 909197401Smarius for (i = 0; i < nchildren; i++) { 910197401Smarius if (pci_get_devid(children[i]) == 0x153310b9) { 911197401Smarius lowaddr = BUS_SPACE_MAXADDR_32BIT; 912197401Smarius data = pci_read_config(children[i], 913197401Smarius 0x7e, 1); 914197401Smarius if (bootverbose) 915197401Smarius device_printf(dev, 916197401Smarius "M1533 0x7e: 0x%x -> ", 917197401Smarius data); 918197401Smarius data |= 0x1; 919197401Smarius if (bootverbose) 920197401Smarius printf("0x%x\n", data); 921197401Smarius pci_write_config(children[i], 0x7e, 922197401Smarius data, 1); 923197401Smarius break; 924197401Smarius } 925197401Smarius } 926197401Smarius } 927197401Smarius free(children, M_TEMP); 928197401Smarius#endif 929197401Smarius tr->hwchns = ALI_MAXHWCH; 930197401Smarius tr->bufsz = ALI_BUFSZ; 931197401Smarius } else { 932197401Smarius lowaddr = TR_MAXADDR; 933197401Smarius tr->hwchns = TR_MAXHWCH; 934197401Smarius tr->bufsz = pcm_getbuffersize(dev, 4096, TR_DEFAULT_BUFSZ, 935197401Smarius 65536); 936197401Smarius } 937197401Smarius 938197401Smarius if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), 939197401Smarius /*alignment*/TR_BUFALGN, 940166904Snetchild /*boundary*/0, 941197401Smarius /*lowaddr*/lowaddr, 94250724Scg /*highaddr*/BUS_SPACE_MAXADDR, 94350724Scg /*filter*/NULL, /*filterarg*/NULL, 944197401Smarius /*maxsize*/tr->bufsz, /*nsegments*/1, /*maxsegz*/tr->bufsz, 945117126Sscottl /*flags*/0, /*lockfunc*/busdma_lock_mutex, 946117126Sscottl /*lockarg*/&Giant, &tr->parent_dmat) != 0) { 94750724Scg device_printf(dev, "unable to create dma tag\n"); 94850724Scg goto bad; 94950724Scg } 95050724Scg 951126695Smatk snprintf(status, 64, "at io 0x%lx irq %ld %s", 952126695Smatk rman_get_start(tr->reg), rman_get_start(tr->irq),PCM_KLDSTRING(snd_t4dwave)); 95350724Scg 954173511Sariff if (pcm_register(dev, tr, dacn, 1)) 955173511Sariff goto bad; 95670325Scg pcm_addchan(dev, PCMDIR_REC, &trrchan_class, tr); 957173511Sariff for (i = 0; i < dacn; i++) 95870325Scg pcm_addchan(dev, PCMDIR_PLAY, &trpchan_class, tr); 95950724Scg pcm_setstatus(dev, status); 96050724Scg 96150724Scg return 0; 96250724Scg 96350724Scgbad: 96465644Scg if (codec) ac97_destroy(codec); 96550724Scg if (tr->reg) bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 96650724Scg if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih); 96750724Scg if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 96865644Scg if (tr->parent_dmat) bus_dma_tag_destroy(tr->parent_dmat); 96974763Scg if (tr->lock) snd_mtxfree(tr->lock); 97050724Scg free(tr, M_DEVBUF); 97150724Scg return ENXIO; 97250724Scg} 97350724Scg 97465644Scgstatic int 97565644Scgtr_pci_detach(device_t dev) 97665644Scg{ 97765644Scg int r; 97865644Scg struct tr_info *tr; 97965644Scg 98065644Scg r = pcm_unregister(dev); 98165644Scg if (r) 98265644Scg return r; 98365644Scg 98465644Scg tr = pcm_getdevinfo(dev); 98565644Scg bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 98665644Scg bus_teardown_intr(dev, tr->irq, tr->ih); 98765644Scg bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 98865644Scg bus_dma_tag_destroy(tr->parent_dmat); 98974763Scg snd_mtxfree(tr->lock); 99065644Scg free(tr, M_DEVBUF); 99165644Scg 99265644Scg return 0; 99365644Scg} 99465644Scg 99586870Siwasakistatic int 99686870Siwasakitr_pci_suspend(device_t dev) 99786870Siwasaki{ 99886870Siwasaki int i; 99986870Siwasaki struct tr_info *tr; 100086870Siwasaki 100186870Siwasaki tr = pcm_getdevinfo(dev); 100286870Siwasaki 100386870Siwasaki for (i = 0; i < tr->playchns; i++) { 100486870Siwasaki tr->chinfo[i].was_active = tr->chinfo[i].active; 100586870Siwasaki if (tr->chinfo[i].active) { 100686870Siwasaki trpchan_trigger(NULL, &tr->chinfo[i], PCMTRIG_STOP); 100786870Siwasaki } 100886870Siwasaki } 100986870Siwasaki 101086870Siwasaki tr->recchinfo.was_active = tr->recchinfo.active; 101186870Siwasaki if (tr->recchinfo.active) { 101286870Siwasaki trrchan_trigger(NULL, &tr->recchinfo, PCMTRIG_STOP); 101386870Siwasaki } 101486870Siwasaki 101586870Siwasaki return 0; 101686870Siwasaki} 101786870Siwasaki 101886870Siwasakistatic int 101986870Siwasakitr_pci_resume(device_t dev) 102086870Siwasaki{ 102186870Siwasaki int i; 102286870Siwasaki struct tr_info *tr; 102386870Siwasaki 102486870Siwasaki tr = pcm_getdevinfo(dev); 102586870Siwasaki 102686870Siwasaki if (tr_init(tr) == -1) { 102786870Siwasaki device_printf(dev, "unable to initialize the card\n"); 102886870Siwasaki return ENXIO; 102986870Siwasaki } 103086870Siwasaki 103186870Siwasaki if (mixer_reinit(dev) == -1) { 103286870Siwasaki device_printf(dev, "unable to initialize the mixer\n"); 103386870Siwasaki return ENXIO; 103486870Siwasaki } 103586870Siwasaki 103686870Siwasaki for (i = 0; i < tr->playchns; i++) { 103786870Siwasaki if (tr->chinfo[i].was_active) { 103886870Siwasaki trpchan_trigger(NULL, &tr->chinfo[i], PCMTRIG_START); 103986870Siwasaki } 104086870Siwasaki } 104186870Siwasaki 104286870Siwasaki if (tr->recchinfo.was_active) { 104386870Siwasaki trrchan_trigger(NULL, &tr->recchinfo, PCMTRIG_START); 104486870Siwasaki } 104586870Siwasaki 104686870Siwasaki return 0; 104786870Siwasaki} 104886870Siwasaki 104950724Scgstatic device_method_t tr_methods[] = { 105050724Scg /* Device interface */ 105150724Scg DEVMETHOD(device_probe, tr_pci_probe), 105250724Scg DEVMETHOD(device_attach, tr_pci_attach), 105365644Scg DEVMETHOD(device_detach, tr_pci_detach), 105486870Siwasaki DEVMETHOD(device_suspend, tr_pci_suspend), 105586870Siwasaki DEVMETHOD(device_resume, tr_pci_resume), 105650724Scg { 0, 0 } 105750724Scg}; 105850724Scg 105950724Scgstatic driver_t tr_driver = { 106050724Scg "pcm", 106150724Scg tr_methods, 106282180Scg PCM_SOFTC_SIZE, 106350724Scg}; 106450724Scg 106562483ScgDRIVER_MODULE(snd_t4dwave, pci, tr_driver, pcm_devclass, 0, 0); 1066132236StanimuraMODULE_DEPEND(snd_t4dwave, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 106762483ScgMODULE_VERSION(snd_t4dwave, 1); 1068