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