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/sound/pci/maestro.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 /*-
    2  * Copyright (c) 2000-2004 Taku YAMAMOTO <taku@tackymt.homeip.net>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  *      $Id: maestro.c,v 1.18 2003/07/01 15:52:01 scottl Exp $
   27  */
   28 
   29 /*
   30  * Credits:
   31  *
   32  * Part of this code (especially in many magic numbers) was heavily inspired
   33  * by the Linux driver originally written by
   34  * Alan Cox <alan.cox@linux.org>, modified heavily by
   35  * Zach Brown <zab@zabbo.net>.
   36  *
   37  * busdma()-ize and buffer size reduction were suggested by
   38  * Cameron Grant <cg@freebsd.org>.
   39  * Also he showed me the way to use busdma() suite.
   40  *
   41  * Internal speaker problems on NEC VersaPro's and Dell Inspiron 7500
   42  * were looked at by
   43  * Munehiro Matsuda <haro@tk.kubota.co.jp>,
   44  * who brought patches based on the Linux driver with some simplification.
   45  */
   46 
   47 #include <dev/sound/pcm/sound.h>
   48 #include <dev/sound/pcm/ac97.h>
   49 #include <dev/pci/pcireg.h>
   50 #include <dev/pci/pcivar.h>
   51 
   52 #include <dev/sound/pci/maestro_reg.h>
   53 
   54 SND_DECLARE_FILE("$FreeBSD$");
   55 
   56 #define inline __inline
   57 
   58 /*
   59  * PCI IDs of supported chips:
   60  *
   61  * MAESTRO-1    0x01001285
   62  * MAESTRO-2    0x1968125d
   63  * MAESTRO-2E   0x1978125d
   64  */
   65 
   66 #define MAESTRO_1_PCI_ID        0x01001285
   67 #define MAESTRO_2_PCI_ID        0x1968125d
   68 #define MAESTRO_2E_PCI_ID       0x1978125d
   69 
   70 #define NEC_SUBID1      0x80581033      /* Taken from Linux driver */
   71 #define NEC_SUBID2      0x803c1033      /* NEC VersaProNX VA26D    */
   72 
   73 #ifndef AGG_MAXPLAYCH
   74 # define AGG_MAXPLAYCH  4
   75 #endif
   76 
   77 #define AGG_DEFAULT_BUFSZ       0x4000 /* 0x1000, but gets underflows */
   78 
   79 
   80 /* -----------------------------
   81  * Data structures.
   82  */
   83 struct agg_chinfo {
   84         struct agg_info         *parent;
   85         struct pcm_channel      *channel;
   86         struct snd_dbuf         *buffer;
   87         bus_addr_t              offset;
   88         u_int32_t               blocksize;
   89         u_int32_t               speed;
   90         int                     dir;
   91         u_int                   num;
   92         u_int16_t               aputype;
   93         u_int16_t               wcreg_tpl;
   94 };
   95 
   96 struct agg_info {
   97         device_t                dev;
   98         struct resource         *reg;
   99         int                     regid;
  100 
  101         bus_space_tag_t         st;
  102         bus_space_handle_t      sh;
  103         bus_dma_tag_t           parent_dmat;
  104 
  105         struct resource         *irq;
  106         int                     irqid;
  107         void                    *ih;
  108 
  109         u_int8_t                *stat;
  110         bus_addr_t              baseaddr;
  111 
  112         struct ac97_info        *codec;
  113         struct mtx              *lock;
  114 
  115         unsigned int            bufsz;
  116         u_int                   playchns, active;
  117         struct agg_chinfo       pch[AGG_MAXPLAYCH];
  118         struct agg_chinfo       rch;
  119 };
  120 
  121 static inline void       ringbus_setdest(struct agg_info*, int, int);
  122 
  123 static inline u_int16_t  wp_rdreg(struct agg_info*, u_int16_t);
  124 static inline void       wp_wrreg(struct agg_info*, u_int16_t, u_int16_t);
  125 static inline u_int16_t  wp_rdapu(struct agg_info*, int, u_int16_t);
  126 static inline void       wp_wrapu(struct agg_info*, int, u_int16_t, u_int16_t);
  127 static inline void       wp_settimer(struct agg_info*, u_int);
  128 static inline void       wp_starttimer(struct agg_info*);
  129 static inline void       wp_stoptimer(struct agg_info*);
  130 
  131 static inline u_int16_t  wc_rdreg(struct agg_info*, u_int16_t);
  132 static inline void       wc_wrreg(struct agg_info*, u_int16_t, u_int16_t);
  133 static inline u_int16_t  wc_rdchctl(struct agg_info*, int);
  134 static inline void       wc_wrchctl(struct agg_info*, int, u_int16_t);
  135 
  136 static inline void       agg_power(struct agg_info*, int);
  137 
  138 static void              agg_init(struct agg_info*);
  139 
  140 static void              aggch_start_dac(struct agg_chinfo*);
  141 static void              aggch_stop_dac(struct agg_chinfo*);
  142 
  143 static inline void       suppress_jitter(struct agg_chinfo*);
  144 
  145 static inline u_int      calc_timer_freq(struct agg_chinfo*);
  146 static void              set_timer(struct agg_info*);
  147 
  148 static void              agg_intr(void *);
  149 static int               agg_probe(device_t);
  150 static int               agg_attach(device_t);
  151 static int               agg_detach(device_t);
  152 static int               agg_suspend(device_t);
  153 static int               agg_resume(device_t);
  154 static int               agg_shutdown(device_t);
  155 
  156 static void     *dma_malloc(struct agg_info*, u_int32_t, bus_addr_t*);
  157 static void      dma_free(struct agg_info*, void *);
  158 
  159 /* -----------------------------
  160  * Subsystems.
  161  */
  162 
  163 /* Codec/Ringbus */
  164 
  165 /* -------------------------------------------------------------------- */
  166 
  167 static u_int32_t
  168 agg_ac97_init(kobj_t obj, void *sc)
  169 {
  170         struct agg_info *ess = sc;
  171 
  172         return (bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) & CODEC_STAT_MASK)? 0 : 1;
  173 }
  174 
  175 static int
  176 agg_rdcodec(kobj_t obj, void *sc, int regno)
  177 {
  178         struct agg_info *ess = sc;
  179         unsigned t;
  180 
  181         /* We have to wait for a SAFE time to write addr/data */
  182         for (t = 0; t < 20; t++) {
  183                 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT)
  184                     & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS)
  185                         break;
  186                 DELAY(2);       /* 20.8us / 13 */
  187         }
  188         if (t == 20)
  189                 device_printf(ess->dev, "agg_rdcodec() PROGLESS timed out.\n");
  190 
  191         bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD,
  192             CODEC_CMD_READ | regno);
  193         DELAY(21);      /* AC97 cycle = 20.8usec */
  194 
  195         /* Wait for data retrieve */
  196         for (t = 0; t < 20; t++) {
  197                 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT)
  198                     & CODEC_STAT_MASK) == CODEC_STAT_RW_DONE)
  199                         break;
  200                 DELAY(2);       /* 20.8us / 13 */
  201         }
  202         if (t == 20)
  203                 /* Timed out, but perform dummy read. */
  204                 device_printf(ess->dev, "agg_rdcodec() RW_DONE timed out.\n");
  205 
  206         return bus_space_read_2(ess->st, ess->sh, PORT_CODEC_REG);
  207 }
  208 
  209 static int
  210 agg_wrcodec(kobj_t obj, void *sc, int regno, u_int32_t data)
  211 {
  212         unsigned t;
  213         struct agg_info *ess = sc;
  214 
  215         /* We have to wait for a SAFE time to write addr/data */
  216         for (t = 0; t < 20; t++) {
  217                 if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT)
  218                     & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS)
  219                         break;
  220                 DELAY(2);       /* 20.8us / 13 */
  221         }
  222         if (t == 20) {
  223                 /* Timed out. Abort writing. */
  224                 device_printf(ess->dev, "agg_wrcodec() PROGLESS timed out.\n");
  225                 return -1;
  226         }
  227 
  228         bus_space_write_2(ess->st, ess->sh, PORT_CODEC_REG, data);
  229         bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD,
  230             CODEC_CMD_WRITE | regno);
  231 
  232         return 0;
  233 }
  234 
  235 static kobj_method_t agg_ac97_methods[] = {
  236         KOBJMETHOD(ac97_init,           agg_ac97_init),
  237         KOBJMETHOD(ac97_read,           agg_rdcodec),
  238         KOBJMETHOD(ac97_write,          agg_wrcodec),
  239         { 0, 0 }
  240 };
  241 AC97_DECLARE(agg_ac97);
  242 
  243 /* -------------------------------------------------------------------- */
  244 
  245 static inline void
  246 ringbus_setdest(struct agg_info *ess, int src, int dest)
  247 {
  248         u_int32_t       data;
  249 
  250         data = bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL);
  251         data &= ~(0xfU << src);
  252         data |= (0xfU & dest) << src;
  253         bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, data);
  254 }
  255 
  256 /* Wave Processor */
  257 
  258 static inline u_int16_t
  259 wp_rdreg(struct agg_info *ess, u_int16_t reg)
  260 {
  261         bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg);
  262         return bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA);
  263 }
  264 
  265 static inline void
  266 wp_wrreg(struct agg_info *ess, u_int16_t reg, u_int16_t data)
  267 {
  268         bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg);
  269         bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data);
  270 }
  271 
  272 static inline void
  273 apu_setindex(struct agg_info *ess, u_int16_t reg)
  274 {
  275         int t;
  276 
  277         wp_wrreg(ess, WPREG_CRAM_PTR, reg);
  278         /* Sometimes WP fails to set apu register index. */
  279         for (t = 0; t < 1000; t++) {
  280                 if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == reg)
  281                         break;
  282                 bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, reg);
  283         }
  284         if (t == 1000)
  285                 device_printf(ess->dev, "apu_setindex() timed out.\n");
  286 }
  287 
  288 static inline u_int16_t
  289 wp_rdapu(struct agg_info *ess, int ch, u_int16_t reg)
  290 {
  291         u_int16_t ret;
  292 
  293         apu_setindex(ess, ((unsigned)ch << 4) + reg);
  294         ret = wp_rdreg(ess, WPREG_DATA_PORT);
  295         return ret;
  296 }
  297 
  298 static inline void
  299 wp_wrapu(struct agg_info *ess, int ch, u_int16_t reg, u_int16_t data)
  300 {
  301         int t;
  302 
  303         apu_setindex(ess, ((unsigned)ch << 4) + reg);
  304         wp_wrreg(ess, WPREG_DATA_PORT, data);
  305         for (t = 0; t < 1000; t++) {
  306                 if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == data)
  307                         break;
  308                 bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data);
  309         }
  310         if (t == 1000)
  311                 device_printf(ess->dev, "wp_wrapu() timed out.\n");
  312 }
  313 
  314 static inline void
  315 wp_settimer(struct agg_info *ess, u_int freq)
  316 {
  317         u_int clock = 48000 << 2;
  318         u_int prescale = 0, divide = (freq != 0) ? (clock / freq) : ~0;
  319 
  320         RANGE(divide, 4, 32 << 8);
  321 
  322         for (; divide > 32 << 1; divide >>= 1)
  323                 prescale++;
  324         divide = (divide + 1) >> 1;
  325 
  326         for (; prescale < 7 && divide > 2 && !(divide & 1); divide >>= 1)
  327                 prescale++;
  328 
  329         wp_wrreg(ess, WPREG_TIMER_ENABLE, 0);
  330         wp_wrreg(ess, WPREG_TIMER_FREQ,
  331             (prescale << WP_TIMER_FREQ_PRESCALE_SHIFT) | (divide - 1));
  332         wp_wrreg(ess, WPREG_TIMER_ENABLE, 1);
  333 }
  334 
  335 static inline void
  336 wp_starttimer(struct agg_info *ess)
  337 {
  338         wp_wrreg(ess, WPREG_TIMER_START, 1);
  339 }
  340 
  341 static inline void
  342 wp_stoptimer(struct agg_info *ess)
  343 {
  344         wp_wrreg(ess, WPREG_TIMER_START, 0);
  345         bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1);
  346 }
  347 
  348 /* WaveCache */
  349 
  350 static inline u_int16_t
  351 wc_rdreg(struct agg_info *ess, u_int16_t reg)
  352 {
  353         bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg);
  354         return bus_space_read_2(ess->st, ess->sh, PORT_WAVCACHE_DATA);
  355 }
  356 
  357 static inline void
  358 wc_wrreg(struct agg_info *ess, u_int16_t reg, u_int16_t data)
  359 {
  360         bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg);
  361         bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_DATA, data);
  362 }
  363 
  364 static inline u_int16_t
  365 wc_rdchctl(struct agg_info *ess, int ch)
  366 {
  367         return wc_rdreg(ess, ch << 3);
  368 }
  369 
  370 static inline void
  371 wc_wrchctl(struct agg_info *ess, int ch, u_int16_t data)
  372 {
  373         wc_wrreg(ess, ch << 3, data);
  374 }
  375 
  376 /* Power management */
  377 
  378 static inline void
  379 agg_power(struct agg_info *ess, int status)
  380 {
  381         u_int8_t data;
  382 
  383         data = pci_read_config(ess->dev, CONF_PM_PTR, 1);
  384         if (pci_read_config(ess->dev, data, 1) == PPMI_CID)
  385                 pci_write_config(ess->dev, data + PM_CTRL, status, 1);
  386 }
  387 
  388 
  389 /* -----------------------------
  390  * Controller.
  391  */
  392 
  393 static inline void
  394 agg_initcodec(struct agg_info* ess)
  395 {
  396         u_int16_t data;
  397 
  398         if (bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL)
  399             & RINGBUS_CTRL_ACLINK_ENABLED) {
  400                 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0);
  401                 DELAY(104);     /* 20.8us * (4 + 1) */
  402         }
  403         /* XXX - 2nd codec should be looked at. */
  404         bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL,
  405             RINGBUS_CTRL_AC97_SWRESET);
  406         DELAY(2);
  407         bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL,
  408             RINGBUS_CTRL_ACLINK_ENABLED);
  409         DELAY(21);
  410 
  411         agg_rdcodec(NULL, ess, 0);
  412         if (bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT)
  413             & CODEC_STAT_MASK) {
  414                 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0);
  415                 DELAY(21);
  416 
  417                 /* Try cold reset. */
  418                 device_printf(ess->dev, "will perform cold reset.\n");
  419                 data = bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR);
  420                 if (pci_read_config(ess->dev, 0x58, 2) & 1)
  421                         data |= 0x10;
  422                 data |= 0x009 &
  423                     ~bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DATA);
  424                 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 0xff6);
  425                 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR,
  426                     data | 0x009);
  427                 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x000);
  428                 DELAY(2);
  429                 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x001);
  430                 DELAY(1);
  431                 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x009);
  432                 DELAY(500000);
  433                 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, data);
  434                 DELAY(84);      /* 20.8us * 4 */
  435                 bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL,
  436                     RINGBUS_CTRL_ACLINK_ENABLED);
  437                 DELAY(21);
  438         }
  439 }
  440 
  441 static void
  442 agg_init(struct agg_info* ess)
  443 {
  444         u_int32_t data;
  445 
  446         /* Setup PCI config registers. */
  447 
  448         /* Disable all legacy emulations. */
  449         data = pci_read_config(ess->dev, CONF_LEGACY, 2);
  450         data |= LEGACY_DISABLED;
  451         pci_write_config(ess->dev, CONF_LEGACY, data, 2);
  452 
  453         /* Disconnect from CHI. (Makes Dell inspiron 7500 work?)
  454          * Enable posted write.
  455          * Prefer PCI timing rather than that of ISA.
  456          * Don't swap L/R. */
  457         data = pci_read_config(ess->dev, CONF_MAESTRO, 4);
  458         data |= MAESTRO_CHIBUS | MAESTRO_POSTEDWRITE | MAESTRO_DMA_PCITIMING;
  459         data &= ~MAESTRO_SWAP_LR;
  460         pci_write_config(ess->dev, CONF_MAESTRO, data, 4);
  461 
  462         /* Reset direct sound. */
  463         bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL,
  464             HOSTINT_CTRL_DSOUND_RESET);
  465         DELAY(10000);   /* XXX - too long? */
  466         bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0);
  467         DELAY(10000);
  468 
  469         /* Enable direct sound interruption and hardware volume control. */
  470         bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL,
  471             HOSTINT_CTRL_DSOUND_INT_ENABLED | HOSTINT_CTRL_HWVOL_ENABLED);
  472 
  473         /* Setup Wave Processor. */
  474 
  475         /* Enable WaveCache, set DMA base address. */
  476         wp_wrreg(ess, WPREG_WAVE_ROMRAM,
  477             WP_WAVE_VIRTUAL_ENABLED | WP_WAVE_DRAM_ENABLED);
  478         bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_CTRL,
  479             WAVCACHE_ENABLED | WAVCACHE_WTSIZE_4MB);
  480 
  481         for (data = WAVCACHE_PCMBAR; data < WAVCACHE_PCMBAR + 4; data++)
  482                 wc_wrreg(ess, data, ess->baseaddr >> WAVCACHE_BASEADDR_SHIFT);
  483 
  484         /* Setup Codec/Ringbus. */
  485         agg_initcodec(ess);
  486         bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL,
  487             RINGBUS_CTRL_RINGBUS_ENABLED | RINGBUS_CTRL_ACLINK_ENABLED);
  488 
  489         wp_wrreg(ess, WPREG_BASE, 0x8500);      /* Parallel I/O */
  490         ringbus_setdest(ess, RINGBUS_SRC_ADC,
  491             RINGBUS_DEST_STEREO | RINGBUS_DEST_DSOUND_IN);
  492         ringbus_setdest(ess, RINGBUS_SRC_DSOUND,
  493             RINGBUS_DEST_STEREO | RINGBUS_DEST_DAC);
  494 
  495         /* Setup ASSP. Needed for Dell Inspiron 7500? */
  496         bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_B, 0x00);
  497         bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_A, 0x03);
  498         bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_C, 0x00);
  499 
  500         /*
  501          * Setup GPIO.
  502          * There seems to be speciality with NEC systems.
  503          */
  504         switch (pci_get_subvendor(ess->dev)
  505             | (pci_get_subdevice(ess->dev) << 16)) {
  506         case NEC_SUBID1:
  507         case NEC_SUBID2:
  508                 /* Matthew Braithwaite <matt@braithwaite.net> reported that
  509                  * NEC Versa LX doesn't need GPIO operation. */
  510                 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 0x9ff);
  511                 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR,
  512                     bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR) | 0x600);
  513                 bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x200);
  514                 break;
  515         }
  516 }
  517 
  518 /* Channel controller. */
  519 
  520 static void
  521 aggch_start_dac(struct agg_chinfo *ch)
  522 {
  523         bus_addr_t wpwa = APU_USE_SYSMEM | (ch->offset >> 9);
  524         u_int size = ch->parent->bufsz >> 1;
  525         u_int speed = ch->speed;
  526         bus_addr_t offset = ch->offset >> 1;
  527         u_int cp = 0;
  528         u_int16_t apuch = ch->num << 1;
  529         u_int dv;
  530         int pan = 0;
  531 
  532         switch (ch->aputype) {
  533         case APUTYPE_16BITSTEREO:
  534                 wpwa >>= 1;
  535                 size >>= 1;
  536                 offset >>= 1;
  537                 cp >>= 1;
  538                 /* FALLTHROUGH */
  539         case APUTYPE_8BITSTEREO:
  540                 pan = 8;
  541                 apuch++;
  542                 break;
  543         case APUTYPE_8BITLINEAR:
  544                 speed >>= 1;
  545                 break;
  546         }
  547 
  548         dv = (((speed % 48000) << 16) + 24000) / 48000
  549             + ((speed / 48000) << 16);
  550 
  551         do {
  552                 wp_wrapu(ch->parent, apuch, APUREG_WAVESPACE, wpwa & 0xff00);
  553                 wp_wrapu(ch->parent, apuch, APUREG_CURPTR, offset + cp);
  554                 wp_wrapu(ch->parent, apuch, APUREG_ENDPTR, offset + size);
  555                 wp_wrapu(ch->parent, apuch, APUREG_LOOPLEN, size);
  556                 wp_wrapu(ch->parent, apuch, APUREG_AMPLITUDE, 0xe800);
  557                 wp_wrapu(ch->parent, apuch, APUREG_POSITION, 0x8f00
  558                     | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT)
  559                     | ((PAN_FRONT + pan) << APU_PAN_SHIFT));
  560                 wp_wrapu(ch->parent, apuch, APUREG_FREQ_LOBYTE, APU_plus6dB
  561                     | ((dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
  562                 wp_wrapu(ch->parent, apuch, APUREG_FREQ_HIWORD, dv >> 8);
  563 
  564                 if (ch->aputype == APUTYPE_16BITSTEREO)
  565                         wpwa |= APU_STEREO >> 1;
  566                 pan = -pan;
  567         } while (pan < 0 && apuch--);
  568 
  569         wc_wrchctl(ch->parent, apuch, ch->wcreg_tpl);
  570         wc_wrchctl(ch->parent, apuch + 1, ch->wcreg_tpl);
  571 
  572         wp_wrapu(ch->parent, apuch, APUREG_APUTYPE,
  573             (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
  574         if (ch->wcreg_tpl & WAVCACHE_CHCTL_STEREO)
  575                 wp_wrapu(ch->parent, apuch + 1, APUREG_APUTYPE,
  576                     (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
  577 }
  578 
  579 static void
  580 aggch_stop_dac(struct agg_chinfo *ch)
  581 {
  582         wp_wrapu(ch->parent, (ch->num << 1), APUREG_APUTYPE,
  583             APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
  584         wp_wrapu(ch->parent, (ch->num << 1) + 1, APUREG_APUTYPE,
  585             APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
  586 }
  587 
  588 /*
  589  * Stereo jitter suppressor.
  590  * Sometimes playback pointers differ in stereo-paired channels.
  591  * Calling this routine within intr fixes the problem.
  592  */
  593 static inline void
  594 suppress_jitter(struct agg_chinfo *ch)
  595 {
  596         if (ch->wcreg_tpl & WAVCACHE_CHCTL_STEREO) {
  597                 int cp, diff, halfsize = ch->parent->bufsz >> 2;
  598 
  599                 if (ch->aputype == APUTYPE_16BITSTEREO)
  600                         halfsize >>= 1;
  601                 cp = wp_rdapu(ch->parent, (ch->num << 1), APUREG_CURPTR);
  602                 diff = wp_rdapu(ch->parent, (ch->num << 1) + 1, APUREG_CURPTR);
  603                 diff -= cp;
  604                 if (diff >> 1 && diff > -halfsize && diff < halfsize)
  605                         bus_space_write_2(ch->parent->st, ch->parent->sh,
  606                             PORT_DSP_DATA, cp);
  607         }
  608 }
  609 
  610 static inline u_int
  611 calc_timer_freq(struct agg_chinfo *ch)
  612 {
  613         u_int   ss = 2;
  614 
  615         if (ch->aputype == APUTYPE_16BITSTEREO)
  616                 ss <<= 1;
  617         if (ch->aputype == APUTYPE_8BITLINEAR)
  618                 ss >>= 1;
  619 
  620         return (ch->speed * ss) / ch->blocksize;
  621 }
  622 
  623 static void
  624 set_timer(struct agg_info *ess)
  625 {
  626         int i;
  627         u_int   freq = 0;
  628 
  629         for (i = 0; i < ess->playchns; i++)
  630                 if ((ess->active & (1 << i)) &&
  631                     (freq < calc_timer_freq(ess->pch + i)))
  632                         freq = calc_timer_freq(ess->pch + i);
  633 
  634         wp_settimer(ess, freq);
  635 }
  636 
  637 
  638 /* -----------------------------
  639  * Newpcm glue.
  640  */
  641 
  642 static void *
  643 aggch_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
  644 {
  645         struct agg_info *ess = devinfo;
  646         struct agg_chinfo *ch;
  647         bus_addr_t physaddr;
  648         void *p;
  649 
  650         ch = (dir == PCMDIR_PLAY)? ess->pch + ess->playchns : &ess->rch;
  651 
  652         ch->parent = ess;
  653         ch->channel = c;
  654         ch->buffer = b;
  655         ch->num = ess->playchns;
  656         ch->dir = dir;
  657 
  658         physaddr = ess->baseaddr + ch->offset;
  659         p = ess->stat + ch->offset;
  660         sndbuf_setup(b, p, ess->bufsz);
  661 
  662         ch->wcreg_tpl = (physaddr - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
  663 
  664         if (dir == PCMDIR_PLAY) {
  665                 ess->playchns++;
  666                 if (bootverbose)
  667                         device_printf(ess->dev, "pch[%d].offset = %#llx\n", ch->num, (long long)ch->offset);
  668         } else if (bootverbose)
  669                 device_printf(ess->dev, "rch.offset = %#llx\n", (long long)ch->offset);
  670 
  671         return ch;
  672 }
  673 
  674 static int
  675 aggch_free(kobj_t obj, void *data)
  676 {
  677         /* return 0 if ok */
  678         return 0;
  679 }
  680 
  681 static int
  682 aggch_setplayformat(kobj_t obj, void *data, u_int32_t format)
  683 {
  684         struct agg_chinfo *ch = data;
  685         u_int16_t wcreg_tpl;
  686         u_int16_t aputype = APUTYPE_16BITLINEAR;
  687 
  688         wcreg_tpl = ch->wcreg_tpl & WAVCACHE_CHCTL_ADDRTAG_MASK;
  689 
  690         if (format & AFMT_STEREO) {
  691                 wcreg_tpl |= WAVCACHE_CHCTL_STEREO;
  692                 aputype += 1;
  693         }
  694         if (format & AFMT_U8 || format & AFMT_S8) {
  695                 aputype += 2;
  696                 if (format & AFMT_U8)
  697                         wcreg_tpl |= WAVCACHE_CHCTL_U8;
  698         }
  699         if (format & AFMT_BIGENDIAN || format & AFMT_U16_LE) {
  700                 format &= ~AFMT_BIGENDIAN & ~AFMT_U16_LE;
  701                 format |= AFMT_S16_LE;
  702         }
  703         ch->wcreg_tpl = wcreg_tpl;
  704         ch->aputype = aputype;
  705         return 0;
  706 }
  707 
  708 static int
  709 aggch_setspeed(kobj_t obj, void *data, u_int32_t speed)
  710 {
  711         struct agg_chinfo *ch = data;
  712 
  713         ch->speed = speed;
  714         return ch->speed;
  715 }
  716 
  717 static int
  718 aggch_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
  719 {
  720         return ((struct agg_chinfo*)data)->blocksize = blocksize;
  721 }
  722 
  723 static int
  724 aggch_trigger(kobj_t obj, void *data, int go)
  725 {
  726         struct agg_chinfo *ch = data;
  727 
  728         switch (go) {
  729         case PCMTRIG_EMLDMAWR:
  730                 return 0;
  731         case PCMTRIG_START:
  732                 ch->parent->active |= (1 << ch->num);
  733                 if (ch->dir == PCMDIR_PLAY)
  734                         aggch_start_dac(ch);
  735 #if 0   /* XXX - RECORDING */
  736                 else
  737                         aggch_start_adc(ch);
  738 #endif
  739                 break;
  740         case PCMTRIG_ABORT:
  741         case PCMTRIG_STOP:
  742                 ch->parent->active &= ~(1 << ch->num);
  743                 if (ch->dir == PCMDIR_PLAY)
  744                         aggch_stop_dac(ch);
  745 #if 0   /* XXX - RECORDING */
  746                 else
  747                         aggch_stop_adc(ch);
  748 #endif
  749                 break;
  750         }
  751 
  752         if (ch->parent->active) {
  753                 set_timer(ch->parent);
  754                 wp_starttimer(ch->parent);
  755         } else
  756                 wp_stoptimer(ch->parent);
  757 
  758         return 0;
  759 }
  760 
  761 static int
  762 aggch_getplayptr(kobj_t obj, void *data)
  763 {
  764         struct agg_chinfo *ch = data;
  765         u_int cp;
  766 
  767         cp = wp_rdapu(ch->parent, (ch->num << 1), APUREG_CURPTR);
  768         if (ch->aputype == APUTYPE_16BITSTEREO)
  769                 cp = (0xffff << 2) & ((cp << 2) - ch->offset);
  770         else
  771                 cp = (0xffff << 1) & ((cp << 1) - ch->offset);
  772 
  773         return cp;
  774 }
  775 
  776 static struct pcmchan_caps *
  777 aggch_getcaps(kobj_t obj, void *data)
  778 {
  779         static u_int32_t playfmt[] = {
  780                 AFMT_U8,
  781                 AFMT_STEREO | AFMT_U8,
  782                 AFMT_S8,
  783                 AFMT_STEREO | AFMT_S8,
  784                 AFMT_S16_LE,
  785                 AFMT_STEREO | AFMT_S16_LE,
  786                 0
  787         };
  788         static struct pcmchan_caps playcaps = {2000, 96000, playfmt, 0};
  789 
  790         static u_int32_t recfmt[] = {
  791                 AFMT_S8,
  792                 AFMT_STEREO | AFMT_S8,
  793                 AFMT_S16_LE,
  794                 AFMT_STEREO | AFMT_S16_LE,
  795                 0
  796         };
  797         static struct pcmchan_caps reccaps = {4000, 48000, recfmt, 0};
  798 
  799         return (((struct agg_chinfo*)data)->dir == PCMDIR_PLAY)?
  800             &playcaps : &reccaps;
  801 }
  802 
  803 static kobj_method_t aggch_methods[] = {
  804         KOBJMETHOD(channel_init,                aggch_init),
  805         KOBJMETHOD(channel_free,                aggch_free),
  806         KOBJMETHOD(channel_setformat,           aggch_setplayformat),
  807         KOBJMETHOD(channel_setspeed,            aggch_setspeed),
  808         KOBJMETHOD(channel_setblocksize,        aggch_setblocksize),
  809         KOBJMETHOD(channel_trigger,             aggch_trigger),
  810         KOBJMETHOD(channel_getptr,              aggch_getplayptr),
  811         KOBJMETHOD(channel_getcaps,             aggch_getcaps),
  812         { 0, 0 }
  813 };
  814 CHANNEL_DECLARE(aggch);
  815 
  816 /* -----------------------------
  817  * Bus space.
  818  */
  819 
  820 static void
  821 agg_intr(void *sc)
  822 {
  823         struct agg_info* ess = sc;
  824         u_int16_t status;
  825         int i;
  826 
  827         status = bus_space_read_1(ess->st, ess->sh, PORT_HOSTINT_STAT);
  828         if (!status)
  829                 return;
  830 
  831         /* Acknowledge all. */
  832         bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1);
  833         bus_space_write_1(ess->st, ess->sh, PORT_HOSTINT_STAT, 0xff);
  834 
  835         if (status & HOSTINT_STAT_HWVOL) {
  836                 u_int event;
  837 
  838                 event = bus_space_read_1(ess->st, ess->sh, PORT_HWVOL_MASTER);
  839                 switch (event) {
  840                 case HWVOL_MUTE:
  841                         mixer_hwvol_mute(ess->dev);
  842                         break;
  843                 case HWVOL_UP:
  844                         mixer_hwvol_step(ess->dev, 1, 1);
  845                         break;
  846                 case HWVOL_DOWN:
  847                         mixer_hwvol_step(ess->dev, -1, -1);
  848                         break;
  849                 case HWVOL_NOP:
  850                         break;
  851                 default:
  852                         device_printf(ess->dev, "%s: unknown HWVOL event 0x%x\n",
  853                             device_get_nameunit(ess->dev), event);
  854                 }
  855                 bus_space_write_1(ess->st, ess->sh, PORT_HWVOL_MASTER,
  856                     HWVOL_NOP);
  857         }
  858 
  859         for (i = 0; i < ess->playchns; i++)
  860                 if (ess->active & (1 << i)) {
  861                         suppress_jitter(ess->pch + i);
  862                         chn_intr(ess->pch[i].channel);
  863                 }
  864 #if 0   /* XXX - RECORDING */
  865         if (ess->active & (1 << i))
  866                 chn_intr(ess->rch.channel);
  867 #endif
  868 }
  869 
  870 static void
  871 setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
  872 {
  873         bus_addr_t *phys = arg;
  874 
  875         *phys = error? 0 : segs->ds_addr;
  876 
  877         if (bootverbose) {
  878                 printf("setmap (%lx, %lx), nseg=%d, error=%d\n",
  879                     (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len,
  880                     nseg, error);
  881         }
  882 }
  883 
  884 static void *
  885 dma_malloc(struct agg_info *sc, u_int32_t sz, bus_addr_t *phys)
  886 {
  887         void *buf;
  888         bus_dmamap_t map;
  889 
  890         if (bus_dmamem_alloc(sc->parent_dmat, &buf, BUS_DMA_NOWAIT, &map))
  891                 return NULL;
  892         if (bus_dmamap_load(sc->parent_dmat, map, buf, sz, setmap, phys, 0)
  893             || !*phys) {
  894                 bus_dmamem_free(sc->parent_dmat, buf, map);
  895                 return NULL;
  896         }
  897         return buf;
  898 }
  899 
  900 static void
  901 dma_free(struct agg_info *sc, void *buf)
  902 {
  903         bus_dmamem_free(sc->parent_dmat, buf, NULL);
  904 }
  905 
  906 static int
  907 agg_probe(device_t dev)
  908 {
  909         char *s = NULL;
  910 
  911         switch (pci_get_devid(dev)) {
  912         case MAESTRO_1_PCI_ID:
  913                 s = "ESS Technology Maestro-1";
  914                 break;
  915 
  916         case MAESTRO_2_PCI_ID:
  917                 s = "ESS Technology Maestro-2";
  918                 break;
  919 
  920         case MAESTRO_2E_PCI_ID:
  921                 s = "ESS Technology Maestro-2E";
  922                 break;
  923         }
  924 
  925         if (s != NULL && pci_get_class(dev) == PCIC_MULTIMEDIA) {
  926                 device_set_desc(dev, s);
  927                 return 0;
  928         }
  929         return ENXIO;
  930 }
  931 
  932 static int
  933 agg_attach(device_t dev)
  934 {
  935         struct agg_info *ess = NULL;
  936         u_int32_t       data;
  937         int     mapped = 0;
  938         int     regid = PCIR_BAR(0);
  939         struct resource *reg = NULL;
  940         struct ac97_info        *codec = NULL;
  941         int     irqid = 0;
  942         struct resource *irq = NULL;
  943         void    *ih = NULL;
  944         char    status[SND_STATUSLEN];
  945         bus_addr_t offset;
  946         int     i;
  947 
  948         if ((ess = malloc(sizeof *ess, M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
  949                 device_printf(dev, "cannot allocate softc\n");
  950                 return ENXIO;
  951         }
  952         ess->dev = dev;
  953 
  954         ess->bufsz = pcm_getbuffersize(dev, 4096, AGG_DEFAULT_BUFSZ, 65536);
  955 
  956         if (bus_dma_tag_create(/*parent*/NULL,
  957             /*alignment*/1 << WAVCACHE_BASEADDR_SHIFT,
  958             /*boundary*/WPWA_MAXADDR + 1,
  959             /*lowaddr*/MAESTRO_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR,
  960             /*filter*/NULL, /*filterarg*/NULL,
  961             /*maxsize*/ess->bufsz * (1 + AGG_MAXPLAYCH + 1), /*nsegments*/1,
  962             /*maxsegz*/0x3ffff, /*flags*/0, /*lockfunc*/busdma_lock_mutex,
  963             /*lockarg*/&Giant, &ess->parent_dmat) != 0) {
  964                 device_printf(dev, "unable to create dma tag\n");
  965                 goto bad;
  966         }
  967 
  968         ess->stat = dma_malloc(ess, ess->bufsz * (1 + AGG_MAXPLAYCH + 1),
  969             &ess->baseaddr);
  970         if (ess->stat == NULL) {
  971                 device_printf(dev, "cannot allocate DMA memory\n");
  972                 goto bad;
  973         }
  974         if (bootverbose)
  975                 device_printf(dev, "Maestro DMA base: %#llx\n",
  976                     (long long)ess->baseaddr);
  977         offset = ess->bufsz;
  978         for (i = 0; i < AGG_MAXPLAYCH; i++) {
  979                 ess->pch[i].offset = offset;
  980                 offset += ess->bufsz;
  981         }
  982         ess->rch.offset = offset;
  983 
  984         agg_power(ess, PPMI_D0);
  985         DELAY(100000);
  986 
  987         data = pci_read_config(dev, PCIR_COMMAND, 2);
  988         data |= (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN);
  989         pci_write_config(dev, PCIR_COMMAND, data, 2);
  990         data = pci_read_config(dev, PCIR_COMMAND, 2);
  991 
  992         if (data & PCIM_CMD_PORTEN) {
  993                 reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &regid,
  994                     0, BUS_SPACE_UNRESTRICTED, 256, RF_ACTIVE);
  995                 if (reg != NULL) {
  996                         ess->reg = reg;
  997                         ess->regid = regid;
  998                         ess->st = rman_get_bustag(reg);
  999                         ess->sh = rman_get_bushandle(reg);
 1000                         mapped++;
 1001                 }
 1002         }
 1003         if (mapped == 0) {
 1004                 device_printf(dev, "unable to map register space\n");
 1005                 goto bad;
 1006         }
 1007 
 1008         agg_init(ess);
 1009         if (agg_rdcodec(NULL, ess, 0) == 0x80) {
 1010                 device_printf(dev, "PT101 codec detected!\n");
 1011                 goto bad;
 1012         }
 1013         codec = AC97_CREATE(dev, ess, agg_ac97);
 1014         if (codec == NULL)
 1015                 goto bad;
 1016         if (mixer_init(dev, ac97_getmixerclass(), codec) == -1)
 1017                 goto bad;
 1018         ess->codec = codec;
 1019 
 1020         irq = bus_alloc_resource(dev, SYS_RES_IRQ, &irqid,
 1021             0, BUS_SPACE_UNRESTRICTED, 1, RF_ACTIVE | RF_SHAREABLE);
 1022         if (irq == NULL || snd_setup_intr(dev, irq, 0, agg_intr, ess, &ih)) {
 1023                 device_printf(dev, "unable to map interrupt\n");
 1024                 goto bad;
 1025         }
 1026         ess->irq = irq;
 1027         ess->irqid = irqid;
 1028         ess->ih = ih;
 1029 
 1030         snprintf(status, SND_STATUSLEN, "at I/O port 0x%lx irq %ld %s",
 1031             rman_get_start(reg), rman_get_start(irq),PCM_KLDSTRING(snd_maestro));
 1032 
 1033         if (pcm_register(dev, ess, AGG_MAXPLAYCH, 1))
 1034                 goto bad;
 1035 
 1036         mixer_hwvol_init(dev);
 1037         for (data = 0; data < AGG_MAXPLAYCH; data++)
 1038                 pcm_addchan(dev, PCMDIR_PLAY, &aggch_class, ess);
 1039 #if 0   /* XXX - RECORDING */
 1040         pcm_addchan(dev, PCMDIR_REC, &aggrch_class, ess);
 1041 #endif
 1042         pcm_setstatus(dev, status);
 1043 
 1044         return 0;
 1045 
 1046  bad:
 1047         if (codec != NULL)
 1048                 ac97_destroy(codec);
 1049         if (ih != NULL)
 1050                 bus_teardown_intr(dev, irq, ih);
 1051         if (irq != NULL)
 1052                 bus_release_resource(dev, SYS_RES_IRQ, irqid, irq);
 1053         if (reg != NULL)
 1054                 bus_release_resource(dev, SYS_RES_IOPORT, regid, reg);
 1055         if (ess != NULL) {
 1056                 agg_power(ess, PPMI_D3);
 1057                 if (ess->stat != NULL)
 1058                         dma_free(ess, ess->stat);
 1059                 if (ess->parent_dmat != NULL)
 1060                         bus_dma_tag_destroy(ess->parent_dmat);
 1061                 free(ess, M_DEVBUF);
 1062         }
 1063 
 1064         return ENXIO;
 1065 }
 1066 
 1067 static int
 1068 agg_detach(device_t dev)
 1069 {
 1070         struct agg_info *ess = pcm_getdevinfo(dev);
 1071         int r;
 1072 
 1073         r = pcm_unregister(dev);
 1074         if (r)
 1075                 return r;
 1076 
 1077         ess = pcm_getdevinfo(dev);
 1078         dma_free(ess, ess->stat);
 1079 
 1080         /* Power down everything except clock and vref. */
 1081         agg_wrcodec(NULL, ess, AC97_REG_POWER, 0xd700);
 1082         DELAY(20);
 1083         bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0);
 1084         agg_power(ess, PPMI_D3);
 1085 
 1086         bus_teardown_intr(dev, ess->irq, ess->ih);
 1087         bus_release_resource(dev, SYS_RES_IRQ, ess->irqid, ess->irq);
 1088         bus_release_resource(dev, SYS_RES_IOPORT, ess->regid, ess->reg);
 1089         bus_dma_tag_destroy(ess->parent_dmat);
 1090         free(ess, M_DEVBUF);
 1091         return 0;
 1092 }
 1093 
 1094 static int
 1095 agg_suspend(device_t dev)
 1096 {
 1097         struct agg_info *ess = pcm_getdevinfo(dev);
 1098         int i, x;
 1099 
 1100         x = spltty();
 1101         wp_stoptimer(ess);
 1102         bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0);
 1103 
 1104         for (i = 0; i < ess->playchns; i++)
 1105                 aggch_stop_dac(ess->pch + i);
 1106 
 1107 #if 0   /* XXX - RECORDING */
 1108         aggch_stop_adc(&ess->rch);
 1109 #endif
 1110         splx(x);
 1111         /* Power down everything except clock. */
 1112         agg_wrcodec(NULL, ess, AC97_REG_POWER, 0xdf00);
 1113         DELAY(20);
 1114         bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0);
 1115         DELAY(1);
 1116         agg_power(ess, PPMI_D3);
 1117 
 1118         return 0;
 1119 }
 1120 
 1121 static int
 1122 agg_resume(device_t dev)
 1123 {
 1124         int i, x;
 1125         struct agg_info *ess = pcm_getdevinfo(dev);
 1126 
 1127         agg_power(ess, PPMI_D0);
 1128         DELAY(100000);
 1129         agg_init(ess);
 1130         if (mixer_reinit(dev)) {
 1131                 device_printf(dev, "unable to reinitialize the mixer\n");
 1132                 return ENXIO;
 1133         }
 1134 
 1135         x = spltty();
 1136         for (i = 0; i < ess->playchns; i++)
 1137                 if (ess->active & (1 << i))
 1138                         aggch_start_dac(ess->pch + i);
 1139 #if 0   /* XXX - RECORDING */
 1140         if (ess->active & (1 << i))
 1141                 aggch_start_adc(&ess->rch);
 1142 #endif
 1143         if (ess->active) {
 1144                 set_timer(ess);
 1145                 wp_starttimer(ess);
 1146         }
 1147         splx(x);
 1148         return 0;
 1149 }
 1150 
 1151 static int
 1152 agg_shutdown(device_t dev)
 1153 {
 1154         struct agg_info *ess = pcm_getdevinfo(dev);
 1155         int i;
 1156 
 1157         wp_stoptimer(ess);
 1158         bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0);
 1159 
 1160         for (i = 0; i < ess->playchns; i++)
 1161                 aggch_stop_dac(ess->pch + i);
 1162 
 1163 #if 0   /* XXX - RECORDING */
 1164         aggch_stop_adc(&ess->rch);
 1165 #endif
 1166         return 0;
 1167 }
 1168 
 1169 
 1170 static device_method_t agg_methods[] = {
 1171     DEVMETHOD(device_probe,     agg_probe),
 1172     DEVMETHOD(device_attach,    agg_attach),
 1173     DEVMETHOD(device_detach,    agg_detach),
 1174     DEVMETHOD(device_suspend,   agg_suspend),
 1175     DEVMETHOD(device_resume,    agg_resume),
 1176     DEVMETHOD(device_shutdown,  agg_shutdown),
 1177 
 1178     { 0, 0 }
 1179 };
 1180 
 1181 static driver_t agg_driver = {
 1182     "pcm",
 1183     agg_methods,
 1184     PCM_SOFTC_SIZE,
 1185 };
 1186 
 1187 DRIVER_MODULE(snd_maestro, pci, agg_driver, pcm_devclass, 0, 0);
 1188 MODULE_DEPEND(snd_maestro, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
 1189 MODULE_VERSION(snd_maestro, 1);

Cache object: e0a01b3e0bdc3644a52a89a9bf101f1e


[ 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.