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