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