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