2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2006 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
5 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
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 #ifdef HAVE_KERNEL_OPTION_HEADERS
46 #include <dev/sound/pcm/sound.h>
47 #include <dev/sound/pcm/ac97.h>
48 #include <dev/sound/pci/spicds.h>
49 #include <dev/sound/pci/envy24ht.h>
51 #include <dev/pci/pcireg.h>
52 #include <dev/pci/pcivar.h>
56 SND_DECLARE_FILE("$FreeBSD$");
58 static MALLOC_DEFINE(M_ENVY24HT, "envy24ht", "envy24ht audio");
60 /* -------------------------------------------------------------------- */
64 #define ENVY24HT_PLAY_CHNUM 8
65 #define ENVY24HT_REC_CHNUM 2
66 #define ENVY24HT_PLAY_BUFUNIT (4 /* byte/sample */ * 8 /* channel */)
67 #define ENVY24HT_REC_BUFUNIT (4 /* byte/sample */ * 2 /* channel */)
68 #define ENVY24HT_SAMPLE_NUM 4096
70 #define ENVY24HT_TIMEOUT 1000
72 #define ENVY24HT_DEFAULT_FORMAT SND_FORMAT(AFMT_S16_LE, 2, 0)
74 #define ENVY24HT_NAMELEN 32
76 struct envy24ht_sample {
77 volatile u_int32_t buffer;
80 typedef struct envy24ht_sample sample32_t;
82 /* channel registers */
84 struct snd_dbuf *buffer;
85 struct pcm_channel *channel;
86 struct sc_info *parent;
88 unsigned num; /* hw channel number */
90 /* channel information */
93 u_int32_t blk; /* hw block size(dword) */
95 /* format conversion structure */
97 unsigned int size; /* data buffer size(byte) */
98 int unit; /* sample size(byte) */
99 unsigned int offset; /* samples number offset */
100 void (*emldma)(struct sc_chinfo *);
106 /* codec interface entrys */
108 void *(*create)(device_t dev, void *devinfo, int dir, int num);
109 void (*destroy)(void *codec);
110 void (*init)(void *codec);
111 void (*reinit)(void *codec);
112 void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
113 void (*setrate)(void *codec, int which, int rate);
116 /* system configuration information */
119 u_int16_t subvendor, subdevice;
120 u_int8_t scfg, acl, i2s, spdif;
121 u_int32_t gpiomask, gpiostate, gpiodir;
122 u_int32_t cdti, cclk, cs;
123 u_int8_t cif, type, free;
124 struct codec_entry *codec;
127 /* device private data */
132 /* Control/Status registor */
136 bus_space_handle_t csh;
137 /* MultiTrack registor */
141 bus_space_handle_t mth;
145 struct resource *irq;
149 /* system configuration data */
150 struct cfg_info *cfg;
152 /* ADC/DAC number and info */
154 void *adc[4], *dac[4];
156 /* mixer control data */
158 u_int8_t left[ENVY24HT_CHAN_NUM];
159 u_int8_t right[ENVY24HT_CHAN_NUM];
161 /* Play/Record DMA fifo */
164 u_int32_t psize, rsize; /* DMA buffer size(byte) */
165 u_int16_t blk[2]; /* transfer check blocksize(dword) */
166 bus_dmamap_t pmap, rmap;
167 bus_addr_t paddr, raddr;
173 struct pcmchan_caps caps[2];
175 /* channel info table */
177 struct sc_chinfo chan[11];
180 /* -------------------------------------------------------------------- */
187 static void envy24ht_p8u(struct sc_chinfo *);
188 static void envy24ht_p16sl(struct sc_chinfo *);
189 static void envy24ht_p32sl(struct sc_chinfo *);
190 static void envy24ht_r16sl(struct sc_chinfo *);
191 static void envy24ht_r32sl(struct sc_chinfo *);
193 /* channel interface */
194 static void *envy24htchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
195 static int envy24htchan_setformat(kobj_t, void *, u_int32_t);
196 static u_int32_t envy24htchan_setspeed(kobj_t, void *, u_int32_t);
197 static u_int32_t envy24htchan_setblocksize(kobj_t, void *, u_int32_t);
198 static int envy24htchan_trigger(kobj_t, void *, int);
199 static u_int32_t envy24htchan_getptr(kobj_t, void *);
200 static struct pcmchan_caps *envy24htchan_getcaps(kobj_t, void *);
202 /* mixer interface */
203 static int envy24htmixer_init(struct snd_mixer *);
204 static int envy24htmixer_reinit(struct snd_mixer *);
205 static int envy24htmixer_uninit(struct snd_mixer *);
206 static int envy24htmixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
207 static u_int32_t envy24htmixer_setrecsrc(struct snd_mixer *, u_int32_t);
209 /* SPI codec access interface */
210 static void *envy24ht_spi_create(device_t, void *, int, int);
211 static void envy24ht_spi_destroy(void *);
212 static void envy24ht_spi_init(void *);
213 static void envy24ht_spi_reinit(void *);
214 static void envy24ht_spi_setvolume(void *, int, unsigned int, unsigned int);
216 /* -------------------------------------------------------------------- */
219 system constant tables
222 /* API -> hardware channel map */
223 static unsigned envy24ht_chanmap[ENVY24HT_CHAN_NUM] = {
224 ENVY24HT_CHAN_PLAY_DAC1, /* 1 */
225 ENVY24HT_CHAN_PLAY_DAC2, /* 2 */
226 ENVY24HT_CHAN_PLAY_DAC3, /* 3 */
227 ENVY24HT_CHAN_PLAY_DAC4, /* 4 */
228 ENVY24HT_CHAN_PLAY_SPDIF, /* 0 */
229 ENVY24HT_CHAN_REC_MIX, /* 5 */
230 ENVY24HT_CHAN_REC_SPDIF, /* 6 */
231 ENVY24HT_CHAN_REC_ADC1, /* 7 */
232 ENVY24HT_CHAN_REC_ADC2, /* 8 */
233 ENVY24HT_CHAN_REC_ADC3, /* 9 */
234 ENVY24HT_CHAN_REC_ADC4, /* 10 */
237 /* mixer -> API channel map. see above */
238 static int envy24ht_mixmap[] = {
239 -1, /* Master output level. It is depend on codec support */
240 -1, /* Treble level of all output channels */
241 -1, /* Bass level of all output channels */
242 -1, /* Volume of synthesier input */
243 0, /* Output level for the audio device */
244 -1, /* Output level for the PC speaker */
245 7, /* line in jack */
246 -1, /* microphone jack */
247 -1, /* CD audio input */
248 -1, /* Recording monitor */
249 1, /* alternative codec */
250 -1, /* global recording level */
252 -1, /* Output gain */
253 8, /* Input source 1 */
254 9, /* Input source 2 */
255 10, /* Input source 3 */
256 6, /* Digital (input) 1 */
257 -1, /* Digital (input) 2 */
258 -1, /* Digital (input) 3 */
259 -1, /* Phone input */
260 -1, /* Phone output */
261 -1, /* Video/TV (audio) in */
263 -1, /* Monitor volume */
266 /* variable rate audio */
267 static u_int32_t envy24ht_speed[] = {
268 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
269 12000, 11025, 9600, 8000, 0
272 /* known boards configuration */
273 static struct codec_entry spi_codec = {
275 envy24ht_spi_destroy,
278 envy24ht_spi_setvolume,
282 static struct cfg_info cfg_table[] = {
284 "Envy24HT audio (Terratec Aureon 7.1 Space)",
286 0x0b, 0x80, 0xfc, 0xc3,
287 0x21efff, 0x7fffff, 0x5e1000,
288 0x40000, 0x80000, 0x1000, 0x00, 0x02,
293 "Envy24HT audio (Terratec Aureon 5.1 Sky)",
295 0x0a, 0x80, 0xfc, 0xc3,
296 0x21efff, 0x7fffff, 0x5e1000,
297 0x40000, 0x80000, 0x1000, 0x00, 0x02,
302 "Envy24HT audio (Terratec Aureon 7.1 Universe)",
304 0x0b, 0x80, 0xfc, 0xc3,
305 0x21efff, 0x7fffff, 0x5e1000,
306 0x40000, 0x80000, 0x1000, 0x00, 0x02,
311 "Envy24HT audio (AudioTrak Prodigy 7.1)",
313 0x0b, 0x80, 0xfc, 0xc3,
314 0x21efff, 0x7fffff, 0x5e1000,
315 0x40000, 0x80000, 0x1000, 0x00, 0x02,
320 "Envy24HT audio (Terratec PHASE 28)",
322 0x0b, 0x80, 0xfc, 0xc3,
323 0x21efff, 0x7fffff, 0x5e1000,
324 0x40000, 0x80000, 0x1000, 0x00, 0x02,
329 "Envy24HT-S audio (Terratec PHASE 22)",
331 0x10, 0x80, 0xf0, 0xc3,
332 0x7ffbc7, 0x7fffff, 0x438,
333 0x10, 0x20, 0x400, 0x01, 0x00,
338 "Envy24HT audio (AudioTrak Prodigy 7.1 LT)",
340 0x4b, 0x80, 0xfc, 0xc3,
341 0x7ff8ff, 0x7fffff, 0x700,
342 0x400, 0x200, 0x100, 0x00, 0x02,
347 "Envy24HT audio (AudioTrak Prodigy 7.1 XT)",
349 0x4b, 0x80, 0xfc, 0xc3,
350 0x7ff8ff, 0x7fffff, 0x700,
351 0x400, 0x200, 0x100, 0x00, 0x02,
356 "Envy24HT audio (M-Audio Revolution 7.1)",
358 0x43, 0x80, 0xf8, 0xc1,
359 0x3fff85, 0x400072, 0x4000fa,
360 0x08, 0x02, 0x20, 0x00, 0x04,
365 "Envy24GT audio (M-Audio Revolution 5.1)",
367 0x42, 0x80, 0xf8, 0xc1,
368 0x3fff05, 0x4000f0, 0x4000fa,
369 0x08, 0x02, 0x10, 0x00, 0x03,
374 "Envy24HT audio (M-Audio Audiophile 192)",
376 0x68, 0x80, 0xf8, 0xc3,
377 0x45, 0x4000b5, 0x7fffba,
378 0x08, 0x02, 0x10, 0x00, 0x03,
383 "Envy24HT audio (AudioTrak Prodigy HD2)",
385 0x68, 0x80, 0x78, 0xc3,
386 0xfff8ff, 0x200700, 0xdfffff,
387 0x400, 0x200, 0x100, 0x00, 0x05,
392 "Envy24HT audio (ESI Juli@)",
394 0x20, 0x80, 0xf8, 0xc3,
395 0x7fff9f, 0x8016, 0x7fff9f,
396 0x08, 0x02, 0x10, 0x00, 0x03,
401 "Envy24HT-S audio (Terrasoniq TS22PCI)",
403 0x10, 0x80, 0xf0, 0xc3,
404 0x7ffbc7, 0x7fffff, 0x438,
405 0x10, 0x20, 0x400, 0x01, 0x00,
410 "Envy24HT audio (Generic)",
412 0x0b, 0x80, 0xfc, 0xc3,
413 0x21efff, 0x7fffff, 0x5e1000,
414 0x40000, 0x80000, 0x1000, 0x00, 0x02,
416 &spi_codec, /* default codec routines */
420 static u_int32_t envy24ht_recfmt[] = {
421 SND_FORMAT(AFMT_S16_LE, 2, 0),
422 SND_FORMAT(AFMT_S32_LE, 2, 0),
425 static struct pcmchan_caps envy24ht_reccaps = {8000, 96000, envy24ht_recfmt, 0};
427 static u_int32_t envy24ht_playfmt[] = {
428 SND_FORMAT(AFMT_U8, 2, 0),
429 SND_FORMAT(AFMT_S16_LE, 2, 0),
430 SND_FORMAT(AFMT_S32_LE, 2, 0),
434 static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0};
436 struct envy24ht_emldma {
438 void (*emldma)(struct sc_chinfo *);
442 static struct envy24ht_emldma envy24ht_pemltab[] = {
443 {SND_FORMAT(AFMT_U8, 2, 0), envy24ht_p8u, 2},
444 {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_p16sl, 4},
445 {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_p32sl, 8},
449 static struct envy24ht_emldma envy24ht_remltab[] = {
450 {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_r16sl, 4},
451 {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_r32sl, 8},
455 /* -------------------------------------------------------------------- */
457 /* common routines */
459 envy24ht_rdcs(struct sc_info *sc, int regno, int size)
463 return bus_space_read_1(sc->cst, sc->csh, regno);
465 return bus_space_read_2(sc->cst, sc->csh, regno);
467 return bus_space_read_4(sc->cst, sc->csh, regno);
474 envy24ht_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
478 bus_space_write_1(sc->cst, sc->csh, regno, data);
481 bus_space_write_2(sc->cst, sc->csh, regno, data);
484 bus_space_write_4(sc->cst, sc->csh, regno, data);
490 envy24ht_rdmt(struct sc_info *sc, int regno, int size)
494 return bus_space_read_1(sc->mtt, sc->mth, regno);
496 return bus_space_read_2(sc->mtt, sc->mth, regno);
498 return bus_space_read_4(sc->mtt, sc->mth, regno);
505 envy24ht_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
509 bus_space_write_1(sc->mtt, sc->mth, regno, data);
512 bus_space_write_2(sc->mtt, sc->mth, regno, data);
515 bus_space_write_4(sc->mtt, sc->mth, regno, data);
520 /* -------------------------------------------------------------------- */
522 /* I2C port/E2PROM access routines */
525 envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
531 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
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 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
543 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
544 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_RD, 1);
545 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
546 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
547 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
549 DELAY(32); /* 31.25kHz */
551 if (i == ENVY24HT_TIMEOUT) {
554 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CDATA, 1);
557 device_printf(sc->dev, "envy24ht_rdi2c(): return 0x%x\n", data);
563 envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
569 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
571 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
572 tmp = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
573 if ((tmp & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
575 DELAY(32); /* 31.25kHz */
577 if (i == ENVY24HT_TIMEOUT) {
580 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
581 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDATA, data, 1);
582 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
583 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_WR, 1);
584 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
585 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
586 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
588 DELAY(32); /* 31.25kHz */
590 if (i == ENVY24HT_TIMEOUT) {
598 envy24ht_rdrom(struct sc_info *sc, u_int32_t addr)
603 device_printf(sc->dev, "envy24ht_rdrom(sc, 0x%02x)\n", addr);
605 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
606 if ((data & ENVY24HT_CCS_I2CSTAT_ROM) == 0) {
608 device_printf(sc->dev, "envy24ht_rdrom(): E2PROM not presented\n");
613 return envy24ht_rdi2c(sc, ENVY24HT_CCS_I2CDEV_ROM, addr);
616 static struct cfg_info *
617 envy24ht_rom2cfg(struct sc_info *sc)
619 struct cfg_info *buff;
624 device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n");
626 size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE);
627 if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) {
629 device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size);
631 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
634 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
640 /* no valid e2prom, using default values */
641 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
642 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
643 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
644 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
649 buff->gpiomask = 0x21efff;
650 buff->gpiostate = 0x7fffff;
651 buff->gpiodir = 0x5e1000;
652 buff->cdti = 0x40000;
653 buff->cclk = 0x80000;
658 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0;
660 if (cfg_table[i].subvendor == buff->subvendor &&
661 cfg_table[i].subdevice == buff->subdevice)
663 buff->name = cfg_table[i].name;
664 buff->codec = cfg_table[i].codec;
671 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
674 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
680 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
681 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
682 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
683 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
684 buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG);
685 buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL);
686 buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S);
687 buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF);
688 buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \
689 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \
690 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16;
691 buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \
692 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \
693 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16;
694 buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \
695 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \
696 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16;
698 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
699 if (cfg_table[i].subvendor == buff->subvendor &&
700 cfg_table[i].subdevice == buff->subdevice)
702 buff->name = cfg_table[i].name;
703 buff->codec = cfg_table[i].codec;
709 envy24ht_cfgfree(struct cfg_info *cfg) {
713 free(cfg, M_ENVY24HT);
717 /* -------------------------------------------------------------------- */
719 /* AC'97 codec access routines */
723 envy24ht_coldcd(struct sc_info *sc)
729 device_printf(sc->dev, "envy24ht_coldcd()\n");
731 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1);
733 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
735 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
736 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
737 if (data & ENVY24HT_MT_AC97CMD_RDY) {
746 envy24ht_slavecd(struct sc_info *sc)
752 device_printf(sc->dev, "envy24ht_slavecd()\n");
754 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD,
755 ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1);
757 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
759 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
760 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
761 if (data & ENVY24HT_MT_AC97CMD_RDY) {
770 envy24ht_rdcd(kobj_t obj, void *devinfo, int regno)
772 struct sc_info *sc = (struct sc_info *)devinfo;
777 device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno);
779 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
780 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1);
781 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
782 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
783 if ((data & ENVY24HT_MT_AC97CMD_RD) == 0)
786 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2);
789 device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data);
795 envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
797 struct sc_info *sc = (struct sc_info *)devinfo;
802 device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
804 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
805 envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2);
806 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1);
807 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
808 cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
809 if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0)
816 static kobj_method_t envy24ht_ac97_methods[] = {
817 KOBJMETHOD(ac97_read, envy24ht_rdcd),
818 KOBJMETHOD(ac97_write, envy24ht_wrcd),
821 AC97_DECLARE(envy24ht_ac97);
824 /* -------------------------------------------------------------------- */
826 /* GPIO access routines */
829 envy24ht_gpiord(struct sc_info *sc)
831 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
832 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2);
834 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2));
838 envy24ht_gpiowr(struct sc_info *sc, u_int32_t data)
841 device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF);
844 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2);
845 if (sc->cfg->subdevice != 0x1150)
846 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1);
852 envy24ht_gpiogetmask(struct sc_info *sc)
854 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2));
859 envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask)
861 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2);
862 if (sc->cfg->subdevice != 0x1150)
863 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1);
869 envy24ht_gpiogetdir(struct sc_info *sc)
871 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4);
876 envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir)
878 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
879 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2);
881 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4);
885 /* -------------------------------------------------------------------- */
887 /* SPI codec access interface routine */
889 struct envy24ht_spi_codec {
890 struct spicds_info *info;
891 struct sc_info *parent;
898 envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
901 struct envy24ht_spi_codec *ptr = codec;
904 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
906 data = envy24ht_gpiord(ptr->parent);
907 data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
908 if (cs) data += ptr->cs;
909 if (cclk) data += ptr->cclk;
910 if (cdti) data += ptr->cdti;
911 envy24ht_gpiowr(ptr->parent, data);
916 envy24ht_spi_create(device_t dev, void *info, int dir, int num)
918 struct sc_info *sc = info;
919 struct envy24ht_spi_codec *buff = NULL;
922 device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num);
925 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
929 if (dir == PCMDIR_REC && sc->adc[num] != NULL)
930 buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info;
931 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
932 buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info;
934 buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl);
935 if (buff->info == NULL) {
936 free(buff, M_ENVY24HT);
948 envy24ht_spi_destroy(void *codec)
950 struct envy24ht_spi_codec *ptr = codec;
954 device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n");
957 if (ptr->dir == PCMDIR_PLAY) {
958 if (ptr->parent->dac[ptr->num] != NULL)
959 spicds_destroy(ptr->info);
962 if (ptr->parent->adc[ptr->num] != NULL)
963 spicds_destroy(ptr->info);
966 free(codec, M_ENVY24HT);
970 envy24ht_spi_init(void *codec)
972 struct envy24ht_spi_codec *ptr = codec;
976 device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n");
978 ptr->cs = ptr->parent->cfg->cs;
979 ptr->cclk = ptr->parent->cfg->cclk;
980 ptr->cdti = ptr->parent->cfg->cdti;
981 spicds_settype(ptr->info, ptr->parent->cfg->type);
982 spicds_setcif(ptr->info, ptr->parent->cfg->cif);
983 if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \
984 ptr->parent->cfg->type == SPICDS_TYPE_AK4528) {
985 spicds_setformat(ptr->info,
986 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
987 spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
990 /* for the time being, init only first codec */
992 spicds_init(ptr->info);
996 envy24ht_spi_reinit(void *codec)
998 struct envy24ht_spi_codec *ptr = codec;
1002 device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n");
1005 spicds_reinit(ptr->info);
1009 envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
1011 struct envy24ht_spi_codec *ptr = codec;
1015 device_printf(ptr->parent->dev, "envy24ht_spi_set()\n");
1018 spicds_set(ptr->info, dir, left, right);
1021 /* -------------------------------------------------------------------- */
1023 /* hardware access routeines */
1028 } envy24ht_speedtab[] = {
1029 {48000, ENVY24HT_MT_RATE_48000},
1030 {24000, ENVY24HT_MT_RATE_24000},
1031 {12000, ENVY24HT_MT_RATE_12000},
1032 {9600, ENVY24HT_MT_RATE_9600},
1033 {32000, ENVY24HT_MT_RATE_32000},
1034 {16000, ENVY24HT_MT_RATE_16000},
1035 {8000, ENVY24HT_MT_RATE_8000},
1036 {96000, ENVY24HT_MT_RATE_96000},
1037 {192000, ENVY24HT_MT_RATE_192000},
1038 {64000, ENVY24HT_MT_RATE_64000},
1039 {44100, ENVY24HT_MT_RATE_44100},
1040 {22050, ENVY24HT_MT_RATE_22050},
1041 {11025, ENVY24HT_MT_RATE_11025},
1042 {88200, ENVY24HT_MT_RATE_88200},
1043 {176400, ENVY24HT_MT_RATE_176400},
1048 envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) {
1049 u_int32_t code, i2sfmt;
1053 device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed);
1055 code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */
1056 envy24ht_slavecd(sc);
1060 for (i = 0; envy24ht_speedtab[i].speed != 0; i++) {
1061 if (envy24ht_speedtab[i].speed == speed)
1064 code = envy24ht_speedtab[i].code;
1067 device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code);
1070 envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1);
1071 if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \
1072 (code == ENVY24HT_MT_RATE_176400)) {
1073 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1074 i2sfmt |= ENVY24HT_MT_I2S_MLR128;
1075 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1078 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1079 i2sfmt &= ~ENVY24HT_MT_I2S_MLR128;
1080 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1082 code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1);
1083 code &= ENVY24HT_MT_RATE_MASK;
1084 for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) {
1085 if (envy24ht_speedtab[i].code == code)
1088 speed = envy24ht_speedtab[i].speed;
1094 device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed);
1100 envy24ht_setvolume(struct sc_info *sc, unsigned ch)
1103 device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch);
1104 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1105 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1106 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1107 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1112 envy24ht_mutevolume(struct sc_info *sc, unsigned ch)
1117 device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch);
1118 vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE;
1119 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1120 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1121 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1122 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1127 envy24ht_gethwptr(struct sc_info *sc, int dir)
1133 device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir);
1135 if (dir == PCMDIR_PLAY) {
1136 rtn = sc->psize / 4;
1137 unit = ENVY24HT_PLAY_BUFUNIT / 4;
1138 regno = ENVY24HT_MT_PCNT;
1141 rtn = sc->rsize / 4;
1142 unit = ENVY24HT_REC_BUFUNIT / 4;
1143 regno = ENVY24HT_MT_RCNT;
1146 ptr = envy24ht_rdmt(sc, regno, 2);
1151 device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn);
1157 envy24ht_updintr(struct sc_info *sc, int dir)
1159 int regptr, regintr;
1160 u_int32_t mask, intr;
1161 u_int32_t ptr, size, cnt;
1165 device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir);
1167 if (dir == PCMDIR_PLAY) {
1169 size = sc->psize / 4;
1170 regptr = ENVY24HT_MT_PCNT;
1171 regintr = ENVY24HT_MT_PTERM;
1172 mask = ~ENVY24HT_MT_INT_PMASK;
1176 size = sc->rsize / 4;
1177 regptr = ENVY24HT_MT_RCNT;
1178 regintr = ENVY24HT_MT_RTERM;
1179 mask = ~ENVY24HT_MT_INT_RMASK;
1182 ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1;
1184 cnt = blk - ptr % blk - 1;
1190 device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1192 envy24ht_wrmt(sc, regintr, cnt, 2);
1193 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1195 device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1197 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
1199 device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
1200 envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
1208 envy24ht_maskintr(struct sc_info *sc, int dir)
1210 u_int32_t mask, intr;
1213 device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
1215 if (dir == PCMDIR_PLAY)
1216 mask = ENVY24HT_MT_INT_PMASK;
1218 mask = ENVY24HT_MT_INT_RMASK;
1219 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
1220 envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
1227 envy24ht_checkintr(struct sc_info *sc, int dir)
1229 u_int32_t mask, stat, intr, rtn;
1232 device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
1234 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
1235 if (dir == PCMDIR_PLAY) {
1236 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
1237 mask = ~ENVY24HT_MT_INT_RSTAT;
1238 envy24ht_wrmt(sc, 0x1a, 0x01, 1);
1239 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);
1240 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1241 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
1245 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
1246 mask = ~ENVY24HT_MT_INT_PSTAT;
1248 stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
1250 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
1251 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1252 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
1260 envy24ht_start(struct sc_info *sc, int dir)
1265 device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
1267 if (dir == PCMDIR_PLAY)
1268 sw = ENVY24HT_MT_PCTL_PSTART;
1270 sw = ENVY24HT_MT_PCTL_RSTART;
1272 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1273 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
1276 device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
1277 device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
1284 envy24ht_stop(struct sc_info *sc, int dir)
1289 device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir);
1291 if (dir == PCMDIR_PLAY)
1292 sw = ~ENVY24HT_MT_PCTL_PSTART;
1294 sw = ~ENVY24HT_MT_PCTL_RSTART;
1296 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1297 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1);
1304 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1310 /* -------------------------------------------------------------------- */
1312 /* buffer copy routines */
1314 envy24ht_p32sl(struct sc_chinfo *ch)
1319 int src, dst, ssize, dsize, slot;
1322 length = sndbuf_getready(ch->buffer) / 8;
1323 dmabuf = ch->parent->pbuf;
1324 data = (u_int32_t *)ch->data;
1325 src = sndbuf_getreadyptr(ch->buffer) / 4;
1326 dst = src / 2 + ch->offset;
1327 ssize = ch->size / 4;
1328 dsize = ch->size / 8;
1331 for (i = 0; i < length; i++) {
1332 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
1333 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1344 envy24ht_p16sl(struct sc_chinfo *ch)
1349 int src, dst, ssize, dsize, slot;
1353 device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
1355 length = sndbuf_getready(ch->buffer) / 4;
1356 dmabuf = ch->parent->pbuf;
1357 data = (u_int16_t *)ch->data;
1358 src = sndbuf_getreadyptr(ch->buffer) / 2;
1359 dst = src / 2 + ch->offset;
1360 ssize = ch->size / 2;
1361 dsize = ch->size / 4;
1364 device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1367 for (i = 0; i < length; i++) {
1368 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1369 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1372 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
1373 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
1389 envy24ht_p8u(struct sc_chinfo *ch)
1394 int src, dst, ssize, dsize, slot;
1397 length = sndbuf_getready(ch->buffer) / 2;
1398 dmabuf = ch->parent->pbuf;
1399 data = (u_int8_t *)ch->data;
1400 src = sndbuf_getreadyptr(ch->buffer);
1401 dst = src / 2 + ch->offset;
1403 dsize = ch->size / 4;
1406 for (i = 0; i < length; i++) {
1407 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1408 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1419 envy24ht_r32sl(struct sc_chinfo *ch)
1424 int src, dst, ssize, dsize, slot;
1427 length = sndbuf_getfree(ch->buffer) / 8;
1428 dmabuf = ch->parent->rbuf;
1429 data = (u_int32_t *)ch->data;
1430 dst = sndbuf_getfreeptr(ch->buffer) / 4;
1431 src = dst / 2 + ch->offset;
1432 dsize = ch->size / 4;
1433 ssize = ch->size / 8;
1434 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1436 for (i = 0; i < length; i++) {
1437 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1438 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1449 envy24ht_r16sl(struct sc_chinfo *ch)
1454 int src, dst, ssize, dsize, slot;
1457 length = sndbuf_getfree(ch->buffer) / 4;
1458 dmabuf = ch->parent->rbuf;
1459 data = (u_int16_t *)ch->data;
1460 dst = sndbuf_getfreeptr(ch->buffer) / 2;
1461 src = dst / 2 + ch->offset;
1462 dsize = ch->size / 2;
1463 ssize = ch->size / 8;
1464 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1466 for (i = 0; i < length; i++) {
1467 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1468 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1478 /* -------------------------------------------------------------------- */
1480 /* channel interface */
1482 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1484 struct sc_info *sc = (struct sc_info *)devinfo;
1485 struct sc_chinfo *ch;
1489 device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
1491 snd_mtxlock(sc->lock);
1493 if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1494 (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1495 snd_mtxunlock(sc->lock);
1501 ch = &sc->chan[num];
1502 ch->size = 8 * ENVY24HT_SAMPLE_NUM;
1503 ch->data = malloc(ch->size, M_ENVY24HT, M_NOWAIT);
1504 if (ch->data == NULL) {
1513 /* set channel map */
1514 ch->num = envy24ht_chanmap[num];
1515 snd_mtxunlock(sc->lock);
1516 sndbuf_setup(ch->buffer, ch->data, ch->size);
1517 snd_mtxlock(sc->lock);
1518 /* these 2 values are dummy */
1522 snd_mtxunlock(sc->lock);
1528 envy24htchan_free(kobj_t obj, void *data)
1530 struct sc_chinfo *ch = data;
1531 struct sc_info *sc = ch->parent;
1534 device_printf(sc->dev, "envy24htchan_free()\n");
1536 snd_mtxlock(sc->lock);
1537 if (ch->data != NULL) {
1538 free(ch->data, M_ENVY24HT);
1541 snd_mtxunlock(sc->lock);
1547 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
1549 struct sc_chinfo *ch = data;
1550 struct sc_info *sc = ch->parent;
1551 struct envy24ht_emldma *emltab;
1552 /* unsigned int bcnt, bsize; */
1556 device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
1558 snd_mtxlock(sc->lock);
1559 /* check and get format related information */
1560 if (ch->dir == PCMDIR_PLAY)
1561 emltab = envy24ht_pemltab;
1563 emltab = envy24ht_remltab;
1564 if (emltab == NULL) {
1565 snd_mtxunlock(sc->lock);
1568 for (i = 0; emltab[i].format != 0; i++)
1569 if (emltab[i].format == format)
1571 if (emltab[i].format == 0) {
1572 snd_mtxunlock(sc->lock);
1576 /* set format information */
1577 ch->format = format;
1578 ch->emldma = emltab[i].emldma;
1579 if (ch->unit > emltab[i].unit)
1580 ch->blk *= ch->unit / emltab[i].unit;
1582 ch->blk /= emltab[i].unit / ch->unit;
1583 ch->unit = emltab[i].unit;
1585 /* set channel buffer information */
1586 ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
1588 if (ch->dir == PCMDIR_PLAY)
1589 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1591 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1593 bcnt = ch->size / bsize;
1594 sndbuf_resize(ch->buffer, bcnt, bsize);
1596 snd_mtxunlock(sc->lock);
1599 device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
1605 IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1606 of speed information value. And real hardware speed setting is done
1607 at start triggered(see envy24htchan_trigger()). So, at this function
1608 is called, any value that ENVY24 can use is able to set. But, at
1609 start triggerd, some other channel is running, and that channel's
1610 speed isn't same with, then trigger function will fail.
1613 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1615 struct sc_chinfo *ch = data;
1616 u_int32_t val, prev;
1620 device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
1623 for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
1624 if (abs(val - speed) < abs(prev - speed))
1632 device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
1638 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1640 struct sc_chinfo *ch = data;
1641 /* struct sc_info *sc = ch->parent; */
1642 u_int32_t size, prev;
1643 unsigned int bcnt, bsize;
1646 device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
1649 /* snd_mtxlock(sc->lock); */
1650 for (size = ch->size / 2; size > 0; size /= 2) {
1651 if (abs(size - blocksize) < abs(prev - blocksize))
1657 ch->blk = prev / ch->unit;
1658 if (ch->dir == PCMDIR_PLAY)
1659 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
1661 ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
1662 /* set channel buffer information */
1663 /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
1664 if (ch->dir == PCMDIR_PLAY)
1665 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1667 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1669 bcnt = ch->size / bsize;
1670 sndbuf_resize(ch->buffer, bcnt, bsize);
1671 /* snd_mtxunlock(sc->lock); */
1674 device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
1679 /* semantic note: must start at beginning of buffer */
1681 envy24htchan_trigger(kobj_t obj, void *data, int go)
1683 struct sc_chinfo *ch = data;
1684 struct sc_info *sc = ch->parent;
1691 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1693 snd_mtxlock(sc->lock);
1694 if (ch->dir == PCMDIR_PLAY)
1701 device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1703 /* check or set channel speed */
1704 if (sc->run[0] == 0 && sc->run[1] == 0) {
1705 sc->speed = envy24ht_setspeed(sc, ch->speed);
1706 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1707 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1709 else if (ch->speed != 0 && ch->speed != sc->speed) {
1714 ch->channel->speed = sc->speed;
1715 /* start or enable channel */
1717 if (sc->run[slot] == 1) {
1720 sc->blk[slot] = ch->blk;
1723 ptr = envy24ht_gethwptr(sc, ch->dir);
1724 ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1725 (ch->size / 4)) * 4 / ch->unit;
1726 if (ch->blk < sc->blk[slot])
1727 sc->blk[slot] = ch->blk;
1729 if (ch->dir == PCMDIR_PLAY) {
1731 envy24ht_setvolume(sc, ch->num);
1733 envy24ht_updintr(sc, ch->dir);
1734 if (sc->run[slot] == 1)
1735 envy24ht_start(sc, ch->dir);
1738 case PCMTRIG_EMLDMAWR:
1740 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1748 case PCMTRIG_EMLDMARD:
1750 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1761 device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1765 if (ch->dir == PCMDIR_PLAY)
1766 envy24ht_mutevolume(sc, ch->num);
1767 if (sc->run[slot] == 0) {
1768 envy24ht_stop(sc, ch->dir);
1771 /* else if (ch->blk == sc->blk[slot]) {
1772 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1773 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1774 if (sc->chan[i].dir == ch->dir &&
1775 sc->chan[i].run == 1 &&
1776 sc->chan[i].blk < sc->blk[slot])
1777 sc->blk[slot] = sc->chan[i].blk;
1779 if (ch->blk != sc->blk[slot])
1780 envy24ht_updintr(sc, ch->dir);
1786 snd_mtxunlock(sc->lock);
1791 envy24htchan_getptr(kobj_t obj, void *data)
1793 struct sc_chinfo *ch = data;
1794 struct sc_info *sc = ch->parent;
1798 device_printf(sc->dev, "envy24htchan_getptr()\n");
1800 snd_mtxlock(sc->lock);
1801 ptr = envy24ht_gethwptr(sc, ch->dir);
1802 rtn = ptr * ch->unit;
1803 snd_mtxunlock(sc->lock);
1806 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1812 static struct pcmchan_caps *
1813 envy24htchan_getcaps(kobj_t obj, void *data)
1815 struct sc_chinfo *ch = data;
1816 struct sc_info *sc = ch->parent;
1817 struct pcmchan_caps *rtn;
1820 device_printf(sc->dev, "envy24htchan_getcaps()\n");
1822 snd_mtxlock(sc->lock);
1823 if (ch->dir == PCMDIR_PLAY) {
1824 if (sc->run[0] == 0)
1825 rtn = &envy24ht_playcaps;
1830 if (sc->run[1] == 0)
1831 rtn = &envy24ht_reccaps;
1835 snd_mtxunlock(sc->lock);
1840 static kobj_method_t envy24htchan_methods[] = {
1841 KOBJMETHOD(channel_init, envy24htchan_init),
1842 KOBJMETHOD(channel_free, envy24htchan_free),
1843 KOBJMETHOD(channel_setformat, envy24htchan_setformat),
1844 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed),
1845 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize),
1846 KOBJMETHOD(channel_trigger, envy24htchan_trigger),
1847 KOBJMETHOD(channel_getptr, envy24htchan_getptr),
1848 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps),
1851 CHANNEL_DECLARE(envy24htchan);
1853 /* -------------------------------------------------------------------- */
1855 /* mixer interface */
1858 envy24htmixer_init(struct snd_mixer *m)
1860 struct sc_info *sc = mix_getdevinfo(m);
1863 device_printf(sc->dev, "envy24htmixer_init()\n");
1868 /* set volume control rate */
1869 snd_mtxlock(sc->lock);
1871 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1874 pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1876 mix_setdevs(m, ENVY24HT_MIX_MASK);
1877 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1879 snd_mtxunlock(sc->lock);
1885 envy24htmixer_reinit(struct snd_mixer *m)
1887 struct sc_info *sc = mix_getdevinfo(m);
1892 device_printf(sc->dev, "envy24htmixer_reinit()\n");
1899 envy24htmixer_uninit(struct snd_mixer *m)
1901 struct sc_info *sc = mix_getdevinfo(m);
1906 device_printf(sc->dev, "envy24htmixer_uninit()\n");
1913 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1915 struct sc_info *sc = mix_getdevinfo(m);
1916 int ch = envy24ht_mixmap[dev];
1922 if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1924 if (dev != 0 && ch == -1)
1926 hwch = envy24ht_chanmap[ch];
1928 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1932 snd_mtxlock(sc->lock);
1934 for (i = 0; i < sc->dacn; i++) {
1935 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1939 /* set volume value for hardware */
1940 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1941 sc->left[hwch] = ENVY24HT_VOL_MUTE;
1942 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1943 sc->right[hwch] = ENVY24HT_VOL_MUTE;
1945 /* set volume for record channel and running play channel */
1946 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1947 envy24ht_setvolume(sc, hwch);
1949 snd_mtxunlock(sc->lock);
1951 return right << 8 | left;
1955 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1957 struct sc_info *sc = mix_getdevinfo(m);
1958 int ch = envy24ht_mixmap[src];
1960 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1963 if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1968 static kobj_method_t envy24htmixer_methods[] = {
1969 KOBJMETHOD(mixer_init, envy24htmixer_init),
1970 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit),
1971 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit),
1972 KOBJMETHOD(mixer_set, envy24htmixer_set),
1973 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc),
1976 MIXER_DECLARE(envy24htmixer);
1978 /* -------------------------------------------------------------------- */
1980 /* The interrupt handler */
1982 envy24ht_intr(void *p)
1984 struct sc_info *sc = (struct sc_info *)p;
1985 struct sc_chinfo *ch;
1986 u_int32_t ptr, dsize, feed;
1990 device_printf(sc->dev, "envy24ht_intr()\n");
1992 snd_mtxlock(sc->lock);
1993 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1995 device_printf(sc->dev, "envy24ht_intr(): play\n");
1997 dsize = sc->psize / 4;
1998 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
2000 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
2002 ptr -= ptr % sc->blk[0];
2003 feed = (ptr + dsize - sc->intr[0]) % dsize;
2005 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2007 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
2011 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
2013 if (ch->run && ch->blk <= feed) {
2014 snd_mtxunlock(sc->lock);
2015 chn_intr(ch->channel);
2016 snd_mtxlock(sc->lock);
2020 envy24ht_updintr(sc, PCMDIR_PLAY);
2022 if (envy24ht_checkintr(sc, PCMDIR_REC)) {
2024 device_printf(sc->dev, "envy24ht_intr(): rec\n");
2026 dsize = sc->rsize / 4;
2027 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
2028 ptr -= ptr % sc->blk[1];
2029 feed = (ptr + dsize - sc->intr[1]) % dsize;
2030 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
2032 if (ch->run && ch->blk <= feed) {
2033 snd_mtxunlock(sc->lock);
2034 chn_intr(ch->channel);
2035 snd_mtxlock(sc->lock);
2039 envy24ht_updintr(sc, PCMDIR_REC);
2041 snd_mtxunlock(sc->lock);
2047 * Probe and attach the card
2051 envy24ht_pci_probe(device_t dev)
2057 printf("envy24ht_pci_probe()\n");
2059 if (pci_get_device(dev) == PCID_ENVY24HT &&
2060 pci_get_vendor(dev) == PCIV_ENVY24) {
2061 sv = pci_get_subvendor(dev);
2062 sd = pci_get_subdevice(dev);
2063 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2064 if (cfg_table[i].subvendor == sv &&
2065 cfg_table[i].subdevice == sd) {
2069 device_set_desc(dev, cfg_table[i].name);
2071 printf("envy24ht_pci_probe(): return 0\n");
2077 printf("envy24ht_pci_probe(): return ENXIO\n");
2084 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2086 struct sc_info *sc = arg;
2088 sc->paddr = segs->ds_addr;
2090 device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2092 printf("envy24ht(play): setmap %lx, %lx; ",
2093 (unsigned long)segs->ds_addr,
2094 (unsigned long)segs->ds_len);
2097 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, (uint32_t)segs->ds_addr, 4);
2098 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2102 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2104 struct sc_info *sc = arg;
2106 sc->raddr = segs->ds_addr;
2108 device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2110 printf("envy24ht(record): setmap %lx, %lx; ",
2111 (unsigned long)segs->ds_addr,
2112 (unsigned long)segs->ds_len);
2115 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, (uint32_t)segs->ds_addr, 4);
2116 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2120 envy24ht_dmafree(struct sc_info *sc)
2123 device_printf(sc->dev, "envy24ht_dmafree():");
2124 printf(" sc->raddr(0x%08x)", (u_int32_t)sc->raddr);
2125 printf(" sc->paddr(0x%08x)", (u_int32_t)sc->paddr);
2126 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2127 else printf(" sc->rbuf(null)");
2128 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2129 else printf(" sc->pbuf(null)\n");
2133 bus_dmamap_unload(sc->dmat, sc->rmap);
2135 bus_dmamap_unload(sc->dmat, sc->pmap);
2137 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2139 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2141 bus_dmamap_unload(sc->dmat, sc->rmap);
2142 bus_dmamap_unload(sc->dmat, sc->pmap);
2143 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2144 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2147 sc->raddr = sc->paddr = 0;
2155 envy24ht_dmainit(struct sc_info *sc)
2159 device_printf(sc->dev, "envy24ht_dmainit()\n");
2162 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2163 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2166 sc->paddr = sc->raddr = 0;
2167 sc->blk[0] = sc->blk[1] = 0;
2169 /* allocate DMA buffer */
2171 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2173 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2176 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2178 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2181 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2183 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, BUS_DMA_NOWAIT))
2186 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2188 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, BUS_DMA_NOWAIT))
2190 bzero(sc->pbuf, sc->psize);
2191 bzero(sc->rbuf, sc->rsize);
2195 envy24ht_dmafree(sc);
2200 envy24ht_putcfg(struct sc_info *sc)
2202 device_printf(sc->dev, "system configuration\n");
2203 printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2204 sc->cfg->subvendor, sc->cfg->subdevice);
2205 printf(" XIN2 Clock Source: ");
2206 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2208 printf("24.576MHz(96kHz*256)\n");
2211 printf("49.152MHz(192kHz*256)\n");
2214 printf("reserved\n");
2217 printf("illegal system setting\n");
2219 printf(" MPU-401 UART(s) #: ");
2220 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2223 printf("not implemented\n");
2228 printf("%d\n", sc->adcn);
2233 printf(" and SPDIF receiver connected\n");
2236 printf(" no physical inputs\n");
2239 printf("%d\n", sc->dacn);
2240 printf(" Multi-track converter type: ");
2241 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2242 printf("AC'97(SDATA_OUT:");
2243 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2251 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2252 printf("with volume, ");
2253 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2254 printf("192KHz support, ");
2256 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2257 printf("192KHz support, ");
2259 printf("48KHz support, ");
2260 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2261 case ENVY24HT_CCSM_I2S_16BIT:
2262 printf("16bit resolution, ");
2264 case ENVY24HT_CCSM_I2S_18BIT:
2265 printf("18bit resolution, ");
2267 case ENVY24HT_CCSM_I2S_20BIT:
2268 printf("20bit resolution, ");
2270 case ENVY24HT_CCSM_I2S_24BIT:
2271 printf("24bit resolution, ");
2274 printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2276 printf(" S/PDIF(IN/OUT): ");
2277 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2281 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2285 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2286 printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2287 printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2288 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2292 envy24ht_init(struct sc_info *sc)
2302 device_printf(sc->dev, "envy24ht_init()\n");
2307 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2309 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2312 /* legacy hardware disable */
2313 data = pci_read_config(sc->dev, PCIR_LAC, 2);
2314 data |= PCIM_LAC_DISABLE;
2315 pci_write_config(sc->dev, PCIR_LAC, data, 2);
2318 /* check system configuration */
2320 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2321 /* 1st: search configuration from table */
2322 sv = pci_get_subvendor(sc->dev);
2323 sd = pci_get_subdevice(sc->dev);
2324 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2326 device_printf(sc->dev, "Set configuration from table\n");
2328 sc->cfg = &cfg_table[i];
2332 if (sc->cfg == NULL) {
2333 /* 2nd: read configuration from table */
2334 sc->cfg = envy24ht_rom2cfg(sc);
2336 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2337 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2339 if (1 /* bootverbose */) {
2340 envy24ht_putcfg(sc);
2343 /* set system configuration */
2344 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2345 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2346 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2347 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2348 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2349 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2350 envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2352 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2353 envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2354 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2355 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2358 for (i = 0; i < sc->adcn; i++) {
2359 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2360 sc->cfg->codec->init(sc->adc[i]);
2362 for (i = 0; i < sc->dacn; i++) {
2363 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2364 sc->cfg->codec->init(sc->dac[i]);
2367 /* initialize DMA buffer */
2369 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2371 if (envy24ht_dmainit(sc))
2374 /* initialize status */
2375 sc->run[0] = sc->run[1] = 0;
2376 sc->intr[0] = sc->intr[1] = 0;
2378 sc->caps[0].fmtlist = envy24ht_playfmt;
2379 sc->caps[1].fmtlist = envy24ht_recfmt;
2381 /* set channel router */
2383 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2384 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2385 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2388 /* set macro interrupt mask */
2389 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2390 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2391 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2393 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2400 envy24ht_alloc_resource(struct sc_info *sc)
2402 /* allocate I/O port resource */
2403 sc->csid = PCIR_CCS;
2404 sc->cs = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
2405 &sc->csid, RF_ACTIVE);
2406 sc->mtid = ENVY24HT_PCIR_MT;
2407 sc->mt = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
2408 &sc->mtid, RF_ACTIVE);
2409 if (!sc->cs || !sc->mt) {
2410 device_printf(sc->dev, "unable to map IO port space\n");
2413 sc->cst = rman_get_bustag(sc->cs);
2414 sc->csh = rman_get_bushandle(sc->cs);
2415 sc->mtt = rman_get_bustag(sc->mt);
2416 sc->mth = rman_get_bushandle(sc->mt);
2418 device_printf(sc->dev,
2419 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2420 pci_read_config(sc->dev, PCIR_CCS, 4),
2421 pci_read_config(sc->dev, PCIR_MT, 4));
2424 /* allocate interrupt resource */
2426 sc->irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irqid,
2427 RF_ACTIVE | RF_SHAREABLE);
2429 snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24ht_intr, sc, &sc->ih)) {
2430 device_printf(sc->dev, "unable to map interrupt\n");
2434 /* allocate DMA resource */
2435 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2438 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
2439 /*highaddr*/BUS_SPACE_MAXADDR,
2440 /*filter*/NULL, /*filterarg*/NULL,
2441 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2442 /*nsegments*/1, /*maxsegsz*/0x3ffff,
2443 /*flags*/0, /*lockfunc*/NULL,
2444 /*lockarg*/NULL, &sc->dmat) != 0) {
2445 device_printf(sc->dev, "unable to create dma tag\n");
2453 envy24ht_pci_attach(device_t dev)
2456 char status[SND_STATUSLEN];
2461 device_printf(dev, "envy24ht_pci_attach()\n");
2463 /* get sc_info data area */
2464 if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) {
2465 device_printf(dev, "cannot allocate softc\n");
2469 bzero(sc, sizeof(*sc));
2470 sc->lock = snd_mtxcreate(device_get_nameunit(dev),
2471 "snd_envy24ht softc");
2474 /* initialize PCI interface */
2475 pci_enable_busmaster(dev);
2477 /* allocate resources */
2478 err = envy24ht_alloc_resource(sc);
2480 device_printf(dev, "unable to allocate system resources\n");
2484 /* initialize card */
2485 err = envy24ht_init(sc);
2487 device_printf(dev, "unable to initialize the card\n");
2491 /* set multi track mixer */
2492 mixer_init(dev, &envy24htmixer_class, sc);
2494 /* set channel information */
2495 /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
2496 err = pcm_register(dev, sc, 1, 2 + sc->adcn);
2500 /* for (i = 0; i < 5; i++) { */
2501 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
2504 for (i = 0; i < 2 + sc->adcn; i++) {
2505 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
2509 /* set status iformation */
2510 snprintf(status, SND_STATUSLEN,
2511 "at io 0x%jx:%jd,0x%jx:%jd irq %jd",
2512 rman_get_start(sc->cs),
2513 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2514 rman_get_start(sc->mt),
2515 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2516 rman_get_start(sc->irq));
2517 pcm_setstatus(dev, status);
2523 bus_teardown_intr(dev, sc->irq, sc->ih);
2525 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2526 envy24ht_dmafree(sc);
2528 bus_dma_tag_destroy(sc->dmat);
2529 if (sc->cfg->codec->destroy != NULL) {
2530 for (i = 0; i < sc->adcn; i++)
2531 sc->cfg->codec->destroy(sc->adc[i]);
2532 for (i = 0; i < sc->dacn; i++)
2533 sc->cfg->codec->destroy(sc->dac[i]);
2535 envy24ht_cfgfree(sc->cfg);
2537 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2539 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2541 snd_mtxfree(sc->lock);
2542 free(sc, M_ENVY24HT);
2547 envy24ht_pci_detach(device_t dev)
2554 device_printf(dev, "envy24ht_pci_detach()\n");
2556 sc = pcm_getdevinfo(dev);
2559 r = pcm_unregister(dev);
2563 envy24ht_dmafree(sc);
2564 if (sc->cfg->codec->destroy != NULL) {
2565 for (i = 0; i < sc->adcn; i++)
2566 sc->cfg->codec->destroy(sc->adc[i]);
2567 for (i = 0; i < sc->dacn; i++)
2568 sc->cfg->codec->destroy(sc->dac[i]);
2570 envy24ht_cfgfree(sc->cfg);
2571 bus_dma_tag_destroy(sc->dmat);
2572 bus_teardown_intr(dev, sc->irq, sc->ih);
2573 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2574 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2575 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2576 snd_mtxfree(sc->lock);
2577 free(sc, M_ENVY24HT);
2581 static device_method_t envy24ht_methods[] = {
2582 /* Device interface */
2583 DEVMETHOD(device_probe, envy24ht_pci_probe),
2584 DEVMETHOD(device_attach, envy24ht_pci_attach),
2585 DEVMETHOD(device_detach, envy24ht_pci_detach),
2589 static driver_t envy24ht_driver = {
2595 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0);
2596 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2597 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2598 MODULE_VERSION(snd_envy24ht, 1);