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