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