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