2 * Copyright (c) 2006 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
3 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $FreeBSD: src/sys/dev/sound/pci/envy24ht.c,v 1.11.2.2 2007/06/11 19:33:27 ariff Exp $
28 * $DragonFly: src/sys/dev/sound/pci/envy24ht.c,v 1.2 2007/06/16 20:07:19 dillon Exp $
32 * Konstantin Dimitrov's thanks list:
34 * A huge thanks goes to Spas Filipov for his friendship, support and his
35 * generous gift - an 'Audiotrak Prodigy HD2' audio card! I also want to
36 * thank Keiichi Iwasaki and his parents, because they helped Spas to get
37 * the card from Japan! Having hardware sample of Prodigy HD2 made adding
38 * support for that great card very easy and real fun and pleasure.
42 #include <dev/sound/pcm/sound.h>
43 #include <dev/sound/pcm/ac97.h>
44 #include <dev/sound/pci/spicds.h>
45 #include <dev/sound/pci/envy24ht.h>
47 #include <bus/pci/pcireg.h>
48 #include <bus/pci/pcivar.h>
52 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pci/envy24ht.c,v 1.2 2007/06/16 20:07:19 dillon Exp $");
54 MALLOC_DEFINE(M_ENVY24HT, "envy24ht", "envy24ht audio");
56 /* -------------------------------------------------------------------- */
60 #define ENVY24HT_PLAY_CHNUM 8
61 #define ENVY24HT_REC_CHNUM 2
62 #define ENVY24HT_PLAY_BUFUNIT (4 /* byte/sample */ * 8 /* channel */)
63 #define ENVY24HT_REC_BUFUNIT (4 /* byte/sample */ * 2 /* channel */)
64 #define ENVY24HT_SAMPLE_NUM 4096
66 #define ENVY24HT_TIMEOUT 1000
68 #define ENVY24HT_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE)
70 #define ENVY24HT_NAMELEN 32
72 #define abs(i) (i < 0 ? -i : i)
74 struct envy24ht_sample {
75 volatile u_int32_t buffer;
78 typedef struct envy24ht_sample sample32_t;
80 /* channel registers */
82 struct snd_dbuf *buffer;
83 struct pcm_channel *channel;
84 struct sc_info *parent;
86 unsigned num; /* hw channel number */
88 /* channel information */
91 u_int32_t blk; /* hw block size(dword) */
93 /* format conversion structure */
95 unsigned int size; /* data buffer size(byte) */
96 int unit; /* sample size(byte) */
97 unsigned int offset; /* samples number offset */
98 void (*emldma)(struct sc_chinfo *);
104 /* codec interface entrys */
106 void *(*create)(device_t dev, void *devinfo, int dir, int num);
107 void (*destroy)(void *codec);
108 void (*init)(void *codec);
109 void (*reinit)(void *codec);
110 void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
111 void (*setrate)(void *codec, int which, int rate);
114 /* system configuration information */
117 u_int16_t subvendor, subdevice;
118 u_int8_t scfg, acl, i2s, spdif;
119 u_int32_t gpiomask, gpiostate, gpiodir;
120 u_int32_t cdti, cclk, cs;
121 u_int8_t cif, type, free;
122 struct codec_entry *codec;
125 /* device private data */
130 /* Control/Status registor */
134 bus_space_handle_t csh;
135 /* MultiTrack registor */
139 bus_space_handle_t mth;
143 struct resource *irq;
147 /* system configuration data */
148 struct cfg_info *cfg;
150 /* ADC/DAC number and info */
152 void *adc[4], *dac[4];
154 /* mixer control data */
156 u_int8_t left[ENVY24HT_CHAN_NUM];
157 u_int8_t right[ENVY24HT_CHAN_NUM];
159 /* Play/Record DMA fifo */
162 u_int32_t psize, rsize; /* DMA buffer size(byte) */
163 u_int16_t blk[2]; /* transfer check blocksize(dword) */
164 bus_dmamap_t pmap, rmap;
170 struct pcmchan_caps caps[2];
172 /* channel info table */
174 struct sc_chinfo chan[11];
177 /* -------------------------------------------------------------------- */
184 static void envy24ht_p8u(struct sc_chinfo *);
185 static void envy24ht_p16sl(struct sc_chinfo *);
186 static void envy24ht_p32sl(struct sc_chinfo *);
187 static void envy24ht_r16sl(struct sc_chinfo *);
188 static void envy24ht_r32sl(struct sc_chinfo *);
190 /* channel interface */
191 static void *envy24htchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
192 static int envy24htchan_setformat(kobj_t, void *, u_int32_t);
193 static int envy24htchan_setspeed(kobj_t, void *, u_int32_t);
194 static int envy24htchan_setblocksize(kobj_t, void *, u_int32_t);
195 static int envy24htchan_trigger(kobj_t, void *, int);
196 static int envy24htchan_getptr(kobj_t, void *);
197 static struct pcmchan_caps *envy24htchan_getcaps(kobj_t, void *);
199 /* mixer interface */
200 static int envy24htmixer_init(struct snd_mixer *);
201 static int envy24htmixer_reinit(struct snd_mixer *);
202 static int envy24htmixer_uninit(struct snd_mixer *);
203 static int envy24htmixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
204 static u_int32_t envy24htmixer_setrecsrc(struct snd_mixer *, u_int32_t);
206 /* SPI codec access interface */
207 static void *envy24ht_spi_create(device_t, void *, int, int);
208 static void envy24ht_spi_destroy(void *);
209 static void envy24ht_spi_init(void *);
210 static void envy24ht_spi_reinit(void *);
211 static void envy24ht_spi_setvolume(void *, int, unsigned int, unsigned int);
213 /* -------------------------------------------------------------------- */
216 system constant tables
219 /* API -> hardware channel map */
220 static unsigned envy24ht_chanmap[ENVY24HT_CHAN_NUM] = {
221 ENVY24HT_CHAN_PLAY_DAC1, /* 1 */
222 ENVY24HT_CHAN_PLAY_DAC2, /* 2 */
223 ENVY24HT_CHAN_PLAY_DAC3, /* 3 */
224 ENVY24HT_CHAN_PLAY_DAC4, /* 4 */
225 ENVY24HT_CHAN_PLAY_SPDIF, /* 0 */
226 ENVY24HT_CHAN_REC_MIX, /* 5 */
227 ENVY24HT_CHAN_REC_SPDIF, /* 6 */
228 ENVY24HT_CHAN_REC_ADC1, /* 7 */
229 ENVY24HT_CHAN_REC_ADC2, /* 8 */
230 ENVY24HT_CHAN_REC_ADC3, /* 9 */
231 ENVY24HT_CHAN_REC_ADC4, /* 10 */
234 /* mixer -> API channel map. see above */
235 static int envy24ht_mixmap[] = {
236 -1, /* Master output level. It is depend on codec support */
237 -1, /* Treble level of all output channels */
238 -1, /* Bass level of all output channels */
239 -1, /* Volume of synthesier input */
240 0, /* Output level for the audio device */
241 -1, /* Output level for the PC speaker */
242 7, /* line in jack */
243 -1, /* microphone jack */
244 -1, /* CD audio input */
245 -1, /* Recording monitor */
246 1, /* alternative codec */
247 -1, /* global recording level */
249 -1, /* Output gain */
250 8, /* Input source 1 */
251 9, /* Input source 2 */
252 10, /* Input source 3 */
253 6, /* Digital (input) 1 */
254 -1, /* Digital (input) 2 */
255 -1, /* Digital (input) 3 */
256 -1, /* Phone input */
257 -1, /* Phone output */
258 -1, /* Video/TV (audio) in */
260 -1, /* Monitor volume */
263 /* variable rate audio */
264 static u_int32_t envy24ht_speed[] = {
265 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
266 12000, 11025, 9600, 8000, 0
269 /* known boards configuration */
270 static struct codec_entry spi_codec = {
272 envy24ht_spi_destroy,
275 envy24ht_spi_setvolume,
279 static struct cfg_info cfg_table[] = {
281 "Envy24HT audio (Terratec Aureon 7.1 Space)",
283 0x0b, 0x80, 0xfc, 0xc3,
284 0x21efff, 0x7fffff, 0x5e1000,
285 0x40000, 0x80000, 0x1000, 0x00, 0x02,
290 "Envy24HT audio (Terratec Aureon 5.1 Sky)",
292 0x0a, 0x80, 0xfc, 0xc3,
293 0x21efff, 0x7fffff, 0x5e1000,
294 0x40000, 0x80000, 0x1000, 0x00, 0x02,
299 "Envy24HT audio (Terratec Aureon 7.1 Universe)",
301 0x0b, 0x80, 0xfc, 0xc3,
302 0x21efff, 0x7fffff, 0x5e1000,
303 0x40000, 0x80000, 0x1000, 0x00, 0x02,
308 "Envy24HT audio (AudioTrak Prodigy 7.1)",
310 0x0b, 0x80, 0xfc, 0xc3,
311 0x21efff, 0x7fffff, 0x5e1000,
312 0x40000, 0x80000, 0x1000, 0x00, 0x02,
317 "Envy24HT audio (Terratec PHASE 28)",
319 0x0b, 0x80, 0xfc, 0xc3,
320 0x21efff, 0x7fffff, 0x5e1000,
321 0x40000, 0x80000, 0x1000, 0x00, 0x02,
326 "Envy24HT-S audio (Terratec PHASE 22)",
328 0x10, 0x80, 0xf0, 0xc3,
329 0x7ffbc7, 0x7fffff, 0x438,
330 0x20, 0x10, 0x400, 0x00, 0x00,
335 "Envy24HT audio (AudioTrak Prodigy 7.1 LT)",
337 0x4b, 0x80, 0xfc, 0xc3,
338 0x7ff8ff, 0x7fffff, 0x700,
339 0x400, 0x200, 0x100, 0x00, 0x02,
344 "Envy24HT audio (AudioTrak Prodigy 7.1 XT)",
346 0x4b, 0x80, 0xfc, 0xc3,
347 0x7ff8ff, 0x7fffff, 0x700,
348 0x400, 0x200, 0x100, 0x00, 0x02,
353 "Envy24HT audio (M-Audio Revolution 7.1)",
355 0x43, 0x80, 0xf8, 0xc1,
356 0x3fff85, 0x72, 0x4000fa,
357 0x08, 0x02, 0x20, 0x00, 0x04,
362 "Envy24GT audio (M-Audio Revolution 5.1)",
364 0x42, 0x80, 0xf8, 0xc1,
365 0x3fff85, 0x72, 0x4000fa,
366 0x08, 0x02, 0x10, 0x00, 0x03,
371 "Envy24HT audio (M-Audio Audiophile 192)",
373 0x68, 0x80, 0xf8, 0xc3,
374 0x45, 0x4000b5, 0x7fffba,
375 0x08, 0x02, 0x10, 0x00, 0x03,
380 "Envy24HT audio (AudioTrak Prodigy HD2)",
382 0x68, 0x80, 0x78, 0xc3,
383 0xfff8ff, 0x200700, 0xdfffff,
384 0x400, 0x200, 0x100, 0x00, 0x05,
389 "Envy24HT audio (ESI Juli@)",
391 0x20, 0x80, 0xf8, 0xc3,
392 0x7fff9f, 0x8016, 0x7fff9f,
393 0x08, 0x02, 0x10, 0x00, 0x03,
398 "Envy24HT audio (Generic)",
400 0x0b, 0x80, 0xfc, 0xc3,
401 0x21efff, 0x7fffff, 0x5e1000,
402 0x40000, 0x80000, 0x1000, 0x00, 0x02,
404 &spi_codec, /* default codec routines */
408 static u_int32_t envy24ht_recfmt[] = {
409 AFMT_STEREO | AFMT_S16_LE,
410 AFMT_STEREO | AFMT_S32_LE,
413 static struct pcmchan_caps envy24ht_reccaps = {8000, 96000, envy24ht_recfmt, 0};
415 static u_int32_t envy24ht_playfmt[] = {
416 AFMT_STEREO | AFMT_U8,
417 AFMT_STEREO | AFMT_S16_LE,
418 AFMT_STEREO | AFMT_S32_LE,
422 static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0};
424 struct envy24ht_emldma {
426 void (*emldma)(struct sc_chinfo *);
430 static struct envy24ht_emldma envy24ht_pemltab[] = {
431 {AFMT_STEREO | AFMT_U8, envy24ht_p8u, 2},
432 {AFMT_STEREO | AFMT_S16_LE, envy24ht_p16sl, 4},
433 {AFMT_STEREO | AFMT_S32_LE, envy24ht_p32sl, 8},
437 static struct envy24ht_emldma envy24ht_remltab[] = {
438 {AFMT_STEREO | AFMT_S16_LE, envy24ht_r16sl, 4},
439 {AFMT_STEREO | AFMT_S32_LE, envy24ht_r32sl, 8},
443 /* -------------------------------------------------------------------- */
445 /* common routines */
447 envy24ht_rdcs(struct sc_info *sc, int regno, int size)
451 return bus_space_read_1(sc->cst, sc->csh, regno);
453 return bus_space_read_2(sc->cst, sc->csh, regno);
455 return bus_space_read_4(sc->cst, sc->csh, regno);
462 envy24ht_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
466 bus_space_write_1(sc->cst, sc->csh, regno, data);
469 bus_space_write_2(sc->cst, sc->csh, regno, data);
472 bus_space_write_4(sc->cst, sc->csh, regno, data);
478 envy24ht_rdmt(struct sc_info *sc, int regno, int size)
482 return bus_space_read_1(sc->mtt, sc->mth, regno);
484 return bus_space_read_2(sc->mtt, sc->mth, regno);
486 return bus_space_read_4(sc->mtt, sc->mth, regno);
493 envy24ht_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
497 bus_space_write_1(sc->mtt, sc->mth, regno, data);
500 bus_space_write_2(sc->mtt, sc->mth, regno, data);
503 bus_space_write_4(sc->mtt, sc->mth, regno, data);
508 /* -------------------------------------------------------------------- */
510 /* I2C port/E2PROM access routines */
513 envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
519 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
521 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
522 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
523 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
525 DELAY(32); /* 31.25kHz */
527 if (i == ENVY24HT_TIMEOUT) {
530 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
531 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
532 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_RD, 1);
533 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
534 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
535 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
537 DELAY(32); /* 31.25kHz */
539 if (i == ENVY24HT_TIMEOUT) {
542 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CDATA, 1);
545 device_printf(sc->dev, "envy24ht_rdi2c(): return 0x%x\n", data);
551 envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
557 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
559 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
560 tmp = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
561 if ((tmp & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
563 DELAY(32); /* 31.25kHz */
565 if (i == ENVY24HT_TIMEOUT) {
568 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
569 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDATA, data, 1);
570 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
571 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_WR, 1);
572 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
573 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
574 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
576 DELAY(32); /* 31.25kHz */
578 if (i == ENVY24HT_TIMEOUT) {
586 envy24ht_rdrom(struct sc_info *sc, u_int32_t addr)
591 device_printf(sc->dev, "envy24ht_rdrom(sc, 0x%02x)\n", addr);
593 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
594 if ((data & ENVY24HT_CCS_I2CSTAT_ROM) == 0) {
596 device_printf(sc->dev, "envy24ht_rdrom(): E2PROM not presented\n");
601 return envy24ht_rdi2c(sc, ENVY24HT_CCS_I2CDEV_ROM, addr);
604 static struct cfg_info *
605 envy24ht_rom2cfg(struct sc_info *sc)
607 struct cfg_info *buff;
612 device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n");
614 size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE);
615 if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) {
617 device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size);
619 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
622 device_printf(sc->dev, "envy24ht_rom2cfg(): kmalloc()\n");
628 /* no valid e2prom, using default values */
629 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
630 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
631 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
632 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
637 buff->gpiomask = 0x21efff;
638 buff->gpiostate = 0x7fffff;
639 buff->gpiodir = 0x5e1000;
640 buff->cdti = 0x40000;
641 buff->cclk = 0x80000;
646 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0;
648 if (cfg_table[i].subvendor == buff->subvendor &&
649 cfg_table[i].subdevice == buff->subdevice)
651 buff->name = cfg_table[i].name;
652 buff->codec = cfg_table[i].codec;
659 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
662 device_printf(sc->dev, "envy24ht_rom2cfg(): kmalloc()\n");
668 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
669 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
670 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
671 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
672 buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG);
673 buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL);
674 buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S);
675 buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF);
676 buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \
677 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \
678 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16;
679 buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \
680 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \
681 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16;
682 buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \
683 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \
684 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16;
686 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
687 if (cfg_table[i].subvendor == buff->subvendor &&
688 cfg_table[i].subdevice == buff->subdevice)
690 buff->name = cfg_table[i].name;
691 buff->codec = cfg_table[i].codec;
697 envy24ht_cfgfree(struct cfg_info *cfg) {
701 kfree(cfg, M_ENVY24HT);
705 /* -------------------------------------------------------------------- */
707 /* AC'97 codec access routines */
711 envy24ht_coldcd(struct sc_info *sc)
717 device_printf(sc->dev, "envy24ht_coldcd()\n");
719 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1);
721 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
723 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
724 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
725 if (data & ENVY24HT_MT_AC97CMD_RDY) {
734 envy24ht_slavecd(struct sc_info *sc)
740 device_printf(sc->dev, "envy24ht_slavecd()\n");
742 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD,
743 ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1);
745 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
747 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
748 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
749 if (data & ENVY24HT_MT_AC97CMD_RDY) {
758 envy24ht_rdcd(kobj_t obj, void *devinfo, int regno)
760 struct sc_info *sc = (struct sc_info *)devinfo;
765 device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno);
767 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
768 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1);
769 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
770 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
771 if ((data & ENVY24HT_MT_AC97CMD_RD) == 0)
774 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2);
777 device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data);
783 envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
785 struct sc_info *sc = (struct sc_info *)devinfo;
790 device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
792 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
793 envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2);
794 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1);
795 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
796 cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
797 if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0)
804 static kobj_method_t envy24ht_ac97_methods[] = {
805 KOBJMETHOD(ac97_read, envy24ht_rdcd),
806 KOBJMETHOD(ac97_write, envy24ht_wrcd),
809 AC97_DECLARE(envy24ht_ac97);
812 /* -------------------------------------------------------------------- */
814 /* GPIO access routines */
817 envy24ht_gpiord(struct sc_info *sc)
819 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
820 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2);
822 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2));
826 envy24ht_gpiowr(struct sc_info *sc, u_int32_t data)
829 device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF);
832 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2);
833 if (sc->cfg->subdevice != 0x1150)
834 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1);
840 envy24ht_gpiogetmask(struct sc_info *sc)
842 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2));
847 envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask)
849 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2);
850 if (sc->cfg->subdevice != 0x1150)
851 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1);
857 envy24ht_gpiogetdir(struct sc_info *sc)
859 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4);
864 envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir)
866 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
867 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2);
869 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4);
873 /* -------------------------------------------------------------------- */
875 /* SPI codec access interface routine */
877 struct envy24ht_spi_codec {
878 struct spicds_info *info;
879 struct sc_info *parent;
886 envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
889 struct envy24ht_spi_codec *ptr = codec;
892 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
894 data = envy24ht_gpiord(ptr->parent);
895 data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
896 if (cs) data += ptr->cs;
897 if (cclk) data += ptr->cclk;
898 if (cdti) data += ptr->cdti;
899 envy24ht_gpiowr(ptr->parent, data);
904 envy24ht_spi_create(device_t dev, void *info, int dir, int num)
906 struct sc_info *sc = info;
907 struct envy24ht_spi_codec *buff = NULL;
910 device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num);
913 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
917 if (dir == PCMDIR_REC && sc->adc[num] != NULL)
918 buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info;
919 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
920 buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info;
922 buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl);
923 if (buff->info == NULL) {
924 kfree(buff, M_ENVY24HT);
936 envy24ht_spi_destroy(void *codec)
938 struct envy24ht_spi_codec *ptr = codec;
942 device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n");
945 if (ptr->dir == PCMDIR_PLAY) {
946 if (ptr->parent->dac[ptr->num] != NULL)
947 spicds_destroy(ptr->info);
950 if (ptr->parent->adc[ptr->num] != NULL)
951 spicds_destroy(ptr->info);
954 kfree(codec, M_ENVY24HT);
958 envy24ht_spi_init(void *codec)
960 struct envy24ht_spi_codec *ptr = codec;
964 device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n");
966 ptr->cs = ptr->parent->cfg->cs;
967 ptr->cclk = ptr->parent->cfg->cclk;
968 ptr->cdti = ptr->parent->cfg->cdti;
969 spicds_settype(ptr->info, ptr->parent->cfg->type);
970 spicds_setcif(ptr->info, ptr->parent->cfg->cif);
971 if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \
972 ptr->parent->cfg->type == SPICDS_TYPE_AK4528) {
973 spicds_setformat(ptr->info,
974 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
975 spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
978 /* for the time being, init only first codec */
980 spicds_init(ptr->info);
984 envy24ht_spi_reinit(void *codec)
986 struct envy24ht_spi_codec *ptr = codec;
990 device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n");
993 spicds_reinit(ptr->info);
997 envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
999 struct envy24ht_spi_codec *ptr = codec;
1003 device_printf(ptr->parent->dev, "envy24ht_spi_set()\n");
1006 spicds_set(ptr->info, dir, left, right);
1009 /* -------------------------------------------------------------------- */
1011 /* hardware access routeines */
1016 } envy24ht_speedtab[] = {
1017 {48000, ENVY24HT_MT_RATE_48000},
1018 {24000, ENVY24HT_MT_RATE_24000},
1019 {12000, ENVY24HT_MT_RATE_12000},
1020 {9600, ENVY24HT_MT_RATE_9600},
1021 {32000, ENVY24HT_MT_RATE_32000},
1022 {16000, ENVY24HT_MT_RATE_16000},
1023 {8000, ENVY24HT_MT_RATE_8000},
1024 {96000, ENVY24HT_MT_RATE_96000},
1025 {192000, ENVY24HT_MT_RATE_192000},
1026 {64000, ENVY24HT_MT_RATE_64000},
1027 {44100, ENVY24HT_MT_RATE_44100},
1028 {22050, ENVY24HT_MT_RATE_22050},
1029 {11025, ENVY24HT_MT_RATE_11025},
1030 {88200, ENVY24HT_MT_RATE_88200},
1031 {176400, ENVY24HT_MT_RATE_176400},
1036 envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) {
1037 u_int32_t code, i2sfmt;
1041 device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed);
1043 code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */
1044 envy24ht_slavecd(sc);
1048 for (i = 0; envy24ht_speedtab[i].speed != 0; i++) {
1049 if (envy24ht_speedtab[i].speed == speed)
1052 code = envy24ht_speedtab[i].code;
1055 device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code);
1058 envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1);
1059 if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \
1060 (code == ENVY24HT_MT_RATE_176400)) {
1061 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1062 i2sfmt |= ENVY24HT_MT_I2S_MLR128;
1063 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1066 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1067 i2sfmt &= ~ENVY24HT_MT_I2S_MLR128;
1068 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1070 code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1);
1071 code &= ENVY24HT_MT_RATE_MASK;
1072 for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) {
1073 if (envy24ht_speedtab[i].code == code)
1076 speed = envy24ht_speedtab[i].speed;
1082 device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed);
1088 envy24ht_setvolume(struct sc_info *sc, unsigned ch)
1091 device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch);
1092 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1093 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1094 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1095 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1100 envy24ht_mutevolume(struct sc_info *sc, unsigned ch)
1105 device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch);
1106 vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE;
1107 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1108 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1109 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1110 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1115 envy24ht_gethwptr(struct sc_info *sc, int dir)
1121 device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir);
1123 if (dir == PCMDIR_PLAY) {
1124 rtn = sc->psize / 4;
1125 unit = ENVY24HT_PLAY_BUFUNIT / 4;
1126 regno = ENVY24HT_MT_PCNT;
1129 rtn = sc->rsize / 4;
1130 unit = ENVY24HT_REC_BUFUNIT / 4;
1131 regno = ENVY24HT_MT_RCNT;
1134 ptr = envy24ht_rdmt(sc, regno, 2);
1139 device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn);
1145 envy24ht_updintr(struct sc_info *sc, int dir)
1147 int regptr, regintr;
1148 u_int32_t mask, intr;
1149 u_int32_t ptr, size, cnt;
1153 device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir);
1155 if (dir == PCMDIR_PLAY) {
1157 size = sc->psize / 4;
1158 regptr = ENVY24HT_MT_PCNT;
1159 regintr = ENVY24HT_MT_PTERM;
1160 mask = ~ENVY24HT_MT_INT_PMASK;
1164 size = sc->rsize / 4;
1165 regptr = ENVY24HT_MT_RCNT;
1166 regintr = ENVY24HT_MT_RTERM;
1167 mask = ~ENVY24HT_MT_INT_RMASK;
1170 ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1;
1172 cnt = blk - ptr % blk - 1;
1178 device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1180 envy24ht_wrmt(sc, regintr, cnt, 2);
1181 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1183 device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1185 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
1187 device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
1188 envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
1196 envy24ht_maskintr(struct sc_info *sc, int dir)
1198 u_int32_t mask, intr;
1201 device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
1203 if (dir == PCMDIR_PLAY)
1204 mask = ENVY24HT_MT_INT_PMASK;
1206 mask = ENVY24HT_MT_INT_RMASK;
1207 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
1208 envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
1215 envy24ht_checkintr(struct sc_info *sc, int dir)
1217 u_int32_t mask, stat, intr, rtn;
1220 device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
1222 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
1223 if (dir == PCMDIR_PLAY) {
1224 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
1225 mask = ~ENVY24HT_MT_INT_RSTAT;
1226 envy24ht_wrmt(sc, 0x1a, 0x01, 1);
1227 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);
1228 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1229 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
1233 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
1234 mask = ~ENVY24HT_MT_INT_PSTAT;
1236 stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
1238 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
1239 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1240 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
1248 envy24ht_start(struct sc_info *sc, int dir)
1253 device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
1255 if (dir == PCMDIR_PLAY)
1256 sw = ENVY24HT_MT_PCTL_PSTART;
1258 sw = ENVY24HT_MT_PCTL_RSTART;
1260 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1261 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
1264 device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
1265 device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
1272 envy24ht_stop(struct sc_info *sc, int dir)
1277 device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir);
1279 if (dir == PCMDIR_PLAY)
1280 sw = ~ENVY24HT_MT_PCTL_PSTART;
1282 sw = ~ENVY24HT_MT_PCTL_RSTART;
1284 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1285 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1);
1292 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1298 /* -------------------------------------------------------------------- */
1300 /* buffer copy routines */
1302 envy24ht_p32sl(struct sc_chinfo *ch)
1307 int src, dst, ssize, dsize, slot;
1310 length = sndbuf_getready(ch->buffer) / 8;
1311 dmabuf = ch->parent->pbuf;
1312 data = (u_int32_t *)ch->data;
1313 src = sndbuf_getreadyptr(ch->buffer) / 4;
1314 dst = src / 2 + ch->offset;
1315 ssize = ch->size / 4;
1316 dsize = ch->size / 8;
1319 for (i = 0; i < length; i++) {
1320 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
1321 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1332 envy24ht_p16sl(struct sc_chinfo *ch)
1337 int src, dst, ssize, dsize, slot;
1341 device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
1343 length = sndbuf_getready(ch->buffer) / 4;
1344 dmabuf = ch->parent->pbuf;
1345 data = (u_int16_t *)ch->data;
1346 src = sndbuf_getreadyptr(ch->buffer) / 2;
1347 dst = src / 2 + ch->offset;
1348 ssize = ch->size / 2;
1349 dsize = ch->size / 4;
1352 device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1355 for (i = 0; i < length; i++) {
1356 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1357 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1360 kprintf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
1361 kprintf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
1377 envy24ht_p8u(struct sc_chinfo *ch)
1382 int src, dst, ssize, dsize, slot;
1385 length = sndbuf_getready(ch->buffer) / 2;
1386 dmabuf = ch->parent->pbuf;
1387 data = (u_int8_t *)ch->data;
1388 src = sndbuf_getreadyptr(ch->buffer);
1389 dst = src / 2 + ch->offset;
1391 dsize = ch->size / 4;
1394 for (i = 0; i < length; i++) {
1395 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1396 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1407 envy24ht_r32sl(struct sc_chinfo *ch)
1412 int src, dst, ssize, dsize, slot;
1415 length = sndbuf_getfree(ch->buffer) / 8;
1416 dmabuf = ch->parent->rbuf;
1417 data = (u_int32_t *)ch->data;
1418 dst = sndbuf_getfreeptr(ch->buffer) / 4;
1419 src = dst / 2 + ch->offset;
1420 dsize = ch->size / 4;
1421 ssize = ch->size / 8;
1422 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1424 for (i = 0; i < length; i++) {
1425 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1426 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1437 envy24ht_r16sl(struct sc_chinfo *ch)
1442 int src, dst, ssize, dsize, slot;
1445 length = sndbuf_getfree(ch->buffer) / 4;
1446 dmabuf = ch->parent->rbuf;
1447 data = (u_int16_t *)ch->data;
1448 dst = sndbuf_getfreeptr(ch->buffer) / 2;
1449 src = dst / 2 + ch->offset;
1450 dsize = ch->size / 2;
1451 ssize = ch->size / 8;
1452 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1454 for (i = 0; i < length; i++) {
1455 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1456 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1466 /* -------------------------------------------------------------------- */
1468 /* channel interface */
1470 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1472 struct sc_info *sc = (struct sc_info *)devinfo;
1473 struct sc_chinfo *ch;
1477 device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
1479 snd_mtxlock(sc->lock);
1481 if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1482 (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1483 snd_mtxunlock(sc->lock);
1489 ch = &sc->chan[num];
1490 ch->size = 8 * ENVY24HT_SAMPLE_NUM;
1491 ch->data = kmalloc(ch->size, M_ENVY24HT, M_NOWAIT);
1492 if (ch->data == NULL) {
1501 /* set channel map */
1502 ch->num = envy24ht_chanmap[num];
1503 snd_mtxunlock(sc->lock);
1504 sndbuf_setup(ch->buffer, ch->data, ch->size);
1505 snd_mtxlock(sc->lock);
1506 /* these 2 values are dummy */
1510 snd_mtxunlock(sc->lock);
1516 envy24htchan_free(kobj_t obj, void *data)
1518 struct sc_chinfo *ch = data;
1519 struct sc_info *sc = ch->parent;
1522 device_printf(sc->dev, "envy24htchan_free()\n");
1524 snd_mtxlock(sc->lock);
1525 if (ch->data != NULL) {
1526 kfree(ch->data, M_ENVY24HT);
1529 snd_mtxunlock(sc->lock);
1535 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
1537 struct sc_chinfo *ch = data;
1538 struct sc_info *sc = ch->parent;
1539 struct envy24ht_emldma *emltab;
1540 /* unsigned int bcnt, bsize; */
1544 device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
1546 snd_mtxlock(sc->lock);
1547 /* check and get format related information */
1548 if (ch->dir == PCMDIR_PLAY)
1549 emltab = envy24ht_pemltab;
1551 emltab = envy24ht_remltab;
1552 if (emltab == NULL) {
1553 snd_mtxunlock(sc->lock);
1556 for (i = 0; emltab[i].format != 0; i++)
1557 if (emltab[i].format == format)
1559 if (emltab[i].format == 0) {
1560 snd_mtxunlock(sc->lock);
1564 /* set format information */
1565 ch->format = format;
1566 ch->emldma = emltab[i].emldma;
1567 if (ch->unit > emltab[i].unit)
1568 ch->blk *= ch->unit / emltab[i].unit;
1570 ch->blk /= emltab[i].unit / ch->unit;
1571 ch->unit = emltab[i].unit;
1573 /* set channel buffer information */
1574 ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
1576 if (ch->dir == PCMDIR_PLAY)
1577 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1579 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1581 bcnt = ch->size / bsize;
1582 sndbuf_resize(ch->buffer, bcnt, bsize);
1584 snd_mtxunlock(sc->lock);
1587 device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
1593 IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1594 of speed information value. And real hardware speed setting is done
1595 at start triggered(see envy24htchan_trigger()). So, at this function
1596 is called, any value that ENVY24 can use is able to set. But, at
1597 start triggerd, some other channel is running, and that channel's
1598 speed isn't same with, then trigger function will fail.
1601 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1603 struct sc_chinfo *ch = data;
1604 u_int32_t val, prev;
1608 device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
1611 for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
1612 if (abs(val - speed) < abs(prev - speed))
1620 device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
1626 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1628 struct sc_chinfo *ch = data;
1629 /* struct sc_info *sc = ch->parent; */
1630 u_int32_t size, prev;
1631 unsigned int bcnt, bsize;
1634 device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
1637 /* snd_mtxlock(sc->lock); */
1638 for (size = ch->size / 2; size > 0; size /= 2) {
1639 if (abs(size - blocksize) < abs(prev - blocksize))
1645 ch->blk = prev / ch->unit;
1646 if (ch->dir == PCMDIR_PLAY)
1647 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
1649 ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
1650 /* set channel buffer information */
1651 /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
1652 if (ch->dir == PCMDIR_PLAY)
1653 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1655 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1657 bcnt = ch->size / bsize;
1658 sndbuf_resize(ch->buffer, bcnt, bsize);
1659 /* snd_mtxunlock(sc->lock); */
1662 device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
1667 /* semantic note: must start at beginning of buffer */
1669 envy24htchan_trigger(kobj_t obj, void *data, int go)
1671 struct sc_chinfo *ch = data;
1672 struct sc_info *sc = ch->parent;
1678 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1680 snd_mtxlock(sc->lock);
1681 if (ch->dir == PCMDIR_PLAY)
1688 device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1690 /* check or set channel speed */
1691 if (sc->run[0] == 0 && sc->run[1] == 0) {
1692 sc->speed = envy24ht_setspeed(sc, ch->speed);
1693 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1694 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1696 else if (ch->speed != 0 && ch->speed != sc->speed)
1699 ch->channel->speed = sc->speed;
1700 /* start or enable channel */
1702 if (sc->run[slot] == 1) {
1705 sc->blk[slot] = ch->blk;
1708 ptr = envy24ht_gethwptr(sc, ch->dir);
1709 ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1710 (ch->size / 4)) * 4 / ch->unit;
1711 if (ch->blk < sc->blk[slot])
1712 sc->blk[slot] = ch->blk;
1714 if (ch->dir == PCMDIR_PLAY) {
1716 envy24ht_setvolume(sc, ch->num);
1718 envy24ht_updintr(sc, ch->dir);
1719 if (sc->run[slot] == 1)
1720 envy24ht_start(sc, ch->dir);
1723 case PCMTRIG_EMLDMAWR:
1725 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1731 case PCMTRIG_EMLDMARD:
1733 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1742 device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1746 if (ch->dir == PCMDIR_PLAY)
1747 envy24ht_mutevolume(sc, ch->num);
1748 if (sc->run[slot] == 0) {
1749 envy24ht_stop(sc, ch->dir);
1752 /* else if (ch->blk == sc->blk[slot]) {
1753 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1754 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1755 if (sc->chan[i].dir == ch->dir &&
1756 sc->chan[i].run == 1 &&
1757 sc->chan[i].blk < sc->blk[slot])
1758 sc->blk[slot] = sc->chan[i].blk;
1760 if (ch->blk != sc->blk[slot])
1761 envy24ht_updintr(sc, ch->dir);
1766 snd_mtxunlock(sc->lock);
1772 envy24htchan_getptr(kobj_t obj, void *data)
1774 struct sc_chinfo *ch = data;
1775 struct sc_info *sc = ch->parent;
1780 device_printf(sc->dev, "envy24htchan_getptr()\n");
1782 snd_mtxlock(sc->lock);
1783 ptr = envy24ht_gethwptr(sc, ch->dir);
1784 rtn = ptr * ch->unit;
1785 snd_mtxunlock(sc->lock);
1788 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1794 static struct pcmchan_caps *
1795 envy24htchan_getcaps(kobj_t obj, void *data)
1797 struct sc_chinfo *ch = data;
1798 struct sc_info *sc = ch->parent;
1799 struct pcmchan_caps *rtn;
1802 device_printf(sc->dev, "envy24htchan_getcaps()\n");
1804 snd_mtxlock(sc->lock);
1805 if (ch->dir == PCMDIR_PLAY) {
1806 if (sc->run[0] == 0)
1807 rtn = &envy24ht_playcaps;
1812 if (sc->run[1] == 0)
1813 rtn = &envy24ht_reccaps;
1817 snd_mtxunlock(sc->lock);
1822 static kobj_method_t envy24htchan_methods[] = {
1823 KOBJMETHOD(channel_init, envy24htchan_init),
1824 KOBJMETHOD(channel_free, envy24htchan_free),
1825 KOBJMETHOD(channel_setformat, envy24htchan_setformat),
1826 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed),
1827 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize),
1828 KOBJMETHOD(channel_trigger, envy24htchan_trigger),
1829 KOBJMETHOD(channel_getptr, envy24htchan_getptr),
1830 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps),
1833 CHANNEL_DECLARE(envy24htchan);
1835 /* -------------------------------------------------------------------- */
1837 /* mixer interface */
1840 envy24htmixer_init(struct snd_mixer *m)
1842 struct sc_info *sc = mix_getdevinfo(m);
1845 device_printf(sc->dev, "envy24htmixer_init()\n");
1850 /* set volume control rate */
1851 snd_mtxlock(sc->lock);
1853 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1856 pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1858 mix_setdevs(m, ENVY24HT_MIX_MASK);
1859 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1861 snd_mtxunlock(sc->lock);
1867 envy24htmixer_reinit(struct snd_mixer *m)
1869 struct sc_info *sc = mix_getdevinfo(m);
1874 device_printf(sc->dev, "envy24htmixer_reinit()\n");
1881 envy24htmixer_uninit(struct snd_mixer *m)
1883 struct sc_info *sc = mix_getdevinfo(m);
1888 device_printf(sc->dev, "envy24htmixer_uninit()\n");
1895 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1897 struct sc_info *sc = mix_getdevinfo(m);
1898 int ch = envy24ht_mixmap[dev];
1904 if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1906 if (dev != 0 && ch == -1)
1908 hwch = envy24ht_chanmap[ch];
1910 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1914 snd_mtxlock(sc->lock);
1916 for (i = 0; i < sc->dacn; i++) {
1917 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1921 /* set volume value for hardware */
1922 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1923 sc->left[hwch] = ENVY24HT_VOL_MUTE;
1924 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1925 sc->right[hwch] = ENVY24HT_VOL_MUTE;
1927 /* set volume for record channel and running play channel */
1928 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1929 envy24ht_setvolume(sc, hwch);
1931 snd_mtxunlock(sc->lock);
1933 return right << 8 | left;
1937 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1939 struct sc_info *sc = mix_getdevinfo(m);
1940 int ch = envy24ht_mixmap[src];
1942 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1945 if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1950 static kobj_method_t envy24htmixer_methods[] = {
1951 KOBJMETHOD(mixer_init, envy24htmixer_init),
1952 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit),
1953 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit),
1954 KOBJMETHOD(mixer_set, envy24htmixer_set),
1955 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc),
1958 MIXER_DECLARE(envy24htmixer);
1960 /* -------------------------------------------------------------------- */
1962 /* The interrupt handler */
1964 envy24ht_intr(void *p)
1966 struct sc_info *sc = (struct sc_info *)p;
1967 struct sc_chinfo *ch;
1968 u_int32_t ptr, dsize, feed;
1972 device_printf(sc->dev, "envy24ht_intr()\n");
1974 snd_mtxlock(sc->lock);
1975 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1977 device_printf(sc->dev, "envy24ht_intr(): play\n");
1979 dsize = sc->psize / 4;
1980 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
1982 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
1984 ptr -= ptr % sc->blk[0];
1985 feed = (ptr + dsize - sc->intr[0]) % dsize;
1987 kprintf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
1989 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
1993 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
1995 if (ch->run && ch->blk <= feed) {
1996 snd_mtxunlock(sc->lock);
1997 chn_intr(ch->channel);
1998 snd_mtxlock(sc->lock);
2002 envy24ht_updintr(sc, PCMDIR_PLAY);
2004 if (envy24ht_checkintr(sc, PCMDIR_REC)) {
2006 device_printf(sc->dev, "envy24ht_intr(): rec\n");
2008 dsize = sc->rsize / 4;
2009 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
2010 ptr -= ptr % sc->blk[1];
2011 feed = (ptr + dsize - sc->intr[1]) % dsize;
2012 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
2014 if (ch->run && ch->blk <= feed) {
2015 snd_mtxunlock(sc->lock);
2016 chn_intr(ch->channel);
2017 snd_mtxlock(sc->lock);
2021 envy24ht_updintr(sc, PCMDIR_REC);
2023 snd_mtxunlock(sc->lock);
2029 * Probe and attach the card
2033 envy24ht_pci_probe(device_t dev)
2039 kprintf("envy24ht_pci_probe()\n");
2041 if (pci_get_device(dev) == PCID_ENVY24HT &&
2042 pci_get_vendor(dev) == PCIV_ENVY24) {
2043 sv = pci_get_subvendor(dev);
2044 sd = pci_get_subdevice(dev);
2045 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2046 if (cfg_table[i].subvendor == sv &&
2047 cfg_table[i].subdevice == sd) {
2051 device_set_desc(dev, cfg_table[i].name);
2053 kprintf("envy24ht_pci_probe(): return 0\n");
2059 kprintf("envy24ht_pci_probe(): return ENXIO\n");
2066 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2068 /* struct sc_info *sc = (struct sc_info *)arg; */
2071 device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2073 kprintf("envy24ht(play): setmap %lx, %lx; ",
2074 (unsigned long)segs->ds_addr,
2075 (unsigned long)segs->ds_len);
2076 kprintf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2082 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2084 /* struct sc_info *sc = (struct sc_info *)arg; */
2087 device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2089 kprintf("envy24ht(record): setmap %lx, %lx; ",
2090 (unsigned long)segs->ds_addr,
2091 (unsigned long)segs->ds_len);
2092 kprintf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2098 envy24ht_dmafree(struct sc_info *sc)
2101 device_printf(sc->dev, "envy24ht_dmafree():");
2102 if (sc->rmap) kprintf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2103 else kprintf(" sc->rmap(null)");
2104 if (sc->pmap) kprintf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2105 else kprintf(" sc->pmap(null)");
2106 if (sc->rbuf) kprintf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2107 else kprintf(" sc->rbuf(null)");
2108 if (sc->pbuf) kprintf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2109 else kprintf(" sc->pbuf(null)\n");
2113 bus_dmamap_unload(sc->dmat, sc->rmap);
2115 bus_dmamap_unload(sc->dmat, sc->pmap);
2117 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2119 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2121 bus_dmamap_unload(sc->dmat, sc->rmap);
2122 bus_dmamap_unload(sc->dmat, sc->pmap);
2123 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2124 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2127 sc->rmap = sc->pmap = NULL;
2135 envy24ht_dmainit(struct sc_info *sc)
2140 device_printf(sc->dev, "envy24ht_dmainit()\n");
2143 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2144 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2147 sc->pmap = sc->rmap = NULL;
2148 sc->blk[0] = sc->blk[1] = 0;
2150 /* allocate DMA buffer */
2152 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2154 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2157 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2159 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2162 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2164 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, 0))
2167 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2169 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, 0))
2171 bzero(sc->pbuf, sc->psize);
2172 bzero(sc->rbuf, sc->rsize);
2174 /* set values to register */
2175 addr = vtophys(sc->pbuf);
2177 device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2179 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, addr, 4);
2181 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
2182 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2184 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, sc->psize / 4 - 1, 2);
2186 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
2188 addr = vtophys(sc->rbuf);
2189 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, addr, 4);
2190 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, sc->rsize / 4 - 1, 2);
2194 envy24ht_dmafree(sc);
2199 envy24ht_putcfg(struct sc_info *sc)
2201 device_printf(sc->dev, "system configuration\n");
2202 kprintf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2203 sc->cfg->subvendor, sc->cfg->subdevice);
2204 kprintf(" XIN2 Clock Source: ");
2205 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2207 kprintf("24.576MHz(96kHz*256)\n");
2210 kprintf("49.152MHz(192kHz*256)\n");
2213 kprintf("reserved\n");
2216 kprintf("illeagal system setting\n");
2218 kprintf(" MPU-401 UART(s) #: ");
2219 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2222 kprintf("not implemented\n");
2225 kprintf(" ADC #: ");
2226 kprintf("%d\n", sc->adcn);
2229 kprintf(" ADC #: ");
2231 kprintf(" and SPDIF receiver connected\n");
2234 kprintf(" no physical inputs\n");
2236 kprintf(" DAC #: ");
2237 kprintf("%d\n", sc->dacn);
2238 kprintf(" Multi-track converter type: ");
2239 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2240 kprintf("AC'97(SDATA_OUT:");
2241 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2249 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2250 kprintf("with volume, ");
2251 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2252 kprintf("192KHz support, ");
2254 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2255 kprintf("192KHz support, ");
2257 kprintf("48KHz support, ");
2258 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2259 case ENVY24HT_CCSM_I2S_16BIT:
2260 kprintf("16bit resolution, ");
2262 case ENVY24HT_CCSM_I2S_18BIT:
2263 kprintf("18bit resolution, ");
2265 case ENVY24HT_CCSM_I2S_20BIT:
2266 kprintf("20bit resolution, ");
2268 case ENVY24HT_CCSM_I2S_24BIT:
2269 kprintf("24bit resolution, ");
2272 kprintf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2274 kprintf(" S/PDIF(IN/OUT): ");
2275 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2279 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2283 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2284 kprintf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2285 kprintf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2286 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2290 envy24ht_init(struct sc_info *sc)
2301 device_printf(sc->dev, "envy24ht_init()\n");
2306 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2308 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2311 /* legacy hardware disable */
2312 data = pci_read_config(sc->dev, PCIR_LAC, 2);
2313 data |= PCIM_LAC_DISABLE;
2314 pci_write_config(sc->dev, PCIR_LAC, data, 2);
2317 /* check system configuration */
2319 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2320 /* 1st: search configuration from table */
2321 sv = pci_get_subvendor(sc->dev);
2322 sd = pci_get_subdevice(sc->dev);
2323 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2325 device_printf(sc->dev, "Set configuration from table\n");
2327 sc->cfg = &cfg_table[i];
2331 if (sc->cfg == NULL) {
2332 /* 2nd: read configuration from table */
2333 sc->cfg = envy24ht_rom2cfg(sc);
2335 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2336 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2338 if (1 /* bootverbose */) {
2339 envy24ht_putcfg(sc);
2342 /* set system configuration */
2343 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2344 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2345 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2346 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2347 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2348 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2349 envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2351 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2352 envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2353 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2354 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2357 for (i = 0; i < sc->adcn; i++) {
2358 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2359 sc->cfg->codec->init(sc->adc[i]);
2361 for (i = 0; i < sc->dacn; i++) {
2362 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2363 sc->cfg->codec->init(sc->dac[i]);
2366 /* initialize DMA buffer */
2368 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2370 if (envy24ht_dmainit(sc))
2373 /* initialize status */
2374 sc->run[0] = sc->run[1] = 0;
2375 sc->intr[0] = sc->intr[1] = 0;
2377 sc->caps[0].fmtlist = envy24ht_playfmt;
2378 sc->caps[1].fmtlist = envy24ht_recfmt;
2380 /* set channel router */
2382 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2383 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2384 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2387 /* set macro interrupt mask */
2388 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2389 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2390 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2392 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2399 envy24ht_alloc_resource(struct sc_info *sc)
2401 /* allocate I/O port resource */
2402 sc->csid = PCIR_CCS;
2403 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2404 &sc->csid, 0, ~0, 1, RF_ACTIVE);
2405 sc->mtid = ENVY24HT_PCIR_MT;
2406 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2407 &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2408 if (!sc->cs || !sc->mt) {
2409 device_printf(sc->dev, "unable to map IO port space\n");
2412 sc->cst = rman_get_bustag(sc->cs);
2413 sc->csh = rman_get_bushandle(sc->cs);
2414 sc->mtt = rman_get_bustag(sc->mt);
2415 sc->mth = rman_get_bushandle(sc->mt);
2417 device_printf(sc->dev,
2418 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2419 pci_read_config(sc->dev, PCIR_CCS, 4),
2420 pci_read_config(sc->dev, PCIR_MT, 4));
2423 /* allocate interupt resource */
2425 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2426 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2428 snd_setup_intr(sc->dev, sc->irq, 0, envy24ht_intr, sc, &sc->ih)) {
2429 device_printf(sc->dev, "unable to map interrupt\n");
2433 /* allocate DMA resource */
2434 if (bus_dma_tag_create(/*parent*/NULL,
2437 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2438 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2439 /*filter*/NULL, /*filterarg*/NULL,
2440 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2441 /*nsegments*/1, /*maxsegsz*/0x3ffff,
2442 /*flags*/0 , &sc->dmat) != 0) {
2443 device_printf(sc->dev, "unable to create dma tag\n");
2451 envy24ht_pci_attach(device_t dev)
2455 char status[SND_STATUSLEN];
2460 device_printf(dev, "envy24ht_pci_attach()\n");
2462 /* get sc_info data area */
2463 if ((sc = kmalloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) {
2464 device_printf(dev, "cannot allocate softc\n");
2468 bzero(sc, sizeof(*sc));
2469 sc->lock = snd_mtxcreate(device_get_nameunit(dev),
2470 "snd_envy24ht softc");
2473 /* initialize PCI interface */
2474 data = pci_read_config(dev, PCIR_COMMAND, 2);
2475 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2476 pci_write_config(dev, PCIR_COMMAND, data, 2);
2477 data = pci_read_config(dev, PCIR_COMMAND, 2);
2479 /* allocate resources */
2480 err = envy24ht_alloc_resource(sc);
2482 device_printf(dev, "unable to allocate system resources\n");
2486 /* initialize card */
2487 err = envy24ht_init(sc);
2489 device_printf(dev, "unable to initialize the card\n");
2493 /* set multi track mixer */
2494 mixer_init(dev, &envy24htmixer_class, sc);
2496 /* set channel information */
2497 /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
2498 err = pcm_register(dev, sc, 1, 2 + sc->adcn);
2502 /* for (i = 0; i < 5; i++) { */
2503 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
2506 for (i = 0; i < 2 + sc->adcn; i++) {
2507 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
2511 /* set status iformation */
2512 ksnprintf(status, SND_STATUSLEN,
2513 "at io 0x%lx:%ld,0x%lx:%ld irq %ld",
2514 rman_get_start(sc->cs),
2515 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2516 rman_get_start(sc->mt),
2517 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2518 rman_get_start(sc->irq));
2519 pcm_setstatus(dev, status);
2525 bus_teardown_intr(dev, sc->irq, sc->ih);
2527 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2528 envy24ht_dmafree(sc);
2530 bus_dma_tag_destroy(sc->dmat);
2531 if (sc->cfg->codec->destroy != NULL) {
2532 for (i = 0; i < sc->adcn; i++)
2533 sc->cfg->codec->destroy(sc->adc[i]);
2534 for (i = 0; i < sc->dacn; i++)
2535 sc->cfg->codec->destroy(sc->dac[i]);
2537 envy24ht_cfgfree(sc->cfg);
2539 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2541 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2543 snd_mtxfree(sc->lock);
2544 kfree(sc, M_ENVY24HT);
2549 envy24ht_pci_detach(device_t dev)
2556 device_printf(dev, "envy24ht_pci_detach()\n");
2558 sc = pcm_getdevinfo(dev);
2561 r = pcm_unregister(dev);
2565 envy24ht_dmafree(sc);
2566 if (sc->cfg->codec->destroy != NULL) {
2567 for (i = 0; i < sc->adcn; i++)
2568 sc->cfg->codec->destroy(sc->adc[i]);
2569 for (i = 0; i < sc->dacn; i++)
2570 sc->cfg->codec->destroy(sc->dac[i]);
2572 envy24ht_cfgfree(sc->cfg);
2573 bus_dma_tag_destroy(sc->dmat);
2574 bus_teardown_intr(dev, sc->irq, sc->ih);
2575 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2576 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2577 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2578 snd_mtxfree(sc->lock);
2579 kfree(sc, M_ENVY24HT);
2583 static device_method_t envy24ht_methods[] = {
2584 /* Device interface */
2585 DEVMETHOD(device_probe, envy24ht_pci_probe),
2586 DEVMETHOD(device_attach, envy24ht_pci_attach),
2587 DEVMETHOD(device_detach, envy24ht_pci_detach),
2591 static driver_t envy24ht_driver = {
2594 #if __FreeBSD_version > 500000
2597 sizeof(struct snddev_info),
2601 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0);
2602 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2603 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2604 MODULE_VERSION(snd_envy24ht, 1);