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