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