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