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/envy24ht.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2006 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
    5  * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  */
   30 
   31 /*
   32  * Konstantin Dimitrov's thanks list:
   33  *
   34  * A huge thanks goes to Spas Filipov for his friendship, support and his
   35  * generous gift - an 'Audiotrak Prodigy HD2' audio card! I also want to
   36  * thank Keiichi Iwasaki and his parents, because they helped Spas to get
   37  * the card from Japan! Having hardware sample of Prodigy HD2 made adding
   38  * support for that great card very easy and real fun and pleasure.
   39  *
   40  */
   41 
   42 #ifdef HAVE_KERNEL_OPTION_HEADERS
   43 #include "opt_snd.h"
   44 #endif
   45 
   46 #include <dev/sound/pcm/sound.h>
   47 #include <dev/sound/pcm/ac97.h>
   48 #include <dev/sound/pci/spicds.h>
   49 #include <dev/sound/pci/envy24ht.h>
   50 
   51 #include <dev/pci/pcireg.h>
   52 #include <dev/pci/pcivar.h>
   53 
   54 #include "mixer_if.h"
   55 
   56 SND_DECLARE_FILE("$FreeBSD$");
   57 
   58 static MALLOC_DEFINE(M_ENVY24HT, "envy24ht", "envy24ht audio");
   59 
   60 /* -------------------------------------------------------------------- */
   61 
   62 struct sc_info;
   63 
   64 #define ENVY24HT_PLAY_CHNUM 8
   65 #define ENVY24HT_REC_CHNUM 2
   66 #define ENVY24HT_PLAY_BUFUNIT (4 /* byte/sample */ * 8 /* channel */)
   67 #define ENVY24HT_REC_BUFUNIT  (4 /* byte/sample */ * 2 /* channel */)
   68 #define ENVY24HT_SAMPLE_NUM   4096
   69 
   70 #define ENVY24HT_TIMEOUT 1000
   71 
   72 #define ENVY24HT_DEFAULT_FORMAT SND_FORMAT(AFMT_S16_LE, 2, 0)
   73 
   74 #define ENVY24HT_NAMELEN 32
   75 
   76 struct envy24ht_sample {
   77         volatile u_int32_t buffer;
   78 };
   79 
   80 typedef struct envy24ht_sample sample32_t;
   81 
   82 /* channel registers */
   83 struct sc_chinfo {
   84         struct snd_dbuf         *buffer;
   85         struct pcm_channel      *channel;
   86         struct sc_info          *parent;
   87         int                     dir;
   88         unsigned                num; /* hw channel number */
   89 
   90         /* channel information */
   91         u_int32_t               format;
   92         u_int32_t               speed;
   93         u_int32_t               blk; /* hw block size(dword) */
   94 
   95         /* format conversion structure */
   96         u_int8_t                *data;
   97         unsigned int            size; /* data buffer size(byte) */
   98         int                     unit; /* sample size(byte) */
   99         unsigned int            offset; /* samples number offset */
  100         void                    (*emldma)(struct sc_chinfo *);
  101 
  102         /* flags */
  103         int                     run;
  104 };
  105 
  106 /* codec interface entrys */
  107 struct codec_entry {
  108         void *(*create)(device_t dev, void *devinfo, int dir, int num);
  109         void (*destroy)(void *codec);
  110         void (*init)(void *codec);
  111         void (*reinit)(void *codec);
  112         void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
  113         void (*setrate)(void *codec, int which, int rate);
  114 };
  115 
  116 /* system configuration information */
  117 struct cfg_info {
  118         char *name;
  119         u_int16_t subvendor, subdevice;
  120         u_int8_t scfg, acl, i2s, spdif;
  121         u_int32_t gpiomask, gpiostate, gpiodir;
  122         u_int32_t cdti, cclk, cs;
  123         u_int8_t cif, type, free;
  124         struct codec_entry *codec;
  125 };
  126 
  127 /* device private data */
  128 struct sc_info {
  129         device_t        dev;
  130         struct mtx      *lock;
  131 
  132         /* Control/Status registor */
  133         struct resource *cs;
  134         int             csid;
  135         bus_space_tag_t cst;
  136         bus_space_handle_t csh;
  137         /* MultiTrack registor */
  138         struct resource *mt;
  139         int             mtid;
  140         bus_space_tag_t mtt;
  141         bus_space_handle_t mth;
  142         /* DMA tag */
  143         bus_dma_tag_t dmat;
  144         /* IRQ resource */
  145         struct resource *irq;
  146         int             irqid;
  147         void            *ih;
  148 
  149         /* system configuration data */
  150         struct cfg_info *cfg;
  151 
  152         /* ADC/DAC number and info */
  153         int             adcn, dacn;
  154         void            *adc[4], *dac[4];
  155 
  156         /* mixer control data */
  157         u_int32_t       src;
  158         u_int8_t        left[ENVY24HT_CHAN_NUM];
  159         u_int8_t        right[ENVY24HT_CHAN_NUM];
  160 
  161         /* Play/Record DMA fifo */
  162         sample32_t      *pbuf;
  163         sample32_t      *rbuf;
  164         u_int32_t       psize, rsize; /* DMA buffer size(byte) */
  165         u_int16_t       blk[2]; /* transfer check blocksize(dword) */
  166         bus_dmamap_t    pmap, rmap;
  167         bus_addr_t      paddr, raddr;
  168 
  169         /* current status */
  170         u_int32_t       speed;
  171         int             run[2];
  172         u_int16_t       intr[2];
  173         struct pcmchan_caps     caps[2];
  174 
  175         /* channel info table */
  176         unsigned        chnum;
  177         struct sc_chinfo chan[11];
  178 };
  179 
  180 /* -------------------------------------------------------------------- */
  181 
  182 /*
  183  * prototypes
  184  */
  185 
  186 /* DMA emulator */
  187 static void envy24ht_p8u(struct sc_chinfo *);
  188 static void envy24ht_p16sl(struct sc_chinfo *);
  189 static void envy24ht_p32sl(struct sc_chinfo *);
  190 static void envy24ht_r16sl(struct sc_chinfo *);
  191 static void envy24ht_r32sl(struct sc_chinfo *);
  192 
  193 /* channel interface */
  194 static void *envy24htchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
  195 static int envy24htchan_setformat(kobj_t, void *, u_int32_t);
  196 static u_int32_t envy24htchan_setspeed(kobj_t, void *, u_int32_t);
  197 static u_int32_t envy24htchan_setblocksize(kobj_t, void *, u_int32_t);
  198 static int envy24htchan_trigger(kobj_t, void *, int);
  199 static u_int32_t envy24htchan_getptr(kobj_t, void *);
  200 static struct pcmchan_caps *envy24htchan_getcaps(kobj_t, void *);
  201 
  202 /* mixer interface */
  203 static int envy24htmixer_init(struct snd_mixer *);
  204 static int envy24htmixer_reinit(struct snd_mixer *);
  205 static int envy24htmixer_uninit(struct snd_mixer *);
  206 static int envy24htmixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
  207 static u_int32_t envy24htmixer_setrecsrc(struct snd_mixer *, u_int32_t);
  208 
  209 /* SPI codec access interface */
  210 static void *envy24ht_spi_create(device_t, void *, int, int);
  211 static void envy24ht_spi_destroy(void *);
  212 static void envy24ht_spi_init(void *);
  213 static void envy24ht_spi_reinit(void *);
  214 static void envy24ht_spi_setvolume(void *, int, unsigned int, unsigned int);
  215 
  216 /* -------------------------------------------------------------------- */
  217 
  218 /*
  219   system constant tables
  220 */
  221 
  222 /* API -> hardware channel map */
  223 static unsigned envy24ht_chanmap[ENVY24HT_CHAN_NUM] = {
  224         ENVY24HT_CHAN_PLAY_DAC1,  /* 1 */
  225         ENVY24HT_CHAN_PLAY_DAC2,  /* 2 */
  226         ENVY24HT_CHAN_PLAY_DAC3,  /* 3 */
  227         ENVY24HT_CHAN_PLAY_DAC4,  /* 4 */
  228         ENVY24HT_CHAN_PLAY_SPDIF, /* 0 */
  229         ENVY24HT_CHAN_REC_MIX,    /* 5 */
  230         ENVY24HT_CHAN_REC_SPDIF,  /* 6 */
  231         ENVY24HT_CHAN_REC_ADC1,   /* 7 */
  232         ENVY24HT_CHAN_REC_ADC2,   /* 8 */
  233         ENVY24HT_CHAN_REC_ADC3,   /* 9 */
  234         ENVY24HT_CHAN_REC_ADC4,   /* 10 */
  235 };
  236 
  237 /* mixer -> API channel map. see above */
  238 static int envy24ht_mixmap[] = {
  239         -1, /* Master output level. It is depend on codec support */
  240         -1, /* Treble level of all output channels */
  241         -1, /* Bass level of all output channels */
  242         -1, /* Volume of synthesier input */
  243         0,  /* Output level for the audio device */
  244         -1, /* Output level for the PC speaker */
  245         7,  /* line in jack */
  246         -1, /* microphone jack */
  247         -1, /* CD audio input */
  248         -1, /* Recording monitor */
  249         1,  /* alternative codec */
  250         -1, /* global recording level */
  251         -1, /* Input gain */
  252         -1, /* Output gain */
  253         8,  /* Input source 1 */
  254         9,  /* Input source 2 */
  255         10, /* Input source 3 */
  256         6,  /* Digital (input) 1 */
  257         -1, /* Digital (input) 2 */
  258         -1, /* Digital (input) 3 */
  259         -1, /* Phone input */
  260         -1, /* Phone output */
  261         -1, /* Video/TV (audio) in */
  262         -1, /* Radio in */
  263         -1, /* Monitor volume */
  264 };
  265 
  266 /* variable rate audio */
  267 static u_int32_t envy24ht_speed[] = {
  268     192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
  269     12000, 11025, 9600, 8000, 0
  270 };
  271 
  272 /* known boards configuration */
  273 static struct codec_entry spi_codec = {
  274         envy24ht_spi_create,
  275         envy24ht_spi_destroy,
  276         envy24ht_spi_init,
  277         envy24ht_spi_reinit,
  278         envy24ht_spi_setvolume,
  279         NULL, /* setrate */
  280 };
  281 
  282 static struct cfg_info cfg_table[] = {
  283         {
  284                 "Envy24HT audio (Terratec Aureon 7.1 Space)",
  285                 0x153b, 0x1145,
  286                 0x0b, 0x80, 0xfc, 0xc3,
  287                 0x21efff, 0x7fffff, 0x5e1000,
  288                 0x40000, 0x80000, 0x1000, 0x00, 0x02,
  289                 0,
  290                 &spi_codec,
  291         },
  292         {
  293                 "Envy24HT audio (Terratec Aureon 5.1 Sky)",
  294                 0x153b, 0x1147,
  295                 0x0a, 0x80, 0xfc, 0xc3,
  296                 0x21efff, 0x7fffff, 0x5e1000,
  297                 0x40000, 0x80000, 0x1000, 0x00, 0x02,
  298                 0,
  299                 &spi_codec,
  300         },
  301                 {
  302                 "Envy24HT audio (Terratec Aureon 7.1 Universe)",
  303                 0x153b, 0x1153,
  304                 0x0b, 0x80, 0xfc, 0xc3,
  305                 0x21efff, 0x7fffff, 0x5e1000,
  306                 0x40000, 0x80000, 0x1000, 0x00, 0x02,
  307                 0,
  308                 &spi_codec,
  309         },
  310         {
  311                 "Envy24HT audio (AudioTrak Prodigy 7.1)",
  312                 0x4933, 0x4553,
  313                 0x0b, 0x80, 0xfc, 0xc3,
  314                 0x21efff, 0x7fffff, 0x5e1000,
  315                 0x40000, 0x80000, 0x1000, 0x00, 0x02,
  316                 0,
  317                 &spi_codec,
  318         },
  319         {
  320                 "Envy24HT audio (Terratec PHASE 28)",
  321                 0x153b, 0x1149,
  322                 0x0b, 0x80, 0xfc, 0xc3,
  323                 0x21efff, 0x7fffff, 0x5e1000,
  324                 0x40000, 0x80000, 0x1000, 0x00, 0x02,
  325                 0,
  326                 &spi_codec,
  327         },
  328         {
  329                 "Envy24HT-S audio (Terratec PHASE 22)",
  330                 0x153b, 0x1150,
  331                 0x10, 0x80, 0xf0, 0xc3,
  332                 0x7ffbc7, 0x7fffff, 0x438,
  333                 0x10, 0x20, 0x400, 0x01, 0x00,
  334                 0,
  335                 &spi_codec,
  336         },
  337         {
  338                 "Envy24HT audio (AudioTrak Prodigy 7.1 LT)",
  339                 0x3132, 0x4154,   
  340                 0x4b, 0x80, 0xfc, 0xc3,
  341                 0x7ff8ff, 0x7fffff, 0x700,
  342                 0x400, 0x200, 0x100, 0x00, 0x02,
  343                 0,
  344                 &spi_codec, 
  345         },
  346         {
  347                 "Envy24HT audio (AudioTrak Prodigy 7.1 XT)",
  348                 0x3136, 0x4154,  
  349                 0x4b, 0x80, 0xfc, 0xc3,
  350                 0x7ff8ff, 0x7fffff, 0x700,
  351                 0x400, 0x200, 0x100, 0x00, 0x02,
  352                 0,
  353                 &spi_codec,
  354         },
  355         {
  356                 "Envy24HT audio (M-Audio Revolution 7.1)",
  357                 0x1412, 0x3630,
  358                 0x43, 0x80, 0xf8, 0xc1,
  359                 0x3fff85, 0x400072, 0x4000fa,
  360                 0x08, 0x02, 0x20, 0x00, 0x04,
  361                 0,
  362                 &spi_codec,
  363         },
  364         {
  365                 "Envy24GT audio (M-Audio Revolution 5.1)",
  366                 0x1412, 0x3631,
  367                 0x42, 0x80, 0xf8, 0xc1,
  368                 0x3fff05, 0x4000f0, 0x4000fa,
  369                 0x08, 0x02, 0x10, 0x00, 0x03,
  370                 0,
  371                 &spi_codec,
  372         },
  373         {
  374                 "Envy24HT audio (M-Audio Audiophile 192)",
  375                 0x1412, 0x3632,
  376                 0x68, 0x80, 0xf8, 0xc3,
  377                 0x45, 0x4000b5, 0x7fffba,
  378                 0x08, 0x02, 0x10, 0x00, 0x03,
  379                 0,
  380                 &spi_codec,
  381         },
  382         {
  383                 "Envy24HT audio (AudioTrak Prodigy HD2)",
  384                 0x3137, 0x4154,
  385                 0x68, 0x80, 0x78, 0xc3,
  386                 0xfff8ff, 0x200700, 0xdfffff,
  387                 0x400, 0x200, 0x100, 0x00, 0x05,
  388                 0,
  389                 &spi_codec,
  390         },
  391         {
  392                 "Envy24HT audio (ESI Juli@)",
  393                 0x3031, 0x4553,
  394                 0x20, 0x80, 0xf8, 0xc3,
  395                 0x7fff9f, 0x8016, 0x7fff9f,
  396                 0x08, 0x02, 0x10, 0x00, 0x03,
  397                 0,
  398                 &spi_codec,
  399         },
  400         {
  401                 "Envy24HT-S audio (Terrasoniq TS22PCI)",
  402                 0x153b, 0x117b,
  403                 0x10, 0x80, 0xf0, 0xc3,
  404                 0x7ffbc7, 0x7fffff, 0x438,
  405                 0x10, 0x20, 0x400, 0x01, 0x00,
  406                 0,
  407                 &spi_codec,
  408         },
  409         {
  410                 "Envy24HT audio (Generic)",
  411                 0, 0,
  412                 0x0b, 0x80, 0xfc, 0xc3,
  413                 0x21efff, 0x7fffff, 0x5e1000,
  414                 0x40000, 0x80000, 0x1000, 0x00, 0x02,
  415                 0,
  416                 &spi_codec, /* default codec routines */
  417         }
  418 };
  419 
  420 static u_int32_t envy24ht_recfmt[] = {
  421         SND_FORMAT(AFMT_S16_LE, 2, 0),
  422         SND_FORMAT(AFMT_S32_LE, 2, 0),
  423         0
  424 };
  425 static struct pcmchan_caps envy24ht_reccaps = {8000, 96000, envy24ht_recfmt, 0};
  426 
  427 static u_int32_t envy24ht_playfmt[] = {
  428         SND_FORMAT(AFMT_U8, 2, 0),
  429         SND_FORMAT(AFMT_S16_LE, 2, 0),
  430         SND_FORMAT(AFMT_S32_LE, 2, 0),
  431         0
  432 };
  433 
  434 static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0};
  435 
  436 struct envy24ht_emldma {
  437         u_int32_t       format;
  438         void            (*emldma)(struct sc_chinfo *);
  439         int             unit;
  440 };
  441 
  442 static struct envy24ht_emldma envy24ht_pemltab[] = {
  443         {SND_FORMAT(AFMT_U8, 2, 0), envy24ht_p8u, 2},
  444         {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_p16sl, 4},
  445         {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_p32sl, 8},
  446         {0, NULL, 0}
  447 };
  448 
  449 static struct envy24ht_emldma envy24ht_remltab[] = {
  450         {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_r16sl, 4},
  451         {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_r32sl, 8},
  452         {0, NULL, 0}
  453 };
  454 
  455 /* -------------------------------------------------------------------- */
  456 
  457 /* common routines */
  458 static u_int32_t
  459 envy24ht_rdcs(struct sc_info *sc, int regno, int size)
  460 {
  461         switch (size) {
  462         case 1:
  463                 return bus_space_read_1(sc->cst, sc->csh, regno);
  464         case 2:
  465                 return bus_space_read_2(sc->cst, sc->csh, regno);
  466         case 4:
  467                 return bus_space_read_4(sc->cst, sc->csh, regno);
  468         default:
  469                 return 0xffffffff;
  470         }
  471 }
  472 
  473 static void
  474 envy24ht_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
  475 {
  476         switch (size) {
  477         case 1:
  478                 bus_space_write_1(sc->cst, sc->csh, regno, data);
  479                 break;
  480         case 2:
  481                 bus_space_write_2(sc->cst, sc->csh, regno, data);
  482                 break;
  483         case 4:
  484                 bus_space_write_4(sc->cst, sc->csh, regno, data);
  485                 break;
  486         }
  487 }
  488 
  489 static u_int32_t
  490 envy24ht_rdmt(struct sc_info *sc, int regno, int size)
  491 {
  492         switch (size) {
  493         case 1:
  494                 return bus_space_read_1(sc->mtt, sc->mth, regno);
  495         case 2:
  496                 return bus_space_read_2(sc->mtt, sc->mth, regno);
  497         case 4:
  498                 return bus_space_read_4(sc->mtt, sc->mth, regno);
  499         default:
  500                 return 0xffffffff;
  501         }
  502 }
  503 
  504 static void
  505 envy24ht_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
  506 {
  507         switch (size) {
  508         case 1:
  509                 bus_space_write_1(sc->mtt, sc->mth, regno, data);
  510                 break;
  511         case 2:
  512                 bus_space_write_2(sc->mtt, sc->mth, regno, data);
  513                 break;
  514         case 4:
  515                 bus_space_write_4(sc->mtt, sc->mth, regno, data);
  516                 break;
  517         }
  518 }
  519 
  520 /* -------------------------------------------------------------------- */
  521 
  522 /* I2C port/E2PROM access routines */
  523 
  524 static int
  525 envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
  526 {
  527         u_int32_t data;
  528         int i;
  529 
  530 #if(0)
  531         device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
  532 #endif
  533         for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
  534                 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
  535                 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
  536                         break;
  537                 DELAY(32); /* 31.25kHz */
  538         }
  539         if (i == ENVY24HT_TIMEOUT) {
  540                 return -1;
  541         }
  542         envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
  543         envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
  544             (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_RD, 1);
  545         for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
  546                 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
  547                 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
  548                         break;
  549                 DELAY(32); /* 31.25kHz */
  550         }
  551         if (i == ENVY24HT_TIMEOUT) {
  552                 return -1;
  553         }
  554         data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CDATA, 1);
  555 
  556 #if(0)
  557         device_printf(sc->dev, "envy24ht_rdi2c(): return 0x%x\n", data);
  558 #endif
  559         return (int)data;
  560 }
  561 
  562 static int
  563 envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
  564 {
  565         u_int32_t tmp;
  566         int i;
  567 
  568 #if(0)
  569         device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
  570 #endif
  571         for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
  572                 tmp = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
  573                 if ((tmp & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
  574                         break;
  575                 DELAY(32); /* 31.25kHz */
  576         }
  577         if (i == ENVY24HT_TIMEOUT) {
  578                 return -1;
  579         }
  580         envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
  581         envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDATA, data, 1);
  582         envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
  583             (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_WR, 1);
  584         for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
  585                 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
  586                 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
  587                         break;
  588                 DELAY(32); /* 31.25kHz */
  589         }
  590         if (i == ENVY24HT_TIMEOUT) {
  591                 return -1;
  592         }
  593 
  594         return 0;
  595 }
  596 
  597 static int
  598 envy24ht_rdrom(struct sc_info *sc, u_int32_t addr)
  599 {
  600         u_int32_t data;
  601 
  602 #if(0)
  603         device_printf(sc->dev, "envy24ht_rdrom(sc, 0x%02x)\n", addr);
  604 #endif
  605         data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
  606         if ((data & ENVY24HT_CCS_I2CSTAT_ROM) == 0) {
  607 #if(0)
  608                 device_printf(sc->dev, "envy24ht_rdrom(): E2PROM not presented\n");
  609 #endif
  610                 return -1;
  611         }
  612 
  613         return envy24ht_rdi2c(sc, ENVY24HT_CCS_I2CDEV_ROM, addr);
  614 }
  615 
  616 static struct cfg_info *
  617 envy24ht_rom2cfg(struct sc_info *sc)
  618 {
  619         struct cfg_info *buff;
  620         int size;
  621         int i;
  622 
  623 #if(0)
  624         device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n");
  625 #endif
  626         size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE);
  627         if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) {
  628 #if(0)
  629                 device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size);
  630 #endif
  631         buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
  632         if (buff == NULL) {
  633 #if(0)
  634                 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
  635 #endif
  636                 return NULL;
  637         }
  638         buff->free = 1;
  639 
  640         /* no valid e2prom, using default values */
  641         buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
  642         buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
  643         buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
  644         buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
  645         buff->scfg = 0x0b;
  646         buff->acl = 0x80;
  647         buff->i2s = 0xfc;
  648         buff->spdif = 0xc3;
  649         buff->gpiomask = 0x21efff;
  650         buff->gpiostate = 0x7fffff;
  651         buff->gpiodir = 0x5e1000;
  652         buff->cdti = 0x40000;
  653         buff->cclk = 0x80000;
  654         buff->cs = 0x1000;
  655         buff->cif = 0x00;
  656         buff->type = 0x02;
  657 
  658         for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0;
  659 i++)
  660                 if (cfg_table[i].subvendor == buff->subvendor &&
  661                     cfg_table[i].subdevice == buff->subdevice)
  662                         break;
  663         buff->name = cfg_table[i].name;
  664         buff->codec = cfg_table[i].codec;
  665 
  666                 return buff;
  667 #if 0
  668                 return NULL;
  669 #endif
  670         }
  671         buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
  672         if (buff == NULL) {
  673 #if(0)
  674                 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
  675 #endif
  676                 return NULL;
  677         }
  678         buff->free = 1;
  679 
  680         buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
  681         buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
  682         buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
  683         buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
  684         buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG);
  685         buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL);
  686         buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S);
  687         buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF);
  688         buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \
  689         envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \
  690         envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16;
  691         buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \
  692         envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \
  693         envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16;
  694         buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \
  695         envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \
  696         envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16;
  697 
  698         for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
  699                 if (cfg_table[i].subvendor == buff->subvendor &&
  700                     cfg_table[i].subdevice == buff->subdevice)
  701                         break;
  702         buff->name = cfg_table[i].name;
  703         buff->codec = cfg_table[i].codec;
  704 
  705         return buff;
  706 }
  707 
  708 static void
  709 envy24ht_cfgfree(struct cfg_info *cfg) {
  710         if (cfg == NULL)
  711                 return;
  712         if (cfg->free)
  713                 free(cfg, M_ENVY24HT);
  714         return;
  715 }
  716 
  717 /* -------------------------------------------------------------------- */
  718 
  719 /* AC'97 codec access routines */
  720 
  721 #if 0
  722 static int
  723 envy24ht_coldcd(struct sc_info *sc)
  724 {
  725         u_int32_t data;
  726         int i;
  727 
  728 #if(0)
  729         device_printf(sc->dev, "envy24ht_coldcd()\n");
  730 #endif
  731         envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1);
  732         DELAY(10);
  733         envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
  734         DELAY(1000);
  735         for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
  736                 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
  737                 if (data & ENVY24HT_MT_AC97CMD_RDY) {
  738                         return 0;
  739                 }
  740         }
  741 
  742         return -1;
  743 }
  744 
  745 static int
  746 envy24ht_slavecd(struct sc_info *sc)
  747 {
  748         u_int32_t data;
  749         int i;
  750 
  751 #if(0)
  752         device_printf(sc->dev, "envy24ht_slavecd()\n");
  753 #endif
  754         envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD,
  755             ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1);
  756         DELAY(10);
  757         envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
  758         DELAY(1000);
  759         for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
  760                 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
  761                 if (data & ENVY24HT_MT_AC97CMD_RDY) {
  762                         return 0;
  763                 }
  764         }
  765 
  766         return -1;
  767 }
  768 
  769 static int
  770 envy24ht_rdcd(kobj_t obj, void *devinfo, int regno)
  771 {
  772         struct sc_info *sc = (struct sc_info *)devinfo;
  773         u_int32_t data;
  774         int i;
  775 
  776 #if(0)
  777         device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno);
  778 #endif
  779         envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
  780         envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1);
  781         for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
  782                 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
  783                 if ((data & ENVY24HT_MT_AC97CMD_RD) == 0)
  784                         break;
  785         }
  786         data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2);
  787 
  788 #if(0)
  789         device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data);
  790 #endif
  791         return (int)data;
  792 }
  793 
  794 static int
  795 envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
  796 {
  797         struct sc_info *sc = (struct sc_info *)devinfo;
  798         u_int32_t cmd;
  799         int i;
  800 
  801 #if(0)
  802         device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
  803 #endif
  804         envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
  805         envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2);
  806         envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1);
  807         for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
  808                 cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
  809                 if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0)
  810                         break;
  811         }
  812 
  813         return 0;
  814 }
  815 
  816 static kobj_method_t envy24ht_ac97_methods[] = {
  817         KOBJMETHOD(ac97_read,   envy24ht_rdcd),
  818         KOBJMETHOD(ac97_write,  envy24ht_wrcd),
  819         KOBJMETHOD_END
  820 };
  821 AC97_DECLARE(envy24ht_ac97);
  822 #endif
  823 
  824 /* -------------------------------------------------------------------- */
  825 
  826 /* GPIO access routines */
  827 
  828 static u_int32_t
  829 envy24ht_gpiord(struct sc_info *sc)
  830 {
  831         if (sc->cfg->subvendor == 0x153b  && sc->cfg->subdevice == 0x1150) 
  832         return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2);
  833         else
  834         return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2));
  835 }
  836 
  837 static void
  838 envy24ht_gpiowr(struct sc_info *sc, u_int32_t data)
  839 {
  840 #if(0)
  841         device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF);
  842         return;
  843 #endif
  844         envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2);
  845         if (sc->cfg->subdevice != 0x1150)
  846         envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1);
  847         return;
  848 }
  849 
  850 #if 0
  851 static u_int32_t
  852 envy24ht_gpiogetmask(struct sc_info *sc)
  853 {
  854         return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2));
  855 }
  856 #endif
  857 
  858 static void
  859 envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask)
  860 {
  861         envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2);
  862         if (sc->cfg->subdevice != 0x1150)
  863         envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1);
  864         return;
  865 }
  866 
  867 #if 0
  868 static u_int32_t
  869 envy24ht_gpiogetdir(struct sc_info *sc)
  870 {
  871         return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4);
  872 }
  873 #endif
  874 
  875 static void
  876 envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir)
  877 {
  878         if (sc->cfg->subvendor == 0x153b  && sc->cfg->subdevice == 0x1150)
  879         envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2);
  880         else 
  881         envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4);
  882         return;
  883 }
  884 
  885 /* -------------------------------------------------------------------- */
  886 
  887 /* SPI codec access interface routine */
  888 
  889 struct envy24ht_spi_codec {
  890         struct spicds_info *info;
  891         struct sc_info *parent;
  892         int dir;
  893         int num;
  894         int cs, cclk, cdti;
  895 };
  896 
  897 static void
  898 envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
  899 {
  900         u_int32_t data = 0;
  901         struct envy24ht_spi_codec *ptr = codec;
  902 
  903 #if(0)
  904         device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
  905 #endif
  906         data = envy24ht_gpiord(ptr->parent);
  907         data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
  908         if (cs) data += ptr->cs;
  909         if (cclk) data += ptr->cclk;
  910         if (cdti) data += ptr->cdti;
  911         envy24ht_gpiowr(ptr->parent, data);
  912         return;
  913 }
  914 
  915 static void *
  916 envy24ht_spi_create(device_t dev, void *info, int dir, int num)
  917 {
  918         struct sc_info *sc = info;
  919         struct envy24ht_spi_codec *buff = NULL;
  920 
  921 #if(0)
  922         device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num);
  923 #endif
  924 
  925         buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
  926         if (buff == NULL)
  927                 return NULL;
  928 
  929         if (dir == PCMDIR_REC && sc->adc[num] != NULL)
  930                 buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info;
  931         else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
  932                 buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info;
  933         else
  934                 buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl);
  935         if (buff->info == NULL) {
  936                 free(buff, M_ENVY24HT);
  937                 return NULL;
  938         }
  939 
  940         buff->parent = sc;
  941         buff->dir = dir;
  942         buff->num = num;
  943 
  944         return (void *)buff;
  945 }
  946 
  947 static void
  948 envy24ht_spi_destroy(void *codec)
  949 {
  950         struct envy24ht_spi_codec *ptr = codec;
  951         if (ptr == NULL)
  952                 return;
  953 #if(0)
  954         device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n");
  955 #endif
  956 
  957         if (ptr->dir == PCMDIR_PLAY) {
  958                 if (ptr->parent->dac[ptr->num] != NULL)
  959                         spicds_destroy(ptr->info);
  960         }
  961         else {
  962                 if (ptr->parent->adc[ptr->num] != NULL)
  963                         spicds_destroy(ptr->info);
  964         }
  965 
  966         free(codec, M_ENVY24HT);
  967 }
  968 
  969 static void
  970 envy24ht_spi_init(void *codec)
  971 {
  972         struct envy24ht_spi_codec *ptr = codec;
  973         if (ptr == NULL)
  974                 return;
  975 #if(0)
  976         device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n");
  977 #endif
  978         ptr->cs = ptr->parent->cfg->cs;
  979         ptr->cclk = ptr->parent->cfg->cclk;
  980         ptr->cdti =  ptr->parent->cfg->cdti;
  981         spicds_settype(ptr->info, ptr->parent->cfg->type);
  982         spicds_setcif(ptr->info, ptr->parent->cfg->cif);
  983         if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \
  984         ptr->parent->cfg->type == SPICDS_TYPE_AK4528) {
  985         spicds_setformat(ptr->info,
  986             AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
  987         spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
  988         }
  989 
  990         /* for the time being, init only first codec */
  991         if (ptr->num == 0)
  992         spicds_init(ptr->info);
  993 }
  994 
  995 static void
  996 envy24ht_spi_reinit(void *codec)
  997 {
  998         struct envy24ht_spi_codec *ptr = codec;
  999         if (ptr == NULL)
 1000                 return;
 1001 #if(0)
 1002         device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n");
 1003 #endif
 1004 
 1005         spicds_reinit(ptr->info);
 1006 }
 1007 
 1008 static void
 1009 envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
 1010 {
 1011         struct envy24ht_spi_codec *ptr = codec;
 1012         if (ptr == NULL)
 1013                 return;
 1014 #if(0)
 1015         device_printf(ptr->parent->dev, "envy24ht_spi_set()\n");
 1016 #endif
 1017 
 1018         spicds_set(ptr->info, dir, left, right);
 1019 }
 1020 
 1021 /* -------------------------------------------------------------------- */
 1022 
 1023 /* hardware access routeines */
 1024 
 1025 static struct {
 1026         u_int32_t speed;
 1027         u_int32_t code;
 1028 } envy24ht_speedtab[] = {
 1029         {48000, ENVY24HT_MT_RATE_48000},
 1030         {24000, ENVY24HT_MT_RATE_24000},
 1031         {12000, ENVY24HT_MT_RATE_12000},
 1032         {9600, ENVY24HT_MT_RATE_9600},
 1033         {32000, ENVY24HT_MT_RATE_32000},
 1034         {16000, ENVY24HT_MT_RATE_16000},
 1035         {8000, ENVY24HT_MT_RATE_8000},
 1036         {96000, ENVY24HT_MT_RATE_96000},
 1037         {192000, ENVY24HT_MT_RATE_192000},
 1038         {64000, ENVY24HT_MT_RATE_64000},
 1039         {44100, ENVY24HT_MT_RATE_44100},
 1040         {22050, ENVY24HT_MT_RATE_22050},
 1041         {11025, ENVY24HT_MT_RATE_11025},
 1042         {88200, ENVY24HT_MT_RATE_88200},
 1043         {176400, ENVY24HT_MT_RATE_176400},
 1044         {0, 0x10}
 1045 };
 1046 
 1047 static u_int32_t
 1048 envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) {
 1049         u_int32_t code, i2sfmt;
 1050         int i = 0;
 1051 
 1052 #if(0)
 1053         device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed);
 1054         if (speed == 0) {
 1055                 code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */
 1056                 envy24ht_slavecd(sc);
 1057         }
 1058         else {
 1059 #endif
 1060                 for (i = 0; envy24ht_speedtab[i].speed != 0; i++) {
 1061                         if (envy24ht_speedtab[i].speed == speed)
 1062                                 break;
 1063                 }
 1064                 code = envy24ht_speedtab[i].code;
 1065 #if 0
 1066         }
 1067         device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code);
 1068 #endif
 1069         if (code < 0x10) {
 1070                 envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1);
 1071                 if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \
 1072                                                                             (code == ENVY24HT_MT_RATE_176400)) {
 1073                         i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
 1074                         i2sfmt |= ENVY24HT_MT_I2S_MLR128;
 1075                         envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
 1076                 }
 1077                 else {
 1078                         i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
 1079                         i2sfmt &= ~ENVY24HT_MT_I2S_MLR128;
 1080                         envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
 1081                 }
 1082                 code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1);
 1083                 code &= ENVY24HT_MT_RATE_MASK;
 1084                 for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) {
 1085                         if (envy24ht_speedtab[i].code == code)
 1086                                 break;
 1087                 }
 1088                 speed = envy24ht_speedtab[i].speed;
 1089         }
 1090         else
 1091                 speed = 0;
 1092 
 1093 #if(0)
 1094         device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed);
 1095 #endif
 1096         return speed;
 1097 }
 1098 
 1099 static void
 1100 envy24ht_setvolume(struct sc_info *sc, unsigned ch)
 1101 {
 1102 #if(0)
 1103         device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch);
 1104         envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
 1105         envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
 1106         envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
 1107         envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
 1108 #endif
 1109 }
 1110 
 1111 static void
 1112 envy24ht_mutevolume(struct sc_info *sc, unsigned ch)
 1113 {
 1114 #if 0
 1115         u_int32_t vol;
 1116 
 1117         device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch);
 1118         vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE;
 1119         envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
 1120         envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
 1121         envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
 1122         envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
 1123 #endif
 1124 }
 1125 
 1126 static u_int32_t
 1127 envy24ht_gethwptr(struct sc_info *sc, int dir)
 1128 {
 1129         int unit, regno;
 1130         u_int32_t ptr, rtn;
 1131 
 1132 #if(0)
 1133         device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir);
 1134 #endif
 1135         if (dir == PCMDIR_PLAY) {
 1136                 rtn = sc->psize / 4;
 1137                 unit = ENVY24HT_PLAY_BUFUNIT / 4;
 1138                 regno = ENVY24HT_MT_PCNT;
 1139         }
 1140         else {
 1141                 rtn = sc->rsize / 4;
 1142                 unit = ENVY24HT_REC_BUFUNIT / 4;
 1143                 regno = ENVY24HT_MT_RCNT;
 1144         }
 1145 
 1146         ptr = envy24ht_rdmt(sc, regno, 2);
 1147         rtn -= (ptr + 1);
 1148         rtn /= unit;
 1149 
 1150 #if(0)
 1151         device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn);
 1152 #endif
 1153         return rtn;
 1154 }
 1155 
 1156 static void
 1157 envy24ht_updintr(struct sc_info *sc, int dir)
 1158 {
 1159         int regintr;
 1160         u_int32_t mask, intr;
 1161         u_int32_t cnt;
 1162         u_int16_t blk;
 1163 
 1164 #if(0)
 1165         device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir);
 1166 #endif
 1167         if (dir == PCMDIR_PLAY) {
 1168                 blk = sc->blk[0];
 1169                 regintr = ENVY24HT_MT_PTERM;
 1170                 mask = ~ENVY24HT_MT_INT_PMASK;
 1171         }
 1172         else {
 1173                 blk = sc->blk[1];
 1174                 regintr = ENVY24HT_MT_RTERM;
 1175                 mask = ~ENVY24HT_MT_INT_RMASK;
 1176         }
 1177 
 1178         cnt = blk - 1;
 1179 #if(0)
 1180         device_printf(sc->dev, "envy24ht_updintr():blk = %d, cnt = %d\n", blk, cnt);
 1181 #endif
 1182         envy24ht_wrmt(sc, regintr, cnt, 2);
 1183         intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
 1184 #if(0)
 1185         device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
 1186 #endif
 1187         envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
 1188 #if(0)
 1189         device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
 1190                       envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
 1191 #endif
 1192 
 1193         return;
 1194 }
 1195 
 1196 #if 0
 1197 static void
 1198 envy24ht_maskintr(struct sc_info *sc, int dir)
 1199 {
 1200         u_int32_t mask, intr;
 1201 
 1202 #if(0)
 1203         device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
 1204 #endif
 1205         if (dir == PCMDIR_PLAY)
 1206                 mask = ENVY24HT_MT_INT_PMASK;
 1207         else
 1208                 mask = ENVY24HT_MT_INT_RMASK;
 1209         intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
 1210         envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
 1211 
 1212         return;
 1213 }
 1214 #endif
 1215 
 1216 static int
 1217 envy24ht_checkintr(struct sc_info *sc, int dir)
 1218 {
 1219         u_int32_t mask, stat, intr, rtn;
 1220 
 1221 #if(0)
 1222         device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
 1223 #endif
 1224         intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
 1225         if (dir == PCMDIR_PLAY) {
 1226                 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
 1227                         mask = ~ENVY24HT_MT_INT_RSTAT;
 1228                         envy24ht_wrmt(sc, 0x1a, 0x01, 1);
 1229                         envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);       
 1230                         stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
 1231                         envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
 1232                 }
 1233         }
 1234         else {
 1235                 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
 1236                         mask = ~ENVY24HT_MT_INT_PSTAT;
 1237 #if 0
 1238                         stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
 1239 #endif
 1240                         envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
 1241                         stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
 1242                         envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
 1243                 }
 1244         }
 1245 
 1246         return rtn;
 1247 }
 1248 
 1249 static void
 1250 envy24ht_start(struct sc_info *sc, int dir)
 1251 {
 1252         u_int32_t stat, sw;
 1253 
 1254 #if(0)
 1255         device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
 1256 #endif
 1257         if (dir == PCMDIR_PLAY)
 1258                 sw = ENVY24HT_MT_PCTL_PSTART;
 1259         else
 1260                 sw = ENVY24HT_MT_PCTL_RSTART;
 1261 
 1262         stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
 1263         envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
 1264 #if(0)
 1265         DELAY(100);
 1266         device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
 1267         device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
 1268 #endif
 1269 
 1270         return;
 1271 }
 1272 
 1273 static void
 1274 envy24ht_stop(struct sc_info *sc, int dir)
 1275 {
 1276         u_int32_t stat, sw;
 1277 
 1278 #if(0)
 1279         device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir);
 1280 #endif
 1281         if (dir == PCMDIR_PLAY)
 1282                 sw = ~ENVY24HT_MT_PCTL_PSTART;
 1283         else
 1284                 sw = ~ENVY24HT_MT_PCTL_RSTART;
 1285 
 1286         stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
 1287         envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1);
 1288 
 1289         return;
 1290 }
 1291 
 1292 #if 0
 1293 static int
 1294 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
 1295 {
 1296         return 0;
 1297 }
 1298 #endif
 1299 
 1300 /* -------------------------------------------------------------------- */
 1301 
 1302 /* buffer copy routines */
 1303 static void
 1304 envy24ht_p32sl(struct sc_chinfo *ch)
 1305 {
 1306         int length;
 1307         sample32_t *dmabuf;
 1308         u_int32_t *data;
 1309         int src, dst, ssize, dsize, slot;
 1310         int i;
 1311 
 1312         length = sndbuf_getready(ch->buffer) / 8;
 1313         dmabuf = ch->parent->pbuf;
 1314         data = (u_int32_t *)ch->data;
 1315         src = sndbuf_getreadyptr(ch->buffer) / 4;
 1316         dst = src / 2 + ch->offset;
 1317         ssize = ch->size / 4;
 1318         dsize = ch->size / 8;
 1319         slot = ch->num * 2;
 1320 
 1321         for (i = 0; i < length; i++) {
 1322                 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
 1323                 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
 1324                 dst++;
 1325                 dst %= dsize;
 1326                 src += 2;
 1327                 src %= ssize;
 1328         }
 1329 
 1330         return;
 1331 }
 1332 
 1333 static void
 1334 envy24ht_p16sl(struct sc_chinfo *ch)
 1335 {
 1336         int length;
 1337         sample32_t *dmabuf;
 1338         u_int16_t *data;
 1339         int src, dst, ssize, dsize, slot;
 1340         int i;
 1341 
 1342 #if(0)
 1343         device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
 1344 #endif
 1345         length = sndbuf_getready(ch->buffer) / 4;
 1346         dmabuf = ch->parent->pbuf;
 1347         data = (u_int16_t *)ch->data;
 1348         src = sndbuf_getreadyptr(ch->buffer) / 2;
 1349         dst = src / 2 + ch->offset;
 1350         ssize = ch->size / 2;
 1351         dsize = ch->size / 4;
 1352         slot = ch->num * 2;
 1353 #if(0)
 1354         device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
 1355 #endif
 1356 
 1357         for (i = 0; i < length; i++) {
 1358                 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
 1359                 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
 1360 #if(0)
 1361                 if (i < 16) {
 1362                         printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
 1363                         printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
 1364                 }
 1365 #endif
 1366                 dst++;
 1367                 dst %= dsize;
 1368                 src += 2;
 1369                 src %= ssize;
 1370         }
 1371 #if(0)
 1372         printf("\n");
 1373 #endif
 1374 
 1375         return;
 1376 }
 1377 
 1378 static void
 1379 envy24ht_p8u(struct sc_chinfo *ch)
 1380 {
 1381         int length;
 1382         sample32_t *dmabuf;
 1383         u_int8_t *data;
 1384         int src, dst, ssize, dsize, slot;
 1385         int i;
 1386 
 1387         length = sndbuf_getready(ch->buffer) / 2;
 1388         dmabuf = ch->parent->pbuf;
 1389         data = (u_int8_t *)ch->data;
 1390         src = sndbuf_getreadyptr(ch->buffer);
 1391         dst = src / 2 + ch->offset;
 1392         ssize = ch->size;
 1393         dsize = ch->size / 4;
 1394         slot = ch->num * 2;
 1395 
 1396         for (i = 0; i < length; i++) {
 1397                 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
 1398                 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
 1399                 dst++;
 1400                 dst %= dsize;
 1401                 src += 2;
 1402                 src %= ssize;
 1403         }
 1404 
 1405         return;
 1406 }
 1407 
 1408 static void
 1409 envy24ht_r32sl(struct sc_chinfo *ch)
 1410 {
 1411         int length;
 1412         sample32_t *dmabuf;
 1413         u_int32_t *data;
 1414         int src, dst, ssize, dsize, slot;
 1415         int i;
 1416 
 1417         length = sndbuf_getfree(ch->buffer) / 8;
 1418         dmabuf = ch->parent->rbuf;
 1419         data = (u_int32_t *)ch->data;
 1420         dst = sndbuf_getfreeptr(ch->buffer) / 4;
 1421         src = dst / 2 + ch->offset;
 1422         dsize = ch->size / 4;
 1423         ssize = ch->size / 8;
 1424         slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
 1425 
 1426         for (i = 0; i < length; i++) {
 1427                 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
 1428                 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
 1429                 dst += 2;
 1430                 dst %= dsize;
 1431                 src++;
 1432                 src %= ssize;
 1433         }
 1434 
 1435         return;
 1436 }
 1437 
 1438 static void
 1439 envy24ht_r16sl(struct sc_chinfo *ch)
 1440 {
 1441         int length;
 1442         sample32_t *dmabuf;
 1443         u_int16_t *data;
 1444         int src, dst, ssize, dsize, slot;
 1445         int i;
 1446 
 1447         length = sndbuf_getfree(ch->buffer) / 4;
 1448         dmabuf = ch->parent->rbuf;
 1449         data = (u_int16_t *)ch->data;
 1450         dst = sndbuf_getfreeptr(ch->buffer) / 2;
 1451         src = dst / 2 + ch->offset;
 1452         dsize = ch->size / 2;
 1453         ssize = ch->size / 8;
 1454         slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
 1455 
 1456         for (i = 0; i < length; i++) {
 1457                 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
 1458                 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
 1459                 dst += 2;
 1460                 dst %= dsize;
 1461                 src++;
 1462                 src %= ssize;
 1463         }
 1464 
 1465         return;
 1466 }
 1467 
 1468 /* -------------------------------------------------------------------- */
 1469 
 1470 /* channel interface */
 1471 static void *
 1472 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
 1473 {
 1474         struct sc_info  *sc = (struct sc_info *)devinfo;
 1475         struct sc_chinfo *ch;
 1476         unsigned num;
 1477 
 1478 #if(0)
 1479         device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
 1480 #endif
 1481         snd_mtxlock(sc->lock);
 1482 #if 0
 1483         if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
 1484             (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
 1485                 snd_mtxunlock(sc->lock);
 1486                 return NULL;
 1487         }
 1488 #endif
 1489         num = sc->chnum;
 1490 
 1491         ch = &sc->chan[num];
 1492         ch->size = 8 * ENVY24HT_SAMPLE_NUM;
 1493         ch->data = malloc(ch->size, M_ENVY24HT, M_NOWAIT);
 1494         if (ch->data == NULL) {
 1495                 ch->size = 0;
 1496                 ch = NULL;
 1497         }
 1498         else {
 1499                 ch->buffer = b;
 1500                 ch->channel = c;
 1501                 ch->parent = sc;
 1502                 ch->dir = dir;
 1503                 /* set channel map */
 1504                 ch->num = envy24ht_chanmap[num];
 1505                 snd_mtxunlock(sc->lock);
 1506                 sndbuf_setup(ch->buffer, ch->data, ch->size);
 1507                 snd_mtxlock(sc->lock);
 1508                 /* these 2 values are dummy */
 1509                 ch->unit = 4;
 1510                 ch->blk = 10240;
 1511         }
 1512         snd_mtxunlock(sc->lock);
 1513 
 1514         return ch;
 1515 }
 1516 
 1517 static int
 1518 envy24htchan_free(kobj_t obj, void *data)
 1519 {
 1520         struct sc_chinfo *ch = data;
 1521         struct sc_info *sc = ch->parent;
 1522 
 1523 #if(0)
 1524         device_printf(sc->dev, "envy24htchan_free()\n");
 1525 #endif
 1526         snd_mtxlock(sc->lock);
 1527         if (ch->data != NULL) {
 1528                 free(ch->data, M_ENVY24HT);
 1529                 ch->data = NULL;
 1530         }
 1531         snd_mtxunlock(sc->lock);
 1532 
 1533         return 0;
 1534 }
 1535 
 1536 static int
 1537 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
 1538 {
 1539         struct sc_chinfo *ch = data;
 1540         struct sc_info *sc = ch->parent;
 1541         struct envy24ht_emldma *emltab;
 1542         /* unsigned int bcnt, bsize; */
 1543         int i;
 1544 
 1545 #if(0)
 1546         device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
 1547 #endif
 1548         snd_mtxlock(sc->lock);
 1549         /* check and get format related information */
 1550         if (ch->dir == PCMDIR_PLAY)
 1551                 emltab = envy24ht_pemltab;
 1552         else
 1553                 emltab = envy24ht_remltab;
 1554         if (emltab == NULL) {
 1555                 snd_mtxunlock(sc->lock);
 1556                 return -1;
 1557         }
 1558         for (i = 0; emltab[i].format != 0; i++)
 1559                 if (emltab[i].format == format)
 1560                         break;
 1561         if (emltab[i].format == 0) {
 1562                 snd_mtxunlock(sc->lock);
 1563                 return -1;
 1564         }
 1565 
 1566         /* set format information */
 1567         ch->format = format;
 1568         ch->emldma = emltab[i].emldma;
 1569         if (ch->unit > emltab[i].unit)
 1570                 ch->blk *= ch->unit / emltab[i].unit;
 1571         else
 1572                 ch->blk /= emltab[i].unit / ch->unit;
 1573         ch->unit = emltab[i].unit;
 1574 
 1575         /* set channel buffer information */
 1576         ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
 1577 #if 0
 1578         if (ch->dir == PCMDIR_PLAY)
 1579                 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
 1580         else
 1581                 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
 1582         bsize *= ch->unit;
 1583         bcnt = ch->size / bsize;
 1584         sndbuf_resize(ch->buffer, bcnt, bsize);
 1585 #endif
 1586         snd_mtxunlock(sc->lock);
 1587 
 1588 #if(0)
 1589         device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
 1590 #endif
 1591         return 0;
 1592 }
 1593 
 1594 /*
 1595   IMPLEMENT NOTICE: In this driver, setspeed function only do setting
 1596   of speed information value. And real hardware speed setting is done
 1597   at start triggered(see envy24htchan_trigger()). So, at this function
 1598   is called, any value that ENVY24 can use is able to set. But, at
 1599   start triggerd, some other channel is running, and that channel's
 1600   speed isn't same with, then trigger function will fail.
 1601 */
 1602 static u_int32_t
 1603 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
 1604 {
 1605         struct sc_chinfo *ch = data;
 1606         u_int32_t val, prev;
 1607         int i;
 1608 
 1609 #if(0)
 1610         device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
 1611 #endif
 1612         prev = 0x7fffffff;
 1613         for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
 1614                 if (abs(val - speed) < abs(prev - speed))
 1615                         prev = val;
 1616                 else
 1617                         break;
 1618         }
 1619         ch->speed = prev;
 1620 
 1621 #if(0)
 1622         device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
 1623 #endif
 1624         return ch->speed;
 1625 }
 1626 
 1627 static u_int32_t
 1628 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
 1629 {
 1630         struct sc_chinfo *ch = data;
 1631         /* struct sc_info *sc = ch->parent; */
 1632         u_int32_t size, prev;
 1633         unsigned int bcnt, bsize;
 1634 
 1635 #if(0)
 1636         device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
 1637 #endif
 1638         prev = 0x7fffffff;
 1639         /* snd_mtxlock(sc->lock); */
 1640         for (size = ch->size / 2; size > 0; size /= 2) {
 1641                 if (abs(size - blocksize) < abs(prev - blocksize))
 1642                         prev = size;
 1643                 else
 1644                         break;
 1645         }
 1646 
 1647         ch->blk = prev / ch->unit;
 1648         if (ch->dir == PCMDIR_PLAY)
 1649                 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
 1650         else
 1651                 ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
 1652         /* set channel buffer information */
 1653         /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
 1654         if (ch->dir == PCMDIR_PLAY)
 1655                 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
 1656         else
 1657                 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
 1658         bsize *= ch->unit;
 1659         bcnt = ch->size / bsize;
 1660         sndbuf_resize(ch->buffer, bcnt, bsize);
 1661         /* snd_mtxunlock(sc->lock); */
 1662 
 1663 #if(0)
 1664         device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
 1665 #endif
 1666         return prev;
 1667 }
 1668 
 1669 /* semantic note: must start at beginning of buffer */
 1670 static int
 1671 envy24htchan_trigger(kobj_t obj, void *data, int go)
 1672 {
 1673         struct sc_chinfo *ch = data;
 1674         struct sc_info *sc = ch->parent;
 1675         u_int32_t ptr;
 1676         int slot;
 1677         int error = 0;
 1678 #if 0
 1679         int i;
 1680 
 1681         device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
 1682 #endif
 1683         snd_mtxlock(sc->lock);
 1684         if (ch->dir == PCMDIR_PLAY)
 1685                 slot = 0;
 1686         else
 1687                 slot = 1;
 1688         switch (go) {
 1689         case PCMTRIG_START:
 1690 #if(0)
 1691                 device_printf(sc->dev, "envy24htchan_trigger(): start\n");
 1692 #endif
 1693                 /* check or set channel speed */
 1694                 if (sc->run[0] == 0 && sc->run[1] == 0) {
 1695                         sc->speed = envy24ht_setspeed(sc, ch->speed);
 1696                         sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
 1697                         sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
 1698                 }
 1699                 else if (ch->speed != 0 && ch->speed != sc->speed) {
 1700                         error = -1;
 1701                         goto fail;
 1702                 }
 1703                 if (ch->speed == 0)
 1704                         ch->channel->speed = sc->speed;
 1705                 /* start or enable channel */
 1706                 sc->run[slot]++;
 1707                 if (sc->run[slot] == 1) {
 1708                         /* first channel */
 1709                         ch->offset = 0;
 1710                         sc->blk[slot] = ch->blk;
 1711                 }
 1712                 else {
 1713                         ptr = envy24ht_gethwptr(sc, ch->dir);
 1714                         ch->offset = ((ptr / ch->blk + 1) * ch->blk %
 1715                             (ch->size / 4)) * 4 / ch->unit;
 1716                         if (ch->blk < sc->blk[slot])
 1717                                 sc->blk[slot] = ch->blk;
 1718                 }
 1719                 if (ch->dir == PCMDIR_PLAY) {
 1720                         ch->emldma(ch);
 1721                         envy24ht_setvolume(sc, ch->num);
 1722                 }
 1723                 envy24ht_updintr(sc, ch->dir);
 1724                 if (sc->run[slot] == 1)
 1725                         envy24ht_start(sc, ch->dir);
 1726                 ch->run = 1;
 1727                 break;
 1728         case PCMTRIG_EMLDMAWR:
 1729 #if(0)
 1730                 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
 1731 #endif
 1732                 if (ch->run != 1) {
 1733                         error = -1;
 1734                         goto fail;
 1735                 }
 1736                 ch->emldma(ch);
 1737                 break;
 1738         case PCMTRIG_EMLDMARD:
 1739 #if(0)
 1740                 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
 1741 #endif
 1742                 if (ch->run != 1) {
 1743                         error = -1;
 1744                         goto fail;
 1745                 }
 1746                 ch->emldma(ch);
 1747                 break;
 1748         case PCMTRIG_ABORT:
 1749                 if (ch->run) {
 1750 #if(0)
 1751                 device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
 1752 #endif
 1753                 ch->run = 0;
 1754                 sc->run[slot]--;
 1755                 if (ch->dir == PCMDIR_PLAY)
 1756                         envy24ht_mutevolume(sc, ch->num);
 1757                 if (sc->run[slot] == 0) {
 1758                         envy24ht_stop(sc, ch->dir);
 1759                         sc->intr[slot] = 0;
 1760                 }
 1761 /*              else if (ch->blk == sc->blk[slot]) {
 1762                         sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
 1763                         for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
 1764                                 if (sc->chan[i].dir == ch->dir &&
 1765                                     sc->chan[i].run == 1 &&
 1766                                     sc->chan[i].blk < sc->blk[slot])
 1767                                         sc->blk[slot] = sc->chan[i].blk;
 1768                         }
 1769                         if (ch->blk != sc->blk[slot])
 1770                                 envy24ht_updintr(sc, ch->dir);
 1771                 }*/
 1772                 }
 1773                 break;
 1774         }
 1775 fail:
 1776         snd_mtxunlock(sc->lock);
 1777         return (error);
 1778 }
 1779 
 1780 static u_int32_t
 1781 envy24htchan_getptr(kobj_t obj, void *data)
 1782 {
 1783         struct sc_chinfo *ch = data;
 1784         struct sc_info *sc = ch->parent;
 1785         u_int32_t ptr, rtn;
 1786 
 1787 #if(0)
 1788         device_printf(sc->dev, "envy24htchan_getptr()\n");
 1789 #endif
 1790         snd_mtxlock(sc->lock);
 1791         ptr = envy24ht_gethwptr(sc, ch->dir);
 1792         rtn = ptr * ch->unit;
 1793         snd_mtxunlock(sc->lock);
 1794 
 1795 #if(0)
 1796         device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
 1797             rtn);
 1798 #endif
 1799         return rtn;
 1800 }
 1801 
 1802 static struct pcmchan_caps *
 1803 envy24htchan_getcaps(kobj_t obj, void *data)
 1804 {
 1805         struct sc_chinfo *ch = data;
 1806         struct sc_info *sc = ch->parent;
 1807         struct pcmchan_caps *rtn;
 1808 
 1809 #if(0)
 1810         device_printf(sc->dev, "envy24htchan_getcaps()\n");
 1811 #endif
 1812         snd_mtxlock(sc->lock);
 1813         if (ch->dir == PCMDIR_PLAY) {
 1814                 if (sc->run[0] == 0)
 1815                         rtn = &envy24ht_playcaps;
 1816                 else
 1817                         rtn = &sc->caps[0];
 1818         }
 1819         else {
 1820                 if (sc->run[1] == 0)
 1821                         rtn = &envy24ht_reccaps;
 1822                 else
 1823                         rtn = &sc->caps[1];
 1824         }
 1825         snd_mtxunlock(sc->lock);
 1826 
 1827         return rtn;
 1828 }
 1829 
 1830 static kobj_method_t envy24htchan_methods[] = {
 1831         KOBJMETHOD(channel_init,                envy24htchan_init),
 1832         KOBJMETHOD(channel_free,                envy24htchan_free),
 1833         KOBJMETHOD(channel_setformat,           envy24htchan_setformat),
 1834         KOBJMETHOD(channel_setspeed,            envy24htchan_setspeed),
 1835         KOBJMETHOD(channel_setblocksize,        envy24htchan_setblocksize),
 1836         KOBJMETHOD(channel_trigger,             envy24htchan_trigger),
 1837         KOBJMETHOD(channel_getptr,              envy24htchan_getptr),
 1838         KOBJMETHOD(channel_getcaps,             envy24htchan_getcaps),
 1839         KOBJMETHOD_END
 1840 };
 1841 CHANNEL_DECLARE(envy24htchan);
 1842 
 1843 /* -------------------------------------------------------------------- */
 1844 
 1845 /* mixer interface */
 1846 
 1847 static int
 1848 envy24htmixer_init(struct snd_mixer *m)
 1849 {
 1850         struct sc_info *sc = mix_getdevinfo(m);
 1851 
 1852 #if(0)
 1853         device_printf(sc->dev, "envy24htmixer_init()\n");
 1854 #endif
 1855         if (sc == NULL)
 1856                 return -1;
 1857 
 1858         /* set volume control rate */
 1859         snd_mtxlock(sc->lock);
 1860 #if 0
 1861         envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
 1862 #endif
 1863 
 1864         pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
 1865 
 1866         mix_setdevs(m, ENVY24HT_MIX_MASK);
 1867         mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
 1868 
 1869         snd_mtxunlock(sc->lock);
 1870 
 1871         return 0;
 1872 }
 1873 
 1874 static int
 1875 envy24htmixer_reinit(struct snd_mixer *m)
 1876 {
 1877         struct sc_info *sc = mix_getdevinfo(m);
 1878 
 1879         if (sc == NULL)
 1880                 return -1;
 1881 #if(0)
 1882         device_printf(sc->dev, "envy24htmixer_reinit()\n");
 1883 #endif
 1884 
 1885         return 0;
 1886 }
 1887 
 1888 static int
 1889 envy24htmixer_uninit(struct snd_mixer *m)
 1890 {
 1891         struct sc_info *sc = mix_getdevinfo(m);
 1892 
 1893         if (sc == NULL)
 1894                 return -1;
 1895 #if(0)
 1896         device_printf(sc->dev, "envy24htmixer_uninit()\n");
 1897 #endif
 1898 
 1899         return 0;
 1900 }
 1901 
 1902 static int
 1903 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
 1904 {
 1905         struct sc_info *sc = mix_getdevinfo(m);
 1906         int ch = envy24ht_mixmap[dev];
 1907         int hwch;
 1908         int i;
 1909 
 1910         if (sc == NULL)
 1911                 return -1;
 1912         if (dev == 0 && sc->cfg->codec->setvolume == NULL)
 1913                 return -1;
 1914         if (dev != 0 && ch == -1)
 1915                 return -1;
 1916         hwch = envy24ht_chanmap[ch];
 1917 #if(0)
 1918         device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
 1919             dev, left, right);
 1920 #endif
 1921 
 1922         snd_mtxlock(sc->lock);
 1923         if (dev == 0) {
 1924                 for (i = 0; i < sc->dacn; i++) {
 1925                         sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
 1926                 }
 1927         }
 1928         else {
 1929                 /* set volume value for hardware */
 1930                 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
 1931                         sc->left[hwch] = ENVY24HT_VOL_MUTE;
 1932                 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
 1933                         sc->right[hwch] = ENVY24HT_VOL_MUTE;
 1934 
 1935                 /* set volume for record channel and running play channel */
 1936                 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
 1937                         envy24ht_setvolume(sc, hwch);
 1938         }
 1939         snd_mtxunlock(sc->lock);
 1940 
 1941         return right << 8 | left;
 1942 }
 1943 
 1944 static u_int32_t
 1945 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
 1946 {
 1947         struct sc_info *sc = mix_getdevinfo(m);
 1948         int ch = envy24ht_mixmap[src];
 1949 #if(0)
 1950         device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
 1951 #endif
 1952 
 1953         if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
 1954                 sc->src = ch;
 1955         return src;
 1956 }
 1957 
 1958 static kobj_method_t envy24htmixer_methods[] = {
 1959         KOBJMETHOD(mixer_init,          envy24htmixer_init),
 1960         KOBJMETHOD(mixer_reinit,        envy24htmixer_reinit),
 1961         KOBJMETHOD(mixer_uninit,        envy24htmixer_uninit),
 1962         KOBJMETHOD(mixer_set,           envy24htmixer_set),
 1963         KOBJMETHOD(mixer_setrecsrc,     envy24htmixer_setrecsrc),
 1964         KOBJMETHOD_END
 1965 };
 1966 MIXER_DECLARE(envy24htmixer);
 1967 
 1968 /* -------------------------------------------------------------------- */
 1969 
 1970 /* The interrupt handler */
 1971 static void
 1972 envy24ht_intr(void *p)
 1973 {
 1974         struct sc_info *sc = (struct sc_info *)p;
 1975         struct sc_chinfo *ch;
 1976         u_int32_t ptr, dsize, feed;
 1977         int i;
 1978 
 1979 #if(0)
 1980         device_printf(sc->dev, "envy24ht_intr()\n");
 1981 #endif
 1982         snd_mtxlock(sc->lock);
 1983         if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
 1984 #if(0)
 1985                 device_printf(sc->dev, "envy24ht_intr(): play\n");
 1986 #endif
 1987                 dsize = sc->psize / 4;
 1988                 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
 1989 #if(0)
 1990                 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
 1991 #endif
 1992                 ptr -= ptr % sc->blk[0];
 1993                 feed = (ptr + dsize - sc->intr[0]) % dsize; 
 1994 #if(0)
 1995                 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
 1996 #endif
 1997                 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
 1998                         ch = &sc->chan[i];
 1999 #if(0)
 2000                         if (ch->run)
 2001                                 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
 2002 #endif
 2003                         if (ch->run && ch->blk <= feed) {
 2004                                 snd_mtxunlock(sc->lock);
 2005                                 chn_intr(ch->channel);
 2006                                 snd_mtxlock(sc->lock);
 2007                         }
 2008                 }
 2009                 sc->intr[0] = ptr;
 2010                 envy24ht_updintr(sc, PCMDIR_PLAY);
 2011         }
 2012         if (envy24ht_checkintr(sc, PCMDIR_REC)) {
 2013 #if(0)
 2014                 device_printf(sc->dev, "envy24ht_intr(): rec\n");
 2015 #endif
 2016                 dsize = sc->rsize / 4;
 2017                 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
 2018                 ptr -= ptr % sc->blk[1];
 2019                 feed = (ptr + dsize - sc->intr[1]) % dsize; 
 2020                 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
 2021                         ch = &sc->chan[i];
 2022                         if (ch->run && ch->blk <= feed) {
 2023                                 snd_mtxunlock(sc->lock);
 2024                                 chn_intr(ch->channel);
 2025                                 snd_mtxlock(sc->lock);
 2026                         }
 2027                 }
 2028                 sc->intr[1] = ptr;
 2029                 envy24ht_updintr(sc, PCMDIR_REC);
 2030         }
 2031         snd_mtxunlock(sc->lock);
 2032 
 2033         return;
 2034 }
 2035 
 2036 /*
 2037  * Probe and attach the card
 2038  */
 2039 
 2040 static int
 2041 envy24ht_pci_probe(device_t dev)
 2042 {
 2043         u_int16_t sv, sd;
 2044         int i;
 2045 
 2046 #if(0)
 2047         printf("envy24ht_pci_probe()\n");
 2048 #endif
 2049         if (pci_get_device(dev) == PCID_ENVY24HT &&
 2050             pci_get_vendor(dev) == PCIV_ENVY24) {
 2051                 sv = pci_get_subvendor(dev);
 2052                 sd = pci_get_subdevice(dev);
 2053                 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
 2054                         if (cfg_table[i].subvendor == sv &&
 2055                             cfg_table[i].subdevice == sd) {
 2056                                 break;
 2057                         }
 2058                 }
 2059                 device_set_desc(dev, cfg_table[i].name);
 2060 #if(0)
 2061                 printf("envy24ht_pci_probe(): return 0\n");
 2062 #endif
 2063                 return 0;
 2064         }
 2065         else {
 2066 #if(0)
 2067                 printf("envy24ht_pci_probe(): return ENXIO\n");
 2068 #endif
 2069                 return ENXIO;
 2070         }
 2071 }
 2072 
 2073 static void
 2074 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 2075 {
 2076         struct sc_info *sc = arg;
 2077 
 2078         sc->paddr = segs->ds_addr;
 2079 #if(0)
 2080         device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
 2081         if (bootverbose) {
 2082                 printf("envy24ht(play): setmap %lx, %lx; ",
 2083                     (unsigned long)segs->ds_addr,
 2084                     (unsigned long)segs->ds_len);
 2085         }
 2086 #endif
 2087         envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, (uint32_t)segs->ds_addr, 4);
 2088         envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
 2089 }
 2090 
 2091 static void
 2092 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 2093 {
 2094         struct sc_info *sc = arg;
 2095 
 2096         sc->raddr = segs->ds_addr;
 2097 #if(0)
 2098         device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
 2099         if (bootverbose) {
 2100                 printf("envy24ht(record): setmap %lx, %lx; ",
 2101                     (unsigned long)segs->ds_addr,
 2102                     (unsigned long)segs->ds_len);
 2103         }
 2104 #endif
 2105         envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, (uint32_t)segs->ds_addr, 4);
 2106         envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
 2107 }
 2108 
 2109 static void
 2110 envy24ht_dmafree(struct sc_info *sc)
 2111 {
 2112 #if(0)
 2113         device_printf(sc->dev, "envy24ht_dmafree():");
 2114         printf(" sc->raddr(0x%08x)", (u_int32_t)sc->raddr);
 2115         printf(" sc->paddr(0x%08x)", (u_int32_t)sc->paddr);
 2116         if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
 2117         else printf(" sc->rbuf(null)");
 2118         if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
 2119         else printf(" sc->pbuf(null)\n");
 2120 #endif
 2121 #if(0)
 2122         if (sc->raddr)
 2123                 bus_dmamap_unload(sc->dmat, sc->rmap);
 2124         if (sc->paddr)
 2125                 bus_dmamap_unload(sc->dmat, sc->pmap);
 2126         if (sc->rbuf)
 2127                 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
 2128         if (sc->pbuf)
 2129                 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
 2130 #else
 2131         bus_dmamap_unload(sc->dmat, sc->rmap);
 2132         bus_dmamap_unload(sc->dmat, sc->pmap);
 2133         bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
 2134         bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
 2135 #endif
 2136 
 2137         sc->raddr = sc->paddr = 0;
 2138         sc->pbuf = NULL;
 2139         sc->rbuf = NULL;
 2140 
 2141         return;
 2142 }
 2143 
 2144 static int
 2145 envy24ht_dmainit(struct sc_info *sc)
 2146 {
 2147 
 2148 #if(0)
 2149         device_printf(sc->dev, "envy24ht_dmainit()\n");
 2150 #endif
 2151         /* init values */
 2152         sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
 2153         sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
 2154         sc->pbuf = NULL;
 2155         sc->rbuf = NULL;
 2156         sc->paddr = sc->raddr = 0;
 2157         sc->blk[0] = sc->blk[1] = 0;
 2158 
 2159         /* allocate DMA buffer */
 2160 #if(0)
 2161         device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
 2162 #endif
 2163         if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
 2164                 goto bad;
 2165 #if(0)
 2166         device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
 2167 #endif
 2168         if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
 2169                 goto bad;
 2170 #if(0)
 2171         device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
 2172 #endif
 2173         if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, BUS_DMA_NOWAIT))
 2174                 goto bad;
 2175 #if(0)
 2176         device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
 2177 #endif
 2178         if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, BUS_DMA_NOWAIT))
 2179                 goto bad;
 2180         bzero(sc->pbuf, sc->psize);
 2181         bzero(sc->rbuf, sc->rsize);
 2182 
 2183         return 0;
 2184  bad:
 2185         envy24ht_dmafree(sc);
 2186         return ENOSPC;
 2187 }
 2188 
 2189 static void
 2190 envy24ht_putcfg(struct sc_info *sc)
 2191 {
 2192         device_printf(sc->dev, "system configuration\n");
 2193         printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
 2194             sc->cfg->subvendor, sc->cfg->subdevice);
 2195         printf("  XIN2 Clock Source: ");
 2196         switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
 2197         case 0x00:
 2198                 printf("24.576MHz(96kHz*256)\n");
 2199                 break;
 2200         case 0x40:
 2201                 printf("49.152MHz(192kHz*256)\n");
 2202                 break;
 2203         case 0x80:
 2204                 printf("reserved\n");
 2205                 break;
 2206         default:
 2207                 printf("illegal system setting\n");
 2208         }
 2209         printf("  MPU-401 UART(s) #: ");
 2210         if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
 2211                 printf("1\n");
 2212         else
 2213                 printf("not implemented\n");
 2214         switch (sc->adcn) {
 2215         case 0x01:
 2216         case 0x02:
 2217                 printf("  ADC #: ");
 2218                 printf("%d\n", sc->adcn);
 2219                 break;
 2220         case 0x03:
 2221                 printf("  ADC #: ");
 2222                 printf("%d", 1);
 2223                 printf(" and SPDIF receiver connected\n");
 2224                 break;
 2225         default:
 2226                 printf("  no physical inputs\n");
 2227         }
 2228         printf("  DAC #: ");
 2229         printf("%d\n", sc->dacn);
 2230         printf("  Multi-track converter type: ");
 2231         if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
 2232                 printf("AC'97(SDATA_OUT:");
 2233                 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
 2234                         printf("packed");
 2235                 else
 2236                         printf("split");
 2237                 printf(")\n");
 2238         }
 2239         else {
 2240                 printf("I2S(");
 2241                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
 2242                         printf("with volume, ");
 2243                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
 2244                         printf("192KHz support, ");
 2245                 else
 2246                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
 2247                         printf("192KHz support, ");
 2248                 else
 2249                         printf("48KHz support, ");
 2250                 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
 2251                 case ENVY24HT_CCSM_I2S_16BIT:
 2252                         printf("16bit resolution, ");
 2253                         break;
 2254                 case ENVY24HT_CCSM_I2S_18BIT:
 2255                         printf("18bit resolution, ");
 2256                         break;
 2257                 case ENVY24HT_CCSM_I2S_20BIT:
 2258                         printf("20bit resolution, ");
 2259                         break;
 2260                 case ENVY24HT_CCSM_I2S_24BIT:
 2261                         printf("24bit resolution, ");
 2262                         break;
 2263                 }
 2264                 printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
 2265         }
 2266         printf("  S/PDIF(IN/OUT): ");
 2267         if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
 2268                 printf("1/");
 2269         else
 2270                 printf("0/");
 2271         if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
 2272                 printf("1 ");
 2273         else
 2274                 printf("0 ");
 2275         if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
 2276                 printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
 2277         printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
 2278             sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
 2279 }
 2280 
 2281 static int
 2282 envy24ht_init(struct sc_info *sc)
 2283 {
 2284         u_int32_t data;
 2285 #if(0)
 2286         int rtn;
 2287 #endif
 2288         int i;
 2289         u_int32_t sv, sd;
 2290 
 2291 #if(0)
 2292         device_printf(sc->dev, "envy24ht_init()\n");
 2293 #endif
 2294 
 2295         /* reset chip */
 2296 #if 0
 2297         envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
 2298         DELAY(200);
 2299         envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
 2300         DELAY(200);
 2301 
 2302         /* legacy hardware disable */
 2303         data = pci_read_config(sc->dev, PCIR_LAC, 2);
 2304         data |= PCIM_LAC_DISABLE;
 2305         pci_write_config(sc->dev, PCIR_LAC, data, 2);
 2306 #endif
 2307 
 2308         /* check system configuration */
 2309         sc->cfg = NULL;
 2310         for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
 2311                 /* 1st: search configuration from table */
 2312                 sv = pci_get_subvendor(sc->dev);
 2313                 sd = pci_get_subdevice(sc->dev);
 2314                 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
 2315 #if(0)
 2316                         device_printf(sc->dev, "Set configuration from table\n");
 2317 #endif
 2318                         sc->cfg = &cfg_table[i];
 2319                         break;
 2320                 }
 2321         }
 2322         if (sc->cfg == NULL) {
 2323                 /* 2nd: read configuration from table */
 2324                 sc->cfg = envy24ht_rom2cfg(sc);
 2325         }
 2326         sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
 2327         sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
 2328 
 2329         if (1 /* bootverbose */) {
 2330                 envy24ht_putcfg(sc);
 2331         }
 2332 
 2333         /* set system configuration */
 2334         envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
 2335         envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
 2336         envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
 2337         envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
 2338         envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
 2339         envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
 2340         envy24ht_gpiowr(sc, sc->cfg->gpiostate);
 2341 
 2342         if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
 2343                 envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
 2344                 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
 2345                 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
 2346         }
 2347 
 2348         for (i = 0; i < sc->adcn; i++) {
 2349                 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
 2350                 sc->cfg->codec->init(sc->adc[i]);
 2351         }
 2352         for (i = 0; i < sc->dacn; i++) {
 2353                 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
 2354                 sc->cfg->codec->init(sc->dac[i]);
 2355         }
 2356 
 2357         /* initialize DMA buffer */
 2358 #if(0)
 2359         device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
 2360 #endif
 2361         if (envy24ht_dmainit(sc))
 2362                 return ENOSPC;
 2363 
 2364         /* initialize status */
 2365         sc->run[0] = sc->run[1] = 0;
 2366         sc->intr[0] = sc->intr[1] = 0;
 2367         sc->speed = 0;
 2368         sc->caps[0].fmtlist = envy24ht_playfmt;
 2369         sc->caps[1].fmtlist = envy24ht_recfmt;
 2370 
 2371         /* set channel router */
 2372 #if 0
 2373         envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
 2374         envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
 2375         envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
 2376 #endif
 2377 
 2378         /* set macro interrupt mask */
 2379         data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
 2380         envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
 2381         data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
 2382 #if(0)
 2383         device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
 2384 #endif
 2385 
 2386         return 0;
 2387 }
 2388 
 2389 static int
 2390 envy24ht_alloc_resource(struct sc_info *sc)
 2391 {
 2392         /* allocate I/O port resource */
 2393         sc->csid = PCIR_CCS;
 2394         sc->cs = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
 2395             &sc->csid, RF_ACTIVE);
 2396         sc->mtid = ENVY24HT_PCIR_MT;
 2397         sc->mt = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
 2398             &sc->mtid, RF_ACTIVE);
 2399         if (!sc->cs || !sc->mt) {
 2400                 device_printf(sc->dev, "unable to map IO port space\n");
 2401                 return ENXIO;
 2402         }
 2403         sc->cst = rman_get_bustag(sc->cs);
 2404         sc->csh = rman_get_bushandle(sc->cs);
 2405         sc->mtt = rman_get_bustag(sc->mt);
 2406         sc->mth = rman_get_bushandle(sc->mt);
 2407 #if(0)
 2408         device_printf(sc->dev,
 2409             "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
 2410             pci_read_config(sc->dev, PCIR_CCS, 4),
 2411             pci_read_config(sc->dev, PCIR_MT, 4));
 2412 #endif
 2413 
 2414         /* allocate interrupt resource */
 2415         sc->irqid = 0;
 2416         sc->irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irqid,
 2417                                  RF_ACTIVE | RF_SHAREABLE);
 2418         if (!sc->irq ||
 2419             snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24ht_intr, sc, &sc->ih)) {
 2420                 device_printf(sc->dev, "unable to map interrupt\n");
 2421                 return ENXIO;
 2422         }
 2423 
 2424         /* allocate DMA resource */
 2425         if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
 2426             /*alignment*/4,
 2427             /*boundary*/0,
 2428             /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
 2429             /*highaddr*/BUS_SPACE_MAXADDR,
 2430             /*filter*/NULL, /*filterarg*/NULL,
 2431             /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
 2432             /*nsegments*/1, /*maxsegsz*/0x3ffff,
 2433             /*flags*/0, /*lockfunc*/NULL,
 2434             /*lockarg*/NULL, &sc->dmat) != 0) {
 2435                 device_printf(sc->dev, "unable to create dma tag\n");
 2436                 return ENXIO;
 2437         }
 2438 
 2439         return 0;
 2440 }
 2441 
 2442 static int
 2443 envy24ht_pci_attach(device_t dev)
 2444 {
 2445         struct sc_info          *sc;
 2446         char                    status[SND_STATUSLEN];
 2447         int                     err = 0;
 2448         int                     i;
 2449 
 2450 #if(0)
 2451         device_printf(dev, "envy24ht_pci_attach()\n");
 2452 #endif
 2453         /* get sc_info data area */
 2454         if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) {
 2455                 device_printf(dev, "cannot allocate softc\n");
 2456                 return ENXIO;
 2457         }
 2458 
 2459         bzero(sc, sizeof(*sc));
 2460         sc->lock = snd_mtxcreate(device_get_nameunit(dev),
 2461             "snd_envy24ht softc");
 2462         sc->dev = dev;
 2463 
 2464         /* initialize PCI interface */
 2465         pci_enable_busmaster(dev);
 2466 
 2467         /* allocate resources */
 2468         err = envy24ht_alloc_resource(sc);
 2469         if (err) {
 2470                 device_printf(dev, "unable to allocate system resources\n");
 2471                 goto bad;
 2472         }
 2473 
 2474         /* initialize card */
 2475         err = envy24ht_init(sc);
 2476         if (err) {
 2477                 device_printf(dev, "unable to initialize the card\n");
 2478                 goto bad;
 2479         }
 2480 
 2481         /* set multi track mixer */
 2482         mixer_init(dev, &envy24htmixer_class, sc);
 2483 
 2484         /* set channel information */
 2485         /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
 2486         err = pcm_register(dev, sc, 1, 2 + sc->adcn);
 2487         if (err)
 2488                 goto bad;
 2489         sc->chnum = 0;
 2490         /* for (i = 0; i < 5; i++) { */
 2491                 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
 2492                 sc->chnum++;
 2493         /* } */
 2494         for (i = 0; i < 2 + sc->adcn; i++) {
 2495                 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
 2496                 sc->chnum++;
 2497         }
 2498 
 2499         /* set status iformation */
 2500         snprintf(status, SND_STATUSLEN,
 2501             "at io 0x%jx:%jd,0x%jx:%jd irq %jd",
 2502             rman_get_start(sc->cs),
 2503             rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
 2504             rman_get_start(sc->mt),
 2505             rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
 2506             rman_get_start(sc->irq));
 2507         pcm_setstatus(dev, status);
 2508 
 2509         return 0;
 2510 
 2511 bad:
 2512         if (sc->ih)
 2513                 bus_teardown_intr(dev, sc->irq, sc->ih);
 2514         if (sc->irq)
 2515                 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
 2516         envy24ht_dmafree(sc);
 2517         if (sc->dmat)
 2518                 bus_dma_tag_destroy(sc->dmat);
 2519         if (sc->cfg->codec->destroy != NULL) {
 2520                 for (i = 0; i < sc->adcn; i++)
 2521                         sc->cfg->codec->destroy(sc->adc[i]);
 2522                 for (i = 0; i < sc->dacn; i++)
 2523                         sc->cfg->codec->destroy(sc->dac[i]);
 2524         }
 2525         envy24ht_cfgfree(sc->cfg);
 2526         if (sc->cs)
 2527                 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
 2528         if (sc->mt)
 2529                 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
 2530         if (sc->lock)
 2531                 snd_mtxfree(sc->lock);
 2532         free(sc, M_ENVY24HT);
 2533         return err;
 2534 }
 2535 
 2536 static int
 2537 envy24ht_pci_detach(device_t dev)
 2538 {
 2539         struct sc_info *sc;
 2540         int r;
 2541         int i;
 2542 
 2543 #if(0)
 2544         device_printf(dev, "envy24ht_pci_detach()\n");
 2545 #endif
 2546         sc = pcm_getdevinfo(dev);
 2547         if (sc == NULL)
 2548                 return 0;
 2549         r = pcm_unregister(dev);
 2550         if (r)
 2551                 return r;
 2552 
 2553         envy24ht_dmafree(sc);
 2554         if (sc->cfg->codec->destroy != NULL) {
 2555                 for (i = 0; i < sc->adcn; i++)
 2556                         sc->cfg->codec->destroy(sc->adc[i]);
 2557                 for (i = 0; i < sc->dacn; i++)
 2558                         sc->cfg->codec->destroy(sc->dac[i]);
 2559         }
 2560         envy24ht_cfgfree(sc->cfg);
 2561         bus_dma_tag_destroy(sc->dmat);
 2562         bus_teardown_intr(dev, sc->irq, sc->ih);
 2563         bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
 2564         bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
 2565         bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
 2566         snd_mtxfree(sc->lock);
 2567         free(sc, M_ENVY24HT);
 2568         return 0;
 2569 }
 2570 
 2571 static device_method_t envy24ht_methods[] = {
 2572         /* Device interface */
 2573         DEVMETHOD(device_probe,         envy24ht_pci_probe),
 2574         DEVMETHOD(device_attach,        envy24ht_pci_attach),
 2575         DEVMETHOD(device_detach,        envy24ht_pci_detach),
 2576         { 0, 0 }
 2577 };
 2578 
 2579 static driver_t envy24ht_driver = {
 2580         "pcm",
 2581         envy24ht_methods,
 2582         PCM_SOFTC_SIZE,
 2583 };
 2584 
 2585 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, 0, 0);
 2586 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
 2587 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
 2588 MODULE_VERSION(snd_envy24ht, 1);

Cache object: 8eb27d614408c7cd92c1a4c0fcd2e26f


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