1 /* $NetBSD: esm.c,v 1.35 2006/06/17 23:34:26 christos 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.35 2006/06/17 23:34:26 christos 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 /* ----------------------------- 532 * Controller. 533 */ 534 535 int 536 esm_attach_codec(void *sc, struct ac97_codec_if *codec_if) 537 { 538 struct esm_softc *ess; 539 540 ess = sc; 541 ess->codec_if = codec_if; 542 543 return 0; 544 } 545 546 int 547 esm_reset_codec(void *sc) 548 { 549 550 return 0; 551 } 552 553 554 enum ac97_host_flags 555 esm_flags_codec(void *sc) 556 { 557 struct esm_softc *ess; 558 559 ess = sc; 560 return ess->codec_flags; 561 } 562 563 564 void 565 esm_initcodec(struct esm_softc *ess) 566 { 567 uint16_t data; 568 569 DPRINTF(ESM_DEBUG_CODEC, ("esm_initcodec(%p)\n", ess)); 570 571 if (bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL) 572 & RINGBUS_CTRL_ACLINK_ENABLED) { 573 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 574 delay(104); /* 20.8us * (4 + 1) */ 575 } 576 /* XXX - 2nd codec should be looked at. */ 577 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 578 RINGBUS_CTRL_AC97_SWRESET); 579 delay(2); 580 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 581 RINGBUS_CTRL_ACLINK_ENABLED); 582 delay(21); 583 584 esm_read_codec(ess, 0, &data); 585 if (bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) 586 & CODEC_STAT_MASK) { 587 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 588 delay(21); 589 590 /* Try cold reset. */ 591 printf("%s: will perform cold reset.\n", ess->sc_dev.dv_xname); 592 data = bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR); 593 if (pci_conf_read(ess->pc, ess->tag, 0x58) & 1) 594 data |= 0x10; 595 data |= 0x009 & 596 ~bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DATA); 597 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 0xff6); 598 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, 599 data | 0x009); 600 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x000); 601 delay(2); 602 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x001); 603 delay(1); 604 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x009); 605 delay(500000); 606 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, data); 607 delay(84); /* 20.8us * 4 */ 608 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 609 RINGBUS_CTRL_ACLINK_ENABLED); 610 delay(21); 611 } 612 } 613 614 void 615 esm_init(struct esm_softc *ess) 616 { 617 618 /* Reset direct sound. */ 619 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 620 HOSTINT_CTRL_DSOUND_RESET); 621 delay(10000); 622 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); 623 delay(10000); 624 625 /* Enable direct sound interruption. */ 626 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 627 HOSTINT_CTRL_DSOUND_INT_ENABLED); 628 629 /* Setup Wave Processor. */ 630 631 /* Enable WaveCache */ 632 wp_wrreg(ess, WPREG_WAVE_ROMRAM, 633 WP_WAVE_VIRTUAL_ENABLED | WP_WAVE_DRAM_ENABLED); 634 bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_CTRL, 635 WAVCACHE_ENABLED | WAVCACHE_WTSIZE_4MB); 636 637 /* Setup Codec/Ringbus. */ 638 esm_initcodec(ess); 639 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 640 RINGBUS_CTRL_RINGBUS_ENABLED | RINGBUS_CTRL_ACLINK_ENABLED); 641 642 /* Undocumented registers from the Linux driver. */ 643 wp_wrreg(ess, 0x8, 0xB004); 644 wp_wrreg(ess, 0x9, 0x001B); 645 wp_wrreg(ess, 0xA, 0x8000); 646 wp_wrreg(ess, 0xB, 0x3F37); 647 wp_wrreg(ess, 0xD, 0x7632); 648 649 wp_wrreg(ess, WPREG_BASE, 0x8598); /* Parallel I/O */ 650 ringbus_setdest(ess, RINGBUS_SRC_ADC, 651 RINGBUS_DEST_STEREO | RINGBUS_DEST_DSOUND_IN); 652 ringbus_setdest(ess, RINGBUS_SRC_DSOUND, 653 RINGBUS_DEST_STEREO | RINGBUS_DEST_DAC); 654 655 /* Setup ASSP. Needed for Dell Inspiron 7500? */ 656 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_B, 0x00); 657 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_A, 0x03); 658 bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_C, 0x00); 659 660 /* 661 * Setup GPIO. 662 * There seems to be speciality with NEC systems. 663 */ 664 if (esm_get_quirks(ess->subid) & ESM_QUIRKF_GPIO) { 665 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 666 0x9ff); 667 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, 668 bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR) | 669 0x600); 670 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 671 0x200); 672 } 673 674 DUMPREG(ess); 675 } 676 677 /* Channel controller. */ 678 679 int 680 esm_init_output (void *sc, void *start, int size) 681 { 682 struct esm_softc *ess; 683 struct esm_dma *p; 684 685 ess = sc; 686 p = &ess->sc_dma; 687 if ((caddr_t)start != p->addr + MAESTRO_PLAYBUF_OFF) { 688 printf("%s: esm_init_output: bad addr %p\n", 689 ess->sc_dev.dv_xname, start); 690 return EINVAL; 691 } 692 693 ess->pch.base = DMAADDR(p) + MAESTRO_PLAYBUF_OFF; 694 695 DPRINTF(ESM_DEBUG_DMA, ("%s: pch.base = 0x%x\n", 696 ess->sc_dev.dv_xname, ess->pch.base)); 697 698 return 0; 699 } 700 701 int 702 esm_init_input (void *sc, void *start, int size) 703 { 704 struct esm_softc *ess; 705 struct esm_dma *p; 706 707 ess = sc; 708 p = &ess->sc_dma; 709 if ((caddr_t)start != p->addr + MAESTRO_RECBUF_OFF) { 710 printf("%s: esm_init_input: bad addr %p\n", 711 ess->sc_dev.dv_xname, start); 712 return EINVAL; 713 } 714 715 switch (ess->rch.aputype) { 716 case APUTYPE_16BITSTEREO: 717 ess->rch.base = DMAADDR(p) + MAESTRO_RECBUF_L_OFF; 718 break; 719 default: 720 ess->rch.base = DMAADDR(p) + MAESTRO_RECBUF_OFF; 721 break; 722 } 723 724 DPRINTF(ESM_DEBUG_DMA, ("%s: rch.base = 0x%x\n", 725 ess->sc_dev.dv_xname, ess->rch.base)); 726 727 return 0; 728 } 729 730 int 731 esm_trigger_output(void *sc, void *start, void *end, int blksize, 732 void (*intr)(void *), void *arg, const audio_params_t *param) 733 { 734 size_t size; 735 struct esm_softc *ess; 736 struct esm_chinfo *ch; 737 struct esm_dma *p; 738 int pan, choffset; 739 int i, nch; 740 unsigned speed, offset, wpwa, dv; 741 uint16_t apuch; 742 743 DPRINTF(ESM_DEBUG_DMA, 744 ("esm_trigger_output(%p, %p, %p, 0x%x, %p, %p, %p)\n", 745 sc, start, end, blksize, intr, arg, param)); 746 ess = sc; 747 ch = &ess->pch; 748 pan = 0; 749 nch = 1; 750 speed = ch->sample_rate; 751 apuch = ch->num << 1; 752 753 #ifdef DIAGNOSTIC 754 if (ess->pactive) { 755 printf("%s: esm_trigger_output: already running", 756 ess->sc_dev.dv_xname); 757 return EINVAL; 758 } 759 #endif 760 761 ess->sc_pintr = intr; 762 ess->sc_parg = arg; 763 p = &ess->sc_dma; 764 if ((caddr_t)start != p->addr + MAESTRO_PLAYBUF_OFF) { 765 printf("%s: esm_trigger_output: bad addr %p\n", 766 ess->sc_dev.dv_xname, start); 767 return EINVAL; 768 } 769 770 ess->pch.blocksize = blksize; 771 ess->pch.apublk = blksize >> 1; 772 ess->pactive = 1; 773 774 size = (size_t)(((caddr_t)end - (caddr_t)start) >> 1); 775 choffset = MAESTRO_PLAYBUF_OFF; 776 offset = choffset >> 1; 777 wpwa = APU_USE_SYSMEM | ((offset >> 8) & APU_64KPAGE_MASK); 778 779 DPRINTF(ESM_DEBUG_DMA, 780 ("choffs=0x%x, wpwa=0x%x, size=0x%lx words\n", 781 choffset, wpwa, (unsigned long int)size)); 782 783 switch (ch->aputype) { 784 case APUTYPE_16BITSTEREO: 785 ess->pch.apublk >>= 1; 786 wpwa >>= 1; 787 size >>= 1; 788 offset >>= 1; 789 /* FALLTHROUGH */ 790 case APUTYPE_8BITSTEREO: 791 if (ess->codec_flags & AC97_HOST_SWAPPED_CHANNELS) 792 pan = 8; 793 else 794 pan = -8; 795 nch++; 796 break; 797 case APUTYPE_8BITLINEAR: 798 ess->pch.apublk <<= 1; 799 speed >>= 1; 800 break; 801 } 802 803 ess->pch.apubase = offset; 804 ess->pch.apubuf = size; 805 ess->pch.nextirq = ess->pch.apublk; 806 807 set_timer(ess); 808 wp_starttimer(ess); 809 810 dv = (((speed % 48000) << 16) + 24000) / 48000 811 + ((speed / 48000) << 16); 812 813 for (i = nch-1; i >= 0; i--) { 814 wp_wrapu(ess, apuch + i, APUREG_WAVESPACE, wpwa & 0xff00); 815 wp_wrapu(ess, apuch + i, APUREG_CURPTR, offset); 816 wp_wrapu(ess, apuch + i, APUREG_ENDPTR, offset + size); 817 wp_wrapu(ess, apuch + i, APUREG_LOOPLEN, size - 1); 818 wp_wrapu(ess, apuch + i, APUREG_AMPLITUDE, 0xe800); 819 wp_wrapu(ess, apuch + i, APUREG_POSITION, 0x8f00 820 | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT) 821 | ((PAN_FRONT + pan) << APU_PAN_SHIFT)); 822 wp_wrapu(ess, apuch + i, APUREG_FREQ_LOBYTE, APU_plus6dB 823 | ((dv & 0xff) << APU_FREQ_LOBYTE_SHIFT)); 824 wp_wrapu(ess, apuch + i, APUREG_FREQ_HIWORD, dv >> 8); 825 826 if (ch->aputype == APUTYPE_16BITSTEREO) 827 wpwa |= APU_STEREO >> 1; 828 pan = -pan; 829 } 830 831 wc_wrchctl(ess, apuch, ch->wcreg_tpl); 832 if (nch > 1) 833 wc_wrchctl(ess, apuch + 1, ch->wcreg_tpl); 834 835 wp_wrapu(ess, apuch, APUREG_APUTYPE, 836 (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf); 837 if (ch->wcreg_tpl & WAVCACHE_CHCTL_STEREO) 838 wp_wrapu(ess, apuch + 1, APUREG_APUTYPE, 839 (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf); 840 841 return 0; 842 } 843 844 int 845 esm_trigger_input(void *sc, void *start, void *end, int blksize, 846 void (*intr)(void *), void *arg, const audio_params_t *param) 847 { 848 size_t size; 849 size_t mixsize; 850 struct esm_softc *ess; 851 struct esm_chinfo *ch; 852 struct esm_dma *p; 853 uint32_t chctl, choffset; 854 uint32_t speed, offset, wpwa, dv; 855 uint32_t mixoffset, mixdv; 856 int i, nch; 857 uint16_t apuch; 858 uint16_t reg; 859 860 DPRINTF(ESM_DEBUG_DMA, 861 ("esm_trigger_input(%p, %p, %p, 0x%x, %p, %p, %p)\n", 862 sc, start, end, blksize, intr, arg, param)); 863 ess = sc; 864 ch = &ess->rch; 865 nch = 1; 866 speed = ch->sample_rate; 867 apuch = ch->num << 1; 868 869 #ifdef DIAGNOSTIC 870 if (ess->ractive) { 871 printf("%s: esm_trigger_input: already running", 872 ess->sc_dev.dv_xname); 873 return EINVAL; 874 } 875 #endif 876 877 ess->sc_rintr = intr; 878 ess->sc_rarg = arg; 879 p = &ess->sc_dma; 880 if ((caddr_t)start != p->addr + MAESTRO_RECBUF_OFF) { 881 printf("%s: esm_trigger_input: bad addr %p\n", 882 ess->sc_dev.dv_xname, start); 883 return EINVAL; 884 } 885 886 ess->rch.buffer = (caddr_t)start; 887 ess->rch.offset = 0; 888 ess->rch.blocksize = blksize; 889 ess->rch.bufsize = ((caddr_t)end - (caddr_t)start); 890 ess->rch.apublk = blksize >> 1; 891 ess->ractive = 1; 892 893 size = (size_t)(((caddr_t)end - (caddr_t)start) >> 1); 894 choffset = MAESTRO_RECBUF_OFF; 895 switch (ch->aputype) { 896 case APUTYPE_16BITSTEREO: 897 size >>= 1; 898 choffset = MAESTRO_RECBUF_L_OFF; 899 ess->rch.apublk >>= 1; 900 nch++; 901 break; 902 case APUTYPE_16BITLINEAR: 903 break; 904 default: 905 ess->ractive = 0; 906 return EINVAL; 907 } 908 909 mixsize = (MAESTRO_MIXBUF_SZ >> 1) >> 1; 910 mixoffset = MAESTRO_MIXBUF_OFF; 911 912 ess->rch.apubase = (choffset >> 1); 913 ess->rch.apubuf = size; 914 ess->rch.nextirq = ess->rch.apublk; 915 916 set_timer(ess); 917 wp_starttimer(ess); 918 919 if (speed > 47999) speed = 47999; 920 if (speed < 4000) speed = 4000; 921 dv = (((speed % 48000) << 16) + 24000) / 48000 922 + ((speed / 48000) << 16); 923 mixdv = 65536; /* 48 kHz */ 924 925 for (i = 0; i < nch; i++) { 926 927 /* Clear all rate conversion WP channel registers first. */ 928 for (reg = 0; reg < 15; reg++) 929 wp_wrapu(ess, apuch + i, reg, 0); 930 931 /* Program the WaveCache for the rate conversion WP channel. */ 932 chctl = (DMAADDR(p) + choffset - 0x10) & 933 WAVCACHE_CHCTL_ADDRTAG_MASK; 934 wc_wrchctl(ess, apuch + i, chctl); 935 936 /* Program the rate conversion WP channel. */ 937 wp_wrapu(ess, apuch + i, APUREG_FREQ_LOBYTE, APU_plus6dB 938 | ((dv & 0xff) << APU_FREQ_LOBYTE_SHIFT) | 0x08); 939 wp_wrapu(ess, apuch + i, APUREG_FREQ_HIWORD, dv >> 8); 940 offset = choffset >> 1; 941 wpwa = APU_USE_SYSMEM | ((offset >> 8) & APU_64KPAGE_MASK); 942 wp_wrapu(ess, apuch + i, APUREG_WAVESPACE, wpwa); 943 wp_wrapu(ess, apuch + i, APUREG_CURPTR, offset); 944 wp_wrapu(ess, apuch + i, APUREG_ENDPTR, offset + size); 945 wp_wrapu(ess, apuch + i, APUREG_LOOPLEN, size - 1); 946 wp_wrapu(ess, apuch + i, APUREG_EFFECTS_ENV, 0x00f0); 947 wp_wrapu(ess, apuch + i, APUREG_AMPLITUDE, 0xe800); 948 wp_wrapu(ess, apuch + i, APUREG_POSITION, 0x8f00 949 | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT) 950 | (PAN_FRONT << APU_PAN_SHIFT)); 951 wp_wrapu(ess, apuch + i, APUREG_ROUTE, apuch + 2 + i); 952 953 DPRINTF(ESM_DEBUG_DMA, 954 ("choffs=0x%x, wpwa=0x%x, offset=0x%x words, size=0x%lx words\n", 955 choffset, wpwa, offset, (unsigned long int)size)); 956 957 /* Clear all mixer WP channel registers first. */ 958 for (reg = 0; reg < 15; reg++) 959 wp_wrapu(ess, apuch + 2 + i, reg, 0); 960 961 /* Program the WaveCache for the mixer WP channel. */ 962 chctl = (ess->rch.base + mixoffset - 0x10) & 963 WAVCACHE_CHCTL_ADDRTAG_MASK; 964 wc_wrchctl(ess, apuch + 2 + i, chctl); 965 966 /* Program the mixer WP channel. */ 967 wp_wrapu(ess, apuch + 2 + i, APUREG_FREQ_LOBYTE, APU_plus6dB 968 | ((mixdv & 0xff) << APU_FREQ_LOBYTE_SHIFT) | 0x08); 969 wp_wrapu(ess, apuch + 2 + i, APUREG_FREQ_HIWORD, mixdv >> 8); 970 offset = mixoffset >> 1; 971 wpwa = APU_USE_SYSMEM | ((offset >> 8) & APU_64KPAGE_MASK); 972 wp_wrapu(ess, apuch + 2 + i, APUREG_WAVESPACE, wpwa); 973 wp_wrapu(ess, apuch + 2 + i, APUREG_CURPTR, offset); 974 wp_wrapu(ess, apuch + 2 + i, APUREG_ENDPTR, 975 offset + mixsize); 976 wp_wrapu(ess, apuch + 2 + i, APUREG_LOOPLEN, mixsize); 977 wp_wrapu(ess, apuch + 2 + i, APUREG_EFFECTS_ENV, 0x00f0); 978 wp_wrapu(ess, apuch + 2 + i, APUREG_AMPLITUDE, 0xe800); 979 wp_wrapu(ess, apuch + 2 + i, APUREG_POSITION, 0x8f00 980 | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT) 981 | (PAN_FRONT << APU_PAN_SHIFT)); 982 wp_wrapu(ess, apuch + 2 + i, APUREG_ROUTE, 983 ROUTE_PARALLEL + i); 984 985 DPRINTF(ESM_DEBUG_DMA, 986 ("mixoffs=0x%x, wpwa=0x%x, offset=0x%x words, size=0x%lx words\n", 987 mixoffset, wpwa, offset, (unsigned long int)mixsize)); 988 989 /* Assume we're going to loop to do the right channel. */ 990 choffset += MAESTRO_RECBUF_L_SZ; 991 mixoffset += MAESTRO_MIXBUF_SZ >> 1; 992 } 993 994 wp_wrapu(ess, apuch, APUREG_APUTYPE, 995 (APUTYPE_RATECONV << APU_APUTYPE_SHIFT) | 996 APU_DMA_ENABLED | 0xf); 997 if (nch > 1) 998 wp_wrapu(ess, apuch + 1, APUREG_APUTYPE, 999 (APUTYPE_RATECONV << APU_APUTYPE_SHIFT) | 1000 APU_DMA_ENABLED | 0xf); 1001 wp_wrapu(ess, apuch + 2, APUREG_APUTYPE, 1002 (APUTYPE_INPUTMIXER << APU_APUTYPE_SHIFT) | 1003 APU_DMA_ENABLED | 0xf); 1004 if (nch > 1) 1005 wp_wrapu(ess, apuch + 3, APUREG_APUTYPE, 1006 (APUTYPE_RATECONV << APU_APUTYPE_SHIFT) | 1007 APU_DMA_ENABLED | 0xf); 1008 1009 return 0; 1010 } 1011 1012 int 1013 esm_halt_output(void *sc) 1014 { 1015 struct esm_softc *ess; 1016 struct esm_chinfo *ch; 1017 1018 DPRINTF(ESM_DEBUG_PARAM, ("esm_halt_output(%p)\n", sc)); 1019 ess = sc; 1020 ch = &ess->pch; 1021 1022 wp_wrapu(ess, (ch->num << 1), APUREG_APUTYPE, 1023 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1024 wp_wrapu(ess, (ch->num << 1) + 1, APUREG_APUTYPE, 1025 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1026 1027 ess->pactive = 0; 1028 if (!ess->ractive) 1029 wp_stoptimer(ess); 1030 1031 return 0; 1032 } 1033 1034 int 1035 esm_halt_input(void *sc) 1036 { 1037 struct esm_softc *ess; 1038 struct esm_chinfo *ch; 1039 1040 DPRINTF(ESM_DEBUG_PARAM, ("esm_halt_input(%p)\n", sc)); 1041 ess = sc; 1042 ch = &ess->rch; 1043 1044 wp_wrapu(ess, (ch->num << 1), APUREG_APUTYPE, 1045 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1046 wp_wrapu(ess, (ch->num << 1) + 1, APUREG_APUTYPE, 1047 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1048 wp_wrapu(ess, (ch->num << 1) + 2, APUREG_APUTYPE, 1049 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1050 wp_wrapu(ess, (ch->num << 1) + 3, APUREG_APUTYPE, 1051 APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); 1052 1053 ess->ractive = 0; 1054 if (!ess->pactive) 1055 wp_stoptimer(ess); 1056 1057 return 0; 1058 } 1059 1060 static inline u_int 1061 calc_timer_freq(struct esm_chinfo *ch) 1062 { 1063 u_int freq; 1064 1065 freq = (ch->sample_rate + ch->apublk - 1) / ch->apublk; 1066 1067 DPRINTF(ESM_DEBUG_TIMER, 1068 ("calc_timer_freq(%p): rate = %u, blk = 0x%x (0x%x): freq = %u\n", 1069 ch, ch->sample_rate, ch->apublk, ch->blocksize, freq)); 1070 1071 return freq; 1072 } 1073 1074 static void 1075 set_timer(struct esm_softc *ess) 1076 { 1077 unsigned freq, freq2; 1078 1079 freq = 0; 1080 if (ess->pactive) 1081 freq = calc_timer_freq(&ess->pch); 1082 1083 if (ess->ractive) { 1084 freq2 = calc_timer_freq(&ess->rch); 1085 if (freq2 > freq) 1086 freq = freq2; 1087 } 1088 1089 KASSERT(freq != 0); 1090 1091 for (; freq < MAESTRO_MINFREQ; freq <<= 1) 1092 continue; 1093 1094 if (freq > 0) 1095 wp_settimer(ess, freq); 1096 } 1097 1098 static void 1099 esmch_set_format(struct esm_chinfo *ch, const audio_params_t *p) 1100 { 1101 uint16_t wcreg_tpl; 1102 uint16_t aputype; 1103 1104 wcreg_tpl = (ch->base - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK; 1105 aputype = APUTYPE_16BITLINEAR; 1106 if (p->channels == 2) { 1107 wcreg_tpl |= WAVCACHE_CHCTL_STEREO; 1108 aputype++; 1109 } 1110 if (p->precision == 8) { 1111 aputype += 2; 1112 switch (p->encoding) { 1113 case AUDIO_ENCODING_ULINEAR: 1114 case AUDIO_ENCODING_ULINEAR_BE: 1115 case AUDIO_ENCODING_ULINEAR_LE: 1116 wcreg_tpl |= WAVCACHE_CHCTL_U8; 1117 break; 1118 } 1119 } 1120 ch->wcreg_tpl = wcreg_tpl; 1121 ch->aputype = aputype; 1122 ch->sample_rate = p->sample_rate; 1123 1124 DPRINTF(ESM_DEBUG_PARAM, ("esmch_set_format: " 1125 "numch=%u, prec=%u, tpl=0x%x, aputype=%d, rate=%u\n", 1126 p->channels, p->precision, wcreg_tpl, aputype, p->sample_rate)); 1127 } 1128 1129 /* 1130 * Since we can't record in true stereo, this function combines 1131 * the separately recorded left and right channels into the final 1132 * buffer for the upper layer. 1133 */ 1134 static void 1135 esmch_combine_input(struct esm_softc *ess, struct esm_chinfo *ch) 1136 { 1137 size_t offset, resid, count; 1138 uint32_t *dst32s; 1139 const uint32_t *left32s, *right32s; 1140 uint32_t left32, right32; 1141 1142 /* The current offset into the upper layer buffer. */ 1143 offset = ch->offset; 1144 1145 /* The number of bytes left to combine. */ 1146 resid = ch->blocksize; 1147 1148 while (resid > 0) { 1149 1150 /* The 32-bit words for the left channel. */ 1151 left32s = (const uint32_t *)(ess->sc_dma.addr + 1152 MAESTRO_RECBUF_L_OFF + offset / 2); 1153 1154 /* The 32-bit words for the right channel. */ 1155 right32s = (const uint32_t *)(ess->sc_dma.addr + 1156 MAESTRO_RECBUF_R_OFF + offset / 2); 1157 1158 /* The pointer to the 32-bit words we will write. */ 1159 dst32s = (uint32_t *)(ch->buffer + offset); 1160 1161 /* Get the number of bytes we will combine now. */ 1162 count = ch->bufsize - offset; 1163 if (count > resid) 1164 count = resid; 1165 resid -= count; 1166 offset += count; 1167 if (offset == ch->bufsize) 1168 offset = 0; 1169 1170 /* Combine, writing two 32-bit words at a time. */ 1171 KASSERT((count & (sizeof(uint32_t) * 2 - 1)) == 0); 1172 count /= (sizeof(uint32_t) * 2); 1173 while (count > 0) { 1174 left32 = *(left32s++); 1175 right32 = *(right32s++); 1176 /* XXX this endian handling is half-baked at best */ 1177 #if BYTE_ORDER == LITTLE_ENDIAN 1178 *(dst32s++) = (left32 & 0xFFFF) | (right32 << 16); 1179 *(dst32s++) = (left32 >> 16) | (right32 & 0xFFFF0000); 1180 #else /* BYTE_ORDER == BIG_ENDIAN */ 1181 *(dst32s++) = (left32 & 0xFFFF0000) | (right32 >> 16); 1182 *(dst32s++) = (left32 << 16) | (right32 & 0xFFFF); 1183 #endif /* BYTE_ORDER == BIG_ENDIAN */ 1184 count--; 1185 } 1186 } 1187 1188 /* Update the offset. */ 1189 ch->offset = offset; 1190 } 1191 1192 /* 1193 * Audio interface glue functions 1194 */ 1195 1196 int 1197 esm_getdev (void *sc, struct audio_device *adp) 1198 { 1199 1200 *adp = esm_device; 1201 return 0; 1202 } 1203 1204 int 1205 esm_round_blocksize(void *sc, int blk, int mode, const audio_params_t *param) 1206 { 1207 1208 DPRINTF(ESM_DEBUG_PARAM, 1209 ("esm_round_blocksize(%p, 0x%x)", sc, blk)); 1210 1211 blk &= ~0x3f; /* keep good alignment */ 1212 1213 DPRINTF(ESM_DEBUG_PARAM, (" = 0x%x\n", blk)); 1214 1215 return blk; 1216 } 1217 1218 int 1219 esm_query_encoding(void *sc, struct audio_encoding *fp) 1220 { 1221 1222 DPRINTF(ESM_DEBUG_PARAM, 1223 ("esm_query_encoding(%p, %d)\n", sc, fp->index)); 1224 1225 if (fp->index < 0 || fp->index >= MAESTRO_NENCODINGS) 1226 return EINVAL; 1227 1228 *fp = esm_encoding[fp->index]; 1229 return 0; 1230 } 1231 1232 int 1233 esm_set_params(void *sc, int setmode, int usemode, 1234 audio_params_t *play, audio_params_t *rec, 1235 stream_filter_list_t *pfil, stream_filter_list_t *rfil) 1236 { 1237 struct esm_softc *ess; 1238 audio_params_t *p; 1239 const audio_params_t *hw_play, *hw_rec; 1240 stream_filter_list_t *fil; 1241 int mode, i; 1242 1243 DPRINTF(ESM_DEBUG_PARAM, 1244 ("esm_set_params(%p, 0x%x, 0x%x, %p, %p)\n", 1245 sc, setmode, usemode, play, rec)); 1246 ess = sc; 1247 hw_play = NULL; 1248 hw_rec = NULL; 1249 for (mode = AUMODE_RECORD; mode != -1; 1250 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 1251 if ((setmode & mode) == 0) 1252 continue; 1253 1254 p = mode == AUMODE_PLAY ? play : rec; 1255 1256 if (p->sample_rate < 4000 || p->sample_rate > 48000 || 1257 (p->precision != 8 && p->precision != 16) || 1258 (p->channels != 1 && p->channels != 2)) 1259 return EINVAL; 1260 1261 fil = mode == AUMODE_PLAY ? pfil : rfil; 1262 i = auconv_set_converter(esm_formats, ESM_NFORMATS, 1263 mode, p, FALSE, fil); 1264 if (i < 0) 1265 return EINVAL; 1266 if (fil->req_size > 0) 1267 p = &fil->filters[0].param; 1268 if (mode == AUMODE_PLAY) 1269 hw_play = p; 1270 else 1271 hw_rec = p; 1272 } 1273 1274 if (hw_play) 1275 esmch_set_format(&ess->pch, hw_play); 1276 1277 if (hw_rec) 1278 esmch_set_format(&ess->rch, hw_rec); 1279 1280 return 0; 1281 } 1282 1283 int 1284 esm_set_port(void *sc, mixer_ctrl_t *cp) 1285 { 1286 struct esm_softc *ess; 1287 1288 ess = sc; 1289 return ess->codec_if->vtbl->mixer_set_port(ess->codec_if, cp); 1290 } 1291 1292 int 1293 esm_get_port(void *sc, mixer_ctrl_t *cp) 1294 { 1295 struct esm_softc *ess; 1296 1297 ess = sc; 1298 return ess->codec_if->vtbl->mixer_get_port(ess->codec_if, cp); 1299 } 1300 1301 int 1302 esm_query_devinfo(void *sc, mixer_devinfo_t *dip) 1303 { 1304 struct esm_softc *ess; 1305 1306 ess = sc; 1307 return ess->codec_if->vtbl->query_devinfo(ess->codec_if, dip); 1308 } 1309 1310 void * 1311 esm_malloc(void *sc, int direction, size_t size, struct malloc_type *pool, 1312 int flags) 1313 { 1314 struct esm_softc *ess; 1315 int off; 1316 1317 DPRINTF(ESM_DEBUG_DMA, 1318 ("esm_malloc(%p, %d, 0x%lx, %p, 0x%x)", 1319 sc, direction, (unsigned long int)size, pool, flags)); 1320 ess = sc; 1321 /* 1322 * Each buffer can only be allocated once. 1323 */ 1324 if (ess->rings_alloced & direction) { 1325 DPRINTF(ESM_DEBUG_DMA, (" = 0 (ENOMEM)\n")); 1326 return 0; 1327 } 1328 1329 /* 1330 * Mark this buffer as allocated and return its 1331 * kernel virtual address. 1332 */ 1333 ess->rings_alloced |= direction; 1334 off = (direction == AUMODE_PLAY ? 1335 MAESTRO_PLAYBUF_OFF : MAESTRO_RECBUF_OFF); 1336 DPRINTF(ESM_DEBUG_DMA, (" = %p (DMAADDR 0x%x)\n", 1337 ess->sc_dma.addr + off, 1338 (int)DMAADDR(&ess->sc_dma) + off)); 1339 return ess->sc_dma.addr + off; 1340 } 1341 1342 void 1343 esm_free(void *sc, void *ptr, struct malloc_type *pool) 1344 { 1345 struct esm_softc *ess; 1346 1347 DPRINTF(ESM_DEBUG_DMA, 1348 ("esm_free(%p, %p, %p)\n", 1349 sc, ptr, pool)); 1350 ess = sc; 1351 if ((caddr_t)ptr == ess->sc_dma.addr + MAESTRO_PLAYBUF_OFF) 1352 ess->rings_alloced &= ~AUMODE_PLAY; 1353 else if ((caddr_t)ptr == ess->sc_dma.addr + MAESTRO_RECBUF_OFF) 1354 ess->rings_alloced &= ~AUMODE_RECORD; 1355 } 1356 1357 size_t 1358 esm_round_buffersize(void *sc, int direction, size_t size) 1359 { 1360 1361 if (size > MAESTRO_PLAYBUF_SZ) 1362 size = MAESTRO_PLAYBUF_SZ; 1363 if (size > MAESTRO_RECBUF_SZ) 1364 size = MAESTRO_RECBUF_SZ; 1365 return size; 1366 } 1367 1368 paddr_t 1369 esm_mappage(void *sc, void *mem, off_t off, int prot) 1370 { 1371 struct esm_softc *ess; 1372 1373 DPRINTF(ESM_DEBUG_DMA, 1374 ("esm_mappage(%p, %p, 0x%lx, 0x%x)\n", 1375 sc, mem, (unsigned long)off, prot)); 1376 ess = sc; 1377 if (off < 0) 1378 return -1; 1379 1380 if ((caddr_t)mem == ess->sc_dma.addr + MAESTRO_PLAYBUF_OFF) 1381 off += MAESTRO_PLAYBUF_OFF; 1382 else if ((caddr_t)mem == ess->sc_dma.addr + MAESTRO_RECBUF_OFF) 1383 off += MAESTRO_RECBUF_OFF; 1384 else 1385 return -1; 1386 return bus_dmamem_mmap(ess->dmat, ess->sc_dma.segs, ess->sc_dma.nsegs, 1387 off, prot, BUS_DMA_WAITOK); 1388 } 1389 1390 int 1391 esm_get_props(void *sc) 1392 { 1393 1394 return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 1395 } 1396 1397 1398 /* ----------------------------- 1399 * Bus space. 1400 */ 1401 1402 int 1403 esm_intr(void *sc) 1404 { 1405 struct esm_softc *ess; 1406 uint16_t status; 1407 uint16_t pos; 1408 int ret; 1409 1410 ess = sc; 1411 ret = 0; 1412 status = bus_space_read_1(ess->st, ess->sh, PORT_HOSTINT_STAT); 1413 if (!status) 1414 return 0; 1415 1416 /* Acknowledge all. */ 1417 bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1); 1418 bus_space_write_1(ess->st, ess->sh, PORT_HOSTINT_STAT, 0); 1419 #if 0 /* XXX - HWVOL */ 1420 if (status & HOSTINT_STAT_HWVOL) { 1421 u_int delta; 1422 delta = bus_space_read_1(ess->st, ess->sh, PORT_HWVOL_MASTER) 1423 - 0x88; 1424 if (delta & 0x11) 1425 mixer_set(device_get_softc(ess->dev), 1426 SOUND_MIXER_VOLUME, 0); 1427 else { 1428 mixer_set(device_get_softc(ess->dev), 1429 SOUND_MIXER_VOLUME, 1430 mixer_get(device_get_softc(ess->dev), 1431 SOUND_MIXER_VOLUME) 1432 + ((delta >> 5) & 0x7) - 4 1433 + ((delta << 7) & 0x700) - 0x400); 1434 } 1435 bus_space_write_1(ess->st, ess->sh, PORT_HWVOL_MASTER, 0x88); 1436 ret++; 1437 } 1438 #endif /* XXX - HWVOL */ 1439 1440 if (ess->pactive) { 1441 pos = wp_rdapu(ess, ess->pch.num << 1, APUREG_CURPTR); 1442 1443 DPRINTF(ESM_DEBUG_IRQ, (" %4.4x/%4.4x ", pos, 1444 wp_rdapu(ess, (ess->pch.num<<1)+1, APUREG_CURPTR))); 1445 1446 pos -= ess->pch.apubase; 1447 if (pos >= ess->pch.nextirq && 1448 pos - ess->pch.nextirq < ess->pch.apubuf / 2) { 1449 ess->pch.nextirq += ess->pch.apublk; 1450 1451 if (ess->pch.nextirq >= ess->pch.apubuf) 1452 ess->pch.nextirq = 0; 1453 1454 if (ess->sc_pintr) { 1455 DPRINTF(ESM_DEBUG_IRQ, ("P\n")); 1456 ess->sc_pintr(ess->sc_parg); 1457 } 1458 1459 } 1460 ret++; 1461 } 1462 1463 if (ess->ractive) { 1464 pos = wp_rdapu(ess, ess->rch.num << 1, APUREG_CURPTR); 1465 1466 DPRINTF(ESM_DEBUG_IRQ, (" %4.4x/%4.4x ", pos, 1467 wp_rdapu(ess, (ess->rch.num<<1)+1, APUREG_CURPTR))); 1468 1469 pos -= ess->rch.apubase; 1470 if (pos >= ess->rch.nextirq && 1471 pos - ess->rch.nextirq < ess->rch.apubuf / 2) { 1472 ess->rch.nextirq += ess->rch.apublk; 1473 1474 if (ess->rch.nextirq >= ess->rch.apubuf) 1475 ess->rch.nextirq = 0; 1476 1477 if (ess->sc_rintr) { 1478 DPRINTF(ESM_DEBUG_IRQ, ("R\n")); 1479 switch(ess->rch.aputype) { 1480 case APUTYPE_16BITSTEREO: 1481 esmch_combine_input(ess, &ess->rch); 1482 break; 1483 } 1484 ess->sc_rintr(ess->sc_rarg); 1485 } 1486 1487 } 1488 ret++; 1489 } 1490 1491 return ret; 1492 } 1493 1494 int 1495 esm_allocmem(struct esm_softc *sc, size_t size, size_t align, 1496 struct esm_dma *p) 1497 { 1498 int error; 1499 1500 p->size = size; 1501 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, 1502 p->segs, sizeof(p->segs)/sizeof(p->segs[0]), 1503 &p->nsegs, BUS_DMA_NOWAIT); 1504 if (error) 1505 return error; 1506 1507 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, 1508 &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 1509 if (error) 1510 goto free; 1511 1512 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, 1513 0, BUS_DMA_NOWAIT, &p->map); 1514 if (error) 1515 goto unmap; 1516 1517 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, 1518 BUS_DMA_NOWAIT); 1519 if (error) 1520 goto destroy; 1521 1522 return 0; 1523 1524 destroy: 1525 bus_dmamap_destroy(sc->dmat, p->map); 1526 unmap: 1527 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 1528 free: 1529 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 1530 1531 return error; 1532 } 1533 1534 int 1535 esm_match(struct device *dev, struct cfdata *match, void *aux) 1536 { 1537 struct pci_attach_args *pa; 1538 1539 pa = (struct pci_attach_args *)aux; 1540 switch (PCI_VENDOR(pa->pa_id)) { 1541 case PCI_VENDOR_ESSTECH: 1542 switch (PCI_PRODUCT(pa->pa_id)) { 1543 case PCI_PRODUCT_ESSTECH_MAESTRO1: 1544 case PCI_PRODUCT_ESSTECH_MAESTRO2: 1545 case PCI_PRODUCT_ESSTECH_MAESTRO2E: 1546 return 1; 1547 } 1548 1549 case PCI_VENDOR_ESSTECH2: 1550 switch (PCI_PRODUCT(pa->pa_id)) { 1551 case PCI_PRODUCT_ESSTECH2_MAESTRO1: 1552 return 1; 1553 } 1554 } 1555 return 0; 1556 } 1557 1558 void 1559 esm_attach(struct device *parent, struct device *self, void *aux) 1560 { 1561 char devinfo[256]; 1562 struct esm_softc *ess; 1563 struct pci_attach_args *pa; 1564 const char *intrstr; 1565 pci_chipset_tag_t pc; 1566 pcitag_t tag; 1567 pci_intr_handle_t ih; 1568 pcireg_t csr, data; 1569 int revision; 1570 uint16_t codec_data; 1571 uint16_t pcmbar; 1572 int error; 1573 1574 ess = (struct esm_softc *)self; 1575 pa = (struct pci_attach_args *)aux; 1576 pc = pa->pa_pc; 1577 tag = pa->pa_tag; 1578 aprint_naive(": Audio controller\n"); 1579 1580 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); 1581 revision = PCI_REVISION(pa->pa_class); 1582 aprint_normal(": %s (rev. 0x%02x)\n", devinfo, revision); 1583 1584 /* Enable the device. */ 1585 csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 1586 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, 1587 csr | PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE); 1588 1589 /* Map I/O register */ 1590 if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, 1591 &ess->st, &ess->sh, NULL, NULL)) { 1592 aprint_error("%s: can't map i/o space\n", ess->sc_dev.dv_xname); 1593 return; 1594 } 1595 1596 /* Initialize softc */ 1597 ess->pch.num = 0; 1598 ess->rch.num = 1; 1599 ess->dmat = pa->pa_dmat; 1600 ess->tag = tag; 1601 ess->pc = pc; 1602 ess->subid = pci_conf_read(pc, tag, PCI_SUBSYS_ID_REG); 1603 1604 DPRINTF(ESM_DEBUG_PCI, 1605 ("%s: sub-system vendor 0x%4.4x, product 0x%4.4x\n", 1606 ess->sc_dev.dv_xname, 1607 PCI_VENDOR(ess->subid), PCI_PRODUCT(ess->subid))); 1608 1609 /* Map and establish the interrupt. */ 1610 if (pci_intr_map(pa, &ih)) { 1611 aprint_error("%s: can't map interrupt\n", ess->sc_dev.dv_xname); 1612 return; 1613 } 1614 intrstr = pci_intr_string(pc, ih); 1615 ess->ih = pci_intr_establish(pc, ih, IPL_AUDIO, esm_intr, self); 1616 if (ess->ih == NULL) { 1617 aprint_error("%s: can't establish interrupt", 1618 ess->sc_dev.dv_xname); 1619 if (intrstr != NULL) 1620 aprint_normal(" at %s", intrstr); 1621 aprint_normal("\n"); 1622 return; 1623 } 1624 aprint_normal("%s: interrupting at %s\n", 1625 ess->sc_dev.dv_xname, intrstr); 1626 1627 /* 1628 * Setup PCI config registers 1629 */ 1630 1631 /* power up chip */ 1632 if ((error = pci_activate(pa->pa_pc, pa->pa_tag, ess, 1633 pci_activate_null)) && error != EOPNOTSUPP) { 1634 aprint_error("%s: cannot activate %d\n", ess->sc_dev.dv_xname, 1635 error); 1636 return; 1637 } 1638 delay(100000); 1639 1640 /* Disable all legacy emulations. */ 1641 data = pci_conf_read(pc, tag, CONF_LEGACY); 1642 pci_conf_write(pc, tag, CONF_LEGACY, data | LEGACY_DISABLED); 1643 1644 /* Disconnect from CHI. (Makes Dell inspiron 7500 work?) 1645 * Enable posted write. 1646 * Prefer PCI timing rather than that of ISA. 1647 * Don't swap L/R. */ 1648 data = pci_conf_read(pc, tag, CONF_MAESTRO); 1649 data |= MAESTRO_CHIBUS | MAESTRO_POSTEDWRITE | MAESTRO_DMA_PCITIMING; 1650 data &= ~MAESTRO_SWAP_LR; 1651 pci_conf_write(pc, tag, CONF_MAESTRO, data); 1652 1653 /* initialize sound chip */ 1654 esm_init(ess); 1655 1656 esm_read_codec(ess, 0, &codec_data); 1657 if (codec_data == 0x80) { 1658 aprint_error("%s: PT101 codec detected!\n", 1659 ess->sc_dev.dv_xname); 1660 return; 1661 } 1662 1663 /* 1664 * Some cards and Notebooks appear to have left and right channels 1665 * reversed. Check if there is a corresponding quirk entry for 1666 * the subsystem vendor and product and if so, set the appropriate 1667 * codec flag. 1668 */ 1669 if (esm_get_quirks(ess->subid) & ESM_QUIRKF_SWAPPEDCH) { 1670 ess->codec_flags |= AC97_HOST_SWAPPED_CHANNELS; 1671 } 1672 ess->codec_flags |= AC97_HOST_DONT_READ; 1673 1674 /* initialize AC97 host interface */ 1675 ess->host_if.arg = self; 1676 ess->host_if.attach = esm_attach_codec; 1677 ess->host_if.read = esm_read_codec; 1678 ess->host_if.write = esm_write_codec; 1679 ess->host_if.reset = esm_reset_codec; 1680 ess->host_if.flags = esm_flags_codec; 1681 1682 if (ac97_attach(&ess->host_if, self) != 0) 1683 return; 1684 1685 /* allocate our DMA region */ 1686 if (esm_allocmem(ess, MAESTRO_DMA_SZ, MAESTRO_DMA_ALIGN, 1687 &ess->sc_dma)) { 1688 aprint_error("%s: couldn't allocate memory!\n", 1689 ess->sc_dev.dv_xname); 1690 return; 1691 } 1692 ess->rings_alloced = 0; 1693 1694 /* set DMA base address */ 1695 for (pcmbar = WAVCACHE_PCMBAR; pcmbar < WAVCACHE_PCMBAR + 4; pcmbar++) 1696 wc_wrreg(ess, pcmbar, 1697 DMAADDR(&ess->sc_dma) >> WAVCACHE_BASEADDR_SHIFT); 1698 1699 audio_attach_mi(&esm_hw_if, self, &ess->sc_dev); 1700 1701 ess->esm_suspend = PWR_RESUME; 1702 ess->esm_powerhook = powerhook_establish(esm_powerhook, ess); 1703 } 1704 1705 /* Power Hook */ 1706 void 1707 esm_powerhook(int why, void *v) 1708 { 1709 struct esm_softc *ess; 1710 1711 ess = (struct esm_softc *)v; 1712 DPRINTF(ESM_DEBUG_PARAM, 1713 ("%s: ESS maestro 2E why=%d\n", ess->sc_dev.dv_xname, why)); 1714 switch (why) { 1715 case PWR_SUSPEND: 1716 case PWR_STANDBY: 1717 ess->esm_suspend = why; 1718 esm_suspend(ess); 1719 DPRINTF(ESM_DEBUG_RESUME, ("esm_suspend\n")); 1720 break; 1721 1722 case PWR_RESUME: 1723 ess->esm_suspend = why; 1724 esm_resume(ess); 1725 DPRINTF(ESM_DEBUG_RESUME, ("esm_resumed\n")); 1726 break; 1727 } 1728 } 1729 1730 int 1731 esm_suspend(struct esm_softc *ess) 1732 { 1733 int x; 1734 int error; 1735 1736 x = splaudio(); 1737 wp_stoptimer(ess); 1738 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); 1739 1740 esm_halt_output(ess); 1741 esm_halt_input(ess); 1742 splx(x); 1743 1744 /* Power down everything except clock. */ 1745 esm_write_codec(ess, AC97_REG_POWER, 0xdf00); 1746 delay(20); 1747 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); 1748 delay(1); 1749 if ((error = pci_set_powerstate(ess->pc, ess->tag, PCI_PMCSR_STATE_D3))) 1750 return error; 1751 1752 return 0; 1753 } 1754 1755 int 1756 esm_resume(struct esm_softc *ess) 1757 { 1758 int x; 1759 int error; 1760 1761 if ((error = pci_set_powerstate(ess->pc, ess->tag, PCI_PMCSR_STATE_D0))) 1762 return error; 1763 delay(100000); 1764 esm_init(ess); 1765 1766 ess->codec_if->vtbl->restore_ports(ess->codec_if); 1767 #if 0 1768 if (mixer_reinit(dev)) { 1769 printf("%s: unable to reinitialize the mixer\n", 1770 ess->sc_dev.dv_xname); 1771 return ENXIO; 1772 } 1773 #endif 1774 1775 x = splaudio(); 1776 #if TODO 1777 if (ess->pactive) 1778 esm_start_output(ess); 1779 if (ess->ractive) 1780 esm_start_input(ess); 1781 #endif 1782 if (ess->pactive || ess->ractive) { 1783 set_timer(ess); 1784 wp_starttimer(ess); 1785 } 1786 splx(x); 1787 return 0; 1788 } 1789 1790 #if 0 1791 int 1792 esm_shutdown(struct esm_softc *ess) 1793 { 1794 int i; 1795 1796 wp_stoptimer(ess); 1797 bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); 1798 1799 esm_halt_output(ess); 1800 esm_halt_input(ess); 1801 1802 return 0; 1803 } 1804 #endif 1805