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