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