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