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