The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/pci/esm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 358b9dcaa5f6b451949bf5358f0845b3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.