32 */ 33 34#include <dev/sound/pcm/sound.h> 35 36#include "sbc.h" 37 38#include <dev/sound/isa/sb.h> 39#include <dev/sound/chip.h> 40 41#define ESS_BUFFSIZE (4096) 42#define ABS(x) (((x) < 0)? -(x) : (x)) 43 44/* audio2 never generates irqs and sounds very noisy */ 45#undef ESS18XX_DUPLEX 46 47/* more accurate clocks and split audio1/audio2 rates */ 48#define ESS18XX_NEWSPEED 49 50/* channel interface for ESS */ 51static void *esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); 52static int esschan_setdir(void *data, int dir); 53static int esschan_setformat(void *data, u_int32_t format); 54static int esschan_setspeed(void *data, u_int32_t speed); 55static int esschan_setblocksize(void *data, u_int32_t blocksize); 56static int esschan_trigger(void *data, int go); 57static int esschan_getptr(void *data); 58static pcmchan_caps *esschan_getcaps(void *data); 59 60static pcmchan_caps ess_playcaps = { 61 5000, 49000, 62 AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_U16_LE | AFMT_S16_LE, 63 AFMT_STEREO | AFMT_S16_LE 64}; 65 66static pcmchan_caps ess_reccaps = { 67 5000, 49000, 68 AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_U16_LE | AFMT_S16_LE, 69 AFMT_STEREO | AFMT_S16_LE 70}; 71 72static pcm_channel ess_chantemplate = { 73 esschan_init, 74 esschan_setdir, 75 esschan_setformat, 76 esschan_setspeed, 77 esschan_setblocksize, 78 esschan_trigger, 79 esschan_getptr, 80 esschan_getcaps, 81}; 82 83struct ess_info; 84 85struct ess_chinfo { 86 struct ess_info *parent; 87 pcm_channel *channel; 88 snd_dbuf *buffer; 89 int dir, hwch, stopping; 90 u_int32_t fmt, spd; 91}; 92 93struct ess_info { 94 struct resource *io_base; /* I/O address for the board */ 95 struct resource *irq; 96 struct resource *drq1; 97 struct resource *drq2; 98 bus_dma_tag_t parent_dmat; 99 100 int type, duplex:1, newspeed:1; 101 u_long bd_flags; /* board-specific flags */ 102 struct ess_chinfo pch, rch; 103}; 104 105static int ess_rd(struct ess_info *sc, int reg); 106static void ess_wr(struct ess_info *sc, int reg, u_int8_t val); 107static int ess_dspready(struct ess_info *sc); 108static int ess_cmd(struct ess_info *sc, u_char val); 109static int ess_cmd1(struct ess_info *sc, u_char cmd, int val); 110static int ess_get_byte(struct ess_info *sc); 111static void ess_setmixer(struct ess_info *sc, u_int port, u_int value); 112static int ess_getmixer(struct ess_info *sc, u_int port); 113static int ess_reset_dsp(struct ess_info *sc); 114 115static int ess_write(struct ess_info *sc, u_char reg, int val); 116static int ess_read(struct ess_info *sc, u_char reg); 117 118static void ess_intr(void *arg); 119static int ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len); 120static int ess_start(struct ess_chinfo *ch); 121static int ess_stop(struct ess_chinfo *ch); 122 123static int essmix_init(snd_mixer *m); 124static int essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right); 125static int essmix_setrecsrc(snd_mixer *m, u_int32_t src); 126 127static snd_mixer ess_mixer = { 128 "ESS mixer", 129 essmix_init, 130 essmix_set, 131 essmix_setrecsrc, 132}; 133 134static devclass_t pcm_devclass; 135 136/* 137 * Common code for the midi and pcm functions 138 * 139 * ess_cmd write a single byte to the CMD port. 140 * ess_cmd1 write a CMD + 1 byte arg 141 * ess_cmd2 write a CMD + 2 byte arg 142 * ess_get_byte returns a single byte from the DSP data port 143 * 144 * ess_write is actually ess_cmd1 145 * ess_read access ext. regs via ess_cmd(0xc0, reg) followed by ess_get_byte 146 */ 147 148static int 149port_rd(struct resource *port, int off) 150{ 151 return bus_space_read_1(rman_get_bustag(port), 152 rman_get_bushandle(port), 153 off); 154} 155 156static void 157port_wr(struct resource *port, int off, u_int8_t data) 158{ 159 return bus_space_write_1(rman_get_bustag(port), 160 rman_get_bushandle(port), 161 off, data); 162} 163 164static int 165ess_rd(struct ess_info *sc, int reg) 166{ 167 return port_rd(sc->io_base, reg); 168} 169 170static void 171ess_wr(struct ess_info *sc, int reg, u_int8_t val) 172{ 173 port_wr(sc->io_base, reg, val); 174} 175 176static int 177ess_dspready(struct ess_info *sc) 178{ 179 return ((ess_rd(sc, SBDSP_STATUS) & 0x80) == 0); 180} 181 182static int 183ess_dspwr(struct ess_info *sc, u_char val) 184{ 185 int i; 186 187 for (i = 0; i < 1000; i++) { 188 if (ess_dspready(sc)) { 189 ess_wr(sc, SBDSP_CMD, val); 190 return 1; 191 } 192 if (i > 10) DELAY((i > 100)? 1000 : 10); 193 } 194 printf("ess_dspwr(0x%02x) timed out.\n", val); 195 return 0; 196} 197 198static int 199ess_cmd(struct ess_info *sc, u_char val) 200{ 201#if 0 202 printf("ess_cmd: %x\n", val); 203#endif 204 return ess_dspwr(sc, val); 205} 206 207static int 208ess_cmd1(struct ess_info *sc, u_char cmd, int val) 209{ 210#if 0 211 printf("ess_cmd1: %x, %x\n", cmd, val); 212#endif 213 if (ess_dspwr(sc, cmd)) { 214 return ess_dspwr(sc, val & 0xff); 215 } else return 0; 216} 217 218static void 219ess_setmixer(struct ess_info *sc, u_int port, u_int value) 220{ 221 u_long flags; 222 223 DEB(printf("ess_setmixer: reg=%x, val=%x\n", port, value);) 224 flags = spltty(); 225 ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 226 DELAY(10); 227 ess_wr(sc, SB_MIX_DATA, (u_char) (value & 0xff)); 228 DELAY(10); 229 splx(flags); 230} 231 232static int 233ess_getmixer(struct ess_info *sc, u_int port) 234{ 235 int val; 236 u_long flags; 237 238 flags = spltty(); 239 ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 240 DELAY(10); 241 val = ess_rd(sc, SB_MIX_DATA); 242 DELAY(10); 243 splx(flags); 244 245 return val; 246} 247 248static int 249ess_get_byte(struct ess_info *sc) 250{ 251 int i; 252 253 for (i = 1000; i > 0; i--) { 254 if (ess_rd(sc, DSP_DATA_AVAIL) & 0x80) 255 return ess_rd(sc, DSP_READ); 256 else 257 DELAY(20); 258 } 259 return -1; 260} 261 262static int 263ess_write(struct ess_info *sc, u_char reg, int val) 264{ 265 return ess_cmd1(sc, reg, val); 266} 267 268static int 269ess_read(struct ess_info *sc, u_char reg) 270{ 271 return (ess_cmd(sc, 0xc0) && ess_cmd(sc, reg))? ess_get_byte(sc) : -1; 272} 273 274static int 275ess_reset_dsp(struct ess_info *sc) 276{ 277 ess_wr(sc, SBDSP_RST, 3); 278 DELAY(100); 279 ess_wr(sc, SBDSP_RST, 0); 280 if (ess_get_byte(sc) != 0xAA) { 281 DEB(printf("ess_reset_dsp 0x%lx failed\n", 282 rman_get_start(d->io_base))); 283 return ENXIO; /* Sorry */ 284 } 285 ess_cmd(sc, 0xc6); 286 return 0; 287} 288 289static void 290ess_release_resources(struct ess_info *sc, device_t dev) 291{ 292 /* should we bus_teardown_intr here? */ 293 if (sc->irq) { 294 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 295 sc->irq = 0; 296 } 297 if (sc->drq1) { 298 bus_release_resource(dev, SYS_RES_DRQ, 0, sc->drq1); 299 sc->drq1 = 0; 300 } 301 if (sc->drq2) { 302 bus_release_resource(dev, SYS_RES_DRQ, 1, sc->drq2); 303 sc->drq2 = 0; 304 } 305 if (sc->io_base) { 306 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->io_base); 307 sc->io_base = 0; 308 } 309 free(sc, M_DEVBUF); 310} 311 312static int 313ess_alloc_resources(struct ess_info *sc, device_t dev) 314{ 315 int rid; 316 317 rid = 0; 318 if (!sc->io_base) 319 sc->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, 320 &rid, 0, ~0, 1, 321 RF_ACTIVE); 322 rid = 0; 323 if (!sc->irq) 324 sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, 325 &rid, 0, ~0, 1, 326 RF_ACTIVE); 327 rid = 0; 328 if (!sc->drq1) 329 sc->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, 330 &rid, 0, ~0, 1, 331 RF_ACTIVE); 332 rid = 1; 333 if (!sc->drq2) 334 sc->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, 335 &rid, 0, ~0, 1, 336 RF_ACTIVE); 337 338 if (sc->io_base && sc->drq1 && sc->irq) { 339 isa_dma_acquire(rman_get_start(sc->drq1)); 340 isa_dmainit(rman_get_start(sc->drq1), ESS_BUFFSIZE); 341 342 if (sc->drq2) { 343 isa_dma_acquire(rman_get_start(sc->drq2)); 344 isa_dmainit(rman_get_start(sc->drq2), ESS_BUFFSIZE); 345 } 346 347 return 0; 348 } else return ENXIO; 349} 350 351static int 352ess_doattach(device_t dev, struct ess_info *sc) 353{ 354 snddev_info *d = device_get_softc(dev); 355 void *ih; 356 char status[SND_STATUSLEN], buf[64]; 357 int ver; 358 359 if (ess_alloc_resources(sc, dev)) 360 goto no; 361 if (ess_reset_dsp(sc)) 362 goto no; 363 mixer_init(d, &ess_mixer, sc); 364 365 sc->duplex = 0; 366 sc->newspeed = 0; 367 ver = (ess_getmixer(sc, 0x40) << 8) | ess_rd(sc, SB_MIX_DATA); 368 snprintf(buf, sizeof buf, "ESS %x DSP", ver); 369 device_set_desc_copy(dev, buf); 370 if (bootverbose) 371 device_printf(dev, "ESS%x detected", ver); 372 373 switch (ver) { 374 case 0x1869: 375 case 0x1879: 376#ifdef ESS18XX_DUPLEX 377 sc->duplex = sc->drq2? 1 : 0; 378#endif 379#ifdef ESS18XX_NEWSPEED 380 sc->newspeed = 1; 381#endif 382 break; 383 } 384 if (bootverbose) 385 printf("%s%s\n", sc->duplex? ", duplex" : "", 386 sc->newspeed? ", newspeed" : ""); 387 388 if (sc->newspeed) 389 ess_setmixer(sc, 0x71, 0x22); 390 391 bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ess_intr, sc, &ih); 392 if (!sc->duplex) 393 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 394 395 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 396 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 397 /*highaddr*/BUS_SPACE_MAXADDR, 398 /*filter*/NULL, /*filterarg*/NULL, 399 /*maxsize*/ESS_BUFFSIZE, /*nsegments*/1, 400 /*maxsegz*/0x3ffff, 401 /*flags*/0, &sc->parent_dmat) != 0) { 402 device_printf(dev, "unable to create dma tag\n"); 403 goto no; 404 } 405 406 snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld", 407 rman_get_start(sc->io_base), rman_get_start(sc->irq), 408 rman_get_start(sc->drq1)); 409 if (sc->drq2) 410 snprintf(status + strlen(status), SND_STATUSLEN - strlen(status), 411 ":%ld", rman_get_start(sc->drq2)); 412 413 if (pcm_register(dev, sc, 1, 1)) 414 goto no; 415 pcm_addchan(dev, PCMDIR_REC, &ess_chantemplate, sc); 416 pcm_addchan(dev, PCMDIR_PLAY, &ess_chantemplate, sc); 417 pcm_setstatus(dev, status); 418 419 return 0; 420 421no: 422 ess_release_resources(sc, dev); 423 return ENXIO; 424} 425 426static void 427ess_intr(void *arg) 428{ 429 struct ess_info *sc = (struct ess_info *)arg; 430 int src, pirq, rirq; 431 432 src = 0; 433 if (ess_getmixer(sc, 0x7a) & 0x80) 434 src |= 2; 435 if (ess_rd(sc, 0x0c) & 0x01) 436 src |= 1; 437 438 pirq = (src & sc->pch.hwch)? 1 : 0; 439 rirq = (src & sc->rch.hwch)? 1 : 0; 440 441 if (pirq) { 442 if (sc->pch.stopping) { 443 buf_isadma(sc->pch.buffer, PCMTRIG_STOP); 444 sc->pch.stopping = 0; 445 if (sc->pch.hwch == 1) 446 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01); 447 else 448 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x03); 449 } 450 chn_intr(sc->pch.channel); 451 } 452 453 if (rirq) { 454 if (sc->rch.stopping) { 455 buf_isadma(sc->rch.buffer, PCMTRIG_STOP); 456 sc->rch.stopping = 0; 457 /* XXX: will this stop audio2? */ 458 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01); 459 } 460 chn_intr(sc->rch.channel); 461 } 462 463 if (src & 2) 464 ess_setmixer(sc, 0x7a, ess_getmixer(sc, 0x7a) & ~0x80); 465 if (src & 1) 466 ess_rd(sc, DSP_DATA_AVAIL); 467} 468 469/* utility functions for ESS */ 470static u_int8_t 471ess_calcspeed8(int *spd) 472{ 473 int speed = *spd; 474 u_int32_t t; 475 476 if (speed > 22000) { 477 t = (795500 + speed / 2) / speed; 478 speed = (795500 + t / 2) / t; 479 t = (256 - t) | 0x80; 480 } else { 481 t = (397700 + speed / 2) / speed; 482 speed = (397700 + t / 2) / t; 483 t = 128 - t; 484 } 485 *spd = speed; 486 return t & 0x000000ff; 487} 488 489static u_int8_t 490ess_calcspeed9(int *spd) 491{ 492 int speed, s0, s1, use0; 493 u_int8_t t0, t1; 494 495 /* rate = source / (256 - divisor) */ 496 /* divisor = 256 - (source / rate) */ 497 speed = *spd; 498 t0 = 128 - (793800 / speed); 499 s0 = 793800 / (128 - t0); 500 501 t1 = 128 - (768000 / speed); 502 s1 = 768000 / (128 - t1); 503 t1 |= 0x80; 504 505 use0 = (ABS(speed - s0) < ABS(speed - s1))? 1 : 0; 506 507 *spd = use0? s0 : s1; 508 return use0? t0 : t1; 509} 510 511static u_int8_t 512ess_calcfilter(int spd) 513{ 514 int cutoff; 515 516 /* cutoff = 7160000 / (256 - divisor) */ 517 /* divisor = 256 - (7160000 / cutoff) */ 518 cutoff = (spd * 9 * 82) / 20; 519 return (256 - (7160000 / cutoff)); 520} 521 522static int 523ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len) 524{ 525 int play = (dir == PCMDIR_PLAY)? 1 : 0; 526 int b16 = (fmt & AFMT_16BIT)? 1 : 0; 527 int stereo = (fmt & AFMT_STEREO)? 1 : 0; 528 int unsign = (fmt == AFMT_U8 || fmt == AFMT_U16_LE)? 1 : 0; 529 u_int8_t spdval, fmtval; 530 531 532 spdval = (sc->newspeed)? ess_calcspeed9(&spd) : ess_calcspeed8(&spd); 533 len = -len; 534 535 if (ch == 1) { 536 KASSERT((dir == PCMDIR_PLAY) || (dir == PCMDIR_REC), ("ess_setupch: dir1 bad")); 537 /* transfer length low */ 538 ess_write(sc, 0xa4, len & 0x00ff); 539 /* transfer length high */ 540 ess_write(sc, 0xa5, (len & 0xff00) >> 8); 541 /* autoinit, dma dir */ 542 ess_write(sc, 0xb8, 0x04 | (play? 0x00 : 0x0a)); 543 /* mono/stereo */ 544 ess_write(sc, 0xa8, (ess_read(sc, 0xa8) & ~0x03) | (stereo? 0x01 : 0x02)); 545 /* demand mode, 4 bytes/xfer */ 546 ess_write(sc, 0xb9, 0x02); 547 /* sample rate */ 548 ess_write(sc, 0xa1, spdval); 549 /* filter cutoff */ 550 ess_write(sc, 0xa2, ess_calcfilter(spd)); 551 /* setup dac/adc */ 552 if (play) 553 ess_write(sc, 0xb6, unsign? 0x80 : 0x00); 554 /* mono, b16: signed, load signal */ 555 ess_write(sc, 0xb7, 0x51 | (unsign? 0x00 : 0x20)); 556 /* setup fifo */ 557 ess_write(sc, 0xb7, 0x90 | (unsign? 0x00 : 0x20) | 558 (b16? 0x04 : 0x00) | 559 (stereo? 0x08 : 0x40)); 560 /* irq control */ 561 ess_write(sc, 0xb1, (ess_read(sc, 0xb1) & 0x0f) | 0x50); 562 /* drq control */ 563 ess_write(sc, 0xb2, (ess_read(sc, 0xb2) & 0x0f) | 0x50); 564 } else if (ch == 2) { 565 KASSERT(dir == PCMDIR_PLAY, ("ess_setupch: dir2 bad")); 566 /* transfer length low */ 567 ess_setmixer(sc, 0x74, len & 0x00ff); 568 /* transfer length high */ 569 ess_setmixer(sc, 0x76, (len & 0xff00) >> 8); 570 /* autoinit, 4 bytes/req */ 571 ess_setmixer(sc, 0x78, 0x90); 572 fmtval = b16 | (stereo << 1) | (unsign << 2); 573 /* enable irq, set format */ 574 ess_setmixer(sc, 0x7a, 0x40 | fmtval); 575 if (sc->newspeed) { 576 /* sample rate */ 577 ess_setmixer(sc, 0x70, spdval); 578 /* filter cutoff */ 579 ess_setmixer(sc, 0x72, ess_calcfilter(spd)); 580 } 581 582 } 583 return 0; 584} 585static int 586ess_start(struct ess_chinfo *ch) 587{ 588 struct ess_info *sc = ch->parent; 589 int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 590 591 ess_setupch(sc, ch->hwch, ch->dir, ch->spd, ch->fmt, ch->buffer->dl); 592 ch->stopping = 0; 593 if (ch->hwch == 1) 594 ess_write(sc, 0xb8, ess_read(sc, 0xb8) | 0x01); 595 else 596 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) | 0x03); 597 if (play) 598 ess_cmd(sc, DSP_CMD_SPKON); 599 return 0; 600} 601 602static int 603ess_stop(struct ess_chinfo *ch) 604{ 605 struct ess_info *sc = ch->parent; 606 int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 607 608 ch->stopping = 1; 609 if (ch->hwch == 1) 610 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x04); 611 else 612 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x10); 613 if (play) 614 ess_cmd(sc, DSP_CMD_SPKOFF); 615 return 0; 616} 617 618/* channel interface for ESS18xx */ 619static void * 620esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 621{ 622 struct ess_info *sc = devinfo; 623 struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch; 624 625 ch->parent = sc; 626 ch->channel = c; 627 ch->buffer = b; 628 ch->buffer->bufsize = ESS_BUFFSIZE; 629 if (chn_allocbuf(ch->buffer, sc->parent_dmat) == -1) 630 return NULL; 631 ch->hwch = 1; 632 if ((dir == PCMDIR_PLAY) && (sc->duplex)) 633 ch->hwch = 2; 634 ch->buffer->chan = rman_get_start((ch->hwch == 1)? sc->drq1 : sc->drq2); 635 return ch; 636} 637 638static int 639esschan_setdir(void *data, int dir) 640{ 641 struct ess_chinfo *ch = data; 642 643 ch->dir = dir; 644 return 0; 645} 646 647static int 648esschan_setformat(void *data, u_int32_t format) 649{ 650 struct ess_chinfo *ch = data; 651 652 ch->fmt = format; 653 return 0; 654} 655 656static int 657esschan_setspeed(void *data, u_int32_t speed) 658{ 659 struct ess_chinfo *ch = data; 660 struct ess_info *sc = ch->parent; 661 662 ch->spd = speed; 663 if (sc->newspeed) 664 ess_calcspeed9(&ch->spd); 665 else 666 ess_calcspeed8(&ch->spd); 667 return ch->spd; 668} 669 670static int 671esschan_setblocksize(void *data, u_int32_t blocksize) 672{ 673 return blocksize; 674} 675 676static int 677esschan_trigger(void *data, int go) 678{ 679 struct ess_chinfo *ch = data; 680
|
682 return 0; 683 684 switch (go) { 685 case PCMTRIG_START: 686 buf_isadma(ch->buffer, go); 687 ess_start(ch); 688 break; 689 690 case PCMTRIG_STOP: 691 case PCMTRIG_ABORT: 692 default: 693 ess_stop(ch); 694 break; 695 } 696 return 0; 697} 698 699static int 700esschan_getptr(void *data) 701{ 702 struct ess_chinfo *ch = data; 703 704 return buf_isadmaptr(ch->buffer); 705} 706 707static pcmchan_caps * 708esschan_getcaps(void *data) 709{ 710 struct ess_chinfo *ch = data; 711 712 return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps; 713} 714 715/************************************************************/ 716 717static int 718essmix_init(snd_mixer *m) 719{ 720 struct ess_info *sc = mix_getdevinfo(m); 721 722 mix_setrecdevs(m, SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE | 723 SOUND_MASK_IMIX); 724 725 mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | 726 SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME | 727 SOUND_MASK_LINE1); 728 729 ess_setmixer(sc, 0, 0); /* reset */ 730 731 return 0; 732} 733 734static int 735essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 736{ 737 struct ess_info *sc = mix_getdevinfo(m); 738 int preg = 0, rreg = 0, l, r; 739 740 l = (left * 15) / 100; 741 r = (right * 15) / 100; 742 switch (dev) { 743 case SOUND_MIXER_SYNTH: 744 preg = 0x36; 745 rreg = 0x6b; 746 break; 747 748 case SOUND_MIXER_PCM: 749 preg = 0x14; 750 rreg = 0x7c; 751 break; 752 753 case SOUND_MIXER_LINE: 754 preg = 0x3e; 755 rreg = 0x6e; 756 break; 757 758 case SOUND_MIXER_MIC: 759 preg = 0x1a; 760 rreg = 0x68; 761 break; 762 763 case SOUND_MIXER_LINE1: 764 preg = 0x3a; 765 rreg = 0x6c; 766 break; 767 768 case SOUND_MIXER_CD: 769 preg = 0x38; 770 rreg = 0x6a; 771 break; 772 773 case SOUND_MIXER_VOLUME: 774 l = left? (left * 63) / 100 : 64; 775 r = right? (right * 63) / 100 : 64; 776 ess_setmixer(sc, 0x60, l); 777 ess_setmixer(sc, 0x62, r); 778 left = (l == 64)? 0 : (l * 100) / 63; 779 right = (r == 64)? 0 : (r * 100) / 63; 780 return left | (right << 8); 781 } 782 783 if (preg) 784 ess_setmixer(sc, preg, (l << 4) | r); 785 if (rreg) 786 ess_setmixer(sc, rreg, (l << 4) | r); 787 788 left = (l * 100) / 15; 789 right = (r * 100) / 15; 790 791 return left | (right << 8); 792} 793 794static int 795essmix_setrecsrc(snd_mixer *m, u_int32_t src) 796{ 797 struct ess_info *sc = mix_getdevinfo(m); 798 u_char recdev; 799 800 switch (src) { 801 case SOUND_MASK_CD: 802 recdev = 0x02; 803 break; 804 805 case SOUND_MASK_LINE: 806 recdev = 0x06; 807 break; 808 809 case SOUND_MASK_IMIX: 810 recdev = 0x05; 811 break; 812 813 case SOUND_MASK_MIC: 814 default: 815 recdev = 0x00; 816 src = SOUND_MASK_MIC; 817 break; 818 } 819 820 ess_setmixer(sc, 0x1c, recdev); 821 822 return src; 823} 824 825static int 826ess_probe(device_t dev) 827{ 828 uintptr_t func, ver, r, f; 829 830 /* The parent device has already been probed. */ 831 r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 832 if (func != SCF_PCM) 833 return (ENXIO); 834 835 r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 836 f = (ver & 0xffff0000) >> 16; 837 if (!(f & BD_F_ESS)) 838 return (ENXIO); 839 840 device_set_desc(dev, "ESS 18xx DSP"); 841 842 return 0; 843} 844 845static int 846ess_attach(device_t dev) 847{ 848 struct ess_info *sc; 849 850 sc = (struct ess_info *)malloc(sizeof *sc, M_DEVBUF, M_NOWAIT); 851 if (!sc) 852 return ENXIO; 853 bzero(sc, sizeof *sc); 854 855 return ess_doattach(dev, sc); 856} 857 858static device_method_t ess_methods[] = { 859 /* Device interface */ 860 DEVMETHOD(device_probe, ess_probe), 861 DEVMETHOD(device_attach, ess_attach), 862 863 { 0, 0 } 864}; 865 866static driver_t ess_driver = { 867 "pcm", 868 ess_methods, 869 sizeof(snddev_info), 870}; 871 872DRIVER_MODULE(ess, sbc, ess_driver, pcm_devclass, 0, 0); 873 874static devclass_t esscontrol_devclass; 875 876static struct isa_pnp_id essc_ids[] = { 877 {0x06007316, "ESS Control"}, 878 {0} 879}; 880 881static int 882esscontrol_probe(device_t dev) 883{ 884 return ISA_PNP_PROBE(device_get_parent(dev), dev, essc_ids); 885} 886 887static int 888esscontrol_attach(device_t dev) 889{ 890#ifdef notyet 891 struct resource *io; 892 int rid, i, x; 893 894 rid = 0; 895 io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); 896 x = 0; 897 for (i = 0; i < 0x100; i++) { 898 port_wr(io, 0, i); 899 x = port_rd(io, 1); 900 if ((i & 0x0f) == 0) 901 printf("%3.3x: ", i); 902 printf("%2.2x ", x); 903 if ((i & 0x0f) == 0x0f) 904 printf("\n"); 905 } 906 bus_release_resource(dev, SYS_RES_IOPORT, 0, io); 907 io = NULL; 908#endif 909 910 return 0; 911} 912 913static device_method_t esscontrol_methods[] = { 914 /* Device interface */ 915 DEVMETHOD(device_probe, esscontrol_probe), 916 DEVMETHOD(device_attach, esscontrol_attach), 917 918 { 0, 0 } 919}; 920 921static driver_t esscontrol_driver = { 922 "esscontrol", 923 esscontrol_methods, 924 sizeof(snddev_info), 925}; 926 927DRIVER_MODULE(esscontrol, isa, esscontrol_driver, esscontrol_devclass, 0, 0); 928 929 930 931
|