1987e5972SCameron Grant /* 2987e5972SCameron Grant * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3987e5972SCameron Grant * All rights reserved. 4987e5972SCameron Grant * 5987e5972SCameron Grant * Redistribution and use in source and binary forms, with or without 6987e5972SCameron Grant * modification, are permitted provided that the following conditions 7987e5972SCameron Grant * are met: 8987e5972SCameron Grant * 1. Redistributions of source code must retain the above copyright 9987e5972SCameron Grant * notice, this list of conditions and the following disclaimer. 10987e5972SCameron Grant * 2. Redistributions in binary form must reproduce the above copyright 11987e5972SCameron Grant * notice, this list of conditions and the following disclaimer in the 12987e5972SCameron Grant * documentation and/or other materials provided with the distribution. 13987e5972SCameron Grant * 14987e5972SCameron Grant * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15987e5972SCameron Grant * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16987e5972SCameron Grant * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17987e5972SCameron Grant * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18987e5972SCameron Grant * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19987e5972SCameron Grant * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20987e5972SCameron Grant * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21987e5972SCameron Grant * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22987e5972SCameron Grant * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23987e5972SCameron Grant * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24987e5972SCameron Grant * SUCH DAMAGE. 25987e5972SCameron Grant */ 26987e5972SCameron Grant 27ef9308b1SCameron Grant #include <dev/sound/pcm/sound.h> 28ef9308b1SCameron Grant #include <dev/sound/pcm/ac97.h> 29ef9308b1SCameron Grant #include <dev/sound/pci/t4dwave.h> 30987e5972SCameron Grant 31987e5972SCameron Grant #include <pci/pcireg.h> 32987e5972SCameron Grant #include <pci/pcivar.h> 33987e5972SCameron Grant 3467b1dce3SCameron Grant SND_DECLARE_FILE("$FreeBSD$"); 3567b1dce3SCameron Grant 36987e5972SCameron Grant /* -------------------------------------------------------------------- */ 37987e5972SCameron Grant 38dedf4424SCameron Grant #define TDX_PCI_ID 0x20001023 39dedf4424SCameron Grant #define TNX_PCI_ID 0x20011023 40874f2e78SGeorge C A Reid #define SPA_PCI_ID 0x70181039 41dedf4424SCameron Grant 427ed9700bSCameron Grant #define TR_BUFFSIZE 0x1000 43dedf4424SCameron Grant #define TR_TIMEOUT_CDC 0xffff 44dedf4424SCameron Grant #define TR_MAXPLAYCH 4 45dedf4424SCameron Grant 46987e5972SCameron Grant struct tr_info; 47987e5972SCameron Grant 48987e5972SCameron Grant /* channel registers */ 49987e5972SCameron Grant struct tr_chinfo { 50987e5972SCameron Grant u_int32_t cso, alpha, fms, fmc, ec; 51987e5972SCameron Grant u_int32_t lba; 52987e5972SCameron Grant u_int32_t eso, delta; 53987e5972SCameron Grant u_int32_t rvol, cvol; 54987e5972SCameron Grant u_int32_t gvsel, pan, vol, ctrl; 557ed9700bSCameron Grant int index, bufhalf; 5666ef8af5SCameron Grant struct snd_dbuf *buffer; 5766ef8af5SCameron Grant struct pcm_channel *channel; 58987e5972SCameron Grant struct tr_info *parent; 59987e5972SCameron Grant }; 60987e5972SCameron Grant 61f0fb042eSCameron Grant struct tr_rchinfo { 62f0fb042eSCameron Grant u_int32_t delta; 6366ef8af5SCameron Grant struct snd_dbuf *buffer; 6466ef8af5SCameron Grant struct pcm_channel *channel; 65f0fb042eSCameron Grant struct tr_info *parent; 66f0fb042eSCameron Grant }; 67f0fb042eSCameron Grant 68987e5972SCameron Grant /* device private data */ 69987e5972SCameron Grant struct tr_info { 70987e5972SCameron Grant u_int32_t type; 71987e5972SCameron Grant 72987e5972SCameron Grant bus_space_tag_t st; 73987e5972SCameron Grant bus_space_handle_t sh; 74987e5972SCameron Grant bus_dma_tag_t parent_dmat; 75987e5972SCameron Grant 76987e5972SCameron Grant struct resource *reg, *irq; 77987e5972SCameron Grant int regtype, regid, irqid; 78987e5972SCameron Grant void *ih; 79987e5972SCameron Grant 8066ef8af5SCameron Grant void *lock; 8166ef8af5SCameron Grant 82987e5972SCameron Grant u_int32_t playchns; 83987e5972SCameron Grant struct tr_chinfo chinfo[TR_MAXPLAYCH]; 84f0fb042eSCameron Grant struct tr_rchinfo recchinfo; 85987e5972SCameron Grant }; 86987e5972SCameron Grant 87987e5972SCameron Grant /* -------------------------------------------------------------------- */ 88987e5972SCameron Grant 89513693beSCameron Grant static u_int32_t tr_recfmt[] = { 90513693beSCameron Grant AFMT_U8, 91513693beSCameron Grant AFMT_STEREO | AFMT_U8, 92513693beSCameron Grant AFMT_S8, 93513693beSCameron Grant AFMT_STEREO | AFMT_S8, 94513693beSCameron Grant AFMT_S16_LE, 95513693beSCameron Grant AFMT_STEREO | AFMT_S16_LE, 96513693beSCameron Grant AFMT_U16_LE, 97513693beSCameron Grant AFMT_STEREO | AFMT_U16_LE, 98513693beSCameron Grant 0 99987e5972SCameron Grant }; 10066ef8af5SCameron Grant static struct pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0}; 101987e5972SCameron Grant 102513693beSCameron Grant static u_int32_t tr_playfmt[] = { 103513693beSCameron Grant AFMT_U8, 104513693beSCameron Grant AFMT_STEREO | AFMT_U8, 105513693beSCameron Grant AFMT_S8, 106513693beSCameron Grant AFMT_STEREO | AFMT_S8, 107513693beSCameron Grant AFMT_S16_LE, 108513693beSCameron Grant AFMT_STEREO | AFMT_S16_LE, 109513693beSCameron Grant AFMT_U16_LE, 110513693beSCameron Grant AFMT_STEREO | AFMT_U16_LE, 111513693beSCameron Grant 0 112987e5972SCameron Grant }; 11366ef8af5SCameron Grant static struct pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0}; 114987e5972SCameron Grant 115987e5972SCameron Grant /* -------------------------------------------------------------------- */ 116987e5972SCameron Grant 117987e5972SCameron Grant /* Hardware */ 118987e5972SCameron Grant 119987e5972SCameron Grant static u_int32_t 120987e5972SCameron Grant tr_rd(struct tr_info *tr, int regno, int size) 121987e5972SCameron Grant { 122987e5972SCameron Grant switch(size) { 123987e5972SCameron Grant case 1: 124987e5972SCameron Grant return bus_space_read_1(tr->st, tr->sh, regno); 125987e5972SCameron Grant case 2: 126987e5972SCameron Grant return bus_space_read_2(tr->st, tr->sh, regno); 127987e5972SCameron Grant case 4: 128987e5972SCameron Grant return bus_space_read_4(tr->st, tr->sh, regno); 129987e5972SCameron Grant default: 130987e5972SCameron Grant return 0xffffffff; 131987e5972SCameron Grant } 132987e5972SCameron Grant } 133987e5972SCameron Grant 134987e5972SCameron Grant static void 135987e5972SCameron Grant tr_wr(struct tr_info *tr, int regno, u_int32_t data, int size) 136987e5972SCameron Grant { 137987e5972SCameron Grant switch(size) { 138987e5972SCameron Grant case 1: 139987e5972SCameron Grant bus_space_write_1(tr->st, tr->sh, regno, data); 140987e5972SCameron Grant break; 141987e5972SCameron Grant case 2: 142987e5972SCameron Grant bus_space_write_2(tr->st, tr->sh, regno, data); 143987e5972SCameron Grant break; 144987e5972SCameron Grant case 4: 145987e5972SCameron Grant bus_space_write_4(tr->st, tr->sh, regno, data); 146987e5972SCameron Grant break; 147987e5972SCameron Grant } 148987e5972SCameron Grant } 149987e5972SCameron Grant 1500f55ac6cSCameron Grant /* -------------------------------------------------------------------- */ 151987e5972SCameron Grant /* ac97 codec */ 152987e5972SCameron Grant 1530f55ac6cSCameron Grant static int 1540f55ac6cSCameron Grant tr_rdcd(kobj_t obj, void *devinfo, int regno) 155987e5972SCameron Grant { 156987e5972SCameron Grant struct tr_info *tr = (struct tr_info *)devinfo; 157987e5972SCameron Grant int i, j, treg, trw; 158987e5972SCameron Grant 159987e5972SCameron Grant switch (tr->type) { 160874f2e78SGeorge C A Reid case SPA_PCI_ID: 161874f2e78SGeorge C A Reid treg=SPA_REG_CODECRD; 162874f2e78SGeorge C A Reid trw=SPA_CDC_RWSTAT; 163874f2e78SGeorge C A Reid break; 164987e5972SCameron Grant case TDX_PCI_ID: 165987e5972SCameron Grant treg=TDX_REG_CODECRD; 166987e5972SCameron Grant trw=TDX_CDC_RWSTAT; 167987e5972SCameron Grant break; 168987e5972SCameron Grant case TNX_PCI_ID: 169987e5972SCameron Grant treg=(regno & 0x100)? TNX_REG_CODEC2RD : TNX_REG_CODEC1RD; 170987e5972SCameron Grant trw=TNX_CDC_RWSTAT; 171987e5972SCameron Grant break; 172987e5972SCameron Grant default: 173987e5972SCameron Grant printf("!!! tr_rdcd defaulted !!!\n"); 1740f55ac6cSCameron Grant return -1; 175987e5972SCameron Grant } 176987e5972SCameron Grant 177987e5972SCameron Grant regno &= 0x7f; 17866ef8af5SCameron Grant snd_mtxlock(tr->lock); 179987e5972SCameron Grant tr_wr(tr, treg, regno | trw, 4); 180987e5972SCameron Grant j=trw; 181987e5972SCameron Grant for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) j=tr_rd(tr, treg, 4); 18266ef8af5SCameron Grant snd_mtxunlock(tr->lock); 183987e5972SCameron Grant if (i == 0) printf("codec timeout during read of register %x\n", regno); 184987e5972SCameron Grant return (j >> TR_CDC_DATA) & 0xffff; 185987e5972SCameron Grant } 186987e5972SCameron Grant 1870f55ac6cSCameron Grant static int 1880f55ac6cSCameron Grant tr_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) 189987e5972SCameron Grant { 190987e5972SCameron Grant struct tr_info *tr = (struct tr_info *)devinfo; 191987e5972SCameron Grant int i, j, treg, trw; 192987e5972SCameron Grant 193987e5972SCameron Grant switch (tr->type) { 194874f2e78SGeorge C A Reid case SPA_PCI_ID: 195874f2e78SGeorge C A Reid treg=SPA_REG_CODECWR; 196874f2e78SGeorge C A Reid trw=SPA_CDC_RWSTAT; 197874f2e78SGeorge C A Reid break; 198987e5972SCameron Grant case TDX_PCI_ID: 199987e5972SCameron Grant treg=TDX_REG_CODECWR; 200987e5972SCameron Grant trw=TDX_CDC_RWSTAT; 201987e5972SCameron Grant break; 202987e5972SCameron Grant case TNX_PCI_ID: 203987e5972SCameron Grant treg=TNX_REG_CODECWR; 204987e5972SCameron Grant trw=TNX_CDC_RWSTAT | ((regno & 0x100)? TNX_CDC_SEC : 0); 205987e5972SCameron Grant break; 206987e5972SCameron Grant default: 207987e5972SCameron Grant printf("!!! tr_wrcd defaulted !!!"); 2080f55ac6cSCameron Grant return -1; 209987e5972SCameron Grant } 210987e5972SCameron Grant 211987e5972SCameron Grant regno &= 0x7f; 212987e5972SCameron Grant #if 0 213987e5972SCameron Grant printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno)); 214987e5972SCameron Grant #endif 215987e5972SCameron Grant j=trw; 21666ef8af5SCameron Grant snd_mtxlock(tr->lock); 217987e5972SCameron Grant for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) j=tr_rd(tr, treg, 4); 218987e5972SCameron Grant tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4); 219987e5972SCameron Grant #if 0 220987e5972SCameron Grant printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno)); 221987e5972SCameron Grant #endif 22266ef8af5SCameron Grant snd_mtxunlock(tr->lock); 223987e5972SCameron Grant if (i==0) printf("codec timeout writing %x, data %x\n", regno, data); 2240f55ac6cSCameron Grant return (i > 0)? 0 : -1; 225987e5972SCameron Grant } 226987e5972SCameron Grant 2270f55ac6cSCameron Grant static kobj_method_t tr_ac97_methods[] = { 2280f55ac6cSCameron Grant KOBJMETHOD(ac97_read, tr_rdcd), 2290f55ac6cSCameron Grant KOBJMETHOD(ac97_write, tr_wrcd), 2300f55ac6cSCameron Grant { 0, 0 } 2310f55ac6cSCameron Grant }; 2320f55ac6cSCameron Grant AC97_DECLARE(tr_ac97); 2330f55ac6cSCameron Grant 2340f55ac6cSCameron Grant /* -------------------------------------------------------------------- */ 235987e5972SCameron Grant /* playback channel interrupts */ 236987e5972SCameron Grant 2377ed9700bSCameron Grant #if 0 238987e5972SCameron Grant static u_int32_t 239f0fb042eSCameron Grant tr_testint(struct tr_chinfo *ch) 240987e5972SCameron Grant { 241f0fb042eSCameron Grant struct tr_info *tr = ch->parent; 242f0fb042eSCameron Grant int bank, chan; 243f0fb042eSCameron Grant 244f0fb042eSCameron Grant bank = (ch->index & 0x20) ? 1 : 0; 245f0fb042eSCameron Grant chan = ch->index & 0x1f; 246f0fb042eSCameron Grant return tr_rd(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 4) & (1 << chan); 247987e5972SCameron Grant } 2487ed9700bSCameron Grant #endif 249987e5972SCameron Grant 250987e5972SCameron Grant static void 251f0fb042eSCameron Grant tr_clrint(struct tr_chinfo *ch) 252987e5972SCameron Grant { 253f0fb042eSCameron Grant struct tr_info *tr = ch->parent; 254f0fb042eSCameron Grant int bank, chan; 255f0fb042eSCameron Grant 256f0fb042eSCameron Grant bank = (ch->index & 0x20) ? 1 : 0; 257f0fb042eSCameron Grant chan = ch->index & 0x1f; 258f0fb042eSCameron Grant tr_wr(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 1 << chan, 4); 259987e5972SCameron Grant } 260987e5972SCameron Grant 261987e5972SCameron Grant static void 262f0fb042eSCameron Grant tr_enaint(struct tr_chinfo *ch, int enable) 263987e5972SCameron Grant { 264f0fb042eSCameron Grant struct tr_info *tr = ch->parent; 265f0fb042eSCameron Grant u_int32_t i, reg; 266f0fb042eSCameron Grant int bank, chan; 267f0fb042eSCameron Grant 26866ef8af5SCameron Grant snd_mtxlock(tr->lock); 269f0fb042eSCameron Grant bank = (ch->index & 0x20) ? 1 : 0; 270f0fb042eSCameron Grant chan = ch->index & 0x1f; 271f0fb042eSCameron Grant reg = bank? TR_REG_INTENB : TR_REG_INTENA; 272f0fb042eSCameron Grant 273f0fb042eSCameron Grant i = tr_rd(tr, reg, 4); 274f0fb042eSCameron Grant i &= ~(1 << chan); 275f0fb042eSCameron Grant i |= (enable? 1 : 0) << chan; 276f0fb042eSCameron Grant 277f0fb042eSCameron Grant tr_clrint(ch); 278987e5972SCameron Grant tr_wr(tr, reg, i, 4); 27966ef8af5SCameron Grant snd_mtxunlock(tr->lock); 280987e5972SCameron Grant } 281987e5972SCameron Grant 282987e5972SCameron Grant /* playback channels */ 283987e5972SCameron Grant 284987e5972SCameron Grant static void 285f0fb042eSCameron Grant tr_selch(struct tr_chinfo *ch) 286987e5972SCameron Grant { 287f0fb042eSCameron Grant struct tr_info *tr = ch->parent; 288f0fb042eSCameron Grant int i; 289f0fb042eSCameron Grant 290f0fb042eSCameron Grant i = tr_rd(tr, TR_REG_CIR, 4); 291987e5972SCameron Grant i &= ~TR_CIR_MASK; 292f0fb042eSCameron Grant i |= ch->index & 0x3f; 293987e5972SCameron Grant tr_wr(tr, TR_REG_CIR, i, 4); 294987e5972SCameron Grant } 295987e5972SCameron Grant 296987e5972SCameron Grant static void 297f0fb042eSCameron Grant tr_startch(struct tr_chinfo *ch) 298987e5972SCameron Grant { 299f0fb042eSCameron Grant struct tr_info *tr = ch->parent; 300f0fb042eSCameron Grant int bank, chan; 301f0fb042eSCameron Grant 302f0fb042eSCameron Grant bank = (ch->index & 0x20) ? 1 : 0; 303f0fb042eSCameron Grant chan = ch->index & 0x1f; 304f0fb042eSCameron Grant tr_wr(tr, bank? TR_REG_STARTB : TR_REG_STARTA, 1 << chan, 4); 305987e5972SCameron Grant } 306987e5972SCameron Grant 307987e5972SCameron Grant static void 308f0fb042eSCameron Grant tr_stopch(struct tr_chinfo *ch) 309987e5972SCameron Grant { 310f0fb042eSCameron Grant struct tr_info *tr = ch->parent; 311f0fb042eSCameron Grant int bank, chan; 312f0fb042eSCameron Grant 313f0fb042eSCameron Grant bank = (ch->index & 0x20) ? 1 : 0; 314f0fb042eSCameron Grant chan = ch->index & 0x1f; 315f0fb042eSCameron Grant tr_wr(tr, bank? TR_REG_STOPB : TR_REG_STOPA, 1 << chan, 4); 316987e5972SCameron Grant } 317987e5972SCameron Grant 318987e5972SCameron Grant static void 319f0fb042eSCameron Grant tr_wrch(struct tr_chinfo *ch) 320987e5972SCameron Grant { 321f0fb042eSCameron Grant struct tr_info *tr = ch->parent; 322987e5972SCameron Grant u_int32_t cr[TR_CHN_REGS], i; 323987e5972SCameron Grant 324987e5972SCameron Grant ch->gvsel &= 0x00000001; 325987e5972SCameron Grant ch->fmc &= 0x00000003; 326987e5972SCameron Grant ch->fms &= 0x0000000f; 327987e5972SCameron Grant ch->ctrl &= 0x0000000f; 328987e5972SCameron Grant ch->pan &= 0x0000007f; 329987e5972SCameron Grant ch->rvol &= 0x0000007f; 330987e5972SCameron Grant ch->cvol &= 0x0000007f; 331987e5972SCameron Grant ch->vol &= 0x000000ff; 332987e5972SCameron Grant ch->ec &= 0x00000fff; 333987e5972SCameron Grant ch->alpha &= 0x00000fff; 334987e5972SCameron Grant ch->delta &= 0x0000ffff; 335987e5972SCameron Grant ch->lba &= 0x3fffffff; 336987e5972SCameron Grant 337987e5972SCameron Grant cr[1]=ch->lba; 3387ed9700bSCameron Grant cr[3]=(ch->fmc<<14) | (ch->rvol<<7) | (ch->cvol); 339987e5972SCameron Grant cr[4]=(ch->gvsel<<31) | (ch->pan<<24) | (ch->vol<<16) | (ch->ctrl<<12) | (ch->ec); 340987e5972SCameron Grant 341987e5972SCameron Grant switch (tr->type) { 342874f2e78SGeorge C A Reid case SPA_PCI_ID: 343987e5972SCameron Grant case TDX_PCI_ID: 344987e5972SCameron Grant ch->cso &= 0x0000ffff; 345987e5972SCameron Grant ch->eso &= 0x0000ffff; 346987e5972SCameron Grant cr[0]=(ch->cso<<16) | (ch->alpha<<4) | (ch->fms); 347987e5972SCameron Grant cr[2]=(ch->eso<<16) | (ch->delta); 348987e5972SCameron Grant break; 349987e5972SCameron Grant case TNX_PCI_ID: 350987e5972SCameron Grant ch->cso &= 0x00ffffff; 351987e5972SCameron Grant ch->eso &= 0x00ffffff; 352987e5972SCameron Grant cr[0]=((ch->delta & 0xff)<<24) | (ch->cso); 35348875621SCameron Grant cr[2]=((ch->delta>>8)<<24) | (ch->eso); 354987e5972SCameron Grant cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14); 355987e5972SCameron Grant break; 356987e5972SCameron Grant } 35766ef8af5SCameron Grant snd_mtxlock(tr->lock); 358f0fb042eSCameron Grant tr_selch(ch); 359987e5972SCameron Grant for (i=0; i<TR_CHN_REGS; i++) 360987e5972SCameron Grant tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4); 36166ef8af5SCameron Grant snd_mtxunlock(tr->lock); 362987e5972SCameron Grant } 363987e5972SCameron Grant 364987e5972SCameron Grant static void 365f0fb042eSCameron Grant tr_rdch(struct tr_chinfo *ch) 366987e5972SCameron Grant { 367f0fb042eSCameron Grant struct tr_info *tr = ch->parent; 368987e5972SCameron Grant u_int32_t cr[5], i; 369f0fb042eSCameron Grant 37066ef8af5SCameron Grant snd_mtxlock(tr->lock); 371f0fb042eSCameron Grant tr_selch(ch); 372f0fb042eSCameron Grant for (i=0; i<5; i++) 373f0fb042eSCameron Grant cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4); 37466ef8af5SCameron Grant snd_mtxunlock(tr->lock); 375f0fb042eSCameron Grant 376f0fb042eSCameron Grant 377987e5972SCameron Grant ch->lba= (cr[1] & 0x3fffffff); 378987e5972SCameron Grant ch->fmc= (cr[3] & 0x0000c000) >> 14; 379987e5972SCameron Grant ch->rvol= (cr[3] & 0x00003f80) >> 7; 380987e5972SCameron Grant ch->cvol= (cr[3] & 0x0000007f); 381987e5972SCameron Grant ch->gvsel= (cr[4] & 0x80000000) >> 31; 382987e5972SCameron Grant ch->pan= (cr[4] & 0x7f000000) >> 24; 383987e5972SCameron Grant ch->vol= (cr[4] & 0x00ff0000) >> 16; 384987e5972SCameron Grant ch->ctrl= (cr[4] & 0x0000f000) >> 12; 385987e5972SCameron Grant ch->ec= (cr[4] & 0x00000fff); 386987e5972SCameron Grant switch(tr->type) { 387874f2e78SGeorge C A Reid case SPA_PCI_ID: 388987e5972SCameron Grant case TDX_PCI_ID: 389987e5972SCameron Grant ch->cso= (cr[0] & 0xffff0000) >> 16; 390987e5972SCameron Grant ch->alpha= (cr[0] & 0x0000fff0) >> 4; 391987e5972SCameron Grant ch->fms= (cr[0] & 0x0000000f); 392987e5972SCameron Grant ch->eso= (cr[2] & 0xffff0000) >> 16; 393987e5972SCameron Grant ch->delta= (cr[2] & 0x0000ffff); 394987e5972SCameron Grant break; 395987e5972SCameron Grant case TNX_PCI_ID: 396987e5972SCameron Grant ch->cso= (cr[0] & 0x00ffffff); 397987e5972SCameron Grant ch->eso= (cr[2] & 0x00ffffff); 398f0fb042eSCameron Grant ch->delta= ((cr[2] & 0xff000000) >> 16) | ((cr[0] & 0xff000000) >> 24); 399987e5972SCameron Grant ch->alpha= (cr[3] & 0xfff00000) >> 20; 400987e5972SCameron Grant ch->fms= (cr[3] & 0x000f0000) >> 16; 401987e5972SCameron Grant break; 402987e5972SCameron Grant } 403987e5972SCameron Grant } 404987e5972SCameron Grant 4057ed9700bSCameron Grant static u_int32_t 4067ed9700bSCameron Grant tr_fmttobits(u_int32_t fmt) 4077ed9700bSCameron Grant { 4087ed9700bSCameron Grant u_int32_t bits; 4097ed9700bSCameron Grant 4107ed9700bSCameron Grant bits = 0; 4117ed9700bSCameron Grant bits |= (fmt & AFMT_SIGNED)? 0x2 : 0; 4127ed9700bSCameron Grant bits |= (fmt & AFMT_STEREO)? 0x4 : 0; 4137ed9700bSCameron Grant bits |= (fmt & AFMT_16BIT)? 0x8 : 0; 4147ed9700bSCameron Grant 4157ed9700bSCameron Grant return bits; 4167ed9700bSCameron Grant } 4177ed9700bSCameron Grant 4180f55ac6cSCameron Grant /* -------------------------------------------------------------------- */ 419987e5972SCameron Grant /* channel interface */ 420987e5972SCameron Grant 4210f55ac6cSCameron Grant static void * 42266ef8af5SCameron Grant trpchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 423987e5972SCameron Grant { 424987e5972SCameron Grant struct tr_info *tr = devinfo; 425987e5972SCameron Grant struct tr_chinfo *ch; 426f0fb042eSCameron Grant 427f0fb042eSCameron Grant KASSERT(dir == PCMDIR_PLAY, ("trpchan_init: bad direction")); 428987e5972SCameron Grant ch = &tr->chinfo[tr->playchns]; 429987e5972SCameron Grant ch->index = tr->playchns++; 430987e5972SCameron Grant ch->buffer = b; 431987e5972SCameron Grant ch->parent = tr; 432987e5972SCameron Grant ch->channel = c; 433f0fb042eSCameron Grant if (sndbuf_alloc(ch->buffer, tr->parent_dmat, TR_BUFFSIZE) == -1) 434f0fb042eSCameron Grant return NULL; 435f0fb042eSCameron Grant 436f0fb042eSCameron Grant return ch; 437987e5972SCameron Grant } 438987e5972SCameron Grant 439987e5972SCameron Grant static int 440f0fb042eSCameron Grant trpchan_setformat(kobj_t obj, void *data, u_int32_t format) 441987e5972SCameron Grant { 442987e5972SCameron Grant struct tr_chinfo *ch = data; 443f0fb042eSCameron Grant 444f0fb042eSCameron Grant ch->ctrl = tr_fmttobits(format) | 0x01; 445f0fb042eSCameron Grant 446f0fb042eSCameron Grant return 0; 447f0fb042eSCameron Grant } 448f0fb042eSCameron Grant 449f0fb042eSCameron Grant static int 450f0fb042eSCameron Grant trpchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 451f0fb042eSCameron Grant { 452f0fb042eSCameron Grant struct tr_chinfo *ch = data; 453f0fb042eSCameron Grant 454f0fb042eSCameron Grant ch->delta = (speed << 12) / 48000; 455f0fb042eSCameron Grant return (ch->delta * 48000) >> 12; 456f0fb042eSCameron Grant } 457f0fb042eSCameron Grant 458f0fb042eSCameron Grant static int 459f0fb042eSCameron Grant trpchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 460f0fb042eSCameron Grant { 461f0fb042eSCameron Grant struct tr_chinfo *ch = data; 462f0fb042eSCameron Grant 463f0fb042eSCameron Grant sndbuf_resize(ch->buffer, 2, blocksize); 464f0fb042eSCameron Grant return blocksize; 465f0fb042eSCameron Grant } 466f0fb042eSCameron Grant 467f0fb042eSCameron Grant static int 468f0fb042eSCameron Grant trpchan_trigger(kobj_t obj, void *data, int go) 469f0fb042eSCameron Grant { 470f0fb042eSCameron Grant struct tr_chinfo *ch = data; 471f0fb042eSCameron Grant 472f0fb042eSCameron Grant if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 473f0fb042eSCameron Grant return 0; 474f0fb042eSCameron Grant 475f0fb042eSCameron Grant if (go == PCMTRIG_START) { 4767ed9700bSCameron Grant ch->fmc = 3; 4777ed9700bSCameron Grant ch->fms = 0; 4787ed9700bSCameron Grant ch->ec = 0; 4797ed9700bSCameron Grant ch->alpha = 0; 480350a5fafSCameron Grant ch->lba = vtophys(sndbuf_getbuf(ch->buffer)); 481987e5972SCameron Grant ch->cso = 0; 482f0fb042eSCameron Grant ch->eso = (sndbuf_getsize(ch->buffer) / sndbuf_getbps(ch->buffer)) - 1; 4837ed9700bSCameron Grant ch->rvol = ch->cvol = 0x7f; 484987e5972SCameron Grant ch->gvsel = 0; 485987e5972SCameron Grant ch->pan = 0; 486987e5972SCameron Grant ch->vol = 0; 4877ed9700bSCameron Grant ch->bufhalf = 0; 488f0fb042eSCameron Grant tr_wrch(ch); 489f0fb042eSCameron Grant tr_enaint(ch, 1); 490f0fb042eSCameron Grant tr_startch(ch); 491f0fb042eSCameron Grant } else 492f0fb042eSCameron Grant tr_stopch(ch); 493f0fb042eSCameron Grant 494f0fb042eSCameron Grant return 0; 495f0fb042eSCameron Grant } 496f0fb042eSCameron Grant 497f0fb042eSCameron Grant static int 498f0fb042eSCameron Grant trpchan_getptr(kobj_t obj, void *data) 499f0fb042eSCameron Grant { 500f0fb042eSCameron Grant struct tr_chinfo *ch = data; 501f0fb042eSCameron Grant 502f0fb042eSCameron Grant tr_rdch(ch); 503f0fb042eSCameron Grant return ch->cso * sndbuf_getbps(ch->buffer); 504f0fb042eSCameron Grant } 505f0fb042eSCameron Grant 50666ef8af5SCameron Grant static struct pcmchan_caps * 507f0fb042eSCameron Grant trpchan_getcaps(kobj_t obj, void *data) 508f0fb042eSCameron Grant { 509f0fb042eSCameron Grant return &tr_playcaps; 510f0fb042eSCameron Grant } 511f0fb042eSCameron Grant 512f0fb042eSCameron Grant static kobj_method_t trpchan_methods[] = { 513f0fb042eSCameron Grant KOBJMETHOD(channel_init, trpchan_init), 514f0fb042eSCameron Grant KOBJMETHOD(channel_setformat, trpchan_setformat), 515f0fb042eSCameron Grant KOBJMETHOD(channel_setspeed, trpchan_setspeed), 516f0fb042eSCameron Grant KOBJMETHOD(channel_setblocksize, trpchan_setblocksize), 517f0fb042eSCameron Grant KOBJMETHOD(channel_trigger, trpchan_trigger), 518f0fb042eSCameron Grant KOBJMETHOD(channel_getptr, trpchan_getptr), 519f0fb042eSCameron Grant KOBJMETHOD(channel_getcaps, trpchan_getcaps), 520f0fb042eSCameron Grant { 0, 0 } 521f0fb042eSCameron Grant }; 522f0fb042eSCameron Grant CHANNEL_DECLARE(trpchan); 523f0fb042eSCameron Grant 524f0fb042eSCameron Grant /* -------------------------------------------------------------------- */ 525f0fb042eSCameron Grant /* rec channel interface */ 526f0fb042eSCameron Grant 527f0fb042eSCameron Grant static void * 52866ef8af5SCameron Grant trrchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 529f0fb042eSCameron Grant { 530f0fb042eSCameron Grant struct tr_info *tr = devinfo; 531f0fb042eSCameron Grant struct tr_rchinfo *ch; 532f0fb042eSCameron Grant 533f0fb042eSCameron Grant KASSERT(dir == PCMDIR_REC, ("trrchan_init: bad direction")); 534f0fb042eSCameron Grant ch = &tr->recchinfo; 535f0fb042eSCameron Grant ch->buffer = b; 536f0fb042eSCameron Grant ch->parent = tr; 537f0fb042eSCameron Grant ch->channel = c; 538f0fb042eSCameron Grant if (sndbuf_alloc(ch->buffer, tr->parent_dmat, TR_BUFFSIZE) == -1) 539f0fb042eSCameron Grant return NULL; 540f0fb042eSCameron Grant 541f0fb042eSCameron Grant return ch; 542f0fb042eSCameron Grant } 543f0fb042eSCameron Grant 544f0fb042eSCameron Grant static int 545f0fb042eSCameron Grant trrchan_setformat(kobj_t obj, void *data, u_int32_t format) 546f0fb042eSCameron Grant { 547f0fb042eSCameron Grant struct tr_rchinfo *ch = data; 548f0fb042eSCameron Grant struct tr_info *tr = ch->parent; 549f0fb042eSCameron Grant u_int32_t i, bits; 550f0fb042eSCameron Grant 551f0fb042eSCameron Grant bits = tr_fmttobits(format); 552f0fb042eSCameron Grant /* set # of samples between interrupts */ 5537ed9700bSCameron Grant i = (sndbuf_runsz(ch->buffer) >> ((bits & 0x08)? 1 : 0)) - 1; 554f0fb042eSCameron Grant tr_wr(tr, TR_REG_SBBL, i | (i << 16), 4); 555f0fb042eSCameron Grant /* set sample format */ 556f0fb042eSCameron Grant i = 0x18 | (bits << 4); 557f0fb042eSCameron Grant tr_wr(tr, TR_REG_SBCTRL, i, 1); 558f0fb042eSCameron Grant 559f0fb042eSCameron Grant return 0; 560f0fb042eSCameron Grant 561f0fb042eSCameron Grant } 562f0fb042eSCameron Grant 563f0fb042eSCameron Grant static int 564f0fb042eSCameron Grant trrchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 565f0fb042eSCameron Grant { 566f0fb042eSCameron Grant struct tr_rchinfo *ch = data; 567f0fb042eSCameron Grant struct tr_info *tr = ch->parent; 568f0fb042eSCameron Grant 569f0fb042eSCameron Grant /* setup speed */ 570f0fb042eSCameron Grant ch->delta = (48000 << 12) / speed; 571f0fb042eSCameron Grant tr_wr(tr, TR_REG_SBDELTA, ch->delta, 2); 572f0fb042eSCameron Grant 573f0fb042eSCameron Grant /* return closest possible speed */ 574f0fb042eSCameron Grant return (48000 << 12) / ch->delta; 575f0fb042eSCameron Grant } 576f0fb042eSCameron Grant 577f0fb042eSCameron Grant static int 578f0fb042eSCameron Grant trrchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 579f0fb042eSCameron Grant { 580f0fb042eSCameron Grant struct tr_rchinfo *ch = data; 581f0fb042eSCameron Grant 582f0fb042eSCameron Grant sndbuf_resize(ch->buffer, 2, blocksize); 583f0fb042eSCameron Grant 584f0fb042eSCameron Grant return blocksize; 585f0fb042eSCameron Grant } 586f0fb042eSCameron Grant 587f0fb042eSCameron Grant static int 588f0fb042eSCameron Grant trrchan_trigger(kobj_t obj, void *data, int go) 589f0fb042eSCameron Grant { 590f0fb042eSCameron Grant struct tr_rchinfo *ch = data; 591f0fb042eSCameron Grant struct tr_info *tr = ch->parent; 592987e5972SCameron Grant u_int32_t i; 593f0fb042eSCameron Grant 594f0fb042eSCameron Grant if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 595f0fb042eSCameron Grant return 0; 596f0fb042eSCameron Grant 597f0fb042eSCameron Grant if (go == PCMTRIG_START) { 598f0fb042eSCameron Grant /* set up dma mode regs */ 599987e5972SCameron Grant tr_wr(tr, TR_REG_DMAR15, 0, 1); 600987e5972SCameron Grant i = tr_rd(tr, TR_REG_DMAR11, 1) & 0x03; 601987e5972SCameron Grant tr_wr(tr, TR_REG_DMAR11, i | 0x54, 1); 602987e5972SCameron Grant /* set up base address */ 603350a5fafSCameron Grant tr_wr(tr, TR_REG_DMAR0, vtophys(sndbuf_getbuf(ch->buffer)), 4); 604987e5972SCameron Grant /* set up buffer size */ 605987e5972SCameron Grant i = tr_rd(tr, TR_REG_DMAR4, 4) & ~0x00ffffff; 606f0fb042eSCameron Grant tr_wr(tr, TR_REG_DMAR4, i | (sndbuf_runsz(ch->buffer) - 1), 4); 607f0fb042eSCameron Grant /* start */ 608f0fb042eSCameron Grant tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) | 1, 1); 609f0fb042eSCameron Grant } else 610f0fb042eSCameron Grant tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) & ~7, 1); 611f0fb042eSCameron Grant 612f0fb042eSCameron Grant /* return 0 if ok */ 613987e5972SCameron Grant return 0; 614987e5972SCameron Grant } 615987e5972SCameron Grant 616987e5972SCameron Grant static int 617f0fb042eSCameron Grant trrchan_getptr(kobj_t obj, void *data) 618987e5972SCameron Grant { 619f0fb042eSCameron Grant struct tr_rchinfo *ch = data; 620987e5972SCameron Grant struct tr_info *tr = ch->parent; 621987e5972SCameron Grant 622f0fb042eSCameron Grant /* return current byte offset of channel */ 623f0fb042eSCameron Grant return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(sndbuf_getbuf(ch->buffer)); 624987e5972SCameron Grant } 625987e5972SCameron Grant 62666ef8af5SCameron Grant static struct pcmchan_caps * 627f0fb042eSCameron Grant trrchan_getcaps(kobj_t obj, void *data) 628987e5972SCameron Grant { 629f0fb042eSCameron Grant return &tr_reccaps; 630987e5972SCameron Grant } 631987e5972SCameron Grant 632f0fb042eSCameron Grant static kobj_method_t trrchan_methods[] = { 633f0fb042eSCameron Grant KOBJMETHOD(channel_init, trrchan_init), 634f0fb042eSCameron Grant KOBJMETHOD(channel_setformat, trrchan_setformat), 635f0fb042eSCameron Grant KOBJMETHOD(channel_setspeed, trrchan_setspeed), 636f0fb042eSCameron Grant KOBJMETHOD(channel_setblocksize, trrchan_setblocksize), 637f0fb042eSCameron Grant KOBJMETHOD(channel_trigger, trrchan_trigger), 638f0fb042eSCameron Grant KOBJMETHOD(channel_getptr, trrchan_getptr), 639f0fb042eSCameron Grant KOBJMETHOD(channel_getcaps, trrchan_getcaps), 6400f55ac6cSCameron Grant { 0, 0 } 6410f55ac6cSCameron Grant }; 642f0fb042eSCameron Grant CHANNEL_DECLARE(trrchan); 6430f55ac6cSCameron Grant 6440f55ac6cSCameron Grant /* -------------------------------------------------------------------- */ 645987e5972SCameron Grant /* The interrupt handler */ 646987e5972SCameron Grant 647987e5972SCameron Grant static void 648987e5972SCameron Grant tr_intr(void *p) 649987e5972SCameron Grant { 650987e5972SCameron Grant struct tr_info *tr = (struct tr_info *)p; 651f0fb042eSCameron Grant struct tr_chinfo *ch; 6527ed9700bSCameron Grant u_int32_t active, mask, bufhalf, chnum, intsrc; 6537ed9700bSCameron Grant int tmp; 654987e5972SCameron Grant 655f0fb042eSCameron Grant intsrc = tr_rd(tr, TR_REG_MISCINT, 4); 656987e5972SCameron Grant if (intsrc & TR_INT_ADDR) { 6577ed9700bSCameron Grant chnum = 0; 6587ed9700bSCameron Grant while (chnum < 64) { 6597ed9700bSCameron Grant mask = 0x00000001; 6607ed9700bSCameron Grant active = tr_rd(tr, (chnum < 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, 4); 6617ed9700bSCameron Grant bufhalf = tr_rd(tr, (chnum < 32)? TR_REG_CSPF_A : TR_REG_CSPF_B, 4); 6627ed9700bSCameron Grant if (active) { 6637ed9700bSCameron Grant do { 6647ed9700bSCameron Grant if (active & mask) { 6657ed9700bSCameron Grant tmp = (bufhalf & mask)? 1 : 0; 6667ed9700bSCameron Grant if (chnum < tr->playchns) { 6677ed9700bSCameron Grant ch = &tr->chinfo[chnum]; 6687ed9700bSCameron Grant /* printf("%d @ %d, ", chnum, trpchan_getptr(NULL, ch)); */ 6697ed9700bSCameron Grant if (ch->bufhalf != tmp) { 670f0fb042eSCameron Grant chn_intr(ch->channel); 6717ed9700bSCameron Grant ch->bufhalf = tmp; 67266ef8af5SCameron Grant } 673987e5972SCameron Grant } 674987e5972SCameron Grant } 6757ed9700bSCameron Grant chnum++; 6767ed9700bSCameron Grant mask <<= 1; 6777ed9700bSCameron Grant } while (chnum & 31); 6787ed9700bSCameron Grant } else 6797ed9700bSCameron Grant chnum += 32; 6807ed9700bSCameron Grant 6817ed9700bSCameron Grant tr_wr(tr, (chnum <= 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, active, 4); 6827ed9700bSCameron Grant } 683987e5972SCameron Grant } 684987e5972SCameron Grant if (intsrc & TR_INT_SB) { 685987e5972SCameron Grant chn_intr(tr->recchinfo.channel); 686987e5972SCameron Grant tr_rd(tr, TR_REG_SBR9, 1); 687987e5972SCameron Grant tr_rd(tr, TR_REG_SBR10, 1); 688987e5972SCameron Grant } 689987e5972SCameron Grant } 690987e5972SCameron Grant 691987e5972SCameron Grant /* -------------------------------------------------------------------- */ 692987e5972SCameron Grant 693987e5972SCameron Grant /* 694987e5972SCameron Grant * Probe and attach the card 695987e5972SCameron Grant */ 696987e5972SCameron Grant 697987e5972SCameron Grant static int 698987e5972SCameron Grant tr_init(struct tr_info *tr) 699987e5972SCameron Grant { 700874f2e78SGeorge C A Reid switch (tr->type) { 701874f2e78SGeorge C A Reid case SPA_PCI_ID: 702874f2e78SGeorge C A Reid tr_wr(tr, SPA_REG_GPIO, 0, 4); 703874f2e78SGeorge C A Reid tr_wr(tr, SPA_REG_CODECST, SPA_RST_OFF, 4); 704874f2e78SGeorge C A Reid break; 705874f2e78SGeorge C A Reid case TDX_PCI_ID: 706987e5972SCameron Grant tr_wr(tr, TDX_REG_CODECST, TDX_CDC_ON, 4); 707874f2e78SGeorge C A Reid break; 708874f2e78SGeorge C A Reid case TNX_PCI_ID: 709874f2e78SGeorge C A Reid tr_wr(tr, TNX_REG_CODECST, TNX_CDC_ON, 4); 710874f2e78SGeorge C A Reid break; 711874f2e78SGeorge C A Reid } 712987e5972SCameron Grant 713987e5972SCameron Grant tr_wr(tr, TR_REG_CIR, TR_CIR_MIDENA | TR_CIR_ADDRENA, 4); 714987e5972SCameron Grant tr->playchns = 0; 715987e5972SCameron Grant return 0; 716987e5972SCameron Grant } 717987e5972SCameron Grant 718987e5972SCameron Grant static int 719987e5972SCameron Grant tr_pci_probe(device_t dev) 720987e5972SCameron Grant { 721874f2e78SGeorge C A Reid switch (pci_get_devid(dev)) { 722874f2e78SGeorge C A Reid case SPA_PCI_ID: 723874f2e78SGeorge C A Reid device_set_desc(dev, "SiS 7018"); 724874f2e78SGeorge C A Reid return 0; 725874f2e78SGeorge C A Reid case TDX_PCI_ID: 726987e5972SCameron Grant device_set_desc(dev, "Trident 4DWave DX"); 727987e5972SCameron Grant return 0; 728874f2e78SGeorge C A Reid case TNX_PCI_ID: 729987e5972SCameron Grant device_set_desc(dev, "Trident 4DWave NX"); 730987e5972SCameron Grant return 0; 731987e5972SCameron Grant } 732987e5972SCameron Grant 733987e5972SCameron Grant return ENXIO; 734987e5972SCameron Grant } 735987e5972SCameron Grant 736987e5972SCameron Grant static int 737987e5972SCameron Grant tr_pci_attach(device_t dev) 738987e5972SCameron Grant { 739987e5972SCameron Grant u_int32_t data; 740987e5972SCameron Grant struct tr_info *tr; 7417dfc9325SCameron Grant struct ac97_info *codec = 0; 742987e5972SCameron Grant int i; 743987e5972SCameron Grant char status[SND_STATUSLEN]; 744987e5972SCameron Grant 745733a4ea7SGeorge C A Reid if ((tr = malloc(sizeof(*tr), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 746987e5972SCameron Grant device_printf(dev, "cannot allocate softc\n"); 747987e5972SCameron Grant return ENXIO; 748987e5972SCameron Grant } 749987e5972SCameron Grant 750987e5972SCameron Grant tr->type = pci_get_devid(dev); 75166ef8af5SCameron Grant tr->lock = snd_mtxcreate(device_get_nameunit(dev)); 752987e5972SCameron Grant 753987e5972SCameron Grant data = pci_read_config(dev, PCIR_COMMAND, 2); 754987e5972SCameron Grant data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 755987e5972SCameron Grant pci_write_config(dev, PCIR_COMMAND, data, 2); 756987e5972SCameron Grant data = pci_read_config(dev, PCIR_COMMAND, 2); 757987e5972SCameron Grant 758f0fb042eSCameron Grant tr->regid = PCIR_MAPS; 759987e5972SCameron Grant tr->regtype = SYS_RES_IOPORT; 760f0fb042eSCameron Grant tr->reg = bus_alloc_resource(dev, tr->regtype, &tr->regid, 0, ~0, 1, RF_ACTIVE); 761987e5972SCameron Grant if (tr->reg) { 762987e5972SCameron Grant tr->st = rman_get_bustag(tr->reg); 763987e5972SCameron Grant tr->sh = rman_get_bushandle(tr->reg); 764f0fb042eSCameron Grant } else { 765987e5972SCameron Grant device_printf(dev, "unable to map register space\n"); 766987e5972SCameron Grant goto bad; 767987e5972SCameron Grant } 768987e5972SCameron Grant 769987e5972SCameron Grant if (tr_init(tr) == -1) { 770987e5972SCameron Grant device_printf(dev, "unable to initialize the card\n"); 771987e5972SCameron Grant goto bad; 772987e5972SCameron Grant } 773987e5972SCameron Grant 7740f55ac6cSCameron Grant codec = AC97_CREATE(dev, tr, tr_ac97); 775987e5972SCameron Grant if (codec == NULL) goto bad; 7760f55ac6cSCameron Grant if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad; 777987e5972SCameron Grant 778987e5972SCameron Grant tr->irqid = 0; 779987e5972SCameron Grant tr->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &tr->irqid, 780987e5972SCameron Grant 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 78166ef8af5SCameron Grant if (!tr->irq || snd_setup_intr(dev, tr->irq, INTR_MPSAFE, tr_intr, tr, &tr->ih)) { 782987e5972SCameron Grant device_printf(dev, "unable to map interrupt\n"); 783987e5972SCameron Grant goto bad; 784987e5972SCameron Grant } 785987e5972SCameron Grant 786987e5972SCameron Grant if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 787987e5972SCameron Grant /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 788987e5972SCameron Grant /*highaddr*/BUS_SPACE_MAXADDR, 789987e5972SCameron Grant /*filter*/NULL, /*filterarg*/NULL, 790987e5972SCameron Grant /*maxsize*/TR_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, 791987e5972SCameron Grant /*flags*/0, &tr->parent_dmat) != 0) { 792987e5972SCameron Grant device_printf(dev, "unable to create dma tag\n"); 793987e5972SCameron Grant goto bad; 794987e5972SCameron Grant } 795987e5972SCameron Grant 796f0fb042eSCameron Grant snprintf(status, 64, "at io 0x%lx irq %ld", 797987e5972SCameron Grant rman_get_start(tr->reg), rman_get_start(tr->irq)); 798987e5972SCameron Grant 799987e5972SCameron Grant if (pcm_register(dev, tr, TR_MAXPLAYCH, 1)) goto bad; 800f0fb042eSCameron Grant pcm_addchan(dev, PCMDIR_REC, &trrchan_class, tr); 801987e5972SCameron Grant for (i = 0; i < TR_MAXPLAYCH; i++) 802f0fb042eSCameron Grant pcm_addchan(dev, PCMDIR_PLAY, &trpchan_class, tr); 803987e5972SCameron Grant pcm_setstatus(dev, status); 804987e5972SCameron Grant 805987e5972SCameron Grant return 0; 806987e5972SCameron Grant 807987e5972SCameron Grant bad: 808306f91b6SCameron Grant if (codec) ac97_destroy(codec); 809987e5972SCameron Grant if (tr->reg) bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 810987e5972SCameron Grant if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih); 811987e5972SCameron Grant if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 812306f91b6SCameron Grant if (tr->parent_dmat) bus_dma_tag_destroy(tr->parent_dmat); 81366ef8af5SCameron Grant if (tr->lock) snd_mtxfree(tr->lock); 814987e5972SCameron Grant free(tr, M_DEVBUF); 815987e5972SCameron Grant return ENXIO; 816987e5972SCameron Grant } 817987e5972SCameron Grant 818306f91b6SCameron Grant static int 819306f91b6SCameron Grant tr_pci_detach(device_t dev) 820306f91b6SCameron Grant { 821306f91b6SCameron Grant int r; 822306f91b6SCameron Grant struct tr_info *tr; 823306f91b6SCameron Grant 824306f91b6SCameron Grant r = pcm_unregister(dev); 825306f91b6SCameron Grant if (r) 826306f91b6SCameron Grant return r; 827306f91b6SCameron Grant 828306f91b6SCameron Grant tr = pcm_getdevinfo(dev); 829306f91b6SCameron Grant bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 830306f91b6SCameron Grant bus_teardown_intr(dev, tr->irq, tr->ih); 831306f91b6SCameron Grant bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 832306f91b6SCameron Grant bus_dma_tag_destroy(tr->parent_dmat); 83366ef8af5SCameron Grant snd_mtxfree(tr->lock); 834306f91b6SCameron Grant free(tr, M_DEVBUF); 835306f91b6SCameron Grant 836306f91b6SCameron Grant return 0; 837306f91b6SCameron Grant } 838306f91b6SCameron Grant 839987e5972SCameron Grant static device_method_t tr_methods[] = { 840987e5972SCameron Grant /* Device interface */ 841987e5972SCameron Grant DEVMETHOD(device_probe, tr_pci_probe), 842987e5972SCameron Grant DEVMETHOD(device_attach, tr_pci_attach), 843306f91b6SCameron Grant DEVMETHOD(device_detach, tr_pci_detach), 844987e5972SCameron Grant 845987e5972SCameron Grant { 0, 0 } 846987e5972SCameron Grant }; 847987e5972SCameron Grant 848987e5972SCameron Grant static driver_t tr_driver = { 849987e5972SCameron Grant "pcm", 850987e5972SCameron Grant tr_methods, 85167b1dce3SCameron Grant PCM_SOFTC_SIZE, 852987e5972SCameron Grant }; 853987e5972SCameron Grant 854f314f3daSCameron Grant DRIVER_MODULE(snd_t4dwave, pci, tr_driver, pcm_devclass, 0, 0); 855f314f3daSCameron Grant MODULE_DEPEND(snd_t4dwave, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 856f314f3daSCameron Grant MODULE_VERSION(snd_t4dwave, 1); 857