1 /* $NetBSD: esm.c,v 1.3 2001/01/09 23:27:07 rh Exp $ */ 2 3 /*- 4 * Copyright (c) 2000, 2001 Rene Hexel <rh@netbsd.org> 5 * All rights reserved. 6 * 7 * Copyright (c) 2000 Taku YAMAMOTO <taku@cent.saitama-u.ac.jp> 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * Taku Id: maestro.c,v 1.12 2000/09/06 03:32:34 taku Exp 32 * FreeBSD: /c/ncvs/src/sys/dev/sound/pci/maestro.c,v 1.4 2000/12/18 01:36:35 cg Exp 33 */ 34 35 /* 36 * TODO: 37 * - hardware volume support 38 * - recording 39 * - MIDI support 40 * - joystick support 41 * - power management hooks 42 * 43 * 44 * Credits: 45 * 46 * This code is based on the FreeBSD driver written by Taku YAMAMOTO 47 * 48 * 49 * Original credits from the FreeBSD driver: 50 * 51 * Part of this code (especially in many magic numbers) was heavily inspired 52 * by the Linux driver originally written by 53 * Alan Cox <alan.cox@linux.org>, modified heavily by 54 * Zach Brown <zab@zabbo.net>. 55 * 56 * busdma()-ize and buffer size reduction were suggested by 57 * Cameron Grant <gandalf@vilnya.demon.co.uk>. 58 * Also he showed me the way to use busdma() suite. 59 * 60 * Internal speaker problems on NEC VersaPro's and Dell Inspiron 7500 61 * were looked at by 62 * Munehiro Matsuda <haro@tk.kubota.co.jp>, 63 * who brought patches based on the Linux driver with some simplification. 64 */ 65 66 #include <sys/param.h> 67 #include <sys/systm.h> 68 #include <sys/kernel.h> 69 #include <sys/malloc.h> 70 #include <sys/device.h> 71 72 #include <machine/bus.h> 73 74 #include <sys/audioio.h> 75 #include <dev/audio_if.h> 76 #include <dev/mulaw.h> 77 #include <dev/auconv.h> 78 #include <dev/ic/ac97var.h> 79 80 #include <dev/pci/pcidevs.h> 81 #include <dev/pci/pcivar.h> 82 83 #include <dev/pci/esmreg.h> 84 #include <dev/pci/esmvar.h> 85 86 #define PCI_CBIO 0x10 /* Configuration Base I/O Address */ 87 88 /* Debug */ 89 #ifdef AUDIO_DEBUG 90 #define DPRINTF(l,x) do { if (esm_debug & (l)) printf x; } while(0) 91 #define DUMPREG(x) do { if (esm_debug & ESM_DEBUG_REG) \ 92 esm_dump_regs(x); } while(0) 93 int esm_debug = 0xfffc; 94 #define ESM_DEBUG_CODECIO 0x0001 95 #define ESM_DEBUG_IRQ 0x0002 96 #define ESM_DEBUG_DMA 0x0004 97 #define ESM_DEBUG_TIMER 0x0008 98 #define ESM_DEBUG_REG 0x0010 99 #define ESM_DEBUG_PARAM 0x0020 100 #define ESM_DEBUG_APU 0x0040 101 #define ESM_DEBUG_CODEC 0x0080 102 #define ESM_DEBUG_PCI 0x0100 103 #else 104 #define DPRINTF(x,y) /* nothing */ 105 #define DUMPREG(x) /* nothing */ 106 #endif 107 108 #ifdef DIAGNOSTIC 109 #define RANGE(n, l, h) if ((n) < (l) || (n) >= (h)) \ 110 printf (#n "=%d out of range (%d, %d) in " \ 111 __FILE__ ", line %d\n", (n), (l), (h), __LINE__) 112 #else 113 #define RANGE(x,y,z) /* nothing */ 114 #endif 115 116 #define inline __inline 117 118 static inline void ringbus_setdest(struct esm_softc *, int, int); 119 120 static inline u_int16_t wp_rdreg(struct esm_softc *, u_int16_t); 121 static inline void wp_wrreg(struct esm_softc *, u_int16_t, u_int16_t); 122 static inline u_int16_t wp_rdapu(struct esm_softc *, int, u_int16_t); 123 static inline void wp_wrapu(struct esm_softc *, int, u_int16_t, 124 u_int16_t); 125 static inline void wp_settimer(struct esm_softc *, u_int); 126 static inline void wp_starttimer(struct esm_softc *); 127 static inline void wp_stoptimer(struct esm_softc *); 128 129 static inline u_int16_t wc_rdreg(struct esm_softc *, u_int16_t); 130 static inline void wc_wrreg(struct esm_softc *, u_int16_t, u_int16_t); 131 static inline u_int16_t wc_rdchctl(struct esm_softc *, int); 132 static inline void wc_wrchctl(struct esm_softc *, int, u_int16_t); 133 134 static inline u_int calc_timer_freq(struct esm_chinfo*); 135 static void set_timer(struct esm_softc *); 136 137 static void esmch_set_format(struct esm_chinfo *, 138 struct audio_params *p); 139 140 struct cfattach esm_ca = { 141 sizeof(struct esm_softc), esm_match, esm_attach 142 }; 143 144 struct audio_hw_if esm_hw_if = { 145 esm_open, 146 esm_close, 147 NULL, /* drain */ 148 esm_query_encoding, 149 esm_set_params, 150 esm_round_blocksize, 151 NULL, /* commit_settings */ 152 esm_init_output, 153 NULL, /* init_input */ 154 NULL, /* start_output */ 155 NULL, /* start_input */ 156 esm_halt_output, 157 esm_halt_input, 158 NULL, /* speaker_ctl */ 159 esm_getdev, 160 NULL, /* getfd */ 161 esm_set_port, 162 esm_get_port, 163 esm_query_devinfo, 164 esm_malloc, 165 esm_free, 166 esm_round_buffersize, 167 esm_mappage, 168 esm_get_props, 169 esm_trigger_output, 170 esm_trigger_input 171 }; 172 173 struct audio_device esm_device = { 174 "ESS Maestro", 175 "", 176 "esm" 177 }; 178 179 180 static audio_encoding_t esm_encoding[] = { 181 { 0, AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0 }, 182 { 1, AudioEmulaw, AUDIO_ENCODING_ULAW, 8, 183 AUDIO_ENCODINGFLAG_EMULATED }, 184 { 2, AudioEalaw, AUDIO_ENCODING_ALAW, 8, AUDIO_ENCODINGFLAG_EMULATED }, 185 { 3, AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0 }, 186 { 4, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0 }, 187 { 5, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16, 188 AUDIO_ENCODINGFLAG_EMULATED }, 189 { 6, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 190 AUDIO_ENCODINGFLAG_EMULATED }, 191 { 7, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16, 192 AUDIO_ENCODINGFLAG_EMULATED }, 193 }; 194 195 #define MAESTRO_NENCODINGS 8 196 197 198 static const struct esm_quirks esm_quirks[] = { 199 /* COMPAL 38W2 OEM Notebook, e.g. Dell INSPIRON 5000e */ 200 { PCI_VENDOR_COMPAL, PCI_PRODUCT_COMPAL_38W2, ESM_QUIRKF_SWAPPEDCH }, 201 202 /* NEC Versa Pro LX VA26D */ 203 { PCI_VENDOR_NEC, PCI_PRODUCT_NEC_VA26D, ESM_QUIRKF_GPIO }, 204 205 /* NEC Versa LX */ 206 { PCI_VENDOR_NEC, PCI_PRODUCT_NEC_VERSALX, ESM_QUIRKF_GPIO } 207 }; 208 209 enum esm_quirk_flags 210 esm_get_quirks(pcireg_t subid) 211 { 212 int i; 213 214 for (i = 0; i < (sizeof esm_quirks / sizeof esm_quirks[0]); i++) { 215 if (PCI_VENDOR(subid) == esm_quirks[i].eq_vendor && 216 PCI_PRODUCT(subid) == esm_quirks[i].eq_product) { 217 return esm_quirks[i].eq_quirks; 218 } 219 } 220 221 return 0; 222 } 223 224 225 #ifdef AUDIO_DEBUG 226 struct esm_reg_info { 227 int offset; /* register offset */ 228 int width; /* 1/2/4 bytes */ 229 } dump_regs[] = { 230 { PORT_WAVCACHE_CTRL, 2 }, 231 { PORT_HOSTINT_CTRL, 2 }, 232 { PORT_HOSTINT_STAT, 2 }, 233 { PORT_HWVOL_VOICE_SHADOW, 1 }, 234 { PORT_HWVOL_VOICE, 1 }, 235 { PORT_HWVOL_MASTER_SHADOW, 1 }, 236 { PORT_HWVOL_MASTER, 1 }, 237 { PORT_RINGBUS_CTRL, 4 }, 238 { PORT_GPIO_DATA, 2 }, 239 { PORT_GPIO_MASK, 2 }, 240 { PORT_GPIO_DIR, 2 }, 241 { PORT_ASSP_CTRL_A, 1 }, 242 { PORT_ASSP_CTRL_B, 1 }, 243 { PORT_ASSP_CTRL_C, 1 }, 244 { PORT_ASSP_INT_STAT, 1 } 245 }; 246 247 static void 248 esm_dump_regs(struct esm_softc *ess) 249 { 250 int i; 251 252 printf("%s registers:", ess->sc_dev.dv_xname); 253 for (i = 0; i < (sizeof dump_regs / sizeof dump_regs[0]); i++) { 254 if (i % 5 == 0) 255 printf("\n"); 256 printf("0x%2.2x: ", dump_regs[i].offset); 257 switch(dump_regs[i].width) { 258 case 4: 259 printf("%8.8x, ", bus_space_read_4(ess->st, ess->sh, 260 dump_regs[i].offset)); 261 break; 262 case 2: 263 printf("%4.4x, ", bus_space_read_2(ess->st, ess->sh, 264 dump_regs[i].offset)); 265 break; 266 default: 267 printf("%2.2x, ", 268 bus_space_read_1(ess->st, ess->sh, 269 dump_regs[i].offset)); 270 } 271 } 272 printf("\n"); 273 } 274 #endif 275 276 277 /* ----------------------------- 278 * Subsystems. 279 */ 280 281 /* Codec/Ringbus */ 282 283 /* -------------------------------------------------------------------- */ 284 285 int 286 esm_read_codec(void *sc, u_int8_t regno, u_int16_t *result) 287 { 288 struct esm_softc *ess = sc; 289 unsigned t; 290 291 /* We have to wait for a SAFE time to write addr/data */ 292 for (t = 0; t < 20; t++) { 293 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 294 & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS) 295 break; 296 delay(2); /* 20.8us / 13 */ 297 } 298 if (t == 20) 299 printf("%s: esm_read_codec() PROGLESS timed out.\n", 300 ess->sc_dev.dv_xname); 301 302 bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD, 303 CODEC_CMD_READ | regno); 304 delay(21); /* AC97 cycle = 20.8usec */ 305 306 /* Wait for data retrieve */ 307 for (t = 0; t < 20; t++) { 308 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 309 & CODEC_STAT_MASK) == CODEC_STAT_RW_DONE) 310 break; 311 delay(2); /* 20.8us / 13 */ 312 } 313 if (t == 20) 314 /* Timed out, but perform dummy read. */ 315 printf("%s: esm_read_codec() RW_DONE timed out.\n", 316 ess->sc_dev.dv_xname); 317 318 *result = bus_space_read_2(ess->st, ess->sh, PORT_CODEC_REG); 319 320 return 0; 321 } 322 323 int 324 esm_write_codec(void *sc, u_int8_t regno, u_int16_t data) 325 { 326 struct esm_softc *ess = sc; 327 unsigned t; 328 329 /* We have to wait for a SAFE time to write addr/data */ 330 for (t = 0; t < 20; t++) { 331 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 332 & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS) 333 break; 334 delay(2); /* 20.8us / 13 */ 335 } 336 if (t == 20) { 337 /* Timed out. Abort writing. */ 338 printf("%s: esm_write_codec() PROGLESS timed out.\n", 339 ess->sc_dev.dv_xname); 340 return -1; 341 } 342 343 bus_space_write_2(ess->st, ess->sh, PORT_CODEC_REG, data); 344 bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD, 345 CODEC_CMD_WRITE | regno); 346 347 return 0; 348 } 349 350 /* -------------------------------------------------------------------- */ 351 352 static inline void 353 ringbus_setdest(struct esm_softc *ess, int src, int dest) 354 { 355 u_int32_t data; 356 357 data = bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL); 358 data &= ~(0xfU << src); 359 data |= (0xfU & dest) << src; 360 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, data); 361 } 362 363 /* Wave Processor */ 364 365 static inline u_int16_t 366 wp_rdreg(struct esm_softc *ess, u_int16_t reg) 367 { 368 bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg); 369 return bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA); 370 } 371 372 static inline void 373 wp_wrreg(struct esm_softc *ess, u_int16_t reg, u_int16_t data) 374 { 375 bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg); 376 bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data); 377 } 378 379 static inline void 380 apu_setindex(struct esm_softc *ess, u_int16_t reg) 381 { 382 int t; 383 384 wp_wrreg(ess, WPREG_CRAM_PTR, reg); 385 /* Sometimes WP fails to set apu register index. */ 386 for (t = 0; t < 1000; t++) { 387 if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == reg) 388 break; 389 bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, reg); 390 } 391 if (t == 1000) 392 printf("%s: apu_setindex() timed out.\n", ess->sc_dev.dv_xname); 393 } 394 395 static inline u_int16_t 396 wp_rdapu(struct esm_softc *ess, int ch, u_int16_t reg) 397 { 398 u_int16_t ret; 399 400 apu_setindex(ess, ((unsigned)ch << 4) + reg); 401 ret = wp_rdreg(ess, WPREG_DATA_PORT); 402 return ret; 403 } 404 405 static inline void 406 wp_wrapu(struct esm_softc *ess, int ch, u_int16_t reg, u_int16_t data) 407 { 408 int t; 409 410 DPRINTF(ESM_DEBUG_APU, 411 ("wp_wrapu(%p, ch=%d, reg=0x%x, data=0x%04x)\n", 412 ess, ch, reg, data)); 413 414 apu_setindex(ess, ((unsigned)ch << 4) + reg); 415 wp_wrreg(ess, WPREG_DATA_PORT, data); 416 for (t = 0; t < 1000; t++) { 417 if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == data) 418 break; 419 bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data); 420 } 421 if (t == 1000) 422 printf("%s: wp_wrapu() timed out.\n", ess->sc_dev.dv_xname); 423 } 424 425 static inline void 426 wp_settimer(struct esm_softc *ess, u_int freq) 427 { 428 u_int clock = 48000 << 2; 429 u_int prescale = 0, divide = (freq != 0) ? (clock / freq) : ~0; 430 431 RANGE(divide, WPTIMER_MINDIV, WPTIMER_MAXDIV); 432 433 for (; divide > 32 << 1; divide >>= 1) 434 prescale++; 435 divide = (divide + 1) >> 1; 436 437 for (; prescale < 7 && divide > 2 && !(divide & 1); divide >>= 1) 438 prescale++; 439 440 DPRINTF(ESM_DEBUG_TIMER, 441 ("wp_settimer(%p, %u): clock = %u, prescale = %u, divide = %u\n", 442 ess, freq, clock, prescale, divide)); 443 444 wp_wrreg(ess, WPREG_TIMER_ENABLE, 0); 445 wp_wrreg(ess, WPREG_TIMER_FREQ, 446 (prescale << WP_TIMER_FREQ_PRESCALE_SHIFT) | (divide - 1)); 447 wp_wrreg(ess, WPREG_TIMER_ENABLE, 1); 448 } 449 450 static inline void 451 wp_starttimer(struct esm_softc *ess) 452 { 453 wp_wrreg(ess, WPREG_TIMER_START, 1); 454 } 455 456 static inline void 457 wp_stoptimer(struct esm_softc *ess) 458 { 459 wp_wrreg(ess, WPREG_TIMER_START, 0); 460 bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1); 461 } 462 463 /* WaveCache */ 464 465 static inline u_int16_t 466 wc_rdreg(struct esm_softc *ess, u_int16_t reg) 467 { 468 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg); 469 return bus_space_read_2(ess->st, ess->sh, PORT_WAVCACHE_DATA); 470 } 471 472 static inline void 473 wc_wrreg(struct esm_softc *ess, u_int16_t reg, u_int16_t data) 474 { 475 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg); 476 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_DATA, data); 477 } 478 479 static inline u_int16_t 480 wc_rdchctl(struct esm_softc *ess, int ch) 481 { 482 return wc_rdreg(ess, ch << 3); 483 } 484 485 static inline void 486 wc_wrchctl(struct esm_softc *ess, int ch, u_int16_t data) 487 { 488 wc_wrreg(ess, ch << 3, data); 489 } 490 491 /* Power management */ 492 493 void 494 esm_power(struct esm_softc *ess, int status) 495 { 496 u_int8_t data; 497 498 data = pci_conf_read(ess->pc, ess->tag, CONF_PM_PTR); 499 if ((pci_conf_read(ess->pc, ess->tag, data) & 0xff) == PPMI_CID) 500 pci_conf_write(ess->pc, ess->tag, data + PM_CTRL, status); 501 } 502 503 504 /* ----------------------------- 505 * Controller. 506 */ 507 508 int 509 esm_attach_codec(void *sc, struct ac97_codec_if *codec_if) 510 { 511 struct esm_softc *ess = sc; 512 513 ess->codec_if = codec_if; 514 515 return 0; 516 } 517 518 void 519 esm_reset_codec(void *sc) 520 { 521 } 522 523 524 enum ac97_host_flags 525 esm_flags_codec(void *sc) 526 { 527 struct esm_softc *ess = sc; 528 529 return ess->codec_flags; 530 } 531 532 533 void 534 esm_initcodec(struct esm_softc *ess) 535 { 536 u_int16_t data; 537 538 DPRINTF(ESM_DEBUG_CODEC, ("esm_initcodec(%p)\n", ess)); 539 540 if (bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL) 541 & RINGBUS_CTRL_ACLINK_ENABLED) { 542 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 543 delay(104); /* 20.8us * (4 + 1) */ 544 } 545 /* XXX - 2nd codec should be looked at. */ 546 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 547 RINGBUS_CTRL_AC97_SWRESET); 548 delay(2); 549 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 550 RINGBUS_CTRL_ACLINK_ENABLED); 551 delay(21); 552 553 esm_read_codec(ess, 0, &data); 554 if (bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 555 & CODEC_STAT_MASK) { 556 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 557 delay(21); 558 559 /* Try cold reset. */ 560 printf("%s: will perform cold reset.\n", ess->sc_dev.dv_xname); 561 data = bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR); 562 if (pci_conf_read(ess->pc, ess->tag, 0x58) & 1) 563 data |= 0x10; 564 data |= 0x009 & 565 ~bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DATA); 566 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 0xff6); 567 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, 568 data | 0x009); 569 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x000); 570 delay(2); 571 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x001); 572 delay(1); 573 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x009); 574 delay(500000); 575 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, data); 576 delay(84); /* 20.8us * 4 */ 577 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 578 RINGBUS_CTRL_ACLINK_ENABLED); 579 delay(21); 580 } 581 } 582 583 void 584 esm_init(struct esm_softc *ess) 585 { 586 /* Reset direct sound. */ 587 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 588 HOSTINT_CTRL_DSOUND_RESET); 589 delay(10000); 590 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); 591 delay(10000); 592 593 /* Enable direct sound interruption. */ 594 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 595 HOSTINT_CTRL_DSOUND_INT_ENABLED); 596 597 /* Setup Wave Processor. */ 598 599 /* Enable WaveCache */ 600 wp_wrreg(ess, WPREG_WAVE_ROMRAM, 601 WP_WAVE_VIRTUAL_ENABLED | WP_WAVE_DRAM_ENABLED); 602 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_CTRL, 603 WAVCACHE_ENABLED | WAVCACHE_WTSIZE_4MB); 604 605 /* Setup Codec/Ringbus. */ 606 esm_initcodec(ess); 607 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 608 RINGBUS_CTRL_RINGBUS_ENABLED | RINGBUS_CTRL_ACLINK_ENABLED); 609 610 wp_wrreg(ess, WPREG_BASE, 0x8500); /* Parallel I/O */ 611 ringbus_setdest(ess, RINGBUS_SRC_ADC, 612 RINGBUS_DEST_STEREO | RINGBUS_DEST_DSOUND_IN); 613 ringbus_setdest(ess, RINGBUS_SRC_DSOUND, 614 RINGBUS_DEST_STEREO | RINGBUS_DEST_DAC); 615 616 /* Setup ASSP. Needed for Dell Inspiron 7500? */ 617 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_B, 0x00); 618 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_A, 0x03); 619 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_C, 0x00); 620 621 /* 622 * Setup GPIO. 623 * There seems to be speciality with NEC systems. 624 */ 625 if (esm_get_quirks(ess->subid) & ESM_QUIRKF_GPIO) { 626 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 627 0x9ff); 628 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, 629 bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR) | 630 0x600); 631 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 632 0x200); 633 } 634 635 DUMPREG(ess); 636 } 637 638 639 /* Channel controller. */ 640 641 int 642 esm_init_output (void *sc, void *start, int size) 643 { 644 struct esm_softc *ess = sc; 645 struct esm_dma *p; 646 u_int32_t data; 647 648 for (p = ess->sc_dmas; p && KERNADDR(p) != start; p = p->next) 649 ; 650 if (!p) { 651 printf("%s: esm_init_output: bad addr %p\n", 652 ess->sc_dev.dv_xname, start); 653 return EINVAL; 654 } 655 656 ess->pch.base = DMAADDR(p) & ~0xFFF; 657 658 DPRINTF(ESM_DEBUG_DMA, ("%s: pch.base = 0x%x\n", 659 ess->sc_dev.dv_xname, ess->pch.base)); 660 661 /* set DMA base address */ 662 for (data = WAVCACHE_PCMBAR; data < WAVCACHE_PCMBAR + 4; data++) 663 wc_wrreg(ess, data, ess->pch.base >> WAVCACHE_BASEADDR_SHIFT); 664 665 return 0; 666 } 667 668 669 int 670 esm_trigger_output(void *sc, void *start, void *end, int blksize, 671 void (*intr)(void *), void *arg, struct audio_params *param) 672 { 673 struct esm_softc *ess = sc; 674 struct esm_chinfo *ch = &ess->pch; 675 struct esm_dma *p; 676 int pan = 0, choffset; 677 int i, nch = 1; 678 unsigned speed = ch->sample_rate, offset, wpwa, dv; 679 size_t size; 680 u_int16_t apuch = ch->num << 1; 681 682 DPRINTF(ESM_DEBUG_DMA, 683 ("esm_trigger_output(%p, %p, %p, 0x%x, %p, %p, %p)\n", 684 sc, start, end, blksize, intr, arg, param)); 685 686 #ifdef DIAGNOSTIC 687 if (ess->pactive) { 688 printf("%s: esm_trigger_output: already running", 689 ess->sc_dev.dv_xname); 690 return EINVAL; 691 } 692 #endif 693 694 ess->sc_pintr = intr; 695 ess->sc_parg = arg; 696 for (p = ess->sc_dmas; p && KERNADDR(p) != start; p = p->next) 697 ; 698 if (!p) { 699 printf("%s: esm_trigger_output: bad addr %p\n", 700 ess->sc_dev.dv_xname, start); 701 return EINVAL; 702 } 703 704 ess->pch.blocksize = blksize; 705 ess->pch.apublk = blksize >> 1; 706 ess->pactive = 1; 707 708 size = (size_t)(((caddr_t)end - (caddr_t)start) >> 1); 709 choffset = DMAADDR(p) - ess->pch.base; 710 offset = choffset >> 1; 711 wpwa = APU_USE_SYSMEM | (offset >> 9); 712 713 DPRINTF(ESM_DEBUG_DMA, 714 ("choffs=0x%x, wpwa=0x%x, size=0x%x words\n", 715 choffset, wpwa, size)); 716 717 switch (ch->aputype) { 718 case APUTYPE_16BITSTEREO: 719 ess->pch.apublk >>= 1; 720 wpwa >>= 1; 721 size >>= 1; 722 offset >>= 1; 723 /* FALLTHROUGH */ 724 case APUTYPE_8BITSTEREO: 725 if (ess->codec_flags & AC97_HOST_SWAPPED_CHANNELS) 726 pan = 8; 727 else 728 pan = -8; 729 nch++; 730 break; 731 case APUTYPE_8BITLINEAR: 732 ess->pch.apublk <<= 1; 733 speed >>= 1; 734 break; 735 } 736 737 ess->pch.apubuf = size; 738 ess->pch.nextirq = ess->pch.apublk; 739 740 set_timer(ess); 741 wp_starttimer(ess); 742 743 dv = (((speed % 48000) << 16) + 24000) / 48000 744 + ((speed / 48000) << 16); 745 746 for (i = nch-1; i >= 0; i--) { 747 wp_wrapu(ess, apuch + i, APUREG_WAVESPACE, wpwa & 0xff00); 748 wp_wrapu(ess, apuch + i, APUREG_CURPTR, offset); 749 wp_wrapu(ess, apuch + i, APUREG_ENDPTR, offset + size); 750 wp_wrapu(ess, apuch + i, APUREG_LOOPLEN, size - 1); 751 wp_wrapu(ess, apuch + i, APUREG_AMPLITUDE, 0xe800); 752 wp_wrapu(ess, apuch + i, APUREG_POSITION, 0x8f00 753 | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT) 754 | ((PAN_FRONT + pan) << APU_PAN_SHIFT)); 755 wp_wrapu(ess, apuch + i, APUREG_FREQ_LOBYTE, APU_plus6dB 756 | ((dv & 0xff) << APU_FREQ_LOBYTE_SHIFT)); 757 wp_wrapu(ess, apuch + i, APUREG_FREQ_HIWORD, dv >> 8); 758 759 if (ch->aputype == APUTYPE_16BITSTEREO) 760 wpwa |= APU_STEREO >> 1; 761 pan = -pan; 762 } 763 764 wc_wrchctl(ess, apuch, ch->wcreg_tpl); 765 if (nch > 1) 766 wc_wrchctl(ess, apuch + 1, ch->wcreg_tpl); 767 768 wp_wrapu(ess, apuch, APUREG_APUTYPE, 769 (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf); 770 if (ch->wcreg_tpl & WAVCACHE_CHCTL_STEREO) 771 wp_wrapu(ess, apuch + 1, APUREG_APUTYPE, 772 (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf); 773 774 return 0; 775 } 776 777 778 int 779 esm_trigger_input(void *sc, void *start, void *end, int blksize, 780 void (*intr)(void *), void *arg, struct audio_params *param) 781 { 782 return 0; 783 } 784 785 786 int 787 esm_halt_output(void *sc) 788 { 789 struct esm_softc *ess = sc; 790 struct esm_chinfo *ch = &ess->pch; 791 792 DPRINTF(ESM_DEBUG_PARAM, ("esm_halt_output(%p)\n", sc)); 793 794 wp_wrapu(ess, (ch->num << 1), APUREG_APUTYPE, 795 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 796 wp_wrapu(ess, (ch->num << 1) + 1, APUREG_APUTYPE, 797 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 798 799 ess->pactive = 0; 800 if (!ess->ractive) 801 wp_stoptimer(ess); 802 803 return 0; 804 } 805 806 807 int 808 esm_halt_input(void *sc) 809 { 810 return 0; 811 } 812 813 814 static inline u_int 815 calc_timer_freq(struct esm_chinfo *ch) 816 { 817 u_int freq; 818 819 freq = (ch->sample_rate + ch->apublk - 1) / ch->apublk; 820 821 DPRINTF(ESM_DEBUG_TIMER, 822 ("calc_timer_freq(%p): rate = %u, blk = 0x%x (0x%x): freq = %u\n", 823 ch, ch->sample_rate, ch->apublk, ch->blocksize, freq)); 824 825 return freq; 826 } 827 828 static void 829 set_timer(struct esm_softc *ess) 830 { 831 unsigned freq = 0, freq2; 832 833 if (ess->pactive) 834 freq = calc_timer_freq(&ess->pch); 835 836 if (ess->ractive) { 837 freq2 = calc_timer_freq(&ess->rch); 838 if (freq2 < freq) 839 freq = freq2; 840 } 841 842 for (; freq < MAESTRO_MINFREQ; freq <<= 1) 843 ; 844 845 if (freq > 0) 846 wp_settimer(ess, freq); 847 } 848 849 850 static void 851 esmch_set_format(struct esm_chinfo *ch, struct audio_params *p) 852 { 853 u_int16_t wcreg_tpl = (ch->base - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK; 854 u_int16_t aputype = APUTYPE_16BITLINEAR; 855 856 if (p->channels == 2) { 857 wcreg_tpl |= WAVCACHE_CHCTL_STEREO; 858 aputype++; 859 } 860 if (p->precision * p->factor == 8) { 861 aputype += 2; 862 if (p->encoding == AUDIO_ENCODING_ULINEAR) 863 wcreg_tpl |= WAVCACHE_CHCTL_U8; 864 } 865 ch->wcreg_tpl = wcreg_tpl; 866 ch->aputype = aputype; 867 ch->sample_rate = p->sample_rate; 868 869 DPRINTF(ESM_DEBUG_PARAM, ("esmch_set_format: " 870 "numch=%d, prec=%d*%d, tpl=0x%x, aputype=%d, rate=%ld\n", 871 p->channels, p->precision, p->factor, wcreg_tpl, aputype, 872 p->sample_rate)); 873 } 874 875 876 /* 877 * Audio interface glue functions 878 */ 879 880 int 881 esm_open(void *sc, int flags) 882 { 883 DPRINTF(ESM_DEBUG_PARAM, ("esm_open(%p, 0x%x)\n", sc, flags)); 884 885 return 0; 886 } 887 888 889 void 890 esm_close(void *sc) 891 { 892 DPRINTF(ESM_DEBUG_PARAM, ("esm_close(%p)\n", sc)); 893 } 894 895 896 int 897 esm_getdev (void *sc, struct audio_device *adp) 898 { 899 *adp = esm_device; 900 return 0; 901 } 902 903 904 int 905 esm_round_blocksize (void *sc, int blk) 906 { 907 DPRINTF(ESM_DEBUG_PARAM, 908 ("esm_round_blocksize(%p, 0x%x)", sc, blk)); 909 910 blk &= ~0x3f; /* keep good alignment */ 911 912 DPRINTF(ESM_DEBUG_PARAM, (" = 0x%x\n", blk)); 913 914 return blk; 915 } 916 917 918 int 919 esm_query_encoding(void *sc, struct audio_encoding *fp) 920 { 921 DPRINTF(ESM_DEBUG_PARAM, 922 ("esm_query_encoding(%p, %d)\n", sc, fp->index)); 923 924 if (fp->index < 0 || fp->index >= MAESTRO_NENCODINGS) 925 return EINVAL; 926 927 *fp = esm_encoding[fp->index]; 928 return 0; 929 } 930 931 932 int 933 esm_set_params(void *sc, int setmode, int usemode, 934 struct audio_params *play, struct audio_params *rec) 935 { 936 struct esm_softc *ess = sc; 937 struct audio_params *p; 938 int mode; 939 940 DPRINTF(ESM_DEBUG_PARAM, 941 ("esm_set_params(%p, 0x%x, 0x%x, %p, %p)\n", 942 sc, setmode, usemode, play, rec)); 943 944 for (mode = AUMODE_RECORD; mode != -1; 945 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 946 if ((setmode & mode) == 0) 947 continue; 948 949 p = mode == AUMODE_PLAY ? play : rec; 950 951 if (p->sample_rate < 4000 || p->sample_rate > 48000 || 952 (p->precision != 8 && p->precision != 16) || 953 (p->channels != 1 && p->channels != 2)) 954 return EINVAL; 955 956 p->factor = 1; 957 p->sw_code = 0; 958 switch (p->encoding) { 959 case AUDIO_ENCODING_SLINEAR_BE: 960 if (p->precision == 16) 961 p->sw_code = swap_bytes; 962 else 963 p->sw_code = change_sign8; 964 break; 965 case AUDIO_ENCODING_SLINEAR_LE: 966 if (p->precision != 16) 967 p->sw_code = change_sign8; 968 break; 969 case AUDIO_ENCODING_ULINEAR_BE: 970 if (p->precision == 16) { 971 if (mode == AUMODE_PLAY) 972 p->sw_code = swap_bytes_change_sign16_le; 973 else 974 p->sw_code = change_sign16_swap_bytes_le; 975 } 976 break; 977 case AUDIO_ENCODING_ULINEAR_LE: 978 if (p->precision == 16) 979 p->sw_code = change_sign16_le; 980 break; 981 case AUDIO_ENCODING_ULAW: 982 if (mode == AUMODE_PLAY) { 983 p->factor = 2; 984 p->sw_code = mulaw_to_slinear16_le; 985 } else 986 p->sw_code = ulinear8_to_mulaw; 987 break; 988 case AUDIO_ENCODING_ALAW: 989 if (mode == AUMODE_PLAY) { 990 p->factor = 2; 991 p->sw_code = alaw_to_slinear16_le; 992 } else 993 p->sw_code = ulinear8_to_alaw; 994 break; 995 default: 996 return EINVAL; 997 } 998 } 999 1000 if (setmode & AUMODE_PLAY) 1001 esmch_set_format(&ess->pch, play); 1002 1003 if (setmode & AUMODE_RECORD) 1004 esmch_set_format(&ess->rch, rec); 1005 1006 return 0; 1007 } 1008 1009 1010 int 1011 esm_set_port(void *sc, mixer_ctrl_t *cp) 1012 { 1013 struct esm_softc *ess = sc; 1014 1015 return (ess->codec_if->vtbl->mixer_set_port(ess->codec_if, cp)); 1016 } 1017 1018 1019 int 1020 esm_get_port(void *sc, mixer_ctrl_t *cp) 1021 { 1022 struct esm_softc *ess = sc; 1023 1024 return (ess->codec_if->vtbl->mixer_get_port(ess->codec_if, cp)); 1025 } 1026 1027 1028 int 1029 esm_query_devinfo(void *sc, mixer_devinfo_t *dip) 1030 { 1031 struct esm_softc *ess = sc; 1032 1033 return (ess->codec_if->vtbl->query_devinfo(ess->codec_if, dip)); 1034 } 1035 1036 1037 void * 1038 esm_malloc(void *sc, int direction, size_t size, int pool, int flags) 1039 { 1040 struct esm_softc *ess = sc; 1041 struct esm_dma *p; 1042 int error; 1043 1044 DPRINTF(ESM_DEBUG_DMA, 1045 ("esm_malloc(%p, %d, 0x%x, 0x%x, 0x%x)", 1046 sc, direction, size, pool, flags)); 1047 1048 p = malloc(sizeof(*p), pool, flags); 1049 if (!p) 1050 return 0; 1051 error = esm_allocmem(ess, size, 16, p); 1052 if (error) { 1053 free(p, pool); 1054 DPRINTF(ESM_DEBUG_DMA, (" = 0 (ENOMEM)\n")); 1055 return 0; 1056 } 1057 p->next = ess->sc_dmas; 1058 ess->sc_dmas = p; 1059 1060 DPRINTF(ESM_DEBUG_DMA, 1061 (": KERNADDR(%p) = %p (DMAADDR 0x%x)\n", p, KERNADDR(p), (int)DMAADDR(p))); 1062 1063 return KERNADDR(p); 1064 } 1065 1066 1067 void 1068 esm_free(void *sc, void *ptr, int pool) 1069 { 1070 struct esm_softc *ess = sc; 1071 struct esm_dma *p, **pp; 1072 1073 DPRINTF(ESM_DEBUG_DMA, 1074 ("esm_free(%p, %p, 0x%x)\n", 1075 sc, ptr, pool)); 1076 1077 for (pp = &ess->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 1078 if (KERNADDR(p) == ptr) { 1079 esm_freemem(ess, p); 1080 *pp = p->next; 1081 free(p, pool); 1082 return; 1083 } 1084 } 1085 } 1086 1087 1088 size_t 1089 esm_round_buffersize(void *sc, int direction, size_t size) 1090 { 1091 return size; 1092 } 1093 1094 1095 paddr_t 1096 esm_mappage(void *sc, void *mem, off_t off, int prot) 1097 { 1098 struct esm_softc *ess = sc; 1099 struct esm_dma *p; 1100 1101 DPRINTF(ESM_DEBUG_DMA, 1102 ("esm_mappage(%p, %p, 0x%lx, 0x%x)\n", 1103 sc, mem, (unsigned long)off, prot)); 1104 1105 if (off < 0) 1106 return (-1); 1107 1108 for (p = ess->sc_dmas; p && KERNADDR(p) != mem; p = p->next) 1109 ; 1110 if (!p) 1111 return (-1); 1112 return bus_dmamem_mmap(ess->dmat, p->segs, p->nsegs, off, 1113 prot, BUS_DMA_WAITOK); 1114 } 1115 1116 1117 int 1118 esm_get_props(void *sc) 1119 { 1120 return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 1121 } 1122 1123 1124 /* ----------------------------- 1125 * Bus space. 1126 */ 1127 1128 int 1129 esm_intr(void *sc) 1130 { 1131 struct esm_softc *ess = sc; 1132 u_int16_t status; 1133 u_int16_t pos; 1134 int ret = 0; 1135 1136 status = bus_space_read_1(ess->st, ess->sh, PORT_HOSTINT_STAT); 1137 if (!status) 1138 return 0; 1139 1140 /* Acknowledge all. */ 1141 bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1); 1142 bus_space_write_1(ess->st, ess->sh, PORT_HOSTINT_STAT, 0); 1143 #if 0 /* XXX - HWVOL */ 1144 if (status & HOSTINT_STAT_HWVOL) { 1145 u_int delta; 1146 delta = bus_space_read_1(ess->st, ess->sh, PORT_HWVOL_MASTER) 1147 - 0x88; 1148 if (delta & 0x11) 1149 mixer_set(device_get_softc(ess->dev), 1150 SOUND_MIXER_VOLUME, 0); 1151 else { 1152 mixer_set(device_get_softc(ess->dev), 1153 SOUND_MIXER_VOLUME, 1154 mixer_get(device_get_softc(ess->dev), 1155 SOUND_MIXER_VOLUME) 1156 + ((delta >> 5) & 0x7) - 4 1157 + ((delta << 7) & 0x700) - 0x400); 1158 } 1159 bus_space_write_1(ess->st, ess->sh, PORT_HWVOL_MASTER, 0x88); 1160 ret++; 1161 } 1162 #endif /* XXX - HWVOL */ 1163 1164 if (ess->pactive) { 1165 pos = wp_rdapu(ess, ess->pch.num << 1, APUREG_CURPTR); 1166 1167 DPRINTF(ESM_DEBUG_IRQ, (" %4.4x/%4.4x ", pos, 1168 wp_rdapu(ess, (ess->pch.num<<1)+1, APUREG_CURPTR))); 1169 1170 if (pos >= ess->pch.nextirq && 1171 pos - ess->pch.nextirq < ess->pch.apubuf / 2) { 1172 ess->pch.nextirq += ess->pch.apublk; 1173 1174 if (ess->pch.nextirq >= ess->pch.apubuf) 1175 ess->pch.nextirq = 0; 1176 1177 if (ess->sc_pintr) { 1178 DPRINTF(ESM_DEBUG_IRQ, ("P\n")); 1179 ess->sc_pintr(ess->sc_parg); 1180 } 1181 1182 } 1183 ret++; 1184 } 1185 1186 if (ess->ractive) { 1187 pos = wp_rdapu(ess, ess->rch.num << 1, APUREG_CURPTR); 1188 1189 DPRINTF(ESM_DEBUG_IRQ, (" %4.4x/%4.4x ", pos, 1190 wp_rdapu(ess, (ess->rch.num<<1)+1, APUREG_CURPTR))); 1191 1192 if (pos >= ess->rch.nextirq && 1193 pos - ess->rch.nextirq < ess->rch.apubuf / 2) { 1194 ess->rch.nextirq += ess->rch.apublk; 1195 1196 if (ess->rch.nextirq >= ess->rch.apubuf) 1197 ess->rch.nextirq = 0; 1198 1199 if (ess->sc_rintr) { 1200 DPRINTF(ESM_DEBUG_IRQ, ("R\n")); 1201 ess->sc_rintr(ess->sc_parg); 1202 } 1203 1204 } 1205 ret++; 1206 } 1207 1208 return ret; 1209 } 1210 1211 1212 int 1213 esm_allocmem(struct esm_softc *sc, size_t size, size_t align, 1214 struct esm_dma *p) 1215 { 1216 int error; 1217 1218 p->size = size; 1219 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, 1220 p->segs, sizeof(p->segs)/sizeof(p->segs[0]), 1221 &p->nsegs, BUS_DMA_NOWAIT); 1222 if (error) 1223 return error; 1224 1225 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, 1226 &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 1227 if (error) 1228 goto free; 1229 1230 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, 1231 0, BUS_DMA_NOWAIT, &p->map); 1232 if (error) 1233 goto unmap; 1234 1235 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, 1236 BUS_DMA_NOWAIT); 1237 if (error) 1238 goto destroy; 1239 1240 return 0; 1241 1242 destroy: 1243 bus_dmamap_destroy(sc->dmat, p->map); 1244 unmap: 1245 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1246 free: 1247 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1248 1249 return error; 1250 } 1251 1252 1253 int 1254 esm_freemem(struct esm_softc *sc, struct esm_dma *p) 1255 { 1256 bus_dmamap_unload(sc->dmat, p->map); 1257 bus_dmamap_destroy(sc->dmat, p->map); 1258 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1259 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1260 return 0; 1261 } 1262 1263 1264 int 1265 esm_match(struct device *dev, struct cfdata *match, void *aux) 1266 { 1267 struct pci_attach_args *pa = (struct pci_attach_args *) aux; 1268 1269 switch (PCI_VENDOR(pa->pa_id)) { 1270 case PCI_VENDOR_ESSTECH: 1271 switch (PCI_PRODUCT(pa->pa_id)) { 1272 case PCI_PRODUCT_ESSTECH_MAESTRO1: 1273 case PCI_PRODUCT_ESSTECH_MAESTRO2: 1274 case PCI_PRODUCT_ESSTECH_MAESTRO2E: 1275 return 1; 1276 } 1277 1278 case PCI_VENDOR_ESSTECH2: 1279 switch (PCI_PRODUCT(pa->pa_id)) { 1280 case PCI_PRODUCT_ESSTECH2_MAESTRO1: 1281 return 1; 1282 } 1283 } 1284 return 0; 1285 } 1286 1287 void 1288 esm_attach(struct device *parent, struct device *self, void *aux) 1289 { 1290 struct esm_softc *ess = (struct esm_softc *)self; 1291 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 1292 pci_chipset_tag_t pc = pa->pa_pc; 1293 pcitag_t tag = pa->pa_tag; 1294 pci_intr_handle_t ih; 1295 pcireg_t csr, data; 1296 u_int16_t codec_data; 1297 const char *intrstr; 1298 int revision; 1299 char devinfo[256]; 1300 1301 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo); 1302 revision = PCI_REVISION(pa->pa_class); 1303 printf(": %s (rev. 0x%02x)\n", devinfo, revision); 1304 1305 /* Enable the device. */ 1306 csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 1307 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, 1308 csr | PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE); 1309 1310 /* Map I/O register */ 1311 if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, 1312 &ess->st, &ess->sh, NULL, NULL)) { 1313 printf("%s: can't map i/o space\n", ess->sc_dev.dv_xname); 1314 return; 1315 } 1316 1317 /* Initialize softc */ 1318 ess->pch.num = 0; 1319 ess->rch.num = 2; 1320 ess->dmat = pa->pa_dmat; 1321 ess->tag = tag; 1322 ess->pc = pc; 1323 ess->subid = pci_conf_read(pc, tag, PCI_SUBSYS_ID_REG); 1324 1325 DPRINTF(ESM_DEBUG_PCI, 1326 ("%s: sub-system vendor 0x%4.4x, product 0x%4.4x\n", 1327 ess->sc_dev.dv_xname, 1328 PCI_VENDOR(ess->subid), PCI_PRODUCT(ess->subid))); 1329 1330 /* Map and establish the interrupt. */ 1331 if (pci_intr_map(pa, &ih)) { 1332 printf("%s: can't map interrupt\n", ess->sc_dev.dv_xname); 1333 return; 1334 } 1335 intrstr = pci_intr_string(pc, ih); 1336 ess->ih = pci_intr_establish(pc, ih, IPL_AUDIO, esm_intr, self); 1337 if (ess->ih == NULL) { 1338 printf("%s: can't establish interrupt", ess->sc_dev.dv_xname); 1339 if (intrstr != NULL) 1340 printf(" at %s", intrstr); 1341 printf("\n"); 1342 return; 1343 } 1344 printf("%s: interrupting at %s\n", ess->sc_dev.dv_xname, intrstr); 1345 1346 /* 1347 * Setup PCI config registers 1348 */ 1349 1350 /* set to power state D0 */ 1351 esm_power(ess, PPMI_D0); 1352 delay(100000); 1353 1354 /* Disable all legacy emulations. */ 1355 data = pci_conf_read(pc, tag, CONF_LEGACY); 1356 pci_conf_write(pc, tag, CONF_LEGACY, data | LEGACY_DISABLED); 1357 1358 /* Disconnect from CHI. (Makes Dell inspiron 7500 work?) 1359 * Enable posted write. 1360 * Prefer PCI timing rather than that of ISA. 1361 * Don't swap L/R. */ 1362 data = pci_conf_read(pc, tag, CONF_MAESTRO); 1363 data |= MAESTRO_CHIBUS | MAESTRO_POSTEDWRITE | MAESTRO_DMA_PCITIMING; 1364 data &= ~MAESTRO_SWAP_LR; 1365 pci_conf_write(pc, tag, CONF_MAESTRO, data); 1366 1367 /* initialize sound chip */ 1368 esm_init(ess); 1369 1370 esm_read_codec(ess, 0, &codec_data); 1371 if (codec_data == 0x80) { 1372 printf("%s: PT101 codec detected!\n", ess->sc_dev.dv_xname); 1373 return; 1374 } 1375 1376 /* 1377 * Some cards and Notebooks appear to have left and right channels 1378 * reversed. Check if there is a corresponding quirk entry for 1379 * the subsystem vendor and product and if so, set the appropriate 1380 * codec flag. 1381 */ 1382 if (esm_get_quirks(ess->subid) & ESM_QUIRKF_SWAPPEDCH) { 1383 ess->codec_flags |= AC97_HOST_SWAPPED_CHANNELS; 1384 } 1385 1386 /* initialize AC97 host interface */ 1387 ess->host_if.arg = self; 1388 ess->host_if.attach = esm_attach_codec; 1389 ess->host_if.read = esm_read_codec; 1390 ess->host_if.write = esm_write_codec; 1391 ess->host_if.reset = esm_reset_codec; 1392 ess->host_if.flags = esm_flags_codec; 1393 1394 if (ac97_attach(&ess->host_if) != 0) 1395 return; 1396 1397 audio_attach_mi(&esm_hw_if, self, &ess->sc_dev); 1398 } 1399 1400 #if 0 1401 int 1402 esm_suspend(struct esm_softc *ess) 1403 { 1404 int i, x; 1405 1406 x = splaudio(); 1407 wp_stoptimer(ess); 1408 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); 1409 1410 esm_halt_output(ess); 1411 esm_halt_input(ess); 1412 splx(x); 1413 1414 /* Power down everything except clock. */ 1415 esm_write_codec(ess, AC97_REG_POWER, 0xdf00); 1416 delay(20); 1417 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 1418 delay(1); 1419 esm_power(ess, PPMI_D3); 1420 1421 return 0; 1422 } 1423 1424 1425 int 1426 esm_resume(struct esm_softc *ess) 1427 { 1428 int i, x; 1429 1430 esm_power(ess, PPMI_D0); 1431 delay(100000); 1432 esm_init(ess); 1433 if (mixer_reinit(dev)) { 1434 printf("%s: unable to reinitialize the mixer\n", 1435 ess->sc_dev.dv_xname); 1436 return ENXIO; 1437 } 1438 1439 x = splaudio(); 1440 if (ess->pactive) 1441 esm_start_output(ess); 1442 if (ess->ractive) 1443 esm_start_input(ess); 1444 if (ess->pactive || ess->ractive) { 1445 set_timer(ess); 1446 wp_starttimer(ess); 1447 } 1448 splx(x); 1449 return 0; 1450 } 1451 1452 1453 int 1454 esm_shutdown(struct esm_softc *ess) 1455 { 1456 int i; 1457 1458 wp_stoptimer(ess); 1459 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); 1460 1461 esm_halt_output(ess); 1462 esm_halt_input(ess); 1463 1464 return 0; 1465 } 1466 #endif 1467