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