1 /* $NetBSD: esm.c,v 1.56 2012/01/30 19:41:19 drochner Exp $ */ 2 3 /*- 4 * Copyright (c) 2002, 2003 Matt Fredette 5 * All rights reserved. 6 * 7 * Copyright (c) 2000, 2001 Rene Hexel <rh@NetBSD.org> 8 * All rights reserved. 9 * 10 * Copyright (c) 2000 Taku YAMAMOTO <taku@cent.saitama-u.ac.jp> 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * Taku Id: maestro.c,v 1.12 2000/09/06 03:32:34 taku Exp 35 * FreeBSD: /c/ncvs/src/sys/dev/sound/pci/maestro.c,v 1.4 2000/12/18 01:36:35 cg Exp 36 */ 37 38 /* 39 * TODO: 40 * - hardware volume support 41 * - fix 16-bit stereo recording, add 8-bit recording 42 * - MIDI support 43 * - joystick support 44 * 45 * 46 * Credits: 47 * 48 * This code is based on the FreeBSD driver written by Taku YAMAMOTO 49 * 50 * 51 * Original credits from the FreeBSD driver: 52 * 53 * Part of this code (especially in many magic numbers) was heavily inspired 54 * by the Linux driver originally written by 55 * Alan Cox <alan.cox@linux.org>, modified heavily by 56 * Zach Brown <zab@zabbo.net>. 57 * 58 * busdma()-ize and buffer size reduction were suggested by 59 * Cameron Grant <gandalf@vilnya.demon.co.uk>. 60 * Also he showed me the way to use busdma() suite. 61 * 62 * Internal speaker problems on NEC VersaPro's and Dell Inspiron 7500 63 * were looked at by 64 * Munehiro Matsuda <haro@tk.kubota.co.jp>, 65 * who brought patches based on the Linux driver with some simplification. 66 */ 67 68 #include <sys/cdefs.h> 69 __KERNEL_RCSID(0, "$NetBSD: esm.c,v 1.56 2012/01/30 19:41:19 drochner Exp $"); 70 71 #include <sys/param.h> 72 #include <sys/systm.h> 73 #include <sys/kernel.h> 74 #include <sys/kmem.h> 75 #include <sys/device.h> 76 #include <sys/bus.h> 77 #include <sys/audioio.h> 78 79 #include <dev/audio_if.h> 80 #include <dev/mulaw.h> 81 #include <dev/auconv.h> 82 83 #include <dev/ic/ac97var.h> 84 #include <dev/ic/ac97reg.h> 85 86 #include <dev/pci/pcidevs.h> 87 #include <dev/pci/pcivar.h> 88 #include <dev/pci/esmreg.h> 89 #include <dev/pci/esmvar.h> 90 91 #define PCI_CBIO 0x10 /* Configuration Base I/O Address */ 92 93 /* Debug */ 94 #ifdef AUDIO_DEBUG 95 #define DPRINTF(l,x) do { if (esm_debug & (l)) printf x; } while(0) 96 #define DUMPREG(x) do { if (esm_debug & ESM_DEBUG_REG) \ 97 esm_dump_regs(x); } while(0) 98 int esm_debug = 0xfffc; 99 #define ESM_DEBUG_CODECIO 0x0001 100 #define ESM_DEBUG_IRQ 0x0002 101 #define ESM_DEBUG_DMA 0x0004 102 #define ESM_DEBUG_TIMER 0x0008 103 #define ESM_DEBUG_REG 0x0010 104 #define ESM_DEBUG_PARAM 0x0020 105 #define ESM_DEBUG_APU 0x0040 106 #define ESM_DEBUG_CODEC 0x0080 107 #define ESM_DEBUG_PCI 0x0100 108 #define ESM_DEBUG_RESUME 0x0200 109 #else 110 #define DPRINTF(x,y) /* nothing */ 111 #define DUMPREG(x) /* nothing */ 112 #endif 113 114 #ifdef DIAGNOSTIC 115 #define RANGE(n, l, h) if ((n) < (l) || (n) >= (h)) \ 116 printf (#n "=%d out of range (%d, %d) in " \ 117 __FILE__ ", line %d\n", (n), (l), (h), __LINE__) 118 #else 119 #define RANGE(x,y,z) /* nothing */ 120 #endif 121 122 #define inline inline 123 124 static inline void ringbus_setdest(struct esm_softc *, int, int); 125 126 static inline uint16_t wp_rdreg(struct esm_softc *, uint16_t); 127 static inline void wp_wrreg(struct esm_softc *, uint16_t, uint16_t); 128 static inline uint16_t wp_rdapu(struct esm_softc *, int, uint16_t); 129 static inline void wp_wrapu(struct esm_softc *, int, uint16_t, 130 uint16_t); 131 static inline void wp_settimer(struct esm_softc *, u_int); 132 static inline void wp_starttimer(struct esm_softc *); 133 static inline void wp_stoptimer(struct esm_softc *); 134 135 static inline uint16_t wc_rdreg(struct esm_softc *, uint16_t); 136 static inline void wc_wrreg(struct esm_softc *, uint16_t, uint16_t); 137 static inline uint16_t wc_rdchctl(struct esm_softc *, int); 138 static inline void wc_wrchctl(struct esm_softc *, int, uint16_t); 139 140 static inline u_int calc_timer_freq(struct esm_chinfo*); 141 static void set_timer(struct esm_softc *); 142 143 static void esmch_set_format(struct esm_chinfo *, 144 const audio_params_t *); 145 static void esmch_combine_input(struct esm_softc *, 146 struct esm_chinfo *); 147 148 static bool esm_suspend(device_t, const pmf_qual_t *); 149 static bool esm_resume(device_t, const pmf_qual_t *); 150 static void esm_childdet(device_t, device_t); 151 static int esm_match(device_t, cfdata_t, void *); 152 static void esm_attach(device_t, device_t, void *); 153 static int esm_detach(device_t, int); 154 static int esm_intr(void *); 155 156 static void esm_freemem(struct esm_softc *, struct esm_dma *); 157 static int esm_allocmem(struct esm_softc *, size_t, size_t, 158 struct esm_dma *); 159 160 161 CFATTACH_DECL2_NEW(esm, sizeof(struct esm_softc), 162 esm_match, esm_attach, esm_detach, NULL, NULL, esm_childdet); 163 164 const struct audio_hw_if esm_hw_if = { 165 NULL, /* open */ 166 NULL, /* close */ 167 NULL, /* drain */ 168 esm_query_encoding, 169 esm_set_params, 170 esm_round_blocksize, 171 NULL, /* commit_settings */ 172 esm_init_output, 173 esm_init_input, 174 NULL, /* start_output */ 175 NULL, /* start_input */ 176 esm_halt_output, 177 esm_halt_input, 178 NULL, /* speaker_ctl */ 179 esm_getdev, 180 NULL, /* getfd */ 181 esm_set_port, 182 esm_get_port, 183 esm_query_devinfo, 184 esm_malloc, 185 esm_free, 186 esm_round_buffersize, 187 esm_mappage, 188 esm_get_props, 189 esm_trigger_output, 190 esm_trigger_input, 191 NULL, 192 esm_get_locks, 193 }; 194 195 struct audio_device esm_device = { 196 "ESS Maestro", 197 "", 198 "esm" 199 }; 200 201 #define MAESTRO_NENCODINGS 8 202 static audio_encoding_t esm_encoding[MAESTRO_NENCODINGS] = { 203 { 0, AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0 }, 204 { 1, AudioEmulaw, AUDIO_ENCODING_ULAW, 8, 205 AUDIO_ENCODINGFLAG_EMULATED }, 206 { 2, AudioEalaw, AUDIO_ENCODING_ALAW, 8, AUDIO_ENCODINGFLAG_EMULATED }, 207 { 3, AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0 }, 208 { 4, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0 }, 209 { 5, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16, 210 AUDIO_ENCODINGFLAG_EMULATED }, 211 { 6, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 212 AUDIO_ENCODINGFLAG_EMULATED }, 213 { 7, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16, 214 AUDIO_ENCODINGFLAG_EMULATED }, 215 }; 216 217 #define ESM_NFORMATS 4 218 static const struct audio_format esm_formats[ESM_NFORMATS] = { 219 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16, 220 2, AUFMT_STEREO, 0, {4000, 48000}}, 221 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16, 222 1, AUFMT_MONAURAL, 0, {4000, 48000}}, 223 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8, 224 2, AUFMT_STEREO, 0, {4000, 48000}}, 225 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8, 226 1, AUFMT_MONAURAL, 0, {4000, 48000}}, 227 }; 228 229 static const struct esm_quirks esm_quirks[] = { 230 /* COMPAL 38W2 OEM Notebook, e.g. Dell INSPIRON 5000e */ 231 { PCI_VENDOR_COMPAL, PCI_PRODUCT_COMPAL_38W2, ESM_QUIRKF_SWAPPEDCH }, 232 233 /* COMPAQ Armada M700 Notebook */ 234 { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_M700, ESM_QUIRKF_SWAPPEDCH }, 235 236 /* NEC Versa Pro LX VA26D */ 237 { PCI_VENDOR_NEC, PCI_PRODUCT_NEC_VA26D, ESM_QUIRKF_GPIO }, 238 239 /* NEC Versa LX */ 240 { PCI_VENDOR_NEC, PCI_PRODUCT_NEC_VERSALX, ESM_QUIRKF_GPIO }, 241 242 /* Toshiba Portege */ 243 { PCI_VENDOR_TOSHIBA2, PCI_PRODUCT_TOSHIBA2_PORTEGE, ESM_QUIRKF_SWAPPEDCH } 244 }; 245 246 enum esm_quirk_flags 247 esm_get_quirks(pcireg_t subid) 248 { 249 int i; 250 251 for (i = 0; i < __arraycount(esm_quirks); i++) { 252 if (PCI_VENDOR(subid) == esm_quirks[i].eq_vendor && 253 PCI_PRODUCT(subid) == esm_quirks[i].eq_product) { 254 return esm_quirks[i].eq_quirks; 255 } 256 } 257 258 return 0; 259 } 260 261 262 #ifdef AUDIO_DEBUG 263 struct esm_reg_info { 264 int offset; /* register offset */ 265 int width; /* 1/2/4 bytes */ 266 } dump_regs[] = { 267 { PORT_WAVCACHE_CTRL, 2 }, 268 { PORT_HOSTINT_CTRL, 2 }, 269 { PORT_HOSTINT_STAT, 2 }, 270 { PORT_HWVOL_VOICE_SHADOW, 1 }, 271 { PORT_HWVOL_VOICE, 1 }, 272 { PORT_HWVOL_MASTER_SHADOW, 1 }, 273 { PORT_HWVOL_MASTER, 1 }, 274 { PORT_RINGBUS_CTRL, 4 }, 275 { PORT_GPIO_DATA, 2 }, 276 { PORT_GPIO_MASK, 2 }, 277 { PORT_GPIO_DIR, 2 }, 278 { PORT_ASSP_CTRL_A, 1 }, 279 { PORT_ASSP_CTRL_B, 1 }, 280 { PORT_ASSP_CTRL_C, 1 }, 281 { PORT_ASSP_INT_STAT, 1 } 282 }; 283 284 static void 285 esm_dump_regs(struct esm_softc *ess) 286 { 287 int i; 288 289 printf("%s registers:", device_xname(ess->sc_dev)); 290 for (i = 0; i < __arraycount(dump_regs); i++) { 291 if (i % 5 == 0) 292 printf("\n"); 293 printf("0x%2.2x: ", dump_regs[i].offset); 294 switch(dump_regs[i].width) { 295 case 4: 296 printf("%8.8x, ", bus_space_read_4(ess->st, ess->sh, 297 dump_regs[i].offset)); 298 break; 299 case 2: 300 printf("%4.4x, ", bus_space_read_2(ess->st, ess->sh, 301 dump_regs[i].offset)); 302 break; 303 default: 304 printf("%2.2x, ", 305 bus_space_read_1(ess->st, ess->sh, 306 dump_regs[i].offset)); 307 } 308 } 309 printf("\n"); 310 } 311 #endif 312 313 314 /* ----------------------------- 315 * Subsystems. 316 */ 317 318 /* Codec/Ringbus */ 319 320 /* -------------------------------------------------------------------- */ 321 322 int 323 esm_read_codec(void *sc, uint8_t regno, uint16_t *result) 324 { 325 struct esm_softc *ess; 326 unsigned t; 327 328 ess = sc; 329 /* We have to wait for a SAFE time to write addr/data */ 330 for (t = 0; t < 20; t++) { 331 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 332 & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS) 333 break; 334 delay(2); /* 20.8us / 13 */ 335 } 336 if (t == 20) 337 printf("%s: esm_read_codec() PROGLESS timed out.\n", 338 device_xname(ess->sc_dev)); 339 340 bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD, 341 CODEC_CMD_READ | regno); 342 delay(21); /* AC97 cycle = 20.8usec */ 343 344 /* Wait for data retrieve */ 345 for (t = 0; t < 20; t++) { 346 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 347 & CODEC_STAT_MASK) == CODEC_STAT_RW_DONE) 348 break; 349 delay(2); /* 20.8us / 13 */ 350 } 351 if (t == 20) 352 /* Timed out, but perform dummy read. */ 353 printf("%s: esm_read_codec() RW_DONE timed out.\n", 354 device_xname(ess->sc_dev)); 355 356 *result = bus_space_read_2(ess->st, ess->sh, PORT_CODEC_REG); 357 358 return 0; 359 } 360 361 int 362 esm_write_codec(void *sc, uint8_t regno, uint16_t data) 363 { 364 struct esm_softc *ess; 365 unsigned t; 366 367 ess = sc; 368 /* We have to wait for a SAFE time to write addr/data */ 369 for (t = 0; t < 20; t++) { 370 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 371 & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS) 372 break; 373 delay(2); /* 20.8us / 13 */ 374 } 375 if (t == 20) { 376 /* Timed out. Abort writing. */ 377 printf("%s: esm_write_codec() PROGLESS timed out.\n", 378 device_xname(ess->sc_dev)); 379 return -1; 380 } 381 382 bus_space_write_2(ess->st, ess->sh, PORT_CODEC_REG, data); 383 bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD, 384 CODEC_CMD_WRITE | regno); 385 386 return 0; 387 } 388 389 /* -------------------------------------------------------------------- */ 390 391 static inline void 392 ringbus_setdest(struct esm_softc *ess, int src, int dest) 393 { 394 uint32_t data; 395 396 data = bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL); 397 data &= ~(0xfU << src); 398 data |= (0xfU & dest) << src; 399 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, data); 400 } 401 402 /* Wave Processor */ 403 404 static inline uint16_t 405 wp_rdreg(struct esm_softc *ess, uint16_t reg) 406 { 407 408 bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg); 409 return bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA); 410 } 411 412 static inline void 413 wp_wrreg(struct esm_softc *ess, uint16_t reg, uint16_t data) 414 { 415 416 bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg); 417 bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data); 418 } 419 420 static inline void 421 apu_setindex(struct esm_softc *ess, uint16_t reg) 422 { 423 int t; 424 425 wp_wrreg(ess, WPREG_CRAM_PTR, reg); 426 /* Sometimes WP fails to set apu register index. */ 427 for (t = 0; t < 1000; t++) { 428 if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == reg) 429 break; 430 bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, reg); 431 } 432 if (t == 1000) 433 printf("%s: apu_setindex() timed out.\n", device_xname(ess->sc_dev)); 434 } 435 436 static inline uint16_t 437 wp_rdapu(struct esm_softc *ess, int ch, uint16_t reg) 438 { 439 uint16_t ret; 440 441 apu_setindex(ess, ((unsigned)ch << 4) + reg); 442 ret = wp_rdreg(ess, WPREG_DATA_PORT); 443 return ret; 444 } 445 446 static inline void 447 wp_wrapu(struct esm_softc *ess, int ch, uint16_t reg, uint16_t data) 448 { 449 int t; 450 451 DPRINTF(ESM_DEBUG_APU, 452 ("wp_wrapu(%p, ch=%d, reg=0x%x, data=0x%04x)\n", 453 ess, ch, reg, data)); 454 455 apu_setindex(ess, ((unsigned)ch << 4) + reg); 456 wp_wrreg(ess, WPREG_DATA_PORT, data); 457 for (t = 0; t < 1000; t++) { 458 if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == data) 459 break; 460 bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data); 461 } 462 if (t == 1000) 463 printf("%s: wp_wrapu() timed out.\n", device_xname(ess->sc_dev)); 464 } 465 466 static inline void 467 wp_settimer(struct esm_softc *ess, u_int freq) 468 { 469 u_int clock; 470 u_int prescale, divide; 471 472 clock = 48000 << 2; 473 prescale = 0; 474 divide = (freq != 0) ? (clock / freq) : ~0; 475 RANGE(divide, WPTIMER_MINDIV, WPTIMER_MAXDIV); 476 477 for (; divide > 32 << 1; divide >>= 1) 478 prescale++; 479 divide = (divide + 1) >> 1; 480 481 for (; prescale < 7 && divide > 2 && !(divide & 1); divide >>= 1) 482 prescale++; 483 484 DPRINTF(ESM_DEBUG_TIMER, 485 ("wp_settimer(%p, %u): clock = %u, prescale = %u, divide = %u\n", 486 ess, freq, clock, prescale, divide)); 487 488 wp_wrreg(ess, WPREG_TIMER_ENABLE, 0); 489 wp_wrreg(ess, WPREG_TIMER_FREQ, 490 (prescale << WP_TIMER_FREQ_PRESCALE_SHIFT) | (divide - 1)); 491 wp_wrreg(ess, WPREG_TIMER_ENABLE, 1); 492 } 493 494 static inline void 495 wp_starttimer(struct esm_softc *ess) 496 { 497 498 wp_wrreg(ess, WPREG_TIMER_START, 1); 499 } 500 501 static inline void 502 wp_stoptimer(struct esm_softc *ess) 503 { 504 505 wp_wrreg(ess, WPREG_TIMER_START, 0); 506 bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1); 507 } 508 509 /* WaveCache */ 510 511 static inline uint16_t 512 wc_rdreg(struct esm_softc *ess, uint16_t reg) 513 { 514 515 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg); 516 return bus_space_read_2(ess->st, ess->sh, PORT_WAVCACHE_DATA); 517 } 518 519 static inline void 520 wc_wrreg(struct esm_softc *ess, uint16_t reg, uint16_t data) 521 { 522 523 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg); 524 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_DATA, data); 525 } 526 527 static inline uint16_t 528 wc_rdchctl(struct esm_softc *ess, int ch) 529 { 530 531 return wc_rdreg(ess, ch << 3); 532 } 533 534 static inline void 535 wc_wrchctl(struct esm_softc *ess, int ch, uint16_t data) 536 { 537 538 wc_wrreg(ess, ch << 3, data); 539 } 540 541 /* ----------------------------- 542 * Controller. 543 */ 544 545 int 546 esm_attach_codec(void *sc, struct ac97_codec_if *codec_if) 547 { 548 struct esm_softc *ess; 549 550 ess = sc; 551 ess->codec_if = codec_if; 552 553 return 0; 554 } 555 556 int 557 esm_reset_codec(void *sc) 558 { 559 560 return 0; 561 } 562 563 564 enum ac97_host_flags 565 esm_flags_codec(void *sc) 566 { 567 struct esm_softc *ess; 568 569 ess = sc; 570 return ess->codec_flags; 571 } 572 573 574 void 575 esm_initcodec(struct esm_softc *ess) 576 { 577 uint16_t data; 578 579 DPRINTF(ESM_DEBUG_CODEC, ("esm_initcodec(%p)\n", ess)); 580 581 if (bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL) 582 & RINGBUS_CTRL_ACLINK_ENABLED) { 583 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 584 delay(104); /* 20.8us * (4 + 1) */ 585 } 586 /* XXX - 2nd codec should be looked at. */ 587 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 588 RINGBUS_CTRL_AC97_SWRESET); 589 delay(2); 590 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 591 RINGBUS_CTRL_ACLINK_ENABLED); 592 delay(21); 593 594 esm_read_codec(ess, 0, &data); 595 if (bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 596 & CODEC_STAT_MASK) { 597 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 598 delay(21); 599 600 /* Try cold reset. */ 601 printf("%s: will perform cold reset.\n", device_xname(ess->sc_dev)); 602 data = bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR); 603 if (pci_conf_read(ess->pc, ess->tag, 0x58) & 1) 604 data |= 0x10; 605 data |= 0x009 & 606 ~bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DATA); 607 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 0xff6); 608 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, 609 data | 0x009); 610 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x000); 611 delay(2); 612 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x001); 613 delay(1); 614 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x009); 615 delay(500000); 616 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, data); 617 delay(84); /* 20.8us * 4 */ 618 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 619 RINGBUS_CTRL_ACLINK_ENABLED); 620 delay(21); 621 } 622 } 623 624 void 625 esm_init(struct esm_softc *ess) 626 { 627 628 /* Reset direct sound. */ 629 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 630 HOSTINT_CTRL_DSOUND_RESET); 631 delay(10000); 632 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); 633 delay(10000); 634 635 /* Enable direct sound interruption. */ 636 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 637 HOSTINT_CTRL_DSOUND_INT_ENABLED); 638 639 /* Setup Wave Processor. */ 640 641 /* Enable WaveCache */ 642 wp_wrreg(ess, WPREG_WAVE_ROMRAM, 643 WP_WAVE_VIRTUAL_ENABLED | WP_WAVE_DRAM_ENABLED); 644 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_CTRL, 645 WAVCACHE_ENABLED | WAVCACHE_WTSIZE_4MB); 646 647 /* Setup Codec/Ringbus. */ 648 esm_initcodec(ess); 649 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 650 RINGBUS_CTRL_RINGBUS_ENABLED | RINGBUS_CTRL_ACLINK_ENABLED); 651 652 /* Undocumented registers from the Linux driver. */ 653 wp_wrreg(ess, 0x8, 0xB004); 654 wp_wrreg(ess, 0x9, 0x001B); 655 wp_wrreg(ess, 0xA, 0x8000); 656 wp_wrreg(ess, 0xB, 0x3F37); 657 wp_wrreg(ess, 0xD, 0x7632); 658 659 wp_wrreg(ess, WPREG_BASE, 0x8598); /* Parallel I/O */ 660 ringbus_setdest(ess, RINGBUS_SRC_ADC, 661 RINGBUS_DEST_STEREO | RINGBUS_DEST_DSOUND_IN); 662 ringbus_setdest(ess, RINGBUS_SRC_DSOUND, 663 RINGBUS_DEST_STEREO | RINGBUS_DEST_DAC); 664 665 /* Setup ASSP. Needed for Dell Inspiron 7500? */ 666 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_B, 0x00); 667 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_A, 0x03); 668 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_C, 0x00); 669 670 /* 671 * Setup GPIO. 672 * There seems to be speciality with NEC systems. 673 */ 674 if (esm_get_quirks(ess->subid) & ESM_QUIRKF_GPIO) { 675 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 676 0x9ff); 677 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, 678 bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR) | 679 0x600); 680 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 681 0x200); 682 } 683 684 DUMPREG(ess); 685 } 686 687 /* Channel controller. */ 688 689 int 690 esm_init_output (void *sc, void *start, int size) 691 { 692 struct esm_softc *ess; 693 struct esm_dma *p; 694 695 ess = sc; 696 p = &ess->sc_dma; 697 if ((char *)start != (char *)p->addr + MAESTRO_PLAYBUF_OFF) { 698 printf("%s: esm_init_output: bad addr %p\n", 699 device_xname(ess->sc_dev), start); 700 return EINVAL; 701 } 702 703 ess->pch.base = DMAADDR(p) + MAESTRO_PLAYBUF_OFF; 704 705 DPRINTF(ESM_DEBUG_DMA, ("%s: pch.base = 0x%x\n", 706 device_xname(ess->sc_dev), ess->pch.base)); 707 708 return 0; 709 } 710 711 int 712 esm_init_input (void *sc, void *start, int size) 713 { 714 struct esm_softc *ess; 715 struct esm_dma *p; 716 717 ess = sc; 718 p = &ess->sc_dma; 719 if ((char *)start != (char *)p->addr + MAESTRO_RECBUF_OFF) { 720 printf("%s: esm_init_input: bad addr %p\n", 721 device_xname(ess->sc_dev), start); 722 return EINVAL; 723 } 724 725 switch (ess->rch.aputype) { 726 case APUTYPE_16BITSTEREO: 727 ess->rch.base = DMAADDR(p) + MAESTRO_RECBUF_L_OFF; 728 break; 729 default: 730 ess->rch.base = DMAADDR(p) + MAESTRO_RECBUF_OFF; 731 break; 732 } 733 734 DPRINTF(ESM_DEBUG_DMA, ("%s: rch.base = 0x%x\n", 735 device_xname(ess->sc_dev), ess->rch.base)); 736 737 return 0; 738 } 739 740 int 741 esm_trigger_output(void *sc, void *start, void *end, int blksize, 742 void (*intr)(void *), void *arg, const audio_params_t *param) 743 { 744 size_t size; 745 struct esm_softc *ess; 746 struct esm_chinfo *ch; 747 struct esm_dma *p; 748 int pan, choffset; 749 int i, nch; 750 unsigned speed, offset, wpwa, dv; 751 uint16_t apuch; 752 753 DPRINTF(ESM_DEBUG_DMA, 754 ("esm_trigger_output(%p, %p, %p, 0x%x, %p, %p, %p)\n", 755 sc, start, end, blksize, intr, arg, param)); 756 ess = sc; 757 ch = &ess->pch; 758 pan = 0; 759 nch = 1; 760 speed = ch->sample_rate; 761 apuch = ch->num << 1; 762 763 #ifdef DIAGNOSTIC 764 if (ess->pactive) { 765 printf("%s: esm_trigger_output: already running", 766 device_xname(ess->sc_dev)); 767 return EINVAL; 768 } 769 #endif 770 771 ess->sc_pintr = intr; 772 ess->sc_parg = arg; 773 p = &ess->sc_dma; 774 if ((char *)start != (char *)p->addr + MAESTRO_PLAYBUF_OFF) { 775 printf("%s: esm_trigger_output: bad addr %p\n", 776 device_xname(ess->sc_dev), start); 777 return EINVAL; 778 } 779 780 ess->pch.blocksize = blksize; 781 ess->pch.apublk = blksize >> 1; 782 ess->pactive = 1; 783 784 size = (size_t)(((char *)end - (char *)start) >> 1); 785 choffset = MAESTRO_PLAYBUF_OFF; 786 offset = choffset >> 1; 787 wpwa = APU_USE_SYSMEM | ((offset >> 8) & APU_64KPAGE_MASK); 788 789 DPRINTF(ESM_DEBUG_DMA, 790 ("choffs=0x%x, wpwa=0x%x, size=0x%lx words\n", 791 choffset, wpwa, (unsigned long int)size)); 792 793 switch (ch->aputype) { 794 case APUTYPE_16BITSTEREO: 795 ess->pch.apublk >>= 1; 796 wpwa >>= 1; 797 size >>= 1; 798 offset >>= 1; 799 /* FALLTHROUGH */ 800 case APUTYPE_8BITSTEREO: 801 if (ess->codec_flags & AC97_HOST_SWAPPED_CHANNELS) 802 pan = 8; 803 else 804 pan = -8; 805 nch++; 806 break; 807 case APUTYPE_8BITLINEAR: 808 ess->pch.apublk <<= 1; 809 speed >>= 1; 810 break; 811 } 812 813 ess->pch.apubase = offset; 814 ess->pch.apubuf = size; 815 ess->pch.nextirq = ess->pch.apublk; 816 817 set_timer(ess); 818 wp_starttimer(ess); 819 820 dv = (((speed % 48000) << 16) + 24000) / 48000 821 + ((speed / 48000) << 16); 822 823 for (i = nch-1; i >= 0; i--) { 824 wp_wrapu(ess, apuch + i, APUREG_WAVESPACE, wpwa & 0xff00); 825 wp_wrapu(ess, apuch + i, APUREG_CURPTR, offset); 826 wp_wrapu(ess, apuch + i, APUREG_ENDPTR, offset + size); 827 wp_wrapu(ess, apuch + i, APUREG_LOOPLEN, size - 1); 828 wp_wrapu(ess, apuch + i, APUREG_AMPLITUDE, 0xe800); 829 wp_wrapu(ess, apuch + i, APUREG_POSITION, 0x8f00 830 | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT) 831 | ((PAN_FRONT + pan) << APU_PAN_SHIFT)); 832 wp_wrapu(ess, apuch + i, APUREG_FREQ_LOBYTE, APU_plus6dB 833 | ((dv & 0xff) << APU_FREQ_LOBYTE_SHIFT)); 834 wp_wrapu(ess, apuch + i, APUREG_FREQ_HIWORD, dv >> 8); 835 836 if (ch->aputype == APUTYPE_16BITSTEREO) 837 wpwa |= APU_STEREO >> 1; 838 pan = -pan; 839 } 840 841 wc_wrchctl(ess, apuch, ch->wcreg_tpl); 842 if (nch > 1) 843 wc_wrchctl(ess, apuch + 1, ch->wcreg_tpl); 844 845 wp_wrapu(ess, apuch, APUREG_APUTYPE, 846 (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf); 847 if (ch->wcreg_tpl & WAVCACHE_CHCTL_STEREO) 848 wp_wrapu(ess, apuch + 1, APUREG_APUTYPE, 849 (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf); 850 851 return 0; 852 } 853 854 int 855 esm_trigger_input(void *sc, void *start, void *end, int blksize, 856 void (*intr)(void *), void *arg, const audio_params_t *param) 857 { 858 size_t size; 859 size_t mixsize; 860 struct esm_softc *ess; 861 struct esm_chinfo *ch; 862 struct esm_dma *p; 863 uint32_t chctl, choffset; 864 uint32_t speed, offset, wpwa, dv; 865 uint32_t mixoffset, mixdv; 866 int i, nch; 867 uint16_t apuch; 868 uint16_t reg; 869 870 DPRINTF(ESM_DEBUG_DMA, 871 ("esm_trigger_input(%p, %p, %p, 0x%x, %p, %p, %p)\n", 872 sc, start, end, blksize, intr, arg, param)); 873 ess = sc; 874 ch = &ess->rch; 875 nch = 1; 876 speed = ch->sample_rate; 877 apuch = ch->num << 1; 878 879 #ifdef DIAGNOSTIC 880 if (ess->ractive) { 881 printf("%s: esm_trigger_input: already running", 882 device_xname(ess->sc_dev)); 883 return EINVAL; 884 } 885 #endif 886 887 ess->sc_rintr = intr; 888 ess->sc_rarg = arg; 889 p = &ess->sc_dma; 890 if ((char *)start != (char *)p->addr + MAESTRO_RECBUF_OFF) { 891 printf("%s: esm_trigger_input: bad addr %p\n", 892 device_xname(ess->sc_dev), start); 893 return EINVAL; 894 } 895 896 ess->rch.buffer = (void *)start; 897 ess->rch.offset = 0; 898 ess->rch.blocksize = blksize; 899 ess->rch.bufsize = ((char *)end - (char *)start); 900 ess->rch.apublk = blksize >> 1; 901 ess->ractive = 1; 902 903 size = (size_t)(((char *)end - (char *)start) >> 1); 904 choffset = MAESTRO_RECBUF_OFF; 905 switch (ch->aputype) { 906 case APUTYPE_16BITSTEREO: 907 size >>= 1; 908 choffset = MAESTRO_RECBUF_L_OFF; 909 ess->rch.apublk >>= 1; 910 nch++; 911 break; 912 case APUTYPE_16BITLINEAR: 913 break; 914 default: 915 ess->ractive = 0; 916 return EINVAL; 917 } 918 919 mixsize = (MAESTRO_MIXBUF_SZ >> 1) >> 1; 920 mixoffset = MAESTRO_MIXBUF_OFF; 921 922 ess->rch.apubase = (choffset >> 1); 923 ess->rch.apubuf = size; 924 ess->rch.nextirq = ess->rch.apublk; 925 926 set_timer(ess); 927 wp_starttimer(ess); 928 929 if (speed > 47999) speed = 47999; 930 if (speed < 4000) speed = 4000; 931 dv = (((speed % 48000) << 16) + 24000) / 48000 932 + ((speed / 48000) << 16); 933 mixdv = 65536; /* 48 kHz */ 934 935 for (i = 0; i < nch; i++) { 936 937 /* Clear all rate conversion WP channel registers first. */ 938 for (reg = 0; reg < 15; reg++) 939 wp_wrapu(ess, apuch + i, reg, 0); 940 941 /* Program the WaveCache for the rate conversion WP channel. */ 942 chctl = (DMAADDR(p) + choffset - 0x10) & 943 WAVCACHE_CHCTL_ADDRTAG_MASK; 944 wc_wrchctl(ess, apuch + i, chctl); 945 946 /* Program the rate conversion WP channel. */ 947 wp_wrapu(ess, apuch + i, APUREG_FREQ_LOBYTE, APU_plus6dB 948 | ((dv & 0xff) << APU_FREQ_LOBYTE_SHIFT) | 0x08); 949 wp_wrapu(ess, apuch + i, APUREG_FREQ_HIWORD, dv >> 8); 950 offset = choffset >> 1; 951 wpwa = APU_USE_SYSMEM | ((offset >> 8) & APU_64KPAGE_MASK); 952 wp_wrapu(ess, apuch + i, APUREG_WAVESPACE, wpwa); 953 wp_wrapu(ess, apuch + i, APUREG_CURPTR, offset); 954 wp_wrapu(ess, apuch + i, APUREG_ENDPTR, offset + size); 955 wp_wrapu(ess, apuch + i, APUREG_LOOPLEN, size - 1); 956 wp_wrapu(ess, apuch + i, APUREG_EFFECTS_ENV, 0x00f0); 957 wp_wrapu(ess, apuch + i, APUREG_AMPLITUDE, 0xe800); 958 wp_wrapu(ess, apuch + i, APUREG_POSITION, 0x8f00 959 | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT) 960 | (PAN_FRONT << APU_PAN_SHIFT)); 961 wp_wrapu(ess, apuch + i, APUREG_ROUTE, apuch + 2 + i); 962 963 DPRINTF(ESM_DEBUG_DMA, 964 ("choffs=0x%x, wpwa=0x%x, offset=0x%x words, size=0x%lx words\n", 965 choffset, wpwa, offset, (unsigned long int)size)); 966 967 /* Clear all mixer WP channel registers first. */ 968 for (reg = 0; reg < 15; reg++) 969 wp_wrapu(ess, apuch + 2 + i, reg, 0); 970 971 /* Program the WaveCache for the mixer WP channel. */ 972 chctl = (ess->rch.base + mixoffset - 0x10) & 973 WAVCACHE_CHCTL_ADDRTAG_MASK; 974 wc_wrchctl(ess, apuch + 2 + i, chctl); 975 976 /* Program the mixer WP channel. */ 977 wp_wrapu(ess, apuch + 2 + i, APUREG_FREQ_LOBYTE, APU_plus6dB 978 | ((mixdv & 0xff) << APU_FREQ_LOBYTE_SHIFT) | 0x08); 979 wp_wrapu(ess, apuch + 2 + i, APUREG_FREQ_HIWORD, mixdv >> 8); 980 offset = mixoffset >> 1; 981 wpwa = APU_USE_SYSMEM | ((offset >> 8) & APU_64KPAGE_MASK); 982 wp_wrapu(ess, apuch + 2 + i, APUREG_WAVESPACE, wpwa); 983 wp_wrapu(ess, apuch + 2 + i, APUREG_CURPTR, offset); 984 wp_wrapu(ess, apuch + 2 + i, APUREG_ENDPTR, 985 offset + mixsize); 986 wp_wrapu(ess, apuch + 2 + i, APUREG_LOOPLEN, mixsize); 987 wp_wrapu(ess, apuch + 2 + i, APUREG_EFFECTS_ENV, 0x00f0); 988 wp_wrapu(ess, apuch + 2 + i, APUREG_AMPLITUDE, 0xe800); 989 wp_wrapu(ess, apuch + 2 + i, APUREG_POSITION, 0x8f00 990 | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT) 991 | (PAN_FRONT << APU_PAN_SHIFT)); 992 wp_wrapu(ess, apuch + 2 + i, APUREG_ROUTE, 993 ROUTE_PARALLEL + i); 994 995 DPRINTF(ESM_DEBUG_DMA, 996 ("mixoffs=0x%x, wpwa=0x%x, offset=0x%x words, size=0x%lx words\n", 997 mixoffset, wpwa, offset, (unsigned long int)mixsize)); 998 999 /* Assume we're going to loop to do the right channel. */ 1000 choffset += MAESTRO_RECBUF_L_SZ; 1001 mixoffset += MAESTRO_MIXBUF_SZ >> 1; 1002 } 1003 1004 wp_wrapu(ess, apuch, APUREG_APUTYPE, 1005 (APUTYPE_RATECONV << APU_APUTYPE_SHIFT) | 1006 APU_DMA_ENABLED | 0xf); 1007 if (nch > 1) 1008 wp_wrapu(ess, apuch + 1, APUREG_APUTYPE, 1009 (APUTYPE_RATECONV << APU_APUTYPE_SHIFT) | 1010 APU_DMA_ENABLED | 0xf); 1011 wp_wrapu(ess, apuch + 2, APUREG_APUTYPE, 1012 (APUTYPE_INPUTMIXER << APU_APUTYPE_SHIFT) | 1013 APU_DMA_ENABLED | 0xf); 1014 if (nch > 1) 1015 wp_wrapu(ess, apuch + 3, APUREG_APUTYPE, 1016 (APUTYPE_RATECONV << APU_APUTYPE_SHIFT) | 1017 APU_DMA_ENABLED | 0xf); 1018 1019 return 0; 1020 } 1021 1022 int 1023 esm_halt_output(void *sc) 1024 { 1025 struct esm_softc *ess; 1026 struct esm_chinfo *ch; 1027 1028 DPRINTF(ESM_DEBUG_PARAM, ("esm_halt_output(%p)\n", sc)); 1029 ess = sc; 1030 ch = &ess->pch; 1031 1032 wp_wrapu(ess, (ch->num << 1), APUREG_APUTYPE, 1033 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1034 wp_wrapu(ess, (ch->num << 1) + 1, APUREG_APUTYPE, 1035 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1036 1037 ess->pactive = 0; 1038 if (!ess->ractive) 1039 wp_stoptimer(ess); 1040 1041 return 0; 1042 } 1043 1044 int 1045 esm_halt_input(void *sc) 1046 { 1047 struct esm_softc *ess; 1048 struct esm_chinfo *ch; 1049 1050 DPRINTF(ESM_DEBUG_PARAM, ("esm_halt_input(%p)\n", sc)); 1051 ess = sc; 1052 ch = &ess->rch; 1053 1054 wp_wrapu(ess, (ch->num << 1), APUREG_APUTYPE, 1055 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1056 wp_wrapu(ess, (ch->num << 1) + 1, APUREG_APUTYPE, 1057 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1058 wp_wrapu(ess, (ch->num << 1) + 2, APUREG_APUTYPE, 1059 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1060 wp_wrapu(ess, (ch->num << 1) + 3, APUREG_APUTYPE, 1061 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1062 1063 ess->ractive = 0; 1064 if (!ess->pactive) 1065 wp_stoptimer(ess); 1066 1067 return 0; 1068 } 1069 1070 static inline u_int 1071 calc_timer_freq(struct esm_chinfo *ch) 1072 { 1073 u_int freq; 1074 1075 freq = (ch->sample_rate + ch->apublk - 1) / ch->apublk; 1076 1077 DPRINTF(ESM_DEBUG_TIMER, 1078 ("calc_timer_freq(%p): rate = %u, blk = 0x%x (0x%x): freq = %u\n", 1079 ch, ch->sample_rate, ch->apublk, ch->blocksize, freq)); 1080 1081 return freq; 1082 } 1083 1084 static void 1085 set_timer(struct esm_softc *ess) 1086 { 1087 unsigned freq, freq2; 1088 1089 freq = 0; 1090 if (ess->pactive) 1091 freq = calc_timer_freq(&ess->pch); 1092 1093 if (ess->ractive) { 1094 freq2 = calc_timer_freq(&ess->rch); 1095 if (freq2 > freq) 1096 freq = freq2; 1097 } 1098 1099 KASSERT(freq != 0); 1100 1101 for (; freq < MAESTRO_MINFREQ; freq <<= 1) 1102 continue; 1103 1104 if (freq > 0) 1105 wp_settimer(ess, freq); 1106 } 1107 1108 static void 1109 esmch_set_format(struct esm_chinfo *ch, const audio_params_t *p) 1110 { 1111 uint16_t wcreg_tpl; 1112 uint16_t aputype; 1113 1114 wcreg_tpl = (ch->base - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK; 1115 aputype = APUTYPE_16BITLINEAR; 1116 if (p->channels == 2) { 1117 wcreg_tpl |= WAVCACHE_CHCTL_STEREO; 1118 aputype++; 1119 } 1120 if (p->precision == 8) { 1121 aputype += 2; 1122 switch (p->encoding) { 1123 case AUDIO_ENCODING_ULINEAR: 1124 case AUDIO_ENCODING_ULINEAR_BE: 1125 case AUDIO_ENCODING_ULINEAR_LE: 1126 wcreg_tpl |= WAVCACHE_CHCTL_U8; 1127 break; 1128 } 1129 } 1130 ch->wcreg_tpl = wcreg_tpl; 1131 ch->aputype = aputype; 1132 ch->sample_rate = p->sample_rate; 1133 1134 DPRINTF(ESM_DEBUG_PARAM, ("esmch_set_format: " 1135 "numch=%u, prec=%u, tpl=0x%x, aputype=%d, rate=%u\n", 1136 p->channels, p->precision, wcreg_tpl, aputype, p->sample_rate)); 1137 } 1138 1139 /* 1140 * Since we can't record in true stereo, this function combines 1141 * the separately recorded left and right channels into the final 1142 * buffer for the upper layer. 1143 */ 1144 static void 1145 esmch_combine_input(struct esm_softc *ess, struct esm_chinfo *ch) 1146 { 1147 size_t offset, resid, count; 1148 uint32_t *dst32s; 1149 const uint32_t *left32s, *right32s; 1150 uint32_t left32, right32; 1151 1152 /* The current offset into the upper layer buffer. */ 1153 offset = ch->offset; 1154 1155 /* The number of bytes left to combine. */ 1156 resid = ch->blocksize; 1157 1158 while (resid > 0) { 1159 1160 /* The 32-bit words for the left channel. */ 1161 left32s = (const uint32_t *)((char *)ess->sc_dma.addr + 1162 MAESTRO_RECBUF_L_OFF + offset / 2); 1163 1164 /* The 32-bit words for the right channel. */ 1165 right32s = (const uint32_t *)((char *)ess->sc_dma.addr + 1166 MAESTRO_RECBUF_R_OFF + offset / 2); 1167 1168 /* The pointer to the 32-bit words we will write. */ 1169 dst32s = (uint32_t *)((char *)ch->buffer + offset); 1170 1171 /* Get the number of bytes we will combine now. */ 1172 count = ch->bufsize - offset; 1173 if (count > resid) 1174 count = resid; 1175 resid -= count; 1176 offset += count; 1177 if (offset == ch->bufsize) 1178 offset = 0; 1179 1180 /* Combine, writing two 32-bit words at a time. */ 1181 KASSERT((count & (sizeof(uint32_t) * 2 - 1)) == 0); 1182 count /= (sizeof(uint32_t) * 2); 1183 while (count > 0) { 1184 left32 = *(left32s++); 1185 right32 = *(right32s++); 1186 /* XXX this endian handling is half-baked at best */ 1187 #if BYTE_ORDER == LITTLE_ENDIAN 1188 *(dst32s++) = (left32 & 0xFFFF) | (right32 << 16); 1189 *(dst32s++) = (left32 >> 16) | (right32 & 0xFFFF0000); 1190 #else /* BYTE_ORDER == BIG_ENDIAN */ 1191 *(dst32s++) = (left32 & 0xFFFF0000) | (right32 >> 16); 1192 *(dst32s++) = (left32 << 16) | (right32 & 0xFFFF); 1193 #endif /* BYTE_ORDER == BIG_ENDIAN */ 1194 count--; 1195 } 1196 } 1197 1198 /* Update the offset. */ 1199 ch->offset = offset; 1200 } 1201 1202 /* 1203 * Audio interface glue functions 1204 */ 1205 1206 int 1207 esm_getdev (void *sc, struct audio_device *adp) 1208 { 1209 1210 *adp = esm_device; 1211 return 0; 1212 } 1213 1214 int 1215 esm_round_blocksize(void *sc, int blk, int mode, 1216 const audio_params_t *param) 1217 { 1218 1219 DPRINTF(ESM_DEBUG_PARAM, 1220 ("esm_round_blocksize(%p, 0x%x)", sc, blk)); 1221 1222 blk &= ~0x3f; /* keep good alignment */ 1223 1224 DPRINTF(ESM_DEBUG_PARAM, (" = 0x%x\n", blk)); 1225 1226 return blk; 1227 } 1228 1229 int 1230 esm_query_encoding(void *sc, struct audio_encoding *fp) 1231 { 1232 1233 DPRINTF(ESM_DEBUG_PARAM, 1234 ("esm_query_encoding(%p, %d)\n", sc, fp->index)); 1235 1236 if (fp->index < 0 || fp->index >= MAESTRO_NENCODINGS) 1237 return EINVAL; 1238 1239 *fp = esm_encoding[fp->index]; 1240 return 0; 1241 } 1242 1243 int 1244 esm_set_params(void *sc, int setmode, int usemode, 1245 audio_params_t *play, audio_params_t *rec, 1246 stream_filter_list_t *pfil, stream_filter_list_t *rfil) 1247 { 1248 struct esm_softc *ess; 1249 audio_params_t *p; 1250 const audio_params_t *hw_play, *hw_rec; 1251 stream_filter_list_t *fil; 1252 int mode, i; 1253 1254 DPRINTF(ESM_DEBUG_PARAM, 1255 ("esm_set_params(%p, 0x%x, 0x%x, %p, %p)\n", 1256 sc, setmode, usemode, play, rec)); 1257 ess = sc; 1258 hw_play = NULL; 1259 hw_rec = NULL; 1260 for (mode = AUMODE_RECORD; mode != -1; 1261 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 1262 if ((setmode & mode) == 0) 1263 continue; 1264 1265 p = mode == AUMODE_PLAY ? play : rec; 1266 1267 if (p->sample_rate < 4000 || p->sample_rate > 48000 || 1268 (p->precision != 8 && p->precision != 16) || 1269 (p->channels != 1 && p->channels != 2)) 1270 return EINVAL; 1271 1272 fil = mode == AUMODE_PLAY ? pfil : rfil; 1273 i = auconv_set_converter(esm_formats, ESM_NFORMATS, 1274 mode, p, FALSE, fil); 1275 if (i < 0) 1276 return EINVAL; 1277 if (fil->req_size > 0) 1278 p = &fil->filters[0].param; 1279 if (mode == AUMODE_PLAY) 1280 hw_play = p; 1281 else 1282 hw_rec = p; 1283 } 1284 1285 if (hw_play) 1286 esmch_set_format(&ess->pch, hw_play); 1287 1288 if (hw_rec) 1289 esmch_set_format(&ess->rch, hw_rec); 1290 1291 return 0; 1292 } 1293 1294 int 1295 esm_set_port(void *sc, mixer_ctrl_t *cp) 1296 { 1297 struct esm_softc *ess; 1298 1299 ess = sc; 1300 return ess->codec_if->vtbl->mixer_set_port(ess->codec_if, cp); 1301 } 1302 1303 int 1304 esm_get_port(void *sc, mixer_ctrl_t *cp) 1305 { 1306 struct esm_softc *ess; 1307 1308 ess = sc; 1309 return ess->codec_if->vtbl->mixer_get_port(ess->codec_if, cp); 1310 } 1311 1312 int 1313 esm_query_devinfo(void *sc, mixer_devinfo_t *dip) 1314 { 1315 struct esm_softc *ess; 1316 1317 ess = sc; 1318 return ess->codec_if->vtbl->query_devinfo(ess->codec_if, dip); 1319 } 1320 1321 void * 1322 esm_malloc(void *sc, int direction, size_t size) 1323 { 1324 struct esm_softc *ess; 1325 int off; 1326 1327 DPRINTF(ESM_DEBUG_DMA, 1328 ("esm_malloc(%p, %d, 0x%zd)", sc, direction, size)); 1329 ess = sc; 1330 /* 1331 * Each buffer can only be allocated once. 1332 */ 1333 if (ess->rings_alloced & direction) { 1334 DPRINTF(ESM_DEBUG_DMA, (" = 0 (ENOMEM)\n")); 1335 return 0; 1336 } 1337 1338 /* 1339 * Mark this buffer as allocated and return its 1340 * kernel virtual address. 1341 */ 1342 ess->rings_alloced |= direction; 1343 off = (direction == AUMODE_PLAY ? 1344 MAESTRO_PLAYBUF_OFF : MAESTRO_RECBUF_OFF); 1345 DPRINTF(ESM_DEBUG_DMA, (" = %p (DMAADDR 0x%x)\n", 1346 (char *)ess->sc_dma.addr + off, 1347 (int)DMAADDR(&ess->sc_dma) + off)); 1348 return (char *)ess->sc_dma.addr + off; 1349 } 1350 1351 void 1352 esm_free(void *sc, void *ptr, size_t size) 1353 { 1354 struct esm_softc *ess; 1355 1356 DPRINTF(ESM_DEBUG_DMA, ("esm_free(%p, %p, %zd)\n", sc, ptr, size)); 1357 ess = sc; 1358 if ((char *)ptr == (char *)ess->sc_dma.addr + MAESTRO_PLAYBUF_OFF) 1359 ess->rings_alloced &= ~AUMODE_PLAY; 1360 else if ((char *)ptr == (char *)ess->sc_dma.addr + MAESTRO_RECBUF_OFF) 1361 ess->rings_alloced &= ~AUMODE_RECORD; 1362 } 1363 1364 size_t 1365 esm_round_buffersize(void *sc, int direction, size_t size) 1366 { 1367 1368 if (size > MAESTRO_PLAYBUF_SZ) 1369 size = MAESTRO_PLAYBUF_SZ; 1370 if (size > MAESTRO_RECBUF_SZ) 1371 size = MAESTRO_RECBUF_SZ; 1372 return size; 1373 } 1374 1375 paddr_t 1376 esm_mappage(void *sc, void *mem, off_t off, int prot) 1377 { 1378 struct esm_softc *ess; 1379 1380 DPRINTF(ESM_DEBUG_DMA, 1381 ("esm_mappage(%p, %p, 0x%lx, 0x%x)\n", 1382 sc, mem, (unsigned long)off, prot)); 1383 ess = sc; 1384 if (off < 0) 1385 return -1; 1386 1387 if ((char *)mem == (char *)ess->sc_dma.addr + MAESTRO_PLAYBUF_OFF) 1388 off += MAESTRO_PLAYBUF_OFF; 1389 else if ((char *)mem == (char *)ess->sc_dma.addr + MAESTRO_RECBUF_OFF) 1390 off += MAESTRO_RECBUF_OFF; 1391 else 1392 return -1; 1393 return bus_dmamem_mmap(ess->dmat, ess->sc_dma.segs, ess->sc_dma.nsegs, 1394 off, prot, BUS_DMA_WAITOK); 1395 } 1396 1397 int 1398 esm_get_props(void *sc) 1399 { 1400 1401 return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 1402 } 1403 1404 1405 /* ----------------------------- 1406 * Bus space. 1407 */ 1408 1409 static int 1410 esm_intr(void *sc) 1411 { 1412 struct esm_softc *ess; 1413 uint16_t status; 1414 uint16_t pos; 1415 int ret; 1416 1417 ess = sc; 1418 ret = 0; 1419 1420 mutex_spin_enter(&ess->sc_intr_lock); 1421 status = bus_space_read_1(ess->st, ess->sh, PORT_HOSTINT_STAT); 1422 if (!status) { 1423 mutex_spin_exit(&ess->sc_intr_lock); 1424 return 0; 1425 } 1426 1427 /* Acknowledge all. */ 1428 bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1); 1429 bus_space_write_1(ess->st, ess->sh, PORT_HOSTINT_STAT, 0); 1430 #if 0 /* XXX - HWVOL */ 1431 if (status & HOSTINT_STAT_HWVOL) { 1432 u_int delta; 1433 delta = bus_space_read_1(ess->st, ess->sh, PORT_HWVOL_MASTER) 1434 - 0x88; 1435 if (delta & 0x11) 1436 mixer_set(device_get_softc(ess->dev), 1437 SOUND_MIXER_VOLUME, 0); 1438 else { 1439 mixer_set(device_get_softc(ess->dev), 1440 SOUND_MIXER_VOLUME, 1441 mixer_get(device_get_softc(ess->dev), 1442 SOUND_MIXER_VOLUME) 1443 + ((delta >> 5) & 0x7) - 4 1444 + ((delta << 7) & 0x700) - 0x400); 1445 } 1446 bus_space_write_1(ess->st, ess->sh, PORT_HWVOL_MASTER, 0x88); 1447 ret++; 1448 } 1449 #endif /* XXX - HWVOL */ 1450 1451 if (ess->pactive) { 1452 pos = wp_rdapu(ess, ess->pch.num << 1, APUREG_CURPTR); 1453 1454 DPRINTF(ESM_DEBUG_IRQ, (" %4.4x/%4.4x ", pos, 1455 wp_rdapu(ess, (ess->pch.num<<1)+1, APUREG_CURPTR))); 1456 1457 pos -= ess->pch.apubase; 1458 if (pos >= ess->pch.nextirq && 1459 pos - ess->pch.nextirq < ess->pch.apubuf / 2) { 1460 ess->pch.nextirq += ess->pch.apublk; 1461 1462 if (ess->pch.nextirq >= ess->pch.apubuf) 1463 ess->pch.nextirq = 0; 1464 1465 if (ess->sc_pintr) { 1466 DPRINTF(ESM_DEBUG_IRQ, ("P\n")); 1467 ess->sc_pintr(ess->sc_parg); 1468 } 1469 1470 } 1471 ret++; 1472 } 1473 1474 if (ess->ractive) { 1475 pos = wp_rdapu(ess, ess->rch.num << 1, APUREG_CURPTR); 1476 1477 DPRINTF(ESM_DEBUG_IRQ, (" %4.4x/%4.4x ", pos, 1478 wp_rdapu(ess, (ess->rch.num<<1)+1, APUREG_CURPTR))); 1479 1480 pos -= ess->rch.apubase; 1481 if (pos >= ess->rch.nextirq && 1482 pos - ess->rch.nextirq < ess->rch.apubuf / 2) { 1483 ess->rch.nextirq += ess->rch.apublk; 1484 1485 if (ess->rch.nextirq >= ess->rch.apubuf) 1486 ess->rch.nextirq = 0; 1487 1488 if (ess->sc_rintr) { 1489 DPRINTF(ESM_DEBUG_IRQ, ("R\n")); 1490 switch(ess->rch.aputype) { 1491 case APUTYPE_16BITSTEREO: 1492 esmch_combine_input(ess, &ess->rch); 1493 break; 1494 } 1495 ess->sc_rintr(ess->sc_rarg); 1496 } 1497 1498 } 1499 ret++; 1500 } 1501 mutex_spin_exit(&ess->sc_intr_lock); 1502 1503 return ret; 1504 } 1505 1506 static void 1507 esm_freemem(struct esm_softc *sc, struct esm_dma *p) 1508 { 1509 if (p->size == 0) 1510 return; 1511 1512 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1513 1514 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1515 1516 bus_dmamap_destroy(sc->dmat, p->map); 1517 1518 bus_dmamap_unload(sc->dmat, p->map); 1519 1520 p->size = 0; 1521 } 1522 1523 static int 1524 esm_allocmem(struct esm_softc *sc, size_t size, size_t align, 1525 struct esm_dma *p) 1526 { 1527 int error; 1528 1529 p->size = size; 1530 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, 1531 p->segs, __arraycount(p->segs), 1532 &p->nsegs, BUS_DMA_WAITOK); 1533 if (error) 1534 return error; 1535 1536 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, 1537 &p->addr, BUS_DMA_WAITOK|BUS_DMA_COHERENT); 1538 if (error) 1539 goto free; 1540 1541 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, 1542 0, BUS_DMA_WAITOK, &p->map); 1543 if (error) 1544 goto unmap; 1545 1546 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, 1547 BUS_DMA_WAITOK); 1548 if (error) 1549 goto destroy; 1550 1551 return 0; 1552 1553 destroy: 1554 bus_dmamap_destroy(sc->dmat, p->map); 1555 unmap: 1556 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1557 free: 1558 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1559 1560 p->size = 0; 1561 return error; 1562 } 1563 1564 static int 1565 esm_match(device_t dev, cfdata_t match, void *aux) 1566 { 1567 struct pci_attach_args *pa; 1568 1569 pa = (struct pci_attach_args *)aux; 1570 switch (PCI_VENDOR(pa->pa_id)) { 1571 case PCI_VENDOR_ESSTECH: 1572 switch (PCI_PRODUCT(pa->pa_id)) { 1573 case PCI_PRODUCT_ESSTECH_MAESTRO1: 1574 case PCI_PRODUCT_ESSTECH_MAESTRO2: 1575 case PCI_PRODUCT_ESSTECH_MAESTRO2E: 1576 return 1; 1577 } 1578 1579 case PCI_VENDOR_ESSTECH2: 1580 switch (PCI_PRODUCT(pa->pa_id)) { 1581 case PCI_PRODUCT_ESSTECH2_MAESTRO1: 1582 return 1; 1583 } 1584 } 1585 return 0; 1586 } 1587 1588 static void 1589 esm_attach(device_t parent, device_t self, void *aux) 1590 { 1591 struct esm_softc *ess; 1592 struct pci_attach_args *pa; 1593 const char *intrstr; 1594 pci_chipset_tag_t pc; 1595 pcitag_t tag; 1596 pci_intr_handle_t ih; 1597 pcireg_t csr, data; 1598 uint16_t codec_data; 1599 uint16_t pcmbar; 1600 int error; 1601 1602 ess = device_private(self); 1603 ess->sc_dev = self; 1604 pa = (struct pci_attach_args *)aux; 1605 pc = pa->pa_pc; 1606 tag = pa->pa_tag; 1607 1608 pci_aprint_devinfo(pa, "Audio controller"); 1609 1610 mutex_init(&ess->sc_lock, MUTEX_DEFAULT, IPL_NONE); 1611 mutex_init(&ess->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); 1612 1613 /* Enable the device. */ 1614 csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 1615 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, 1616 csr | PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE); 1617 1618 /* Map I/O register */ 1619 if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, 1620 &ess->st, &ess->sh, NULL, &ess->sz)) { 1621 aprint_error_dev(ess->sc_dev, "can't map i/o space\n"); 1622 mutex_destroy(&ess->sc_lock); 1623 mutex_destroy(&ess->sc_intr_lock); 1624 return; 1625 } 1626 1627 /* Initialize softc */ 1628 ess->pch.num = 0; 1629 ess->rch.num = 1; 1630 ess->dmat = pa->pa_dmat; 1631 ess->tag = tag; 1632 ess->pc = pc; 1633 ess->subid = pci_conf_read(pc, tag, PCI_SUBSYS_ID_REG); 1634 1635 DPRINTF(ESM_DEBUG_PCI, 1636 ("%s: sub-system vendor 0x%4.4x, product 0x%4.4x\n", 1637 device_xname(ess->sc_dev), 1638 PCI_VENDOR(ess->subid), PCI_PRODUCT(ess->subid))); 1639 1640 /* Map and establish the interrupt. */ 1641 if (pci_intr_map(pa, &ih)) { 1642 aprint_error_dev(ess->sc_dev, "can't map interrupt\n"); 1643 mutex_destroy(&ess->sc_lock); 1644 mutex_destroy(&ess->sc_intr_lock); 1645 return; 1646 } 1647 intrstr = pci_intr_string(pc, ih); 1648 ess->ih = pci_intr_establish(pc, ih, IPL_AUDIO, esm_intr, self); 1649 if (ess->ih == NULL) { 1650 aprint_error_dev(ess->sc_dev, "can't establish interrupt"); 1651 if (intrstr != NULL) 1652 aprint_error(" at %s", intrstr); 1653 aprint_error("\n"); 1654 mutex_destroy(&ess->sc_lock); 1655 mutex_destroy(&ess->sc_intr_lock); 1656 return; 1657 } 1658 aprint_normal_dev(ess->sc_dev, "interrupting at %s\n", 1659 intrstr); 1660 1661 /* 1662 * Setup PCI config registers 1663 */ 1664 1665 /* power up chip */ 1666 if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self, 1667 pci_activate_null)) && error != EOPNOTSUPP) { 1668 aprint_error_dev(ess->sc_dev, "cannot activate %d\n", 1669 error); 1670 mutex_destroy(&ess->sc_lock); 1671 mutex_destroy(&ess->sc_intr_lock); 1672 return; 1673 } 1674 delay(100000); 1675 1676 /* Disable all legacy emulations. */ 1677 data = pci_conf_read(pc, tag, CONF_LEGACY); 1678 pci_conf_write(pc, tag, CONF_LEGACY, data | LEGACY_DISABLED); 1679 1680 /* Disconnect from CHI. (Makes Dell inspiron 7500 work?) 1681 * Enable posted write. 1682 * Prefer PCI timing rather than that of ISA. 1683 * Don't swap L/R. */ 1684 data = pci_conf_read(pc, tag, CONF_MAESTRO); 1685 data |= MAESTRO_CHIBUS | MAESTRO_POSTEDWRITE | MAESTRO_DMA_PCITIMING; 1686 data &= ~MAESTRO_SWAP_LR; 1687 pci_conf_write(pc, tag, CONF_MAESTRO, data); 1688 1689 /* initialize sound chip */ 1690 esm_init(ess); 1691 1692 esm_read_codec(ess, 0, &codec_data); 1693 if (codec_data == 0x80) { 1694 aprint_error_dev(ess->sc_dev, "PT101 codec detected!\n"); 1695 mutex_destroy(&ess->sc_lock); 1696 mutex_destroy(&ess->sc_intr_lock); 1697 return; 1698 } 1699 1700 /* 1701 * Some cards and Notebooks appear to have left and right channels 1702 * reversed. Check if there is a corresponding quirk entry for 1703 * the subsystem vendor and product and if so, set the appropriate 1704 * codec flag. 1705 */ 1706 if (esm_get_quirks(ess->subid) & ESM_QUIRKF_SWAPPEDCH) { 1707 ess->codec_flags |= AC97_HOST_SWAPPED_CHANNELS; 1708 } 1709 ess->codec_flags |= AC97_HOST_DONT_READ; 1710 1711 /* initialize AC97 host interface */ 1712 ess->host_if.arg = self; 1713 ess->host_if.attach = esm_attach_codec; 1714 ess->host_if.read = esm_read_codec; 1715 ess->host_if.write = esm_write_codec; 1716 ess->host_if.reset = esm_reset_codec; 1717 ess->host_if.flags = esm_flags_codec; 1718 1719 if (ac97_attach(&ess->host_if, self, &ess->sc_lock) != 0) { 1720 mutex_destroy(&ess->sc_lock); 1721 mutex_destroy(&ess->sc_intr_lock); 1722 return; 1723 } 1724 1725 /* allocate our DMA region */ 1726 if (esm_allocmem(ess, MAESTRO_DMA_SZ, MAESTRO_DMA_ALIGN, 1727 &ess->sc_dma)) { 1728 aprint_error_dev(ess->sc_dev, "couldn't allocate memory!\n"); 1729 mutex_destroy(&ess->sc_lock); 1730 mutex_destroy(&ess->sc_intr_lock); 1731 return; 1732 } 1733 ess->rings_alloced = 0; 1734 1735 /* set DMA base address */ 1736 for (pcmbar = WAVCACHE_PCMBAR; pcmbar < WAVCACHE_PCMBAR + 4; pcmbar++) 1737 wc_wrreg(ess, pcmbar, 1738 DMAADDR(&ess->sc_dma) >> WAVCACHE_BASEADDR_SHIFT); 1739 1740 audio_attach_mi(&esm_hw_if, self, ess->sc_dev); 1741 1742 if (!pmf_device_register(self, esm_suspend, esm_resume)) 1743 aprint_error_dev(self, "couldn't establish power handler\n"); 1744 } 1745 1746 static void 1747 esm_childdet(device_t self, device_t child) 1748 { 1749 /* we hold no child references, so do nothing */ 1750 } 1751 1752 static int 1753 esm_detach(device_t self, int flags) 1754 { 1755 int rc; 1756 struct esm_softc *ess = device_private(self); 1757 1758 if ((rc = config_detach_children(self, flags)) != 0) 1759 return rc; 1760 pmf_device_deregister(self); 1761 1762 /* free our DMA region */ 1763 esm_freemem(ess, &ess->sc_dma); 1764 1765 if (ess->codec_if != NULL) { 1766 mutex_enter(&ess->sc_lock); 1767 ess->codec_if->vtbl->detach(ess->codec_if); 1768 mutex_exit(&ess->sc_lock); 1769 } 1770 1771 /* XXX Restore CONF_MAESTRO? */ 1772 /* XXX Restore legacy emulations? */ 1773 /* XXX Restore PCI config registers? */ 1774 1775 if (ess->ih != NULL) 1776 pci_intr_disestablish(ess->pc, ess->ih); 1777 1778 bus_space_unmap(ess->st, ess->sh, ess->sz); 1779 mutex_destroy(&ess->sc_lock); 1780 mutex_destroy(&ess->sc_intr_lock); 1781 1782 return 0; 1783 } 1784 1785 static bool 1786 esm_suspend(device_t dv, const pmf_qual_t *qual) 1787 { 1788 struct esm_softc *ess = device_private(dv); 1789 1790 mutex_enter(&ess->sc_lock); 1791 mutex_spin_enter(&ess->sc_intr_lock); 1792 wp_stoptimer(ess); 1793 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); 1794 esm_halt_output(ess); 1795 esm_halt_input(ess); 1796 mutex_spin_exit(&ess->sc_intr_lock); 1797 1798 /* Power down everything except clock. */ 1799 esm_write_codec(ess, AC97_REG_POWER, 0xdf00); 1800 delay(20); 1801 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 1802 delay(1); 1803 mutex_exit(&ess->sc_lock); 1804 1805 return true; 1806 } 1807 1808 static bool 1809 esm_resume(device_t dv, const pmf_qual_t *qual) 1810 { 1811 struct esm_softc *ess = device_private(dv); 1812 uint16_t pcmbar; 1813 1814 delay(100000); 1815 1816 mutex_enter(&ess->sc_lock); 1817 mutex_spin_enter(&ess->sc_intr_lock); 1818 esm_init(ess); 1819 1820 /* set DMA base address */ 1821 for (pcmbar = WAVCACHE_PCMBAR; pcmbar < WAVCACHE_PCMBAR + 4; pcmbar++) 1822 wc_wrreg(ess, pcmbar, 1823 DMAADDR(&ess->sc_dma) >> WAVCACHE_BASEADDR_SHIFT); 1824 mutex_spin_exit(&ess->sc_intr_lock); 1825 ess->codec_if->vtbl->restore_ports(ess->codec_if); 1826 mutex_spin_enter(&ess->sc_intr_lock); 1827 #if 0 1828 if (mixer_reinit(dev)) { 1829 printf("%s: unable to reinitialize the mixer\n", 1830 device_xname(ess->sc_dev)); 1831 return ENXIO; 1832 } 1833 #endif 1834 1835 #if TODO 1836 if (ess->pactive) 1837 esm_start_output(ess); 1838 if (ess->ractive) 1839 esm_start_input(ess); 1840 #endif 1841 if (ess->pactive || ess->ractive) { 1842 set_timer(ess); 1843 wp_starttimer(ess); 1844 } 1845 mutex_spin_exit(&ess->sc_intr_lock); 1846 mutex_exit(&ess->sc_lock); 1847 1848 return true; 1849 } 1850 1851 void 1852 esm_get_locks(void *addr, kmutex_t **intr, kmutex_t **proc) 1853 { 1854 struct esm_softc *esm; 1855 1856 esm = addr; 1857 *intr = &esm->sc_intr_lock; 1858 *proc = &esm->sc_lock; 1859 } 1860