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