solo.c revision 64623
1/* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * 25 * $FreeBSD: head/sys/dev/sound/pci/solo.c 64623 2000-08-13 19:20:02Z nsayer $ 26 */ 27 28#include <dev/sound/pcm/sound.h> 29 30#include <pci/pcireg.h> 31#include <pci/pcivar.h> 32 33#include <dev/sound/isa/sb.h> 34#include <dev/sound/chip.h> 35 36#define ESS_BUFFSIZE (16384) 37#define ABS(x) (((x) < 0)? -(x) : (x)) 38 39/* if defined, playback always uses the 2nd channel and full duplex works */ 40#undef ESS18XX_DUPLEX 41 42/* more accurate clocks and split audio1/audio2 rates */ 43#define ESS18XX_NEWSPEED 44 45/* channel interface for ESS */ 46static void *esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); 47static int esschan_setdir(void *data, int dir); 48static int esschan_setformat(void *data, u_int32_t format); 49static int esschan_setspeed(void *data, u_int32_t speed); 50static int esschan_setblocksize(void *data, u_int32_t blocksize); 51static int esschan_trigger(void *data, int go); 52static int esschan_getptr(void *data); 53static pcmchan_caps *esschan_getcaps(void *data); 54 55static pcmchan_caps ess_playcaps = { 56 5000, 49000, 57 AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_U16_LE | AFMT_S16_LE, 58 AFMT_STEREO | AFMT_S16_LE 59}; 60 61/* 62 * Recording output is byte-swapped 63 */ 64static pcmchan_caps ess_reccaps = { 65 5000, 49000, 66 AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_U16_BE | AFMT_S16_BE, 67 AFMT_STEREO | AFMT_S16_BE 68}; 69 70static pcm_channel ess_chantemplate = { 71 esschan_init, 72 esschan_setdir, 73 esschan_setformat, 74 esschan_setspeed, 75 esschan_setblocksize, 76 esschan_trigger, 77 esschan_getptr, 78 esschan_getcaps, 79}; 80 81struct ess_info; 82 83struct ess_chinfo { 84 struct ess_info *parent; 85 pcm_channel *channel; 86 snd_dbuf *buffer; 87 int dir, hwch, stopping; 88 u_int32_t fmt, spd; 89}; 90 91struct ess_info { 92 struct resource *io, *sb, *vc, *mpu, *gp; /* I/O address for the board */ 93 struct resource *irq; 94 bus_dma_tag_t parent_dmat; 95 96 int simplex_dir, type, duplex:1, newspeed:1, dmasz[2]; 97 struct ess_chinfo pch, rch; 98}; 99 100static int ess_rd(struct ess_info *sc, int reg); 101static void ess_wr(struct ess_info *sc, int reg, u_int8_t val); 102static int ess_dspready(struct ess_info *sc); 103static int ess_cmd(struct ess_info *sc, u_char val); 104static int ess_cmd1(struct ess_info *sc, u_char cmd, int val); 105static int ess_get_byte(struct ess_info *sc); 106static void ess_setmixer(struct ess_info *sc, u_int port, u_int value); 107static int ess_getmixer(struct ess_info *sc, u_int port); 108static int ess_reset_dsp(struct ess_info *sc); 109 110static int ess_write(struct ess_info *sc, u_char reg, int val); 111static int ess_read(struct ess_info *sc, u_char reg); 112 113static void ess_intr(void *arg); 114static int ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len); 115static int ess_start(struct ess_chinfo *ch); 116static int ess_stop(struct ess_chinfo *ch); 117 118static int ess_dmasetup(struct ess_info *sc, int ch, u_int32_t base, u_int16_t cnt, int dir); 119static int ess_dmapos(struct ess_info *sc, int ch); 120static int ess_dmatrigger(struct ess_info *sc, int ch, int go); 121 122static int essmix_init(snd_mixer *m); 123static int essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right); 124static int essmix_setrecsrc(snd_mixer *m, u_int32_t src); 125 126static snd_mixer ess_mixer = { 127 "ESS mixer", 128 essmix_init, 129 essmix_set, 130 essmix_setrecsrc, 131}; 132 133static devclass_t pcm_devclass; 134 135/* 136 * Common code for the midi and pcm functions 137 * 138 * ess_cmd write a single byte to the CMD port. 139 * ess_cmd1 write a CMD + 1 byte arg 140 * ess_cmd2 write a CMD + 2 byte arg 141 * ess_get_byte returns a single byte from the DSP data port 142 * 143 * ess_write is actually ess_cmd1 144 * ess_read access ext. regs via ess_cmd(0xc0, reg) followed by ess_get_byte 145 */ 146 147static int 148port_rd(struct resource *port, int regno, int size) 149{ 150 bus_space_tag_t st = rman_get_bustag(port); 151 bus_space_handle_t sh = rman_get_bushandle(port); 152 153 switch (size) { 154 case 1: 155 return bus_space_read_1(st, sh, regno); 156 case 2: 157 return bus_space_read_2(st, sh, regno); 158 case 4: 159 return bus_space_read_4(st, sh, regno); 160 default: 161 return 0xffffffff; 162 } 163} 164 165static void 166port_wr(struct resource *port, int regno, u_int32_t data, int size) 167{ 168 bus_space_tag_t st = rman_get_bustag(port); 169 bus_space_handle_t sh = rman_get_bushandle(port); 170 171 switch (size) { 172 case 1: 173 bus_space_write_1(st, sh, regno, data); 174 break; 175 case 2: 176 bus_space_write_2(st, sh, regno, data); 177 break; 178 case 4: 179 bus_space_write_4(st, sh, regno, data); 180 break; 181 } 182} 183 184static int 185ess_rd(struct ess_info *sc, int reg) 186{ 187 return port_rd(sc->sb, reg, 1); 188} 189 190static void 191ess_wr(struct ess_info *sc, int reg, u_int8_t val) 192{ 193 port_wr(sc->sb, reg, val, 1); 194} 195 196static int 197ess_dspready(struct ess_info *sc) 198{ 199 return ((ess_rd(sc, SBDSP_STATUS) & 0x80) == 0); 200} 201 202static int 203ess_dspwr(struct ess_info *sc, u_char val) 204{ 205 int i; 206 207 for (i = 0; i < 1000; i++) { 208 if (ess_dspready(sc)) { 209 ess_wr(sc, SBDSP_CMD, val); 210 return 1; 211 } 212 if (i > 10) DELAY((i > 100)? 1000 : 10); 213 } 214 printf("ess_dspwr(0x%02x) timed out.\n", val); 215 return 0; 216} 217 218static int 219ess_cmd(struct ess_info *sc, u_char val) 220{ 221 DEB(printf("ess_cmd: %x\n", val)); 222 return ess_dspwr(sc, val); 223} 224 225static int 226ess_cmd1(struct ess_info *sc, u_char cmd, int val) 227{ 228 DEB(printf("ess_cmd1: %x, %x\n", cmd, val)); 229 if (ess_dspwr(sc, cmd)) { 230 return ess_dspwr(sc, val & 0xff); 231 } else return 0; 232} 233 234static void 235ess_setmixer(struct ess_info *sc, u_int port, u_int value) 236{ 237 u_long flags; 238 239 DEB(printf("ess_setmixer: reg=%x, val=%x\n", port, value);) 240 flags = spltty(); 241 ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 242 DELAY(10); 243 ess_wr(sc, SB_MIX_DATA, (u_char) (value & 0xff)); 244 DELAY(10); 245 splx(flags); 246} 247 248static int 249ess_getmixer(struct ess_info *sc, u_int port) 250{ 251 int val; 252 u_long flags; 253 254 flags = spltty(); 255 ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 256 DELAY(10); 257 val = ess_rd(sc, SB_MIX_DATA); 258 DELAY(10); 259 splx(flags); 260 261 return val; 262} 263 264static int 265ess_get_byte(struct ess_info *sc) 266{ 267 int i; 268 269 for (i = 1000; i > 0; i--) { 270 if (ess_rd(sc, 0xc) & 0x40) 271 return ess_rd(sc, DSP_READ); 272 else 273 DELAY(20); 274 } 275 return -1; 276} 277 278static int 279ess_write(struct ess_info *sc, u_char reg, int val) 280{ 281 return ess_cmd1(sc, reg, val); 282} 283 284static int 285ess_read(struct ess_info *sc, u_char reg) 286{ 287 return (ess_cmd(sc, 0xc0) && ess_cmd(sc, reg))? ess_get_byte(sc) : -1; 288} 289 290static int 291ess_reset_dsp(struct ess_info *sc) 292{ 293 DEB(printf("ess_reset_dsp\n")); 294 ess_wr(sc, SBDSP_RST, 3); 295 DELAY(100); 296 ess_wr(sc, SBDSP_RST, 0); 297 if (ess_get_byte(sc) != 0xAA) { 298 DEB(printf("ess_reset_dsp failed\n")); 299/* 300 rman_get_start(d->io_base))); 301*/ 302 return ENXIO; /* Sorry */ 303 } 304 ess_cmd(sc, 0xc6); 305 return 0; 306} 307 308static void 309ess_intr(void *arg) 310{ 311 struct ess_info *sc = (struct ess_info *)arg; 312 int src, pirq = 0, rirq = 0; 313 314 src = 0; 315 if (ess_getmixer(sc, 0x7a) & 0x80) 316 src |= 2; 317 if (ess_rd(sc, 0x0c) & 0x01) 318 src |= 1; 319 320 if (sc->duplex) { 321 pirq = (src & sc->pch.hwch)? 1 : 0; 322 rirq = (src & sc->rch.hwch)? 1 : 0; 323 } else { 324 if (sc->simplex_dir == PCMDIR_PLAY) 325 pirq = 1; 326 if (sc->simplex_dir == PCMDIR_REC) 327 rirq = 1; 328 if (!pirq && !rirq) 329 printf("solo: IRQ neither playback nor rec!\n"); 330 } 331 332 DEB(printf("ess_intr: pirq:%d rirq:%d\n",pirq,rirq)); 333 334 if (pirq) { 335 if (sc->pch.stopping) { 336 ess_dmatrigger(sc, sc->pch.hwch, 0); 337 sc->pch.stopping = 0; 338 if (sc->pch.hwch == 1) 339 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01); 340 else 341 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x03); 342 } 343 chn_intr(sc->pch.channel); 344 } 345 346 if (rirq) { 347 if (sc->rch.stopping) { 348 ess_dmatrigger(sc, sc->rch.hwch, 0); 349 sc->rch.stopping = 0; 350 /* XXX: will this stop audio2? */ 351 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01); 352 } 353 chn_intr(sc->rch.channel); 354 } 355 356 if (src & 2) 357 ess_setmixer(sc, 0x7a, ess_getmixer(sc, 0x7a) & ~0x80); 358 if (src & 1) 359 ess_rd(sc, DSP_DATA_AVAIL); 360} 361 362/* utility functions for ESS */ 363static u_int8_t 364ess_calcspeed8(int *spd) 365{ 366 int speed = *spd; 367 u_int32_t t; 368 369 if (speed > 22000) { 370 t = (795500 + speed / 2) / speed; 371 speed = (795500 + t / 2) / t; 372 t = (256 - t) | 0x80; 373 } else { 374 t = (397700 + speed / 2) / speed; 375 speed = (397700 + t / 2) / t; 376 t = 128 - t; 377 } 378 *spd = speed; 379 return t & 0x000000ff; 380} 381 382static u_int8_t 383ess_calcspeed9(int *spd) 384{ 385 int speed, s0, s1, use0; 386 u_int8_t t0, t1; 387 388 /* rate = source / (256 - divisor) */ 389 /* divisor = 256 - (source / rate) */ 390 speed = *spd; 391 t0 = 128 - (793800 / speed); 392 s0 = 793800 / (128 - t0); 393 394 t1 = 128 - (768000 / speed); 395 s1 = 768000 / (128 - t1); 396 t1 |= 0x80; 397 398 use0 = (ABS(speed - s0) < ABS(speed - s1))? 1 : 0; 399 400 *spd = use0? s0 : s1; 401 return use0? t0 : t1; 402} 403 404static u_int8_t 405ess_calcfilter(int spd) 406{ 407 int cutoff; 408 409 /* cutoff = 7160000 / (256 - divisor) */ 410 /* divisor = 256 - (7160000 / cutoff) */ 411 cutoff = (spd * 9 * 82) / 20; 412 return (256 - (7160000 / cutoff)); 413} 414 415static int 416ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len) 417{ 418 int play = (dir == PCMDIR_PLAY)? 1 : 0; 419 int b16 = (fmt & AFMT_16BIT)? 1 : 0; 420 int stereo = (fmt & AFMT_STEREO)? 1 : 0; 421 int unsign = (fmt == AFMT_U8 || fmt == AFMT_U16_LE || fmt == AFMT_U16_BE)? 1 : 0; 422 u_int8_t spdval, fmtval; 423 424 DEB(printf("ess_setupch\n")); 425 spdval = (sc->newspeed)? ess_calcspeed9(&spd) : ess_calcspeed8(&spd); 426 427 sc->simplex_dir = play ? PCMDIR_PLAY : PCMDIR_REC ; 428 429 if (ch == 1) { 430 KASSERT((dir == PCMDIR_PLAY) || (dir == PCMDIR_REC), ("ess_setupch: dir1 bad")); 431 len = -len; 432 /* transfer length low */ 433 ess_write(sc, 0xa4, len & 0x00ff); 434 /* transfer length high */ 435 ess_write(sc, 0xa5, (len & 0xff00) >> 8); 436 /* autoinit, dma dir */ 437 ess_write(sc, 0xb8, 0x04 | (play? 0x00 : 0x0a)); 438 /* mono/stereo */ 439 ess_write(sc, 0xa8, (ess_read(sc, 0xa8) & ~0x03) | (stereo? 0x01 : 0x02)); 440 /* demand mode, 4 bytes/xfer */ 441 ess_write(sc, 0xb9, 0x02); 442 /* sample rate */ 443 ess_write(sc, 0xa1, spdval); 444 /* filter cutoff */ 445 ess_write(sc, 0xa2, ess_calcfilter(spd)); 446 /* setup dac/adc */ 447 /* 448 if (play) 449 ess_write(sc, 0xb6, unsign? 0x80 : 0x00); 450 */ 451 /* mono, b16: signed, load signal */ 452 /* 453 ess_write(sc, 0xb7, 0x51 | (unsign? 0x00 : 0x20)); 454 */ 455 /* setup fifo */ 456 ess_write(sc, 0xb7, 0x91 | (unsign? 0x00 : 0x20) | 457 (b16? 0x04 : 0x00) | 458 (stereo? 0x08 : 0x40)); 459 /* irq control */ 460 ess_write(sc, 0xb1, (ess_read(sc, 0xb1) & 0x0f) | 0x50); 461 /* drq control */ 462 ess_write(sc, 0xb2, (ess_read(sc, 0xb2) & 0x0f) | 0x50); 463 } else if (ch == 2) { 464 KASSERT(dir == PCMDIR_PLAY, ("ess_setupch: dir2 bad")); 465 len >>= 1; 466 len = -len; 467 /* transfer length low */ 468 ess_setmixer(sc, 0x74, len & 0x00ff); 469 /* transfer length high */ 470 ess_setmixer(sc, 0x76, (len & 0xff00) >> 8); 471 /* autoinit, 4 bytes/req */ 472 ess_setmixer(sc, 0x78, 0x10); 473 fmtval = b16 | (stereo << 1) | ((!unsign) << 2); 474 /* enable irq, set format */ 475 ess_setmixer(sc, 0x7a, 0x40 | fmtval); 476 if (sc->newspeed) { 477 /* sample rate */ 478 ess_setmixer(sc, 0x70, spdval); 479 /* filter cutoff */ 480 ess_setmixer(sc, 0x72, ess_calcfilter(spd)); 481 } 482 483 } 484 return 0; 485} 486static int 487ess_start(struct ess_chinfo *ch) 488{ 489 struct ess_info *sc = ch->parent; 490 491 DEB(printf("ess_start\n");); 492 ess_setupch(sc, ch->hwch, ch->dir, ch->spd, ch->fmt, ch->buffer->dl); 493 ch->stopping = 0; 494 if (ch->hwch == 1) { 495 ess_write(sc, 0xb8, ess_read(sc, 0xb8) | 0x01); 496 if (ch->dir == PCMDIR_PLAY) { 497#if 0 498 DELAY(100000); /* 100 ms */ 499#endif 500 ess_cmd(sc, 0xd1); 501 } 502 } else 503 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) | 0x03); 504 return 0; 505} 506 507static int 508ess_stop(struct ess_chinfo *ch) 509{ 510 struct ess_info *sc = ch->parent; 511 512 DEB(printf("ess_stop\n")); 513 ch->stopping = 1; 514 if (ch->hwch == 1) 515 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x04); 516 else 517 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x10); 518 DEB(printf("done with stop\n")); 519 return 0; 520} 521 522/* channel interface for ESS18xx */ 523static void * 524esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 525{ 526 struct ess_info *sc = devinfo; 527 struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch; 528 529 DEB(printf("esschan_init\n")); 530 ch->parent = sc; 531 ch->channel = c; 532 ch->buffer = b; 533 ch->buffer->bufsize = ESS_BUFFSIZE; 534 if (chn_allocbuf(ch->buffer, sc->parent_dmat) == -1) 535 return NULL; 536 ch->hwch = 1; 537 if ((dir == PCMDIR_PLAY) && (sc->duplex)) 538 ch->hwch = 2; 539 return ch; 540} 541 542static int 543esschan_setdir(void *data, int dir) 544{ 545 struct ess_chinfo *ch = data; 546 547 ch->dir = dir; 548 return 0; 549} 550 551static int 552esschan_setformat(void *data, u_int32_t format) 553{ 554 struct ess_chinfo *ch = data; 555 556 ch->fmt = format; 557 return 0; 558} 559 560static int 561esschan_setspeed(void *data, u_int32_t speed) 562{ 563 struct ess_chinfo *ch = data; 564 struct ess_info *sc = ch->parent; 565 566 ch->spd = speed; 567 if (sc->newspeed) 568 ess_calcspeed9(&ch->spd); 569 else 570 ess_calcspeed8(&ch->spd); 571 return ch->spd; 572} 573 574static int 575esschan_setblocksize(void *data, u_int32_t blocksize) 576{ 577 return blocksize; 578} 579 580static int 581esschan_trigger(void *data, int go) 582{ 583 struct ess_chinfo *ch = data; 584 struct ess_info *sc = ch->parent; 585 586 DEB(printf("esschan_trigger: %d\n",go)); 587 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 588 return 0; 589 590 switch (go) { 591 case PCMTRIG_START: 592 ess_dmasetup(sc, ch->hwch, vtophys(ch->buffer->buf), ch->buffer->bufsize, ch->dir); 593 ess_dmatrigger(sc, ch->hwch, 1); 594 ess_start(ch); 595 break; 596 597 case PCMTRIG_STOP: 598 case PCMTRIG_ABORT: 599 default: 600 ess_stop(ch); 601 break; 602 } 603 return 0; 604} 605 606static int 607esschan_getptr(void *data) 608{ 609 struct ess_chinfo *ch = data; 610 struct ess_info *sc = ch->parent; 611 612 return ess_dmapos(sc, ch->hwch); 613} 614 615static pcmchan_caps * 616esschan_getcaps(void *data) 617{ 618 struct ess_chinfo *ch = data; 619 620 return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps; 621} 622 623/************************************************************/ 624 625static int 626essmix_init(snd_mixer *m) 627{ 628 struct ess_info *sc = mix_getdevinfo(m); 629 630 mix_setrecdevs(m, SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE | 631 SOUND_MASK_IMIX); 632 633 mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | 634 SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME | 635 SOUND_MASK_LINE1); 636 637 ess_setmixer(sc, 0, 0); /* reset */ 638 639 return 0; 640} 641 642static int 643essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 644{ 645 struct ess_info *sc = mix_getdevinfo(m); 646 int preg = 0, rreg = 0, l, r; 647 648 l = (left * 15) / 100; 649 r = (right * 15) / 100; 650 switch (dev) { 651 case SOUND_MIXER_SYNTH: 652 preg = 0x36; 653 rreg = 0x6b; 654 break; 655 656 case SOUND_MIXER_PCM: 657 preg = 0x14; 658 rreg = 0x7c; 659 break; 660 661 case SOUND_MIXER_LINE: 662 preg = 0x3e; 663 rreg = 0x6e; 664 break; 665 666 case SOUND_MIXER_MIC: 667 preg = 0x1a; 668 rreg = 0x68; 669 break; 670 671 case SOUND_MIXER_LINE1: 672 preg = 0x3a; 673 rreg = 0x6c; 674 break; 675 676 case SOUND_MIXER_CD: 677 preg = 0x38; 678 rreg = 0x6a; 679 break; 680 681 case SOUND_MIXER_VOLUME: 682 l = left? (left * 63) / 100 : 64; 683 r = right? (right * 63) / 100 : 64; 684 ess_setmixer(sc, 0x60, l); 685 ess_setmixer(sc, 0x62, r); 686 left = (l == 64)? 0 : (l * 100) / 63; 687 right = (r == 64)? 0 : (r * 100) / 63; 688 return left | (right << 8); 689 } 690 691 if (preg) 692 ess_setmixer(sc, preg, (l << 4) | r); 693 if (rreg) 694 ess_setmixer(sc, rreg, (l << 4) | r); 695 696 left = (l * 100) / 15; 697 right = (r * 100) / 15; 698 699 return left | (right << 8); 700} 701 702static int 703essmix_setrecsrc(snd_mixer *m, u_int32_t src) 704{ 705 struct ess_info *sc = mix_getdevinfo(m); 706 u_char recdev; 707 708 switch (src) { 709 case SOUND_MASK_CD: 710 recdev = 0x02; 711 break; 712 713 case SOUND_MASK_LINE: 714 recdev = 0x06; 715 break; 716 717 case SOUND_MASK_IMIX: 718 recdev = 0x05; 719 break; 720 721 case SOUND_MASK_MIC: 722 default: 723 recdev = 0x00; 724 src = SOUND_MASK_MIC; 725 break; 726 } 727 728 ess_setmixer(sc, 0x1c, recdev); 729 730 return src; 731} 732 733/************************************************************/ 734 735static int 736ess_dmasetup(struct ess_info *sc, int ch, u_int32_t base, u_int16_t cnt, int dir) 737{ 738 KASSERT(ch == 1 || ch == 2, ("bad ch")); 739 sc->dmasz[ch - 1] = cnt; 740 if (ch == 1) { 741 port_wr(sc->vc, 0x8, 0xc4, 1); /* command */ 742 port_wr(sc->vc, 0xd, 0xff, 1); /* reset */ 743 port_wr(sc->vc, 0xf, 0x01, 1); /* mask */ 744 port_wr(sc->vc, 0xb, dir == PCMDIR_PLAY? 0x58 : 0x54, 1); /* mode */ 745 port_wr(sc->vc, 0x0, base, 4); 746 port_wr(sc->vc, 0x4, cnt - 1, 2); 747 748 } else if (ch == 2) { 749 port_wr(sc->io, 0x6, 0x08, 1); /* autoinit */ 750 port_wr(sc->io, 0x0, base, 4); 751 port_wr(sc->io, 0x4, cnt, 2); 752 } 753 return 0; 754} 755 756static int 757ess_dmapos(struct ess_info *sc, int ch) 758{ 759 int p = 0, i = 0, j = 0; 760 u_long flags; 761 762 KASSERT(ch == 1 || ch == 2, ("bad ch")); 763 flags = spltty(); 764 if (ch == 1) { 765 766/* 767 * During recording, this register is known to give back 768 * garbage if it's not quiescent while being read. That's 769 * why we spl, stop the DMA, and try over and over until 770 * adjacent reads are "close", in the right order and not 771 * bigger than is otherwise possible. 772 */ 773 ess_dmatrigger(sc, ch, 0); 774 DELAY(20); 775 do { 776 DELAY(10); 777 if (j > 1) 778 printf("DMA count reg bogus: %04x & %04x\n", 779 i, p); 780 i = port_rd(sc->vc, 0x4, 2) + 1; 781 p = port_rd(sc->vc, 0x4, 2) + 1; 782 } while ((p > sc->dmasz[ch -1 ] || i < p || (p - i) > 0x8) && j++ < 1000); 783 ess_dmatrigger(sc, ch, 1); 784 } 785 else if (ch == 2) 786 p = port_rd(sc->io, 0x4, 2); 787 splx(flags); 788 return sc->dmasz[ch - 1] - p; 789} 790 791static int 792ess_dmatrigger(struct ess_info *sc, int ch, int go) 793{ 794 KASSERT(ch == 1 || ch == 2, ("bad ch")); 795 if (ch == 1) 796 port_wr(sc->vc, 0xf, go? 0x00 : 0x01, 1); /* mask */ 797 else if (ch == 2) 798 port_wr(sc->io, 0x6, 0x08 | (go? 0x02 : 0x00), 1); /* autoinit */ 799 return 0; 800} 801 802static void 803ess_release_resources(struct ess_info *sc, device_t dev) 804{ 805 /* should we bus_teardown_intr here? */ 806 if (sc->irq) { 807 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 808 sc->irq = 0; 809 } 810 if (sc->io) { 811 bus_release_resource(dev, SYS_RES_IOPORT, 0 * 4 + PCIR_MAPS, sc->io); 812 sc->io = 0; 813 } 814 815 if (sc->sb) { 816 bus_release_resource(dev, SYS_RES_IOPORT, 1 * 4 + PCIR_MAPS, sc->sb); 817 sc->sb = 0; 818 } 819 820 if (sc->vc) { 821 bus_release_resource(dev, SYS_RES_IOPORT, 2 * 4 + PCIR_MAPS, sc->vc); 822 sc->vc = 0; 823 } 824 825 if (sc->mpu) { 826 bus_release_resource(dev, SYS_RES_IOPORT, 3 * 4 + PCIR_MAPS, sc->mpu); 827 sc->mpu = 0; 828 } 829 830 if (sc->gp) { 831 bus_release_resource(dev, SYS_RES_IOPORT, 4 * 4 + PCIR_MAPS, sc->gp); 832 sc->gp = 0; 833 } 834 835 free(sc, M_DEVBUF); 836} 837 838static int 839ess_alloc_resources(struct ess_info *sc, device_t dev) 840{ 841 int rid; 842 843 rid = 0 * 4 + PCIR_MAPS; 844 sc->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); 845 846 rid = 1 * 4 + PCIR_MAPS; 847 sc->sb = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); 848 849 rid = 2 * 4 + PCIR_MAPS; 850 sc->vc = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); 851 852 rid = 3 * 4 + PCIR_MAPS; 853 sc->mpu = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); 854 855 rid = 4 * 4 + PCIR_MAPS; 856 sc->gp = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); 857 858 rid = 0; 859 sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 860 861 return (sc->irq && sc->io && sc->sb && sc->vc && sc->mpu && sc->gp)? 0 : ENXIO; 862} 863 864static int 865ess_probe(device_t dev) 866{ 867 char *s = NULL; 868 u_int32_t subdev; 869 870 subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev); 871 switch (pci_get_devid(dev)) { 872 case 0x1969125d: 873 if (subdev == 0x8888125d) 874 s = "ESS Solo-1E"; 875 else if (subdev == 0x1818125d) 876 s = "ESS Solo-1"; 877 else 878 s = "ESS Solo-1 (unknown vendor)"; 879 break; 880 } 881 882 if (s) 883 device_set_desc(dev, s); 884 return s? 0 : ENXIO; 885} 886 887#define PCI_LEGACYCONTROL 0x40 888#define PCI_CONFIG 0x50 889#define PCI_DDMACONTROL 0x60 890 891static int 892ess_attach(device_t dev) 893{ 894 snddev_info *d = device_get_softc(dev); 895 struct ess_info *sc; 896 void *ih; 897 char status[SND_STATUSLEN]; 898 u_int16_t ddma; 899 u_int32_t data; 900 901 sc = (struct ess_info *)malloc(sizeof *sc, M_DEVBUF, M_NOWAIT); 902 if (!sc) 903 return ENXIO; 904 bzero(sc, sizeof *sc); 905 906 data = pci_read_config(dev, PCIR_COMMAND, 2); 907 data |= PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN; 908 pci_write_config(dev, PCIR_COMMAND, data, 2); 909 data = pci_read_config(dev, PCIR_COMMAND, 2); 910 911 if (ess_alloc_resources(sc, dev)) 912 goto no; 913 914 ddma = rman_get_start(sc->vc) | 1; 915 pci_write_config(dev, PCI_LEGACYCONTROL, 0x805f, 2); 916 pci_write_config(dev, PCI_DDMACONTROL, ddma, 2); 917 pci_write_config(dev, PCI_CONFIG, 0, 2); 918 919 if (ess_reset_dsp(sc)) 920 goto no; 921 mixer_init(d, &ess_mixer, sc); 922 923 port_wr(sc->io, 0x7, 0xb0, 1); /* enable irqs */ 924#ifdef ESS18XX_DUPLEX 925 sc->duplex = 1; 926#else 927 sc->duplex = 0; 928#endif 929 930#ifdef ESS18XX_NEWSPEED 931 sc->newspeed = 1; 932#else 933 sc->newspeed = 0; 934#endif 935 if (sc->newspeed) 936 ess_setmixer(sc, 0x71, 0x2a); 937 938 bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ess_intr, sc, &ih); 939 if (!sc->duplex) 940 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 941 942 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/65536, /*boundary*/0, 943 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 944 /*highaddr*/BUS_SPACE_MAXADDR, 945 /*filter*/NULL, /*filterarg*/NULL, 946 /*maxsize*/ESS_BUFFSIZE, /*nsegments*/1, 947 /*maxsegz*/0x3ffff, 948 /*flags*/0, &sc->parent_dmat) != 0) { 949 device_printf(dev, "unable to create dma tag\n"); 950 goto no; 951 } 952 953 snprintf(status, SND_STATUSLEN, "at io 0x%lx,0x%lx,0x%lx irq %ld", 954 rman_get_start(sc->io), rman_get_start(sc->sb), rman_get_start(sc->vc), 955 rman_get_start(sc->irq)); 956 957 if (pcm_register(dev, sc, 1, 1)) 958 goto no; 959 pcm_addchan(dev, PCMDIR_REC, &ess_chantemplate, sc); 960 pcm_addchan(dev, PCMDIR_PLAY, &ess_chantemplate, sc); 961 pcm_setstatus(dev, status); 962 963 return 0; 964 965no: 966 ess_release_resources(sc, dev); 967 return ENXIO; 968} 969 970static device_method_t ess_methods[] = { 971 /* Device interface */ 972 DEVMETHOD(device_probe, ess_probe), 973 DEVMETHOD(device_attach, ess_attach), 974 975 { 0, 0 } 976}; 977 978static driver_t ess_driver = { 979 "pcm", 980 ess_methods, 981 sizeof(snddev_info), 982}; 983 984DRIVER_MODULE(snd_solo, pci, ess_driver, pcm_devclass, 0, 0); 985MODULE_DEPEND(snd_solo, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 986MODULE_VERSION(snd_solo, 1); 987 988 989 990