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