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

Cache object: ced9b1cad5b477f085fcdaa3f4b26f44


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