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