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