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