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