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