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