t4dwave.c revision 105100
1/* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <dev/sound/pcm/sound.h> 28#include <dev/sound/pcm/ac97.h> 29#include <dev/sound/pci/t4dwave.h> 30 31#include <pci/pcireg.h> 32#include <pci/pcivar.h> 33 34SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/t4dwave.c 105100 2002-10-14 11:47:37Z cognet $"); 35 36/* -------------------------------------------------------------------- */ 37 38#define TDX_PCI_ID 0x20001023 39#define TNX_PCI_ID 0x20011023 40#define ALI_PCI_ID 0x545110b9 41#define SPA_PCI_ID 0x70181039 42 43#define TR_DEFAULT_BUFSZ 0x1000 44#define TR_TIMEOUT_CDC 0xffff 45#define TR_MAXPLAYCH 4 46 47struct tr_info; 48 49/* channel registers */ 50struct tr_chinfo { 51 u_int32_t cso, alpha, fms, fmc, ec; 52 u_int32_t lba; 53 u_int32_t eso, delta; 54 u_int32_t rvol, cvol; 55 u_int32_t gvsel, pan, vol, ctrl; 56 u_int32_t active:1, was_active:1; 57 int index, bufhalf; 58 struct snd_dbuf *buffer; 59 struct pcm_channel *channel; 60 struct tr_info *parent; 61}; 62 63struct tr_rchinfo { 64 u_int32_t delta; 65 u_int32_t active:1, was_active:1; 66 struct snd_dbuf *buffer; 67 struct pcm_channel *channel; 68 struct tr_info *parent; 69}; 70 71/* device private data */ 72struct tr_info { 73 u_int32_t type; 74 u_int32_t rev; 75 76 bus_space_tag_t st; 77 bus_space_handle_t sh; 78 bus_dma_tag_t parent_dmat; 79 80 struct resource *reg, *irq; 81 int regtype, regid, irqid; 82 void *ih; 83 84 void *lock; 85 86 u_int32_t playchns; 87 unsigned int bufsz; 88 89 struct tr_chinfo chinfo[TR_MAXPLAYCH]; 90 struct tr_rchinfo recchinfo; 91}; 92 93/* -------------------------------------------------------------------- */ 94 95static u_int32_t tr_recfmt[] = { 96 AFMT_U8, 97 AFMT_STEREO | AFMT_U8, 98 AFMT_S8, 99 AFMT_STEREO | AFMT_S8, 100 AFMT_S16_LE, 101 AFMT_STEREO | AFMT_S16_LE, 102 AFMT_U16_LE, 103 AFMT_STEREO | AFMT_U16_LE, 104 0 105}; 106static struct pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0}; 107 108static u_int32_t tr_playfmt[] = { 109 AFMT_U8, 110 AFMT_STEREO | AFMT_U8, 111 AFMT_S8, 112 AFMT_STEREO | AFMT_S8, 113 AFMT_S16_LE, 114 AFMT_STEREO | AFMT_S16_LE, 115 AFMT_U16_LE, 116 AFMT_STEREO | AFMT_U16_LE, 117 0 118}; 119static struct pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0}; 120 121/* -------------------------------------------------------------------- */ 122 123/* Hardware */ 124 125static u_int32_t 126tr_rd(struct tr_info *tr, int regno, int size) 127{ 128 switch(size) { 129 case 1: 130 return bus_space_read_1(tr->st, tr->sh, regno); 131 case 2: 132 return bus_space_read_2(tr->st, tr->sh, regno); 133 case 4: 134 return bus_space_read_4(tr->st, tr->sh, regno); 135 default: 136 return 0xffffffff; 137 } 138} 139 140static void 141tr_wr(struct tr_info *tr, int regno, u_int32_t data, int size) 142{ 143 switch(size) { 144 case 1: 145 bus_space_write_1(tr->st, tr->sh, regno, data); 146 break; 147 case 2: 148 bus_space_write_2(tr->st, tr->sh, regno, data); 149 break; 150 case 4: 151 bus_space_write_4(tr->st, tr->sh, regno, data); 152 break; 153 } 154} 155 156/* -------------------------------------------------------------------- */ 157/* ac97 codec */ 158 159static int 160tr_rdcd(kobj_t obj, void *devinfo, int regno) 161{ 162 struct tr_info *tr = (struct tr_info *)devinfo; 163 int i, j, treg, trw; 164 165 switch (tr->type) { 166 case SPA_PCI_ID: 167 treg=SPA_REG_CODECRD; 168 trw=SPA_CDC_RWSTAT; 169 break; 170 case ALI_PCI_ID: 171 if (tr->rev > 0x01) 172 treg=TDX_REG_CODECWR; 173 else 174 treg=TDX_REG_CODECRD; 175 trw=TDX_CDC_RWSTAT; 176 break; 177 case TDX_PCI_ID: 178 treg=TDX_REG_CODECRD; 179 trw=TDX_CDC_RWSTAT; 180 break; 181 case TNX_PCI_ID: 182 treg=(regno & 0x100)? TNX_REG_CODEC2RD : TNX_REG_CODEC1RD; 183 trw=TNX_CDC_RWSTAT; 184 break; 185 default: 186 printf("!!! tr_rdcd defaulted !!!\n"); 187 return -1; 188 } 189 190 regno &= 0x7f; 191 snd_mtxlock(tr->lock); 192 if (tr->type == ALI_PCI_ID) { 193 u_int32_t chk1, chk2; 194 j = trw; 195 for (i = TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) 196 j = tr_rd(tr, treg, 4); 197 if (i > 0) { 198 chk1 = tr_rd(tr, 0xc8, 4); 199 chk2 = tr_rd(tr, 0xc8, 4); 200 for (i = TR_TIMEOUT_CDC; (i > 0) && (chk1 == chk2); 201 i--) 202 chk2 = tr_rd(tr, 0xc8, 4); 203 } 204 } 205 if (tr->type != ALI_PCI_ID || i > 0) { 206 tr_wr(tr, treg, regno | trw, 4); 207 j=trw; 208 for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) 209 j=tr_rd(tr, treg, 4); 210 } 211 snd_mtxunlock(tr->lock); 212 if (i == 0) printf("codec timeout during read of register %x\n", regno); 213 return (j >> TR_CDC_DATA) & 0xffff; 214} 215 216static int 217tr_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) 218{ 219 struct tr_info *tr = (struct tr_info *)devinfo; 220 int i, j, treg, trw; 221 222 switch (tr->type) { 223 case SPA_PCI_ID: 224 treg=SPA_REG_CODECWR; 225 trw=SPA_CDC_RWSTAT; 226 break; 227 case ALI_PCI_ID: 228 case TDX_PCI_ID: 229 treg=TDX_REG_CODECWR; 230 trw=TDX_CDC_RWSTAT; 231 break; 232 case TNX_PCI_ID: 233 treg=TNX_REG_CODECWR; 234 trw=TNX_CDC_RWSTAT | ((regno & 0x100)? TNX_CDC_SEC : 0); 235 break; 236 default: 237 printf("!!! tr_wrcd defaulted !!!"); 238 return -1; 239 } 240 241 regno &= 0x7f; 242#if 0 243 printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno)); 244#endif 245 j=trw; 246 snd_mtxlock(tr->lock); 247 if (tr->type == ALI_PCI_ID) { 248 j = trw; 249 for (i = TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) 250 j = tr_rd(tr, treg, 4); 251 if (i > 0) { 252 u_int32_t chk1, chk2; 253 chk1 = tr_rd(tr, 0xc8, 4); 254 chk2 = tr_rd(tr, 0xc8, 4); 255 for (i = TR_TIMEOUT_CDC; (i > 0) && (chk1 == chk2); 256 i--) 257 chk2 = tr_rd(tr, 0xc8, 4); 258 } 259 } 260 if (tr->type != ALI_PCI_ID || i > 0) { 261 for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) 262 j=tr_rd(tr, treg, 4); 263 if (tr->type == ALI_PCI_ID && tr->rev > 0x01) 264 trw |= 0x0100; 265 tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4); 266 } 267#if 0 268 printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno)); 269#endif 270 snd_mtxunlock(tr->lock); 271 if (i==0) printf("codec timeout writing %x, data %x\n", regno, data); 272 return (i > 0)? 0 : -1; 273} 274 275static kobj_method_t tr_ac97_methods[] = { 276 KOBJMETHOD(ac97_read, tr_rdcd), 277 KOBJMETHOD(ac97_write, tr_wrcd), 278 { 0, 0 } 279}; 280AC97_DECLARE(tr_ac97); 281 282/* -------------------------------------------------------------------- */ 283/* playback channel interrupts */ 284 285#if 0 286static u_int32_t 287tr_testint(struct tr_chinfo *ch) 288{ 289 struct tr_info *tr = ch->parent; 290 int bank, chan; 291 292 bank = (ch->index & 0x20) ? 1 : 0; 293 chan = ch->index & 0x1f; 294 return tr_rd(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 4) & (1 << chan); 295} 296#endif 297 298static void 299tr_clrint(struct tr_chinfo *ch) 300{ 301 struct tr_info *tr = ch->parent; 302 int bank, chan; 303 304 bank = (ch->index & 0x20) ? 1 : 0; 305 chan = ch->index & 0x1f; 306 tr_wr(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 1 << chan, 4); 307} 308 309static void 310tr_enaint(struct tr_chinfo *ch, int enable) 311{ 312 struct tr_info *tr = ch->parent; 313 u_int32_t i, reg; 314 int bank, chan; 315 316 snd_mtxlock(tr->lock); 317 bank = (ch->index & 0x20) ? 1 : 0; 318 chan = ch->index & 0x1f; 319 reg = bank? TR_REG_INTENB : TR_REG_INTENA; 320 321 i = tr_rd(tr, reg, 4); 322 i &= ~(1 << chan); 323 i |= (enable? 1 : 0) << chan; 324 325 tr_clrint(ch); 326 tr_wr(tr, reg, i, 4); 327 snd_mtxunlock(tr->lock); 328} 329 330/* playback channels */ 331 332static void 333tr_selch(struct tr_chinfo *ch) 334{ 335 struct tr_info *tr = ch->parent; 336 int i; 337 338 i = tr_rd(tr, TR_REG_CIR, 4); 339 i &= ~TR_CIR_MASK; 340 i |= ch->index & 0x3f; 341 tr_wr(tr, TR_REG_CIR, i, 4); 342} 343 344static void 345tr_startch(struct tr_chinfo *ch) 346{ 347 struct tr_info *tr = ch->parent; 348 int bank, chan; 349 350 bank = (ch->index & 0x20) ? 1 : 0; 351 chan = ch->index & 0x1f; 352 tr_wr(tr, bank? TR_REG_STARTB : TR_REG_STARTA, 1 << chan, 4); 353} 354 355static void 356tr_stopch(struct tr_chinfo *ch) 357{ 358 struct tr_info *tr = ch->parent; 359 int bank, chan; 360 361 bank = (ch->index & 0x20) ? 1 : 0; 362 chan = ch->index & 0x1f; 363 tr_wr(tr, bank? TR_REG_STOPB : TR_REG_STOPA, 1 << chan, 4); 364} 365 366static void 367tr_wrch(struct tr_chinfo *ch) 368{ 369 struct tr_info *tr = ch->parent; 370 u_int32_t cr[TR_CHN_REGS], i; 371 372 ch->gvsel &= 0x00000001; 373 ch->fmc &= 0x00000003; 374 ch->fms &= 0x0000000f; 375 ch->ctrl &= 0x0000000f; 376 ch->pan &= 0x0000007f; 377 ch->rvol &= 0x0000007f; 378 ch->cvol &= 0x0000007f; 379 ch->vol &= 0x000000ff; 380 ch->ec &= 0x00000fff; 381 ch->alpha &= 0x00000fff; 382 ch->delta &= 0x0000ffff; 383 ch->lba &= 0x3fffffff; 384 385 cr[1]=ch->lba; 386 cr[3]=(ch->fmc<<14) | (ch->rvol<<7) | (ch->cvol); 387 cr[4]=(ch->gvsel<<31) | (ch->pan<<24) | (ch->vol<<16) | (ch->ctrl<<12) | (ch->ec); 388 389 switch (tr->type) { 390 case SPA_PCI_ID: 391 case ALI_PCI_ID: 392 case TDX_PCI_ID: 393 ch->cso &= 0x0000ffff; 394 ch->eso &= 0x0000ffff; 395 cr[0]=(ch->cso<<16) | (ch->alpha<<4) | (ch->fms); 396 cr[2]=(ch->eso<<16) | (ch->delta); 397 break; 398 case TNX_PCI_ID: 399 ch->cso &= 0x00ffffff; 400 ch->eso &= 0x00ffffff; 401 cr[0]=((ch->delta & 0xff)<<24) | (ch->cso); 402 cr[2]=((ch->delta>>8)<<24) | (ch->eso); 403 cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14); 404 break; 405 } 406 snd_mtxlock(tr->lock); 407 tr_selch(ch); 408 for (i=0; i<TR_CHN_REGS; i++) 409 tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4); 410 snd_mtxunlock(tr->lock); 411} 412 413static void 414tr_rdch(struct tr_chinfo *ch) 415{ 416 struct tr_info *tr = ch->parent; 417 u_int32_t cr[5], i; 418 419 snd_mtxlock(tr->lock); 420 tr_selch(ch); 421 for (i=0; i<5; i++) 422 cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4); 423 snd_mtxunlock(tr->lock); 424 425 426 ch->lba= (cr[1] & 0x3fffffff); 427 ch->fmc= (cr[3] & 0x0000c000) >> 14; 428 ch->rvol= (cr[3] & 0x00003f80) >> 7; 429 ch->cvol= (cr[3] & 0x0000007f); 430 ch->gvsel= (cr[4] & 0x80000000) >> 31; 431 ch->pan= (cr[4] & 0x7f000000) >> 24; 432 ch->vol= (cr[4] & 0x00ff0000) >> 16; 433 ch->ctrl= (cr[4] & 0x0000f000) >> 12; 434 ch->ec= (cr[4] & 0x00000fff); 435 switch(tr->type) { 436 case SPA_PCI_ID: 437 case ALI_PCI_ID: 438 case TDX_PCI_ID: 439 ch->cso= (cr[0] & 0xffff0000) >> 16; 440 ch->alpha= (cr[0] & 0x0000fff0) >> 4; 441 ch->fms= (cr[0] & 0x0000000f); 442 ch->eso= (cr[2] & 0xffff0000) >> 16; 443 ch->delta= (cr[2] & 0x0000ffff); 444 break; 445 case TNX_PCI_ID: 446 ch->cso= (cr[0] & 0x00ffffff); 447 ch->eso= (cr[2] & 0x00ffffff); 448 ch->delta= ((cr[2] & 0xff000000) >> 16) | ((cr[0] & 0xff000000) >> 24); 449 ch->alpha= (cr[3] & 0xfff00000) >> 20; 450 ch->fms= (cr[3] & 0x000f0000) >> 16; 451 break; 452 } 453} 454 455static u_int32_t 456tr_fmttobits(u_int32_t fmt) 457{ 458 u_int32_t bits; 459 460 bits = 0; 461 bits |= (fmt & AFMT_SIGNED)? 0x2 : 0; 462 bits |= (fmt & AFMT_STEREO)? 0x4 : 0; 463 bits |= (fmt & AFMT_16BIT)? 0x8 : 0; 464 465 return bits; 466} 467 468/* -------------------------------------------------------------------- */ 469/* channel interface */ 470 471static void * 472trpchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 473{ 474 struct tr_info *tr = devinfo; 475 struct tr_chinfo *ch; 476 477 KASSERT(dir == PCMDIR_PLAY, ("trpchan_init: bad direction")); 478 ch = &tr->chinfo[tr->playchns]; 479 ch->index = tr->playchns++; 480 ch->buffer = b; 481 ch->parent = tr; 482 ch->channel = c; 483 if (sndbuf_alloc(ch->buffer, tr->parent_dmat, tr->bufsz) == -1) 484 return NULL; 485 486 return ch; 487} 488 489static int 490trpchan_setformat(kobj_t obj, void *data, u_int32_t format) 491{ 492 struct tr_chinfo *ch = data; 493 494 ch->ctrl = tr_fmttobits(format) | 0x01; 495 496 return 0; 497} 498 499static int 500trpchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 501{ 502 struct tr_chinfo *ch = data; 503 504 ch->delta = (speed << 12) / 48000; 505 return (ch->delta * 48000) >> 12; 506} 507 508static int 509trpchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 510{ 511 struct tr_chinfo *ch = data; 512 513 sndbuf_resize(ch->buffer, 2, blocksize); 514 return blocksize; 515} 516 517static int 518trpchan_trigger(kobj_t obj, void *data, int go) 519{ 520 struct tr_chinfo *ch = data; 521 522 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 523 return 0; 524 525 if (go == PCMTRIG_START) { 526 ch->fmc = 3; 527 ch->fms = 0; 528 ch->ec = 0; 529 ch->alpha = 0; 530 ch->lba = vtophys(sndbuf_getbuf(ch->buffer)); 531 ch->cso = 0; 532 ch->eso = (sndbuf_getsize(ch->buffer) / sndbuf_getbps(ch->buffer)) - 1; 533 ch->rvol = ch->cvol = 0x7f; 534 ch->gvsel = 0; 535 ch->pan = 0; 536 ch->vol = 0; 537 ch->bufhalf = 0; 538 tr_wrch(ch); 539 tr_enaint(ch, 1); 540 tr_startch(ch); 541 ch->active = 1; 542 } else { 543 tr_stopch(ch); 544 ch->active = 0; 545 } 546 547 return 0; 548} 549 550static int 551trpchan_getptr(kobj_t obj, void *data) 552{ 553 struct tr_chinfo *ch = data; 554 555 tr_rdch(ch); 556 return ch->cso * sndbuf_getbps(ch->buffer); 557} 558 559static struct pcmchan_caps * 560trpchan_getcaps(kobj_t obj, void *data) 561{ 562 return &tr_playcaps; 563} 564 565static kobj_method_t trpchan_methods[] = { 566 KOBJMETHOD(channel_init, trpchan_init), 567 KOBJMETHOD(channel_setformat, trpchan_setformat), 568 KOBJMETHOD(channel_setspeed, trpchan_setspeed), 569 KOBJMETHOD(channel_setblocksize, trpchan_setblocksize), 570 KOBJMETHOD(channel_trigger, trpchan_trigger), 571 KOBJMETHOD(channel_getptr, trpchan_getptr), 572 KOBJMETHOD(channel_getcaps, trpchan_getcaps), 573 { 0, 0 } 574}; 575CHANNEL_DECLARE(trpchan); 576 577/* -------------------------------------------------------------------- */ 578/* rec channel interface */ 579 580static void * 581trrchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 582{ 583 struct tr_info *tr = devinfo; 584 struct tr_rchinfo *ch; 585 586 KASSERT(dir == PCMDIR_REC, ("trrchan_init: bad direction")); 587 ch = &tr->recchinfo; 588 ch->buffer = b; 589 ch->parent = tr; 590 ch->channel = c; 591 if (sndbuf_alloc(ch->buffer, tr->parent_dmat, tr->bufsz) == -1) 592 return NULL; 593 594 return ch; 595} 596 597static int 598trrchan_setformat(kobj_t obj, void *data, u_int32_t format) 599{ 600 struct tr_rchinfo *ch = data; 601 struct tr_info *tr = ch->parent; 602 u_int32_t i, bits; 603 604 bits = tr_fmttobits(format); 605 /* set # of samples between interrupts */ 606 i = (sndbuf_runsz(ch->buffer) >> ((bits & 0x08)? 1 : 0)) - 1; 607 tr_wr(tr, TR_REG_SBBL, i | (i << 16), 4); 608 /* set sample format */ 609 i = 0x18 | (bits << 4); 610 tr_wr(tr, TR_REG_SBCTRL, i, 1); 611 612 return 0; 613 614} 615 616static int 617trrchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 618{ 619 struct tr_rchinfo *ch = data; 620 struct tr_info *tr = ch->parent; 621 622 /* setup speed */ 623 ch->delta = (48000 << 12) / speed; 624 tr_wr(tr, TR_REG_SBDELTA, ch->delta, 2); 625 626 /* return closest possible speed */ 627 return (48000 << 12) / ch->delta; 628} 629 630static int 631trrchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 632{ 633 struct tr_rchinfo *ch = data; 634 635 sndbuf_resize(ch->buffer, 2, blocksize); 636 637 return blocksize; 638} 639 640static int 641trrchan_trigger(kobj_t obj, void *data, int go) 642{ 643 struct tr_rchinfo *ch = data; 644 struct tr_info *tr = ch->parent; 645 u_int32_t i; 646 647 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 648 return 0; 649 650 if (go == PCMTRIG_START) { 651 /* set up dma mode regs */ 652 tr_wr(tr, TR_REG_DMAR15, 0, 1); 653 i = tr_rd(tr, TR_REG_DMAR11, 1) & 0x03; 654 tr_wr(tr, TR_REG_DMAR11, i | 0x54, 1); 655 /* set up base address */ 656 tr_wr(tr, TR_REG_DMAR0, vtophys(sndbuf_getbuf(ch->buffer)), 4); 657 /* set up buffer size */ 658 i = tr_rd(tr, TR_REG_DMAR4, 4) & ~0x00ffffff; 659 tr_wr(tr, TR_REG_DMAR4, i | (sndbuf_runsz(ch->buffer) - 1), 4); 660 /* start */ 661 tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) | 1, 1); 662 ch->active = 1; 663 } else { 664 tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) & ~7, 1); 665 ch->active = 0; 666 } 667 668 /* return 0 if ok */ 669 return 0; 670} 671 672static int 673trrchan_getptr(kobj_t obj, void *data) 674{ 675 struct tr_rchinfo *ch = data; 676 struct tr_info *tr = ch->parent; 677 678 /* return current byte offset of channel */ 679 return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(sndbuf_getbuf(ch->buffer)); 680} 681 682static struct pcmchan_caps * 683trrchan_getcaps(kobj_t obj, void *data) 684{ 685 return &tr_reccaps; 686} 687 688static kobj_method_t trrchan_methods[] = { 689 KOBJMETHOD(channel_init, trrchan_init), 690 KOBJMETHOD(channel_setformat, trrchan_setformat), 691 KOBJMETHOD(channel_setspeed, trrchan_setspeed), 692 KOBJMETHOD(channel_setblocksize, trrchan_setblocksize), 693 KOBJMETHOD(channel_trigger, trrchan_trigger), 694 KOBJMETHOD(channel_getptr, trrchan_getptr), 695 KOBJMETHOD(channel_getcaps, trrchan_getcaps), 696 { 0, 0 } 697}; 698CHANNEL_DECLARE(trrchan); 699 700/* -------------------------------------------------------------------- */ 701/* The interrupt handler */ 702 703static void 704tr_intr(void *p) 705{ 706 struct tr_info *tr = (struct tr_info *)p; 707 struct tr_chinfo *ch; 708 u_int32_t active, mask, bufhalf, chnum, intsrc; 709 int tmp; 710 711 intsrc = tr_rd(tr, TR_REG_MISCINT, 4); 712 if (intsrc & TR_INT_ADDR) { 713 chnum = 0; 714 while (chnum < 64) { 715 mask = 0x00000001; 716 active = tr_rd(tr, (chnum < 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, 4); 717 bufhalf = tr_rd(tr, (chnum < 32)? TR_REG_CSPF_A : TR_REG_CSPF_B, 4); 718 if (active) { 719 do { 720 if (active & mask) { 721 tmp = (bufhalf & mask)? 1 : 0; 722 if (chnum < tr->playchns) { 723 ch = &tr->chinfo[chnum]; 724 /* printf("%d @ %d, ", chnum, trpchan_getptr(NULL, ch)); */ 725 if (ch->bufhalf != tmp) { 726 chn_intr(ch->channel); 727 ch->bufhalf = tmp; 728 } 729 } 730 } 731 chnum++; 732 mask <<= 1; 733 } while (chnum & 31); 734 } else 735 chnum += 32; 736 737 tr_wr(tr, (chnum <= 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, active, 4); 738 } 739 } 740 if (intsrc & TR_INT_SB) { 741 chn_intr(tr->recchinfo.channel); 742 tr_rd(tr, TR_REG_SBR9, 1); 743 tr_rd(tr, TR_REG_SBR10, 1); 744 } 745} 746 747/* -------------------------------------------------------------------- */ 748 749/* 750 * Probe and attach the card 751 */ 752 753static int 754tr_init(struct tr_info *tr) 755{ 756 switch (tr->type) { 757 case SPA_PCI_ID: 758 tr_wr(tr, SPA_REG_GPIO, 0, 4); 759 tr_wr(tr, SPA_REG_CODECST, SPA_RST_OFF, 4); 760 break; 761 case TDX_PCI_ID: 762 tr_wr(tr, TDX_REG_CODECST, TDX_CDC_ON, 4); 763 break; 764 case TNX_PCI_ID: 765 tr_wr(tr, TNX_REG_CODECST, TNX_CDC_ON, 4); 766 break; 767 } 768 769 tr_wr(tr, TR_REG_CIR, TR_CIR_MIDENA | TR_CIR_ADDRENA, 4); 770 return 0; 771} 772 773static int 774tr_pci_probe(device_t dev) 775{ 776 switch (pci_get_devid(dev)) { 777 case SPA_PCI_ID: 778 device_set_desc(dev, "SiS 7018"); 779 return 0; 780 case ALI_PCI_ID: 781 device_set_desc(dev, "Acer Labs M5451"); 782 return 0; 783 case TDX_PCI_ID: 784 device_set_desc(dev, "Trident 4DWave DX"); 785 return 0; 786 case TNX_PCI_ID: 787 device_set_desc(dev, "Trident 4DWave NX"); 788 return 0; 789 } 790 791 return ENXIO; 792} 793 794static int 795tr_pci_attach(device_t dev) 796{ 797 u_int32_t data; 798 struct tr_info *tr; 799 struct ac97_info *codec = 0; 800 int i; 801 char status[SND_STATUSLEN]; 802 803 if ((tr = malloc(sizeof(*tr), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 804 device_printf(dev, "cannot allocate softc\n"); 805 return ENXIO; 806 } 807 808 tr->type = pci_get_devid(dev); 809 tr->rev = pci_get_revid(dev); 810 tr->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); 811 812 data = pci_read_config(dev, PCIR_COMMAND, 2); 813 data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 814 pci_write_config(dev, PCIR_COMMAND, data, 2); 815 data = pci_read_config(dev, PCIR_COMMAND, 2); 816 817 tr->regid = PCIR_MAPS; 818 tr->regtype = SYS_RES_IOPORT; 819 tr->reg = bus_alloc_resource(dev, tr->regtype, &tr->regid, 0, ~0, 1, RF_ACTIVE); 820 if (tr->reg) { 821 tr->st = rman_get_bustag(tr->reg); 822 tr->sh = rman_get_bushandle(tr->reg); 823 } else { 824 device_printf(dev, "unable to map register space\n"); 825 goto bad; 826 } 827 828 tr->bufsz = pcm_getbuffersize(dev, 4096, TR_DEFAULT_BUFSZ, 65536); 829 830 if (tr_init(tr) == -1) { 831 device_printf(dev, "unable to initialize the card\n"); 832 goto bad; 833 } 834 tr->playchns = 0; 835 836 codec = AC97_CREATE(dev, tr, tr_ac97); 837 if (codec == NULL) goto bad; 838 if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad; 839 840 tr->irqid = 0; 841 tr->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &tr->irqid, 842 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 843 if (!tr->irq || snd_setup_intr(dev, tr->irq, INTR_MPSAFE, tr_intr, tr, &tr->ih)) { 844 device_printf(dev, "unable to map interrupt\n"); 845 goto bad; 846 } 847 848 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 849 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 850 /*highaddr*/BUS_SPACE_MAXADDR, 851 /*filter*/NULL, /*filterarg*/NULL, 852 /*maxsize*/tr->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, 853 /*flags*/0, &tr->parent_dmat) != 0) { 854 device_printf(dev, "unable to create dma tag\n"); 855 goto bad; 856 } 857 858 snprintf(status, 64, "at io 0x%lx irq %ld", 859 rman_get_start(tr->reg), rman_get_start(tr->irq)); 860 861 if (pcm_register(dev, tr, TR_MAXPLAYCH, 1)) goto bad; 862 pcm_addchan(dev, PCMDIR_REC, &trrchan_class, tr); 863 for (i = 0; i < TR_MAXPLAYCH; i++) 864 pcm_addchan(dev, PCMDIR_PLAY, &trpchan_class, tr); 865 pcm_setstatus(dev, status); 866 867 return 0; 868 869bad: 870 if (codec) ac97_destroy(codec); 871 if (tr->reg) bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 872 if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih); 873 if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 874 if (tr->parent_dmat) bus_dma_tag_destroy(tr->parent_dmat); 875 if (tr->lock) snd_mtxfree(tr->lock); 876 free(tr, M_DEVBUF); 877 return ENXIO; 878} 879 880static int 881tr_pci_detach(device_t dev) 882{ 883 int r; 884 struct tr_info *tr; 885 886 r = pcm_unregister(dev); 887 if (r) 888 return r; 889 890 tr = pcm_getdevinfo(dev); 891 bus_release_resource(dev, tr->regtype, tr->regid, tr->reg); 892 bus_teardown_intr(dev, tr->irq, tr->ih); 893 bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq); 894 bus_dma_tag_destroy(tr->parent_dmat); 895 snd_mtxfree(tr->lock); 896 free(tr, M_DEVBUF); 897 898 return 0; 899} 900 901static int 902tr_pci_suspend(device_t dev) 903{ 904 int i; 905 struct tr_info *tr; 906 907 tr = pcm_getdevinfo(dev); 908 909 for (i = 0; i < tr->playchns; i++) { 910 tr->chinfo[i].was_active = tr->chinfo[i].active; 911 if (tr->chinfo[i].active) { 912 trpchan_trigger(NULL, &tr->chinfo[i], PCMTRIG_STOP); 913 } 914 } 915 916 tr->recchinfo.was_active = tr->recchinfo.active; 917 if (tr->recchinfo.active) { 918 trrchan_trigger(NULL, &tr->recchinfo, PCMTRIG_STOP); 919 } 920 921 return 0; 922} 923 924static int 925tr_pci_resume(device_t dev) 926{ 927 int i; 928 struct tr_info *tr; 929 930 tr = pcm_getdevinfo(dev); 931 932 if (tr_init(tr) == -1) { 933 device_printf(dev, "unable to initialize the card\n"); 934 return ENXIO; 935 } 936 937 if (mixer_reinit(dev) == -1) { 938 device_printf(dev, "unable to initialize the mixer\n"); 939 return ENXIO; 940 } 941 942 for (i = 0; i < tr->playchns; i++) { 943 if (tr->chinfo[i].was_active) { 944 trpchan_trigger(NULL, &tr->chinfo[i], PCMTRIG_START); 945 } 946 } 947 948 if (tr->recchinfo.was_active) { 949 trrchan_trigger(NULL, &tr->recchinfo, PCMTRIG_START); 950 } 951 952 return 0; 953} 954 955static device_method_t tr_methods[] = { 956 /* Device interface */ 957 DEVMETHOD(device_probe, tr_pci_probe), 958 DEVMETHOD(device_attach, tr_pci_attach), 959 DEVMETHOD(device_detach, tr_pci_detach), 960 DEVMETHOD(device_suspend, tr_pci_suspend), 961 DEVMETHOD(device_resume, tr_pci_resume), 962 { 0, 0 } 963}; 964 965static driver_t tr_driver = { 966 "pcm", 967 tr_methods, 968 PCM_SOFTC_SIZE, 969}; 970 971DRIVER_MODULE(snd_t4dwave, pci, tr_driver, pcm_devclass, 0, 0); 972MODULE_DEPEND(snd_t4dwave, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 973MODULE_VERSION(snd_t4dwave, 1); 974