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