]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/sound/pci/envy24.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / sound / pci / envy24.c
1 /*-
2  * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27
28 #ifdef HAVE_KERNEL_OPTION_HEADERS
29 #include "opt_snd.h"
30 #endif
31
32 #include <dev/sound/pcm/sound.h>
33 #include <dev/sound/pcm/ac97.h>
34 #include <dev/sound/pci/spicds.h>
35 #include <dev/sound/pci/envy24.h>
36
37 #include <dev/pci/pcireg.h>
38 #include <dev/pci/pcivar.h>
39
40 #include "mixer_if.h"
41
42 SND_DECLARE_FILE("$FreeBSD$");
43
44 static MALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio");
45
46 /* -------------------------------------------------------------------- */
47
48 struct sc_info;
49
50 #define ENVY24_PLAY_CHNUM 10
51 #define ENVY24_REC_CHNUM 12
52 #define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */)
53 #define ENVY24_REC_BUFUNIT  (4 /* byte/sample */ * 12 /* channel */)
54 #define ENVY24_SAMPLE_NUM   4096
55
56 #define ENVY24_TIMEOUT 1000
57
58 #define ENVY24_DEFAULT_FORMAT   SND_FORMAT(AFMT_S16_LE, 2, 0)
59
60 #define ENVY24_NAMELEN 32
61
62 #define SDA_GPIO 0x10
63 #define SCL_GPIO 0x20
64
65 struct envy24_sample {
66         volatile u_int32_t buffer;
67 };
68
69 typedef struct envy24_sample sample32_t;
70
71 /* channel registers */
72 struct sc_chinfo {
73         struct snd_dbuf         *buffer;
74         struct pcm_channel      *channel;
75         struct sc_info          *parent;
76         int                     dir;
77         unsigned                num; /* hw channel number */
78
79         /* channel information */
80         u_int32_t               format;
81         u_int32_t               speed;
82         u_int32_t               blk; /* hw block size(dword) */
83
84         /* format conversion structure */
85         u_int8_t                *data;
86         unsigned int            size; /* data buffer size(byte) */
87         int                     unit; /* sample size(byte) */
88         unsigned int            offset; /* samples number offset */
89         void                    (*emldma)(struct sc_chinfo *);
90
91         /* flags */
92         int                     run;
93 };
94
95 /* codec interface entrys */
96 struct codec_entry {
97         void *(*create)(device_t dev, void *devinfo, int dir, int num);
98         void (*destroy)(void *codec);
99         void (*init)(void *codec);
100         void (*reinit)(void *codec);
101         void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
102         void (*setrate)(void *codec, int which, int rate);
103 };
104
105 /* system configuration information */
106 struct cfg_info {
107         char *name;
108         u_int16_t subvendor, subdevice;
109         u_int8_t scfg, acl, i2s, spdif;
110         u_int8_t gpiomask, gpiostate, gpiodir;
111         u_int8_t cdti, cclk, cs, cif, type;
112         u_int8_t free;
113         struct codec_entry *codec;
114 };
115
116 /* device private data */
117 struct sc_info {
118         device_t        dev;
119         struct mtx      *lock;
120
121         /* Control/Status registor */
122         struct resource *cs;
123         int             csid;
124         bus_space_tag_t cst;
125         bus_space_handle_t csh;
126         /* DDMA registor */
127         struct resource *ddma;
128         int             ddmaid;
129         bus_space_tag_t ddmat;
130         bus_space_handle_t ddmah;
131         /* Consumer Section DMA Channel Registers */
132         struct resource *ds;
133         int             dsid;
134         bus_space_tag_t dst;
135         bus_space_handle_t dsh;
136         /* MultiTrack registor */
137         struct resource *mt;
138         int             mtid;
139         bus_space_tag_t mtt;
140         bus_space_handle_t mth;
141         /* DMA tag */
142         bus_dma_tag_t dmat;
143         /* IRQ resource */
144         struct resource *irq;
145         int             irqid;
146         void            *ih;
147
148         /* system configuration data */
149         struct cfg_info *cfg;
150
151         /* ADC/DAC number and info */
152         int             adcn, dacn;
153         void            *adc[4], *dac[4];
154
155         /* mixer control data */
156         u_int32_t       src;
157         u_int8_t        left[ENVY24_CHAN_NUM];
158         u_int8_t        right[ENVY24_CHAN_NUM];
159
160         /* Play/Record DMA fifo */
161         sample32_t      *pbuf;
162         sample32_t      *rbuf;
163         u_int32_t       psize, rsize; /* DMA buffer size(byte) */
164         u_int16_t       blk[2]; /* transfer check blocksize(dword) */
165         bus_dmamap_t    pmap, rmap;
166
167         /* current status */
168         u_int32_t       speed;
169         int             run[2];
170         u_int16_t       intr[2];
171         struct pcmchan_caps     caps[2];
172
173         /* channel info table */
174         unsigned        chnum;
175         struct sc_chinfo chan[11];
176 };
177
178 /* -------------------------------------------------------------------- */
179
180 /*
181  * prototypes
182  */
183
184 /* DMA emulator */
185 static void envy24_p8u(struct sc_chinfo *);
186 static void envy24_p16sl(struct sc_chinfo *);
187 static void envy24_p32sl(struct sc_chinfo *);
188 static void envy24_r16sl(struct sc_chinfo *);
189 static void envy24_r32sl(struct sc_chinfo *);
190
191 /* channel interface */
192 static void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
193 static int envy24chan_setformat(kobj_t, void *, u_int32_t);
194 static u_int32_t envy24chan_setspeed(kobj_t, void *, u_int32_t);
195 static u_int32_t envy24chan_setblocksize(kobj_t, void *, u_int32_t);
196 static int envy24chan_trigger(kobj_t, void *, int);
197 static u_int32_t envy24chan_getptr(kobj_t, void *);
198 static struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *);
199
200 /* mixer interface */
201 static int envy24mixer_init(struct snd_mixer *);
202 static int envy24mixer_reinit(struct snd_mixer *);
203 static int envy24mixer_uninit(struct snd_mixer *);
204 static int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
205 static u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t);
206
207 /* M-Audio Delta series AK4524 access interface */
208 static void *envy24_delta_ak4524_create(device_t, void *, int, int);
209 static void envy24_delta_ak4524_destroy(void *);
210 static void envy24_delta_ak4524_init(void *);
211 static void envy24_delta_ak4524_reinit(void *);
212 static void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int);
213
214 /* -------------------------------------------------------------------- */
215
216 /*
217   system constant tables
218 */
219
220 /* API -> hardware channel map */
221 static unsigned envy24_chanmap[ENVY24_CHAN_NUM] = {
222         ENVY24_CHAN_PLAY_SPDIF, /* 0 */
223         ENVY24_CHAN_PLAY_DAC1,  /* 1 */
224         ENVY24_CHAN_PLAY_DAC2,  /* 2 */
225         ENVY24_CHAN_PLAY_DAC3,  /* 3 */
226         ENVY24_CHAN_PLAY_DAC4,  /* 4 */
227         ENVY24_CHAN_REC_MIX,    /* 5 */
228         ENVY24_CHAN_REC_SPDIF,  /* 6 */
229         ENVY24_CHAN_REC_ADC1,   /* 7 */
230         ENVY24_CHAN_REC_ADC2,   /* 8 */
231         ENVY24_CHAN_REC_ADC3,   /* 9 */
232         ENVY24_CHAN_REC_ADC4,   /* 10 */
233 };
234
235 /* mixer -> API channel map. see above */
236 static int envy24_mixmap[] = {
237         -1, /* Master output level. It is depend on codec support */
238         -1, /* Treble level of all output channels */
239         -1, /* Bass level of all output channels */
240         -1, /* Volume of synthesier input */
241         0,  /* Output level for the audio device */
242         -1, /* Output level for the PC speaker */
243         7,  /* line in jack */
244         -1, /* microphone jack */
245         -1, /* CD audio input */
246         -1, /* Recording monitor */
247         1,  /* alternative codec */
248         -1, /* global recording level */
249         -1, /* Input gain */
250         -1, /* Output gain */
251         8,  /* Input source 1 */
252         9,  /* Input source 2 */
253         10, /* Input source 3 */
254         6,  /* Digital (input) 1 */
255         -1, /* Digital (input) 2 */
256         -1, /* Digital (input) 3 */
257         -1, /* Phone input */
258         -1, /* Phone output */
259         -1, /* Video/TV (audio) in */
260         -1, /* Radio in */
261         -1, /* Monitor volume */
262 };
263
264 /* variable rate audio */
265 static u_int32_t envy24_speed[] = {
266     96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
267     12000, 11025, 9600, 8000, 0
268 };
269
270 /* known boards configuration */
271 static struct codec_entry delta_codec = {
272         envy24_delta_ak4524_create,
273         envy24_delta_ak4524_destroy,
274         envy24_delta_ak4524_init,
275         envy24_delta_ak4524_reinit,
276         envy24_delta_ak4524_setvolume,
277         NULL, /* setrate */
278 };
279
280 static struct cfg_info cfg_table[] = {
281         {
282                 "Envy24 audio (M Audio Delta Dio 2496)",
283                 0x1412, 0xd631,
284                 0x10, 0x80, 0xf0, 0x03,
285                 0x02, 0xc0, 0xfd,
286                 0x10, 0x20, 0x40, 0x00, 0x00,
287                 0x00,
288                 &delta_codec,
289         },
290         {
291                 "Envy24 audio (Terratec DMX 6fire)",
292                 0x153b, 0x1138,
293                 0x2f, 0x80, 0xf0, 0x03,
294                 0xc0, 0xff, 0x7f,
295                 0x10, 0x20, 0x01, 0x01, 0x00,
296                 0x00,
297                 &delta_codec,
298         },
299         {
300                 "Envy24 audio (M Audio Audiophile 2496)",
301                 0x1412, 0xd634,
302                 0x10, 0x80, 0x72, 0x03,
303                 0x04, 0xfe, 0xfb,
304                 0x08, 0x02, 0x20, 0x00, 0x01,
305                 0x00,
306                 &delta_codec,
307         },
308         {
309                 "Envy24 audio (M Audio Delta 66)",
310                 0x1412, 0xd632,
311                 0x15, 0x80, 0xf0, 0x03,
312                 0x02, 0xc0, 0xfd,
313                 0x10, 0x20, 0x40, 0x00, 0x00,
314                 0x00,
315                 &delta_codec,
316         },
317         {
318                 "Envy24 audio (M Audio Delta 44)",
319                 0x1412, 0xd633,
320                 0x15, 0x80, 0xf0, 0x00,
321                 0x02, 0xc0, 0xfd,
322                 0x10, 0x20, 0x40, 0x00, 0x00,
323                 0x00,
324                 &delta_codec,
325         },
326         {
327                 "Envy24 audio (M Audio Delta 1010)",
328                 0x1412, 0xd630,
329                 0x1f, 0x80, 0xf0, 0x03,
330                 0x22, 0xd0, 0xdd,
331                 0x10, 0x20, 0x40, 0x00, 0x00,
332                 0x00,
333                 &delta_codec,
334         },
335         {
336                 "Envy24 audio (M Audio Delta 1010LT)",
337                 0x1412, 0xd63b,
338                 0x1f, 0x80, 0x72, 0x03,
339                 0x04, 0x7e, 0xfb,
340                 0x08, 0x02, 0x70, 0x00, 0x00,
341                 0x00,
342                 &delta_codec,
343         },
344         {
345                 "Envy24 audio (Terratec EWX 2496)",
346                 0x153b, 0x1130,
347                 0x10, 0x80, 0xf0, 0x03,
348                 0xc0, 0x3f, 0x3f,
349                 0x10, 0x20, 0x01, 0x01, 0x00,
350                 0x00,
351                 &delta_codec,
352         },
353         {
354                 "Envy24 audio (Generic)",
355                 0, 0,
356                 0x0f, 0x00, 0x01, 0x03,
357                 0xff, 0x00, 0x00,
358                 0x10, 0x20, 0x40, 0x00, 0x00,
359                 0x00,
360                 &delta_codec, /* default codec routines */
361         }
362 };
363
364 static u_int32_t envy24_recfmt[] = {
365         SND_FORMAT(AFMT_S16_LE, 2, 0),
366         SND_FORMAT(AFMT_S32_LE, 2, 0),
367         0
368 };
369 static struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0};
370
371 static u_int32_t envy24_playfmt[] = {
372         SND_FORMAT(AFMT_U8, 2, 0),
373         SND_FORMAT(AFMT_S16_LE, 2, 0),
374         SND_FORMAT(AFMT_S32_LE, 2, 0),
375         0
376 };
377
378 static struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0};
379
380 struct envy24_emldma {
381         u_int32_t       format;
382         void            (*emldma)(struct sc_chinfo *);
383         int             unit;
384 };
385
386 static struct envy24_emldma envy24_pemltab[] = {
387         {SND_FORMAT(AFMT_U8, 2, 0), envy24_p8u, 2},
388         {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24_p16sl, 4},
389         {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24_p32sl, 8},
390         {0, NULL, 0}
391 };
392
393 static struct envy24_emldma envy24_remltab[] = {
394         {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24_r16sl, 4},
395         {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24_r32sl, 8},
396         {0, NULL, 0}
397 };
398
399 /* -------------------------------------------------------------------- */
400
401 /* common routines */
402 static u_int32_t
403 envy24_rdcs(struct sc_info *sc, int regno, int size)
404 {
405         switch (size) {
406         case 1:
407                 return bus_space_read_1(sc->cst, sc->csh, regno);
408         case 2:
409                 return bus_space_read_2(sc->cst, sc->csh, regno);
410         case 4:
411                 return bus_space_read_4(sc->cst, sc->csh, regno);
412         default:
413                 return 0xffffffff;
414         }
415 }
416
417 static void
418 envy24_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
419 {
420         switch (size) {
421         case 1:
422                 bus_space_write_1(sc->cst, sc->csh, regno, data);
423                 break;
424         case 2:
425                 bus_space_write_2(sc->cst, sc->csh, regno, data);
426                 break;
427         case 4:
428                 bus_space_write_4(sc->cst, sc->csh, regno, data);
429                 break;
430         }
431 }
432
433 static u_int32_t
434 envy24_rdmt(struct sc_info *sc, int regno, int size)
435 {
436         switch (size) {
437         case 1:
438                 return bus_space_read_1(sc->mtt, sc->mth, regno);
439         case 2:
440                 return bus_space_read_2(sc->mtt, sc->mth, regno);
441         case 4:
442                 return bus_space_read_4(sc->mtt, sc->mth, regno);
443         default:
444                 return 0xffffffff;
445         }
446 }
447
448 static void
449 envy24_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
450 {
451         switch (size) {
452         case 1:
453                 bus_space_write_1(sc->mtt, sc->mth, regno, data);
454                 break;
455         case 2:
456                 bus_space_write_2(sc->mtt, sc->mth, regno, data);
457                 break;
458         case 4:
459                 bus_space_write_4(sc->mtt, sc->mth, regno, data);
460                 break;
461         }
462 }
463
464 static u_int32_t
465 envy24_rdci(struct sc_info *sc, int regno)
466 {
467         envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
468         return envy24_rdcs(sc, ENVY24_CCS_DATA, 1);
469 }
470
471 static void
472 envy24_wrci(struct sc_info *sc, int regno, u_int32_t data)
473 {
474         envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
475         envy24_wrcs(sc, ENVY24_CCS_DATA, data, 1);
476 }
477
478 /* -------------------------------------------------------------------- */
479
480 /* I2C port/E2PROM access routines */
481
482 static int
483 envy24_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
484 {
485         u_int32_t data;
486         int i;
487
488 #if(0)
489         device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
490 #endif
491         for (i = 0; i < ENVY24_TIMEOUT; i++) {
492                 data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
493                 if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
494                         break;
495                 DELAY(32); /* 31.25kHz */
496         }
497         if (i == ENVY24_TIMEOUT) {
498                 return -1;
499         }
500         envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
501         envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
502             (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_RD, 1);
503         for (i = 0; i < ENVY24_TIMEOUT; i++) {
504                 data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
505                 if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
506                         break;
507                 DELAY(32); /* 31.25kHz */
508         }
509         if (i == ENVY24_TIMEOUT) {
510                 return -1;
511         }
512         data = envy24_rdcs(sc, ENVY24_CCS_I2CDATA, 1);
513
514 #if(0)
515         device_printf(sc->dev, "envy24_rdi2c(): return 0x%x\n", data);
516 #endif
517         return (int)data;
518 }
519
520 #if 0
521 static int
522 envy24_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
523 {
524         u_int32_t tmp;
525         int i;
526
527 #if(0)
528         device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
529 #endif
530         for (i = 0; i < ENVY24_TIMEOUT; i++) {
531                 tmp = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
532                 if ((tmp & ENVY24_CCS_I2CSTAT_BSY) == 0)
533                         break;
534                 DELAY(32); /* 31.25kHz */
535         }
536         if (i == ENVY24_TIMEOUT) {
537                 return -1;
538         }
539         envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
540         envy24_wrcs(sc, ENVY24_CCS_I2CDATA, data, 1);
541         envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
542             (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_WR, 1);
543         for (i = 0; i < ENVY24_TIMEOUT; i++) {
544                 data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
545                 if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
546                         break;
547                 DELAY(32); /* 31.25kHz */
548         }
549         if (i == ENVY24_TIMEOUT) {
550                 return -1;
551         }
552
553         return 0;
554 }
555 #endif
556
557 static int
558 envy24_rdrom(struct sc_info *sc, u_int32_t addr)
559 {
560         u_int32_t data;
561
562 #if(0)
563         device_printf(sc->dev, "envy24_rdrom(sc, 0x%02x)\n", addr);
564 #endif
565         data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
566         if ((data & ENVY24_CCS_I2CSTAT_ROM) == 0) {
567 #if(0)
568                 device_printf(sc->dev, "envy24_rdrom(): E2PROM not presented\n");
569 #endif
570                 return -1;
571         }
572
573         return envy24_rdi2c(sc, ENVY24_CCS_I2CDEV_ROM, addr);
574 }
575
576 static struct cfg_info *
577 envy24_rom2cfg(struct sc_info *sc)
578 {
579         struct cfg_info *buff;
580         int size;
581         int i;
582
583 #if(0)
584         device_printf(sc->dev, "envy24_rom2cfg(sc)\n");
585 #endif
586         size = envy24_rdrom(sc, ENVY24_E2PROM_SIZE);
587         if (size < ENVY24_E2PROM_GPIODIR + 1) {
588 #if(0)
589                 device_printf(sc->dev, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size);
590 #endif
591                 return NULL;
592         }
593         buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
594         if (buff == NULL) {
595 #if(0)
596                 device_printf(sc->dev, "envy24_rom2cfg(): malloc()\n");
597 #endif
598                 return NULL;
599         }
600         buff->free = 1;
601
602         buff->subvendor = envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR) << 8;
603         buff->subvendor += envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR + 1);
604         buff->subdevice = envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE) << 8;
605         buff->subdevice += envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE + 1);
606         buff->scfg = envy24_rdrom(sc, ENVY24_E2PROM_SCFG);
607         buff->acl = envy24_rdrom(sc, ENVY24_E2PROM_ACL);
608         buff->i2s = envy24_rdrom(sc, ENVY24_E2PROM_I2S);
609         buff->spdif = envy24_rdrom(sc, ENVY24_E2PROM_SPDIF);
610         buff->gpiomask = envy24_rdrom(sc, ENVY24_E2PROM_GPIOMASK);
611         buff->gpiostate = envy24_rdrom(sc, ENVY24_E2PROM_GPIOSTATE);
612         buff->gpiodir = envy24_rdrom(sc, ENVY24_E2PROM_GPIODIR);
613
614         for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
615                 if (cfg_table[i].subvendor == buff->subvendor &&
616                     cfg_table[i].subdevice == buff->subdevice)
617                         break;
618         buff->name = cfg_table[i].name;
619         buff->codec = cfg_table[i].codec;
620
621         return buff;
622 }
623
624 static void
625 envy24_cfgfree(struct cfg_info *cfg) {
626         if (cfg == NULL)
627                 return;
628         if (cfg->free)
629                 free(cfg, M_ENVY24);
630         return;
631 }
632
633 /* -------------------------------------------------------------------- */
634
635 /* AC'97 codec access routines */
636
637 #if 0
638 static int
639 envy24_coldcd(struct sc_info *sc)
640 {
641         u_int32_t data;
642         int i;
643
644 #if(0)
645         device_printf(sc->dev, "envy24_coldcd()\n");
646 #endif
647         envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_CLD, 1);
648         DELAY(10);
649         envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
650         DELAY(1000);
651         for (i = 0; i < ENVY24_TIMEOUT; i++) {
652                 data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
653                 if (data & ENVY24_MT_AC97CMD_RDY) {
654                         return 0;
655                 }
656         }
657
658         return -1;
659 }
660 #endif
661
662 static int
663 envy24_slavecd(struct sc_info *sc)
664 {
665         u_int32_t data;
666         int i;
667
668 #if(0)
669         device_printf(sc->dev, "envy24_slavecd()\n");
670 #endif
671         envy24_wrmt(sc, ENVY24_MT_AC97CMD,
672             ENVY24_MT_AC97CMD_CLD | ENVY24_MT_AC97CMD_WRM, 1);
673         DELAY(10);
674         envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
675         DELAY(1000);
676         for (i = 0; i < ENVY24_TIMEOUT; i++) {
677                 data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
678                 if (data & ENVY24_MT_AC97CMD_RDY) {
679                         return 0;
680                 }
681         }
682
683         return -1;
684 }
685
686 #if 0
687 static int
688 envy24_rdcd(kobj_t obj, void *devinfo, int regno)
689 {
690         struct sc_info *sc = (struct sc_info *)devinfo;
691         u_int32_t data;
692         int i;
693
694 #if(0)
695         device_printf(sc->dev, "envy24_rdcd(obj, sc, 0x%02x)\n", regno);
696 #endif
697         envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
698         envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_RD, 1);
699         for (i = 0; i < ENVY24_TIMEOUT; i++) {
700                 data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
701                 if ((data & ENVY24_MT_AC97CMD_RD) == 0)
702                         break;
703         }
704         data = envy24_rdmt(sc, ENVY24_MT_AC97DLO, 2);
705
706 #if(0)
707         device_printf(sc->dev, "envy24_rdcd(): return 0x%x\n", data);
708 #endif
709         return (int)data;
710 }
711
712 static int
713 envy24_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
714 {
715         struct sc_info *sc = (struct sc_info *)devinfo;
716         u_int32_t cmd;
717         int i;
718
719 #if(0)
720         device_printf(sc->dev, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
721 #endif
722         envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
723         envy24_wrmt(sc, ENVY24_MT_AC97DLO, (u_int32_t)data, 2);
724         envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_WR, 1);
725         for (i = 0; i < ENVY24_TIMEOUT; i++) {
726                 cmd = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
727                 if ((cmd & ENVY24_MT_AC97CMD_WR) == 0)
728                         break;
729         }
730
731         return 0;
732 }
733
734 static kobj_method_t envy24_ac97_methods[] = {
735         KOBJMETHOD(ac97_read,   envy24_rdcd),
736         KOBJMETHOD(ac97_write,  envy24_wrcd),
737         KOBJMETHOD_END
738 };
739 AC97_DECLARE(envy24_ac97);
740 #endif
741
742 /* -------------------------------------------------------------------- */
743
744 /* GPIO access routines */
745
746 static u_int32_t
747 envy24_gpiord(struct sc_info *sc)
748 {
749         return envy24_rdci(sc, ENVY24_CCI_GPIODAT);
750 }
751
752 static void
753 envy24_gpiowr(struct sc_info *sc, u_int32_t data)
754 {
755 #if(0)
756         device_printf(sc->dev, "envy24_gpiowr(sc, 0x%02x)\n", data & 0xff);
757         return;
758 #endif
759         envy24_wrci(sc, ENVY24_CCI_GPIODAT, data);
760         return;
761 }
762
763 #if 0
764 static u_int32_t
765 envy24_gpiogetmask(struct sc_info *sc)
766 {
767         return envy24_rdci(sc, ENVY24_CCI_GPIOMASK);
768 }
769 #endif
770
771 static void
772 envy24_gpiosetmask(struct sc_info *sc, u_int32_t mask)
773 {
774         envy24_wrci(sc, ENVY24_CCI_GPIOMASK, mask);
775         return;
776 }
777
778 #if 0
779 static u_int32_t
780 envy24_gpiogetdir(struct sc_info *sc)
781 {
782         return envy24_rdci(sc, ENVY24_CCI_GPIOCTL);
783 }
784 #endif
785
786 static void
787 envy24_gpiosetdir(struct sc_info *sc, u_int32_t dir)
788 {
789         envy24_wrci(sc, ENVY24_CCI_GPIOCTL, dir);
790         return;
791 }
792
793 /* -------------------------------------------------------------------- */
794
795 /* Envy24 I2C through GPIO bit-banging */
796
797 struct envy24_delta_ak4524_codec {
798         struct spicds_info *info;
799         struct sc_info *parent;
800         int dir;
801         int num;
802         int cs, cclk, cdti;
803 };
804
805 static void
806 envy24_gpio_i2c_ctl(void *codec, unsigned int scl, unsigned int sda)
807 {
808         u_int32_t data = 0;
809         struct envy24_delta_ak4524_codec *ptr = codec;
810 #if(0)
811         device_printf(ptr->parent->dev, "--> %d, %d\n", scl, sda);
812 #endif
813         data = envy24_gpiord(ptr->parent);
814         data &= ~(SDA_GPIO | SCL_GPIO);
815         if (scl) data += SCL_GPIO;
816         if (sda) data += SDA_GPIO;
817         envy24_gpiowr(ptr->parent, data);
818         return;
819 }
820
821 static void
822 i2c_wrbit(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), int bit)
823 {
824         struct envy24_delta_ak4524_codec *ptr = codec;
825         unsigned int sda;
826
827         if (bit)
828                 sda = 1;
829         else
830                 sda = 0;
831
832         ctrl(ptr, 0, sda);
833         DELAY(I2C_DELAY);
834         ctrl(ptr, 1, sda);
835         DELAY(I2C_DELAY);
836         ctrl(ptr, 0, sda);
837         DELAY(I2C_DELAY);
838 }
839
840 static void
841 i2c_start(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
842 {
843         struct envy24_delta_ak4524_codec *ptr = codec;
844
845         ctrl(ptr, 1, 1);
846         DELAY(I2C_DELAY);
847         ctrl(ptr, 1, 0);
848         DELAY(I2C_DELAY);
849         ctrl(ptr, 0, 0);
850         DELAY(I2C_DELAY);
851 }
852
853 static void
854 i2c_stop(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
855 {
856         struct envy24_delta_ak4524_codec *ptr = codec;
857
858         ctrl(ptr, 0, 0);
859         DELAY(I2C_DELAY);
860         ctrl(ptr, 1, 0);
861         DELAY(I2C_DELAY);
862         ctrl(ptr, 1, 1);
863         DELAY(I2C_DELAY);
864 }
865
866 static void
867 i2c_ack(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
868 {
869         struct envy24_delta_ak4524_codec *ptr = codec;
870
871         ctrl(ptr, 0, 1);
872         DELAY(I2C_DELAY);
873         ctrl(ptr, 1, 1);
874         DELAY(I2C_DELAY);
875         /* dummy, need routine to change gpio direction */
876         ctrl(ptr, 0, 1);
877         DELAY(I2C_DELAY);
878 }
879
880 static void
881 i2c_wr(void *codec,  void (*ctrl)(void*, unsigned int, unsigned int), u_int32_t dev, int reg, u_int8_t val)
882 {
883         struct envy24_delta_ak4524_codec *ptr = codec;
884         int mask;
885
886         i2c_start(ptr, ctrl);
887
888         for (mask = 0x80; mask != 0; mask >>= 1)
889                 i2c_wrbit(ptr, ctrl, dev & mask);
890         i2c_ack(ptr, ctrl);
891
892         if (reg != 0xff) {
893         for (mask = 0x80; mask != 0; mask >>= 1)
894                 i2c_wrbit(ptr, ctrl, reg & mask);
895         i2c_ack(ptr, ctrl);
896         }
897
898         for (mask = 0x80; mask != 0; mask >>= 1)
899                 i2c_wrbit(ptr, ctrl, val & mask);
900         i2c_ack(ptr, ctrl);
901
902         i2c_stop(ptr, ctrl);
903 }
904
905 /* -------------------------------------------------------------------- */
906
907 /* M-Audio Delta series AK4524 access interface routine */
908
909 static void
910 envy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
911 {
912         u_int32_t data = 0;
913         struct envy24_delta_ak4524_codec *ptr = codec;
914
915 #if(0)
916         device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
917 #endif
918         data = envy24_gpiord(ptr->parent);
919         data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
920         if (cs) data += ptr->cs;
921         if (cclk) data += ptr->cclk;
922         if (cdti) data += ptr->cdti;
923         envy24_gpiowr(ptr->parent, data);
924         return;
925 }
926
927 static void *
928 envy24_delta_ak4524_create(device_t dev, void *info, int dir, int num)
929 {
930         struct sc_info *sc = info;
931         struct envy24_delta_ak4524_codec *buff = NULL;
932
933 #if(0)
934         device_printf(sc->dev, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir, num);
935 #endif
936         
937         buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
938         if (buff == NULL)
939                 return NULL;
940
941         if (dir == PCMDIR_REC && sc->adc[num] != NULL)
942                 buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info;
943         else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
944                 buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info;
945         else
946                 buff->info = spicds_create(dev, buff, num, envy24_delta_ak4524_ctl);
947         if (buff->info == NULL) {
948                 free(buff, M_ENVY24);
949                 return NULL;
950         }
951
952         buff->parent = sc;
953         buff->dir = dir;
954         buff->num = num;
955
956         return (void *)buff;
957 }
958
959 static void
960 envy24_delta_ak4524_destroy(void *codec)
961 {
962         struct envy24_delta_ak4524_codec *ptr = codec;
963         if (ptr == NULL)
964                 return;
965 #if(0)
966         device_printf(ptr->parent->dev, "envy24_delta_ak4524_destroy()\n");
967 #endif
968
969         if (ptr->dir == PCMDIR_PLAY) {
970                 if (ptr->parent->dac[ptr->num] != NULL)
971                         spicds_destroy(ptr->info);
972         }
973         else {
974                 if (ptr->parent->adc[ptr->num] != NULL)
975                         spicds_destroy(ptr->info);
976         }
977
978         free(codec, M_ENVY24);
979 }
980
981 static void
982 envy24_delta_ak4524_init(void *codec)
983 {
984 #if 0
985         u_int32_t gpiomask, gpiodir;
986 #endif
987         struct envy24_delta_ak4524_codec *ptr = codec;
988         if (ptr == NULL)
989                 return;
990 #if(0)
991         device_printf(ptr->parent->dev, "envy24_delta_ak4524_init()\n");
992 #endif
993
994         /*
995         gpiomask = envy24_gpiogetmask(ptr->parent);
996         gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1);
997         envy24_gpiosetmask(ptr->parent, gpiomask);
998         gpiodir = envy24_gpiogetdir(ptr->parent);
999         gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1;
1000         envy24_gpiosetdir(ptr->parent, gpiodir);
1001         */
1002         ptr->cs = ptr->parent->cfg->cs;
1003 #if 0
1004         envy24_gpiosetmask(ptr->parent, ENVY24_GPIO_CS8414_STATUS);
1005         envy24_gpiosetdir(ptr->parent, ~ENVY24_GPIO_CS8414_STATUS);
1006         if (ptr->num == 0)
1007                 ptr->cs = ENVY24_GPIO_AK4524_CS0;
1008         else
1009                 ptr->cs = ENVY24_GPIO_AK4524_CS1;
1010         ptr->cclk = ENVY24_GPIO_AK4524_CCLK;
1011 #endif
1012         ptr->cclk = ptr->parent->cfg->cclk;
1013         ptr->cdti = ptr->parent->cfg->cdti;
1014         spicds_settype(ptr->info,  ptr->parent->cfg->type);
1015         spicds_setcif(ptr->info, ptr->parent->cfg->cif);
1016         spicds_setformat(ptr->info,
1017             AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
1018         spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
1019         /* for the time being, init only first codec */
1020         if (ptr->num == 0)
1021                 spicds_init(ptr->info);
1022
1023         /* 6fire rear input init test, set ptr->num to 1 for test */
1024         if (ptr->parent->cfg->subvendor == 0x153b && \
1025                 ptr->parent->cfg->subdevice == 0x1138 && ptr->num == 100) {
1026                 ptr->cs = 0x02;  
1027                 spicds_init(ptr->info);
1028                 device_printf(ptr->parent->dev, "6fire rear input init\n");
1029                 i2c_wr(ptr, envy24_gpio_i2c_ctl, \
1030                         PCA9554_I2CDEV, PCA9554_DIR, 0x80);
1031                 i2c_wr(ptr, envy24_gpio_i2c_ctl, \
1032                         PCA9554_I2CDEV, PCA9554_OUT, 0x02);
1033         }
1034 }
1035
1036 static void
1037 envy24_delta_ak4524_reinit(void *codec)
1038 {
1039         struct envy24_delta_ak4524_codec *ptr = codec;
1040         if (ptr == NULL)
1041                 return;
1042 #if(0)
1043         device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n");
1044 #endif
1045
1046         spicds_reinit(ptr->info);
1047 }
1048
1049 static void
1050 envy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
1051 {
1052         struct envy24_delta_ak4524_codec *ptr = codec;
1053         if (ptr == NULL)
1054                 return;
1055 #if(0)
1056         device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n");
1057 #endif
1058
1059         spicds_set(ptr->info, dir, left, right);
1060 }
1061
1062 /*
1063   There is no need for AK452[48] codec to set sample rate
1064   static void
1065   envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate)
1066   {
1067   }
1068 */
1069
1070 /* -------------------------------------------------------------------- */
1071
1072 /* hardware access routeines */
1073
1074 static struct {
1075         u_int32_t speed;
1076         u_int32_t code;
1077 } envy24_speedtab[] = {
1078         {48000, ENVY24_MT_RATE_48000},
1079         {24000, ENVY24_MT_RATE_24000},
1080         {12000, ENVY24_MT_RATE_12000},
1081         {9600, ENVY24_MT_RATE_9600},
1082         {32000, ENVY24_MT_RATE_32000},
1083         {16000, ENVY24_MT_RATE_16000},
1084         {8000, ENVY24_MT_RATE_8000},
1085         {96000, ENVY24_MT_RATE_96000},
1086         {64000, ENVY24_MT_RATE_64000},
1087         {44100, ENVY24_MT_RATE_44100},
1088         {22050, ENVY24_MT_RATE_22050},
1089         {11025, ENVY24_MT_RATE_11025},
1090         {88200, ENVY24_MT_RATE_88200},
1091         {0, 0x10}
1092 };
1093
1094 static u_int32_t
1095 envy24_setspeed(struct sc_info *sc, u_int32_t speed) {
1096         u_int32_t code;
1097         int i = 0;
1098
1099 #if(0)
1100         device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed);
1101 #endif
1102         if (speed == 0) {
1103                 code = ENVY24_MT_RATE_SPDIF; /* external master clock */
1104                 envy24_slavecd(sc);
1105         }
1106         else {
1107                 for (i = 0; envy24_speedtab[i].speed != 0; i++) {
1108                         if (envy24_speedtab[i].speed == speed)
1109                                 break;
1110                 }
1111                 code = envy24_speedtab[i].code;
1112         }
1113 #if(0)
1114         device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code);
1115 #endif
1116         if (code < 0x10) {
1117                 envy24_wrmt(sc, ENVY24_MT_RATE, code, 1);
1118                 code = envy24_rdmt(sc, ENVY24_MT_RATE, 1);
1119                 code &= ENVY24_MT_RATE_MASK;
1120                 for (i = 0; envy24_speedtab[i].code < 0x10; i++) {
1121                         if (envy24_speedtab[i].code == code)
1122                                 break;
1123                 }
1124                 speed = envy24_speedtab[i].speed;
1125         }
1126         else
1127                 speed = 0;
1128
1129 #if(0)
1130         device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed);
1131 #endif
1132         return speed;
1133 }
1134
1135 static void
1136 envy24_setvolume(struct sc_info *sc, unsigned ch)
1137 {
1138 #if(0)
1139         device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch);
1140 #endif
1141 if (sc->cfg->subvendor==0x153b  && sc->cfg->subdevice==0x1138 ) {
1142         envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1);
1143         envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1144         envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1);
1145         envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1146         }
1147
1148         envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1149         envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1150         envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1151         envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1152 }
1153
1154 static void
1155 envy24_mutevolume(struct sc_info *sc, unsigned ch)
1156 {
1157         u_int32_t vol;
1158
1159 #if(0)
1160         device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch);
1161 #endif
1162         vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE;
1163         envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1164         envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1165         envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1166         envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1167 }
1168
1169 static u_int32_t
1170 envy24_gethwptr(struct sc_info *sc, int dir)
1171 {
1172         int unit, regno;
1173         u_int32_t ptr, rtn;
1174
1175 #if(0)
1176         device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir);
1177 #endif
1178         if (dir == PCMDIR_PLAY) {
1179                 rtn = sc->psize / 4;
1180                 unit = ENVY24_PLAY_BUFUNIT / 4;
1181                 regno = ENVY24_MT_PCNT;
1182         }
1183         else {
1184                 rtn = sc->rsize / 4;
1185                 unit = ENVY24_REC_BUFUNIT / 4;
1186                 regno = ENVY24_MT_RCNT;
1187         }
1188
1189         ptr = envy24_rdmt(sc, regno, 2);
1190         rtn -= (ptr + 1);
1191         rtn /= unit;
1192
1193 #if(0)
1194         device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn);
1195 #endif
1196         return rtn;
1197 }
1198
1199 static void
1200 envy24_updintr(struct sc_info *sc, int dir)
1201 {
1202         int regptr, regintr;
1203         u_int32_t mask, intr;
1204         u_int32_t ptr, size, cnt;
1205         u_int16_t blk;
1206
1207 #if(0)
1208         device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir);
1209 #endif
1210         if (dir == PCMDIR_PLAY) {
1211                 blk = sc->blk[0];
1212                 size = sc->psize / 4;
1213                 regptr = ENVY24_MT_PCNT;
1214                 regintr = ENVY24_MT_PTERM;
1215                 mask = ~ENVY24_MT_INT_PMASK;
1216         }
1217         else {
1218                 blk = sc->blk[1];
1219                 size = sc->rsize / 4;
1220                 regptr = ENVY24_MT_RCNT;
1221                 regintr = ENVY24_MT_RTERM;
1222                 mask = ~ENVY24_MT_INT_RMASK;
1223         }
1224
1225         ptr = size - envy24_rdmt(sc, regptr, 2) - 1;
1226         /*
1227         cnt = blk - ptr % blk - 1;
1228         if (cnt == 0)
1229                 cnt = blk - 1;
1230         */
1231         cnt = blk - 1;
1232 #if(0)
1233         device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1234 #endif
1235         envy24_wrmt(sc, regintr, cnt, 2);
1236         intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1237 #if(0)
1238         device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1239 #endif
1240         envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1);
1241 #if(0)
1242         device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n",
1243                       envy24_rdmt(sc, ENVY24_MT_INT, 1));
1244 #endif
1245
1246         return;
1247 }
1248
1249 #if 0
1250 static void
1251 envy24_maskintr(struct sc_info *sc, int dir)
1252 {
1253         u_int32_t mask, intr;
1254
1255 #if(0)
1256         device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir);
1257 #endif
1258         if (dir == PCMDIR_PLAY)
1259                 mask = ENVY24_MT_INT_PMASK;
1260         else
1261                 mask = ENVY24_MT_INT_RMASK;
1262         intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1263         envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1);
1264
1265         return;
1266 }
1267 #endif
1268
1269 static int
1270 envy24_checkintr(struct sc_info *sc, int dir)
1271 {
1272         u_int32_t mask, stat, intr, rtn;
1273
1274 #if(0)
1275         device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir);
1276 #endif
1277         intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1278         if (dir == PCMDIR_PLAY) {
1279                 if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) {
1280                         mask = ~ENVY24_MT_INT_RSTAT;
1281                         stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK;
1282                         envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1283                 }
1284         }
1285         else {
1286                 if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) {
1287                         mask = ~ENVY24_MT_INT_PSTAT;
1288                         stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK;
1289                         envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1290                 }
1291         }
1292
1293         return rtn;
1294 }
1295
1296 static void
1297 envy24_start(struct sc_info *sc, int dir)
1298 {
1299         u_int32_t stat, sw;
1300
1301 #if(0)
1302         device_printf(sc->dev, "envy24_start(sc, %d)\n", dir);
1303 #endif
1304         if (dir == PCMDIR_PLAY)
1305                 sw = ENVY24_MT_PCTL_PSTART;
1306         else
1307                 sw = ENVY24_MT_PCTL_RSTART;
1308
1309         stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1310         envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1);
1311 #if(0)
1312         DELAY(100);
1313         device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
1314         device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
1315 #endif
1316
1317         return;
1318 }
1319
1320 static void
1321 envy24_stop(struct sc_info *sc, int dir)
1322 {
1323         u_int32_t stat, sw;
1324
1325 #if(0)
1326         device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir);
1327 #endif
1328         if (dir == PCMDIR_PLAY)
1329                 sw = ~ENVY24_MT_PCTL_PSTART;
1330         else
1331                 sw = ~ENVY24_MT_PCTL_RSTART;
1332
1333         stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1334         envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1);
1335
1336         return;
1337 }
1338
1339 static int
1340 envy24_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1341 {
1342         u_int32_t reg, mask;
1343         u_int32_t left, right;
1344
1345 #if(0)
1346         device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n",
1347             dac, class, adc, rev);
1348 #endif
1349         /* parameter pattern check */
1350         if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac)
1351                 return -1;
1352         if (class == ENVY24_ROUTE_CLASS_MIX &&
1353             (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF))
1354                 return -1;
1355         if (rev) {
1356                 left = ENVY24_ROUTE_RIGHT;
1357                 right = ENVY24_ROUTE_LEFT;
1358         }
1359         else {
1360                 left = ENVY24_ROUTE_LEFT;
1361                 right = ENVY24_ROUTE_RIGHT;
1362         }
1363
1364         if (dac == ENVY24_ROUTE_DAC_SPDIF) {
1365                 reg = class | class << 2 |
1366                         ((adc << 1 | left) | left << 3) << 8 |
1367                         ((adc << 1 | right) | right << 3) << 12;
1368 #if(0)
1369                 device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg);
1370 #endif
1371                 envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2);
1372         }
1373         else {
1374                 mask = ~(0x0303 << dac * 2);
1375                 reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2);
1376                 reg = (reg & mask) | ((class | class << 8) << dac * 2);
1377 #if(0)
1378                 device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg);
1379 #endif
1380                 envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2);
1381                 mask = ~(0xff << dac * 8);
1382                 reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4);
1383                 reg = (reg & mask) |
1384                         (((adc << 1 | left) | left << 3) |
1385                          ((adc << 1 | right) | right << 3) << 4) << dac * 8;
1386 #if(0)
1387                 device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg);
1388 #endif
1389                 envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4);
1390
1391                 /* 6fire rear input init test */
1392                 envy24_wrmt(sc, ENVY24_MT_RECORD, 0x00, 4);
1393         }
1394
1395         return 0;
1396 }
1397
1398 /* -------------------------------------------------------------------- */
1399
1400 /* buffer copy routines */
1401 static void
1402 envy24_p32sl(struct sc_chinfo *ch)
1403 {
1404         int length;
1405         sample32_t *dmabuf;
1406         u_int32_t *data;
1407         int src, dst, ssize, dsize, slot;
1408         int i;
1409
1410         length = sndbuf_getready(ch->buffer) / 8;
1411         dmabuf = ch->parent->pbuf;
1412         data = (u_int32_t *)ch->data;
1413         src = sndbuf_getreadyptr(ch->buffer) / 4;
1414         dst = src / 2 + ch->offset;
1415         ssize = ch->size / 4;
1416         dsize = ch->size / 8;
1417         slot = ch->num * 2;
1418
1419         for (i = 0; i < length; i++) {
1420                 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src];
1421                 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1422                 dst++;
1423                 dst %= dsize;
1424                 src += 2;
1425                 src %= ssize;
1426         }
1427         
1428         return;
1429 }
1430
1431 static void
1432 envy24_p16sl(struct sc_chinfo *ch)
1433 {
1434         int length;
1435         sample32_t *dmabuf;
1436         u_int16_t *data;
1437         int src, dst, ssize, dsize, slot;
1438         int i;
1439
1440 #if(0)
1441         device_printf(ch->parent->dev, "envy24_p16sl()\n");
1442 #endif
1443         length = sndbuf_getready(ch->buffer) / 4;
1444         dmabuf = ch->parent->pbuf;
1445         data = (u_int16_t *)ch->data;
1446         src = sndbuf_getreadyptr(ch->buffer) / 2;
1447         dst = src / 2 + ch->offset;
1448         ssize = ch->size / 2;
1449         dsize = ch->size / 4;
1450         slot = ch->num * 2;
1451 #if(0)
1452         device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1453 #endif
1454         
1455         for (i = 0; i < length; i++) {
1456                 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1457                 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1458 #if(0)
1459                 if (i < 16) {
1460                         printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]);
1461                         printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]);
1462                 }
1463 #endif
1464                 dst++;
1465                 dst %= dsize;
1466                 src += 2;
1467                 src %= ssize;
1468         }
1469 #if(0)
1470         printf("\n");
1471 #endif
1472         
1473         return;
1474 }
1475
1476 static void
1477 envy24_p8u(struct sc_chinfo *ch)
1478 {
1479         int length;
1480         sample32_t *dmabuf;
1481         u_int8_t *data;
1482         int src, dst, ssize, dsize, slot;
1483         int i;
1484
1485         length = sndbuf_getready(ch->buffer) / 2;
1486         dmabuf = ch->parent->pbuf;
1487         data = (u_int8_t *)ch->data;
1488         src = sndbuf_getreadyptr(ch->buffer);
1489         dst = src / 2 + ch->offset;
1490         ssize = ch->size;
1491         dsize = ch->size / 4;
1492         slot = ch->num * 2;
1493         
1494         for (i = 0; i < length; i++) {
1495                 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1496                 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1497                 dst++;
1498                 dst %= dsize;
1499                 src += 2;
1500                 src %= ssize;
1501         }
1502         
1503         return;
1504 }
1505
1506 static void
1507 envy24_r32sl(struct sc_chinfo *ch)
1508 {
1509         int length;
1510         sample32_t *dmabuf;
1511         u_int32_t *data;
1512         int src, dst, ssize, dsize, slot;
1513         int i;
1514
1515         length = sndbuf_getfree(ch->buffer) / 8;
1516         dmabuf = ch->parent->rbuf;
1517         data = (u_int32_t *)ch->data;
1518         dst = sndbuf_getfreeptr(ch->buffer) / 4;
1519         src = dst / 2 + ch->offset;
1520         dsize = ch->size / 4;
1521         ssize = ch->size / 8;
1522         slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1523
1524         for (i = 0; i < length; i++) {
1525                 data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1526                 data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1527                 dst += 2;
1528                 dst %= dsize;
1529                 src++;
1530                 src %= ssize;
1531         }
1532         
1533         return;
1534 }
1535
1536 static void
1537 envy24_r16sl(struct sc_chinfo *ch)
1538 {
1539         int length;
1540         sample32_t *dmabuf;
1541         u_int16_t *data;
1542         int src, dst, ssize, dsize, slot;
1543         int i;
1544
1545         length = sndbuf_getfree(ch->buffer) / 4;
1546         dmabuf = ch->parent->rbuf;
1547         data = (u_int16_t *)ch->data;
1548         dst = sndbuf_getfreeptr(ch->buffer) / 2;
1549         src = dst / 2 + ch->offset;
1550         dsize = ch->size / 2;
1551         ssize = ch->size / 8;
1552         slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1553
1554         for (i = 0; i < length; i++) {
1555                 data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1556                 data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1557                 dst += 2;
1558                 dst %= dsize;
1559                 src++;
1560                 src %= ssize;
1561         }
1562         
1563         return;
1564 }
1565
1566 /* -------------------------------------------------------------------- */
1567
1568 /* channel interface */
1569 static void *
1570 envy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1571 {
1572         struct sc_info  *sc = (struct sc_info *)devinfo;
1573         struct sc_chinfo *ch;
1574         unsigned num;
1575
1576 #if(0)
1577         device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir);
1578 #endif
1579         snd_mtxlock(sc->lock);
1580         if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1581             (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1582                 snd_mtxunlock(sc->lock);
1583                 return NULL;
1584         }
1585         num = sc->chnum;
1586
1587         ch = &sc->chan[num];
1588         ch->size = 8 * ENVY24_SAMPLE_NUM;
1589         ch->data = malloc(ch->size, M_ENVY24, M_NOWAIT);
1590         if (ch->data == NULL) {
1591                 ch->size = 0;
1592                 ch = NULL;
1593         }
1594         else {
1595                 ch->buffer = b;
1596                 ch->channel = c;
1597                 ch->parent = sc;
1598                 ch->dir = dir;
1599                 /* set channel map */
1600                 ch->num = envy24_chanmap[num];
1601                 snd_mtxunlock(sc->lock);
1602                 sndbuf_setup(ch->buffer, ch->data, ch->size);
1603                 snd_mtxlock(sc->lock);
1604                 /* these 2 values are dummy */
1605                 ch->unit = 4;
1606                 ch->blk = 10240;
1607         }
1608         snd_mtxunlock(sc->lock);
1609
1610         return ch;
1611 }
1612
1613 static int
1614 envy24chan_free(kobj_t obj, void *data)
1615 {
1616         struct sc_chinfo *ch = data;
1617         struct sc_info *sc = ch->parent;
1618
1619 #if(0)
1620         device_printf(sc->dev, "envy24chan_free()\n");
1621 #endif
1622         snd_mtxlock(sc->lock);
1623         if (ch->data != NULL) {
1624                 free(ch->data, M_ENVY24);
1625                 ch->data = NULL;
1626         }
1627         snd_mtxunlock(sc->lock);
1628
1629         return 0;
1630 }
1631
1632 static int
1633 envy24chan_setformat(kobj_t obj, void *data, u_int32_t format)
1634 {
1635         struct sc_chinfo *ch = data;
1636         struct sc_info *sc = ch->parent;
1637         struct envy24_emldma *emltab;
1638         /* unsigned int bcnt, bsize; */
1639         int i;
1640
1641 #if(0)
1642         device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format);
1643 #endif
1644         snd_mtxlock(sc->lock);
1645         /* check and get format related information */
1646         if (ch->dir == PCMDIR_PLAY)
1647                 emltab = envy24_pemltab;
1648         else
1649                 emltab = envy24_remltab;
1650         if (emltab == NULL) {
1651                 snd_mtxunlock(sc->lock);
1652                 return -1;
1653         }
1654         for (i = 0; emltab[i].format != 0; i++)
1655                 if (emltab[i].format == format)
1656                         break;
1657         if (emltab[i].format == 0) {
1658                 snd_mtxunlock(sc->lock);
1659                 return -1;
1660         }
1661
1662         /* set format information */
1663         ch->format = format;
1664         ch->emldma = emltab[i].emldma;
1665         if (ch->unit > emltab[i].unit)
1666                 ch->blk *= ch->unit / emltab[i].unit;
1667         else
1668                 ch->blk /= emltab[i].unit / ch->unit;
1669         ch->unit = emltab[i].unit;
1670
1671         /* set channel buffer information */
1672         ch->size = ch->unit * ENVY24_SAMPLE_NUM;
1673 #if 0
1674         if (ch->dir == PCMDIR_PLAY)
1675                 bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1676         else
1677                 bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1678         bsize *= ch->unit;
1679         bcnt = ch->size / bsize;
1680         sndbuf_resize(ch->buffer, bcnt, bsize);
1681 #endif
1682         snd_mtxunlock(sc->lock);
1683
1684 #if(0)
1685         device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0);
1686 #endif
1687         return 0;
1688 }
1689
1690 /*
1691   IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1692   of speed information value. And real hardware speed setting is done
1693   at start triggered(see envy24chan_trigger()). So, at this function
1694   is called, any value that ENVY24 can use is able to set. But, at
1695   start triggerd, some other channel is running, and that channel's
1696   speed isn't same with, then trigger function will fail.
1697 */
1698 static u_int32_t
1699 envy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1700 {
1701         struct sc_chinfo *ch = data;
1702         u_int32_t val, prev;
1703         int i;
1704
1705 #if(0)
1706         device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed);
1707 #endif
1708         prev = 0x7fffffff;
1709         for (i = 0; (val = envy24_speed[i]) != 0; i++) {
1710                 if (abs(val - speed) < abs(prev - speed))
1711                         prev = val;
1712                 else
1713                         break;
1714         }
1715         ch->speed = prev;
1716         
1717 #if(0)
1718         device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed);
1719 #endif
1720         return ch->speed;
1721 }
1722
1723 static u_int32_t
1724 envy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1725 {
1726         struct sc_chinfo *ch = data;
1727         /* struct sc_info *sc = ch->parent; */
1728         u_int32_t size, prev;
1729         unsigned int bcnt, bsize;
1730
1731 #if(0)
1732         device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize);
1733 #endif
1734         prev = 0x7fffffff;
1735         /* snd_mtxlock(sc->lock); */
1736         for (size = ch->size / 2; size > 0; size /= 2) {
1737                 if (abs(size - blocksize) < abs(prev - blocksize))
1738                         prev = size;
1739                 else
1740                         break;
1741         }
1742
1743         ch->blk = prev / ch->unit;
1744         if (ch->dir == PCMDIR_PLAY)
1745                 ch->blk *= ENVY24_PLAY_BUFUNIT / 4;
1746         else
1747                 ch->blk *= ENVY24_REC_BUFUNIT / 4;
1748         /* set channel buffer information */
1749         /* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */
1750         if (ch->dir == PCMDIR_PLAY)
1751                 bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1752         else
1753                 bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1754         bsize *= ch->unit;
1755         bcnt = ch->size / bsize;
1756         sndbuf_resize(ch->buffer, bcnt, bsize);
1757         /* snd_mtxunlock(sc->lock); */
1758
1759 #if(0)
1760         device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev);
1761 #endif
1762         return prev;
1763 }
1764
1765 /* semantic note: must start at beginning of buffer */
1766 static int
1767 envy24chan_trigger(kobj_t obj, void *data, int go)
1768 {
1769         struct sc_chinfo *ch = data;
1770         struct sc_info *sc = ch->parent;
1771         u_int32_t ptr;
1772         int slot;
1773         int error = 0;
1774 #if 0
1775         int i;
1776
1777         device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go);
1778 #endif
1779         snd_mtxlock(sc->lock);
1780         if (ch->dir == PCMDIR_PLAY)
1781                 slot = 0;
1782         else
1783                 slot = 1;
1784         switch (go) {
1785         case PCMTRIG_START:
1786 #if(0)
1787                 device_printf(sc->dev, "envy24chan_trigger(): start\n");
1788 #endif
1789                 /* check or set channel speed */
1790                 if (sc->run[0] == 0 && sc->run[1] == 0) {
1791                         sc->speed = envy24_setspeed(sc, ch->speed);
1792                         sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1793                         sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1794                 }
1795                 else if (ch->speed != 0 && ch->speed != sc->speed) {
1796                         error = -1;
1797                         goto fail;
1798                 }
1799                 if (ch->speed == 0)
1800                         ch->channel->speed = sc->speed;
1801                 /* start or enable channel */
1802                 sc->run[slot]++;
1803                 if (sc->run[slot] == 1) {
1804                         /* first channel */
1805                         ch->offset = 0;
1806                         sc->blk[slot] = ch->blk;
1807                 }
1808                 else {
1809                         ptr = envy24_gethwptr(sc, ch->dir);
1810                         ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1811                             (ch->size / 4)) * 4 / ch->unit;
1812                         if (ch->blk < sc->blk[slot])
1813                                 sc->blk[slot] = ch->blk;
1814                 }
1815                 if (ch->dir == PCMDIR_PLAY) {
1816                         ch->emldma(ch);
1817                         envy24_setvolume(sc, ch->num);
1818                 }
1819                 envy24_updintr(sc, ch->dir);
1820                 if (sc->run[slot] == 1)
1821                         envy24_start(sc, ch->dir);
1822                 ch->run = 1;
1823                 break;
1824         case PCMTRIG_EMLDMAWR:
1825 #if(0)
1826                 device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n");
1827 #endif
1828                 if (ch->run != 1) {
1829                         error = -1;
1830                         goto fail;
1831                 }
1832                 ch->emldma(ch);
1833                 break;
1834         case PCMTRIG_EMLDMARD:
1835 #if(0)
1836                 device_printf(sc->dev, "envy24chan_trigger(): emldmard\n");
1837 #endif
1838                 if (ch->run != 1) {
1839                         error = -1;
1840                         goto fail;
1841                 }
1842                 ch->emldma(ch);
1843                 break;
1844         case PCMTRIG_ABORT:
1845                 if (ch->run) {
1846 #if(0)
1847                 device_printf(sc->dev, "envy24chan_trigger(): abort\n");
1848 #endif
1849                 ch->run = 0;
1850                 sc->run[slot]--;
1851                 if (ch->dir == PCMDIR_PLAY)
1852                         envy24_mutevolume(sc, ch->num);
1853                 if (sc->run[slot] == 0) {
1854                         envy24_stop(sc, ch->dir);
1855                         sc->intr[slot] = 0;
1856                 }
1857 #if 0
1858                 else if (ch->blk == sc->blk[slot]) {
1859                         sc->blk[slot] = ENVY24_SAMPLE_NUM / 2;
1860                         for (i = 0; i < ENVY24_CHAN_NUM; i++) {
1861                                 if (sc->chan[i].dir == ch->dir &&
1862                                     sc->chan[i].run == 1 &&
1863                                     sc->chan[i].blk < sc->blk[slot])
1864                                         sc->blk[slot] = sc->chan[i].blk;
1865                         }
1866                         if (ch->blk != sc->blk[slot])
1867                                 envy24_updintr(sc, ch->dir);
1868                 }
1869 #endif
1870                 }
1871                 break;
1872         }
1873 fail:
1874         snd_mtxunlock(sc->lock);
1875         return (error);
1876 }
1877
1878 static u_int32_t
1879 envy24chan_getptr(kobj_t obj, void *data)
1880 {
1881         struct sc_chinfo *ch = data;
1882         struct sc_info *sc = ch->parent;
1883         u_int32_t ptr, rtn;
1884
1885 #if(0)
1886         device_printf(sc->dev, "envy24chan_getptr()\n");
1887 #endif
1888         snd_mtxlock(sc->lock);
1889         ptr = envy24_gethwptr(sc, ch->dir);
1890         rtn = ptr * ch->unit;
1891         snd_mtxunlock(sc->lock);
1892
1893 #if(0)
1894         device_printf(sc->dev, "envy24chan_getptr(): return %d\n",
1895             rtn);
1896 #endif
1897         return rtn;
1898 }
1899
1900 static struct pcmchan_caps *
1901 envy24chan_getcaps(kobj_t obj, void *data)
1902 {
1903         struct sc_chinfo *ch = data;
1904         struct sc_info *sc = ch->parent;
1905         struct pcmchan_caps *rtn;
1906
1907 #if(0)
1908         device_printf(sc->dev, "envy24chan_getcaps()\n");
1909 #endif
1910         snd_mtxlock(sc->lock);
1911         if (ch->dir == PCMDIR_PLAY) {
1912                 if (sc->run[0] == 0)
1913                         rtn = &envy24_playcaps;
1914                 else
1915                         rtn = &sc->caps[0];
1916         }
1917         else {
1918                 if (sc->run[1] == 0)
1919                         rtn = &envy24_reccaps;
1920                 else
1921                         rtn = &sc->caps[1];
1922         }
1923         snd_mtxunlock(sc->lock);
1924
1925         return rtn;
1926 }
1927
1928 static kobj_method_t envy24chan_methods[] = {
1929         KOBJMETHOD(channel_init,                envy24chan_init),
1930         KOBJMETHOD(channel_free,                envy24chan_free),
1931         KOBJMETHOD(channel_setformat,           envy24chan_setformat),
1932         KOBJMETHOD(channel_setspeed,            envy24chan_setspeed),
1933         KOBJMETHOD(channel_setblocksize,        envy24chan_setblocksize),
1934         KOBJMETHOD(channel_trigger,             envy24chan_trigger),
1935         KOBJMETHOD(channel_getptr,              envy24chan_getptr),
1936         KOBJMETHOD(channel_getcaps,             envy24chan_getcaps),
1937         KOBJMETHOD_END
1938 };
1939 CHANNEL_DECLARE(envy24chan);
1940
1941 /* -------------------------------------------------------------------- */
1942
1943 /* mixer interface */
1944
1945 static int
1946 envy24mixer_init(struct snd_mixer *m)
1947 {
1948         struct sc_info *sc = mix_getdevinfo(m);
1949
1950 #if(0)
1951         device_printf(sc->dev, "envy24mixer_init()\n");
1952 #endif
1953         if (sc == NULL)
1954                 return -1;
1955
1956         /* set volume control rate */
1957         snd_mtxlock(sc->lock);
1958         envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1959
1960         mix_setdevs(m, ENVY24_MIX_MASK);
1961         mix_setrecdevs(m, ENVY24_MIX_REC_MASK);
1962         snd_mtxunlock(sc->lock);
1963
1964         return 0;
1965 }
1966
1967 static int
1968 envy24mixer_reinit(struct snd_mixer *m)
1969 {
1970         struct sc_info *sc = mix_getdevinfo(m);
1971
1972         if (sc == NULL)
1973                 return -1;
1974 #if(0)
1975         device_printf(sc->dev, "envy24mixer_reinit()\n");
1976 #endif
1977
1978         return 0;
1979 }
1980
1981 static int
1982 envy24mixer_uninit(struct snd_mixer *m)
1983 {
1984         struct sc_info *sc = mix_getdevinfo(m);
1985
1986         if (sc == NULL)
1987                 return -1;
1988 #if(0)
1989         device_printf(sc->dev, "envy24mixer_uninit()\n");
1990 #endif
1991
1992         return 0;
1993 }
1994
1995 static int
1996 envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1997 {
1998         struct sc_info *sc = mix_getdevinfo(m);
1999         int ch = envy24_mixmap[dev];
2000         int hwch;
2001         int i;
2002
2003         if (sc == NULL)
2004                 return -1;
2005         if (dev == 0 && sc->cfg->codec->setvolume == NULL)
2006                 return -1;
2007         if (dev != 0 && ch == -1)
2008                 return -1;
2009         hwch = envy24_chanmap[ch];
2010 #if(0)
2011         device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n",
2012             dev, left, right);
2013 #endif
2014
2015         snd_mtxlock(sc->lock);
2016         if (dev == 0) {
2017                 for (i = 0; i < sc->dacn; i++) {
2018                         sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
2019                 }
2020         }
2021         else {
2022                 /* set volume value for hardware */
2023                 if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN)
2024                         sc->left[hwch] = ENVY24_VOL_MUTE;
2025                 if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN)
2026                         sc->right[hwch] = ENVY24_VOL_MUTE;
2027
2028                 /* set volume for record channel and running play channel */
2029                 if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run)
2030                         envy24_setvolume(sc, hwch);
2031         }
2032         snd_mtxunlock(sc->lock);
2033
2034         return right << 8 | left;
2035 }
2036
2037 static u_int32_t
2038 envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
2039 {
2040         struct sc_info *sc = mix_getdevinfo(m);
2041         int ch = envy24_mixmap[src];
2042 #if(0)
2043         device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src);
2044 #endif
2045
2046         if (ch > ENVY24_CHAN_PLAY_SPDIF)
2047                 sc->src = ch;
2048         return src;
2049 }
2050
2051 static kobj_method_t envy24mixer_methods[] = {
2052         KOBJMETHOD(mixer_init,          envy24mixer_init),
2053         KOBJMETHOD(mixer_reinit,        envy24mixer_reinit),
2054         KOBJMETHOD(mixer_uninit,        envy24mixer_uninit),
2055         KOBJMETHOD(mixer_set,           envy24mixer_set),
2056         KOBJMETHOD(mixer_setrecsrc,     envy24mixer_setrecsrc),
2057         KOBJMETHOD_END
2058 };
2059 MIXER_DECLARE(envy24mixer);
2060
2061 /* -------------------------------------------------------------------- */
2062
2063 /* The interrupt handler */
2064 static void
2065 envy24_intr(void *p)
2066 {
2067         struct sc_info *sc = (struct sc_info *)p;
2068         struct sc_chinfo *ch;
2069         u_int32_t ptr, dsize, feed;
2070         int i;
2071
2072 #if(0)
2073         device_printf(sc->dev, "envy24_intr()\n");
2074 #endif
2075         snd_mtxlock(sc->lock);
2076         if (envy24_checkintr(sc, PCMDIR_PLAY)) {
2077 #if(0)
2078                 device_printf(sc->dev, "envy24_intr(): play\n");
2079 #endif
2080                 dsize = sc->psize / 4;
2081                 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1;
2082 #if(0)
2083                 device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr);
2084 #endif
2085                 ptr -= ptr % sc->blk[0];
2086                 feed = (ptr + dsize - sc->intr[0]) % dsize; 
2087 #if(0)
2088                 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2089 #endif
2090                 for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) {
2091                         ch = &sc->chan[i];
2092 #if(0)
2093                         if (ch->run)
2094                                 device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk);
2095 #endif
2096                         if (ch->run && ch->blk <= feed) {
2097                                 snd_mtxunlock(sc->lock);
2098                                 chn_intr(ch->channel);
2099                                 snd_mtxlock(sc->lock);
2100                         }
2101                 }
2102                 sc->intr[0] = ptr;
2103                 envy24_updintr(sc, PCMDIR_PLAY);
2104         }
2105         if (envy24_checkintr(sc, PCMDIR_REC)) {
2106 #if(0)
2107                 device_printf(sc->dev, "envy24_intr(): rec\n");
2108 #endif
2109                 dsize = sc->rsize / 4;
2110                 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1;
2111                 ptr -= ptr % sc->blk[1];
2112                 feed = (ptr + dsize - sc->intr[1]) % dsize; 
2113                 for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) {
2114                         ch = &sc->chan[i];
2115                         if (ch->run && ch->blk <= feed) {
2116                                 snd_mtxunlock(sc->lock);
2117                                 chn_intr(ch->channel);
2118                                 snd_mtxlock(sc->lock);
2119                         }
2120                 }
2121                 sc->intr[1] = ptr;
2122                 envy24_updintr(sc, PCMDIR_REC);
2123         }
2124         snd_mtxunlock(sc->lock);
2125
2126         return;
2127 }
2128
2129 /*
2130  * Probe and attach the card
2131  */
2132
2133 static int
2134 envy24_pci_probe(device_t dev)
2135 {
2136         u_int16_t sv, sd;
2137         int i;
2138
2139 #if(0)
2140         printf("envy24_pci_probe()\n");
2141 #endif
2142         if (pci_get_device(dev) == PCID_ENVY24 &&
2143             pci_get_vendor(dev) == PCIV_ENVY24) {
2144                 sv = pci_get_subvendor(dev);
2145                 sd = pci_get_subdevice(dev);
2146                 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2147                         if (cfg_table[i].subvendor == sv &&
2148                             cfg_table[i].subdevice == sd) {
2149                                 break;
2150                         }
2151                 }
2152                 device_set_desc(dev, cfg_table[i].name);
2153 #if(0)
2154                 printf("envy24_pci_probe(): return 0\n");
2155 #endif
2156                 return 0;
2157         }
2158         else {
2159 #if(0)
2160                 printf("envy24_pci_probe(): return ENXIO\n");
2161 #endif
2162                 return ENXIO;
2163         }
2164 }
2165
2166 static void
2167 envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2168 {
2169         /* struct sc_info *sc = (struct sc_info *)arg; */
2170
2171 #if(0)
2172         device_printf(sc->dev, "envy24_dmapsetmap()\n");
2173         if (bootverbose) {
2174                 printf("envy24(play): setmap %lx, %lx; ",
2175                     (unsigned long)segs->ds_addr,
2176                     (unsigned long)segs->ds_len);
2177                 printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2178         }
2179 #endif
2180 }
2181
2182 static void
2183 envy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2184 {
2185         /* struct sc_info *sc = (struct sc_info *)arg; */
2186
2187 #if(0)
2188         device_printf(sc->dev, "envy24_dmarsetmap()\n");
2189         if (bootverbose) {
2190                 printf("envy24(record): setmap %lx, %lx; ",
2191                     (unsigned long)segs->ds_addr,
2192                     (unsigned long)segs->ds_len);
2193                 printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2194         }
2195 #endif
2196 }
2197
2198 static void
2199 envy24_dmafree(struct sc_info *sc)
2200 {
2201 #if(0)
2202         device_printf(sc->dev, "envy24_dmafree():");
2203         if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2204         else printf(" sc->rmap(null)");
2205         if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2206         else printf(" sc->pmap(null)");
2207         if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2208         else printf(" sc->rbuf(null)");
2209         if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2210         else printf(" sc->pbuf(null)\n");
2211 #endif
2212 #if(0)
2213         if (sc->rmap)
2214                 bus_dmamap_unload(sc->dmat, sc->rmap);
2215         if (sc->pmap)
2216                 bus_dmamap_unload(sc->dmat, sc->pmap);
2217         if (sc->rbuf)
2218                 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2219         if (sc->pbuf)
2220                 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2221 #else
2222         bus_dmamap_unload(sc->dmat, sc->rmap);
2223         bus_dmamap_unload(sc->dmat, sc->pmap);
2224         bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2225         bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2226 #endif
2227
2228         sc->rmap = sc->pmap = NULL;
2229         sc->pbuf = NULL;
2230         sc->rbuf = NULL;
2231
2232         return;
2233 }
2234
2235 static int
2236 envy24_dmainit(struct sc_info *sc)
2237 {
2238         u_int32_t addr;
2239
2240 #if(0)
2241         device_printf(sc->dev, "envy24_dmainit()\n");
2242 #endif
2243         /* init values */
2244         sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM;
2245         sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM;
2246         sc->pbuf = NULL;
2247         sc->rbuf = NULL;
2248         sc->pmap = sc->rmap = NULL;
2249         sc->blk[0] = sc->blk[1] = 0;
2250
2251         /* allocate DMA buffer */
2252 #if(0)
2253         device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2254 #endif
2255         if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2256                 goto bad;
2257 #if(0)
2258         device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2259 #endif
2260         if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2261                 goto bad;
2262 #if(0)
2263         device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2264 #endif
2265         if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0))
2266                 goto bad;
2267 #if(0)
2268         device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2269 #endif
2270         if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0))
2271                 goto bad;
2272         bzero(sc->pbuf, sc->psize);
2273         bzero(sc->rbuf, sc->rsize);
2274
2275         /* set values to register */
2276         addr = vtophys(sc->pbuf);
2277 #if(0)
2278         device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2279 #endif
2280         envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4);
2281 #if(0)
2282         device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
2283         device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2284 #endif
2285         envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2);
2286 #if(0)
2287         device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
2288 #endif
2289         addr = vtophys(sc->rbuf);
2290         envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4);
2291         envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2);
2292
2293         return 0;
2294  bad:
2295         envy24_dmafree(sc);
2296         return ENOSPC;
2297 }
2298
2299 static void
2300 envy24_putcfg(struct sc_info *sc)
2301 {
2302         device_printf(sc->dev, "system configuration\n");
2303         printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2304             sc->cfg->subvendor, sc->cfg->subdevice);
2305         printf("  XIN2 Clock Source: ");
2306         switch (sc->cfg->scfg & PCIM_SCFG_XIN2) {
2307         case 0x00:
2308                 printf("22.5792MHz(44.1kHz*512)\n");
2309                 break;
2310         case 0x40:
2311                 printf("16.9344MHz(44.1kHz*384)\n");
2312                 break;
2313         case 0x80:
2314                 printf("from external clock synthesizer chip\n");
2315                 break;
2316         default:
2317                 printf("illeagal system setting\n");
2318         }
2319         printf("  MPU-401 UART(s) #: ");
2320         if (sc->cfg->scfg & PCIM_SCFG_MPU)
2321                 printf("2\n");
2322         else
2323                 printf("1\n");
2324         printf("  AC'97 codec: ");
2325         if (sc->cfg->scfg & PCIM_SCFG_AC97)
2326                 printf("not exist\n");
2327         else
2328                 printf("exist\n");
2329         printf("  ADC #: ");
2330         printf("%d\n", sc->adcn);
2331         printf("  DAC #: ");
2332         printf("%d\n", sc->dacn);
2333         printf("  Multi-track converter type: ");
2334         if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) {
2335                 printf("AC'97(SDATA_OUT:");
2336                 if (sc->cfg->acl & PCIM_ACL_OMODE)
2337                         printf("packed");
2338                 else
2339                         printf("split");
2340                 printf("|SDATA_IN:");
2341                 if (sc->cfg->acl & PCIM_ACL_IMODE)
2342                         printf("packed");
2343                 else
2344                         printf("split");
2345                 printf(")\n");
2346         }
2347         else {
2348                 printf("I2S(");
2349                 if (sc->cfg->i2s & PCIM_I2S_VOL)
2350                         printf("with volume, ");
2351                 if (sc->cfg->i2s & PCIM_I2S_96KHZ)
2352                         printf("96KHz support, ");
2353                 switch (sc->cfg->i2s & PCIM_I2S_RES) {
2354                 case PCIM_I2S_16BIT:
2355                         printf("16bit resolution, ");
2356                         break;
2357                 case PCIM_I2S_18BIT:
2358                         printf("18bit resolution, ");
2359                         break;
2360                 case PCIM_I2S_20BIT:
2361                         printf("20bit resolution, ");
2362                         break;
2363                 case PCIM_I2S_24BIT:
2364                         printf("24bit resolution, ");
2365                         break;
2366                 }
2367                 printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID);
2368         }
2369         printf("  S/PDIF(IN/OUT): ");
2370         if (sc->cfg->spdif & PCIM_SPDIF_IN)
2371                 printf("1/");
2372         else
2373                 printf("0/");
2374         if (sc->cfg->spdif & PCIM_SPDIF_OUT)
2375                 printf("1 ");
2376         else
2377                 printf("0 ");
2378         if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT))
2379                 printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2);
2380         printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2381             sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2382 }
2383
2384 static int
2385 envy24_init(struct sc_info *sc)
2386 {
2387         u_int32_t data;
2388 #if(0)
2389         int rtn;
2390 #endif
2391         int i;
2392         u_int32_t sv, sd;
2393
2394
2395 #if(0)
2396         device_printf(sc->dev, "envy24_init()\n");
2397 #endif
2398
2399         /* reset chip */
2400         envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1);
2401         DELAY(200);
2402         envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1);
2403         DELAY(200);
2404
2405         /* legacy hardware disable */
2406         data = pci_read_config(sc->dev, PCIR_LAC, 2);
2407         data |= PCIM_LAC_DISABLE;
2408         pci_write_config(sc->dev, PCIR_LAC, data, 2);
2409
2410         /* check system configuration */
2411         sc->cfg = NULL;
2412         for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2413                 /* 1st: search configuration from table */
2414                 sv = pci_get_subvendor(sc->dev);
2415                 sd = pci_get_subdevice(sc->dev);
2416                 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2417 #if(0)
2418                         device_printf(sc->dev, "Set configuration from table\n");
2419 #endif
2420                         sc->cfg = &cfg_table[i];
2421                         break;
2422                 }
2423         }
2424         if (sc->cfg == NULL) {
2425                 /* 2nd: read configuration from table */
2426                 sc->cfg = envy24_rom2cfg(sc);
2427         }
2428         sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1;
2429         sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1;
2430
2431         if (1 /* bootverbose */) {
2432                 envy24_putcfg(sc);
2433         }
2434
2435         /* set system configuration */
2436         pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1);
2437         pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1);
2438         pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1);
2439         pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1);
2440         envy24_gpiosetmask(sc, sc->cfg->gpiomask);
2441         envy24_gpiosetdir(sc, sc->cfg->gpiodir);
2442         envy24_gpiowr(sc, sc->cfg->gpiostate);
2443         for (i = 0; i < sc->adcn; i++) {
2444                 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2445                 sc->cfg->codec->init(sc->adc[i]);
2446         }
2447         for (i = 0; i < sc->dacn; i++) {
2448                 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2449                 sc->cfg->codec->init(sc->dac[i]);
2450         }
2451
2452         /* initialize DMA buffer */
2453 #if(0)
2454         device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n");
2455 #endif
2456         if (envy24_dmainit(sc))
2457                 return ENOSPC;
2458
2459         /* initialize status */
2460         sc->run[0] = sc->run[1] = 0;
2461         sc->intr[0] = sc->intr[1] = 0;
2462         sc->speed = 0;
2463         sc->caps[0].fmtlist = envy24_playfmt;
2464         sc->caps[1].fmtlist = envy24_recfmt;
2465
2466         /* set channel router */
2467         envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0);
2468         envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0);
2469         /* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2470
2471         /* set macro interrupt mask */
2472         data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2473         envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1);
2474         data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2475 #if(0)
2476         device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data);
2477 #endif
2478
2479         return 0;
2480 }
2481
2482 static int
2483 envy24_alloc_resource(struct sc_info *sc)
2484 {
2485         /* allocate I/O port resource */
2486         sc->csid = PCIR_CCS;
2487         sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2488             &sc->csid, 0, ~0, 1, RF_ACTIVE);
2489         sc->ddmaid = PCIR_DDMA;
2490         sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2491             &sc->ddmaid, 0, ~0, 1, RF_ACTIVE);
2492         sc->dsid = PCIR_DS;
2493         sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2494             &sc->dsid, 0, ~0, 1, RF_ACTIVE);
2495         sc->mtid = PCIR_MT;
2496         sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2497             &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2498         if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) {
2499                 device_printf(sc->dev, "unable to map IO port space\n");
2500                 return ENXIO;
2501         }
2502         sc->cst = rman_get_bustag(sc->cs);
2503         sc->csh = rman_get_bushandle(sc->cs);
2504         sc->ddmat = rman_get_bustag(sc->ddma);
2505         sc->ddmah = rman_get_bushandle(sc->ddma);
2506         sc->dst = rman_get_bustag(sc->ds);
2507         sc->dsh = rman_get_bushandle(sc->ds);
2508         sc->mtt = rman_get_bustag(sc->mt);
2509         sc->mth = rman_get_bushandle(sc->mt);
2510 #if(0)
2511         device_printf(sc->dev,
2512             "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2513             pci_read_config(sc->dev, PCIR_CCS, 4),
2514             pci_read_config(sc->dev, PCIR_DDMA, 4),
2515             pci_read_config(sc->dev, PCIR_DS, 4),
2516             pci_read_config(sc->dev, PCIR_MT, 4));
2517 #endif
2518
2519         /* allocate interrupt resource */
2520         sc->irqid = 0;
2521         sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2522                                  0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2523         if (!sc->irq ||
2524             snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) {
2525                 device_printf(sc->dev, "unable to map interrupt\n");
2526                 return ENXIO;
2527         }
2528
2529         /* allocate DMA resource */
2530         if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2531             /*alignment*/4,
2532             /*boundary*/0,
2533             /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2534             /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2535             /*filter*/NULL, /*filterarg*/NULL,
2536             /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2537             /*nsegments*/1, /*maxsegsz*/0x3ffff,
2538             /*flags*/0, /*lockfunc*/busdma_lock_mutex,
2539             /*lockarg*/&Giant, &sc->dmat) != 0) {
2540                 device_printf(sc->dev, "unable to create dma tag\n");
2541                 return ENXIO;
2542         }
2543
2544         return 0;
2545 }
2546
2547 static int
2548 envy24_pci_attach(device_t dev)
2549 {
2550         u_int32_t               data;
2551         struct sc_info          *sc;
2552         char                    status[SND_STATUSLEN];
2553         int                     err = 0;
2554         int                     i;
2555
2556 #if(0)
2557         device_printf(dev, "envy24_pci_attach()\n");
2558 #endif
2559         /* get sc_info data area */
2560         if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) {
2561                 device_printf(dev, "cannot allocate softc\n");
2562                 return ENXIO;
2563         }
2564
2565         bzero(sc, sizeof(*sc));
2566         sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_envy24 softc");
2567         sc->dev = dev;
2568
2569         /* initialize PCI interface */
2570         data = pci_read_config(dev, PCIR_COMMAND, 2);
2571         data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2572         pci_write_config(dev, PCIR_COMMAND, data, 2);
2573         data = pci_read_config(dev, PCIR_COMMAND, 2);
2574
2575         /* allocate resources */
2576         err = envy24_alloc_resource(sc);
2577         if (err) {
2578                 device_printf(dev, "unable to allocate system resources\n");
2579                 goto bad;
2580         }
2581
2582         /* initialize card */
2583         err = envy24_init(sc);
2584         if (err) {
2585                 device_printf(dev, "unable to initialize the card\n");
2586                 goto bad;
2587         }
2588
2589         /* set multi track mixer */
2590         mixer_init(dev, &envy24mixer_class, sc);
2591
2592         /* set channel information */
2593         err = pcm_register(dev, sc, 5, 2 + sc->adcn);
2594         if (err)
2595                 goto bad;
2596         sc->chnum = 0;
2597         for (i = 0; i < 5; i++) {
2598                 pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
2599                 sc->chnum++;
2600         }
2601         for (i = 0; i < 2 + sc->adcn; i++) {
2602                 pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc);
2603                 sc->chnum++;
2604         }
2605
2606         /* set status iformation */
2607         snprintf(status, SND_STATUSLEN,
2608             "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
2609             rman_get_start(sc->cs),
2610             rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2611             rman_get_start(sc->ddma),
2612             rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1,
2613             rman_get_start(sc->ds),
2614             rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1,
2615             rman_get_start(sc->mt),
2616             rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2617             rman_get_start(sc->irq));
2618         pcm_setstatus(dev, status);
2619
2620         return 0;
2621
2622 bad:
2623         if (sc->ih)
2624                 bus_teardown_intr(dev, sc->irq, sc->ih);
2625         if (sc->irq)
2626                 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2627         envy24_dmafree(sc);
2628         if (sc->dmat)
2629                 bus_dma_tag_destroy(sc->dmat);
2630         if (sc->cfg->codec->destroy != NULL) {
2631                 for (i = 0; i < sc->adcn; i++)
2632                         sc->cfg->codec->destroy(sc->adc[i]);
2633                 for (i = 0; i < sc->dacn; i++)
2634                         sc->cfg->codec->destroy(sc->dac[i]);
2635         }
2636         envy24_cfgfree(sc->cfg);
2637         if (sc->cs)
2638                 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2639         if (sc->ddma)
2640                 bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2641         if (sc->ds)
2642                 bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2643         if (sc->mt)
2644                 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2645         if (sc->lock)
2646                 snd_mtxfree(sc->lock);
2647         free(sc, M_ENVY24);
2648         return err;
2649 }
2650
2651 static int
2652 envy24_pci_detach(device_t dev)
2653 {
2654         struct sc_info *sc;
2655         int r;
2656         int i;
2657
2658 #if(0)
2659         device_printf(dev, "envy24_pci_detach()\n");
2660 #endif
2661         sc = pcm_getdevinfo(dev);
2662         if (sc == NULL)
2663                 return 0;
2664         r = pcm_unregister(dev);
2665         if (r)
2666                 return r;
2667
2668         envy24_dmafree(sc);
2669         if (sc->cfg->codec->destroy != NULL) {
2670                 for (i = 0; i < sc->adcn; i++)
2671                         sc->cfg->codec->destroy(sc->adc[i]);
2672                 for (i = 0; i < sc->dacn; i++)
2673                         sc->cfg->codec->destroy(sc->dac[i]);
2674         }
2675         envy24_cfgfree(sc->cfg);
2676         bus_dma_tag_destroy(sc->dmat);
2677         bus_teardown_intr(dev, sc->irq, sc->ih);
2678         bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2679         bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2680         bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2681         bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2682         bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2683         snd_mtxfree(sc->lock);
2684         free(sc, M_ENVY24);
2685         return 0;
2686 }
2687
2688 static device_method_t envy24_methods[] = {
2689         /* Device interface */
2690         DEVMETHOD(device_probe,         envy24_pci_probe),
2691         DEVMETHOD(device_attach,        envy24_pci_attach),
2692         DEVMETHOD(device_detach,        envy24_pci_detach),
2693         { 0, 0 }
2694 };
2695
2696 static driver_t envy24_driver = {
2697         "pcm",
2698         envy24_methods,
2699 #if __FreeBSD_version > 500000
2700         PCM_SOFTC_SIZE,
2701 #else
2702         sizeof(struct snddev_info),
2703 #endif
2704 };
2705
2706 DRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0);
2707 MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2708 MODULE_DEPEND(snd_envy24, snd_spicds, 1, 1, 1);
2709 MODULE_VERSION(snd_envy24, 1);