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
30 * Konstantin Dimitrov's thanks list:
32 * A huge thanks goes to Spas Filipov for his friendship, support and his
33 * generous gift - an 'Audiotrak Prodigy HD2' audio card! I also want to
34 * thank Keiichi Iwasaki and his parents, because they helped Spas to get
35 * the card from Japan! Having hardware sample of Prodigy HD2 made adding
36 * support for that great card very easy and real fun and pleasure.
40 #include <dev/sound/pcm/sound.h>
41 #include <dev/sound/pcm/ac97.h>
42 #include <dev/sound/pci/spicds.h>
43 #include <dev/sound/pci/envy24ht.h>
45 #include <dev/pci/pcireg.h>
46 #include <dev/pci/pcivar.h>
50 SND_DECLARE_FILE("$FreeBSD$");
52 MALLOC_DEFINE(M_ENVY24HT, "envy24ht", "envy24ht audio");
54 /* -------------------------------------------------------------------- */
58 #define ENVY24HT_PLAY_CHNUM 8
59 #define ENVY24HT_REC_CHNUM 2
60 #define ENVY24HT_PLAY_BUFUNIT (4 /* byte/sample */ * 8 /* channel */)
61 #define ENVY24HT_REC_BUFUNIT (4 /* byte/sample */ * 2 /* channel */)
62 #define ENVY24HT_SAMPLE_NUM 4096
64 #define ENVY24HT_TIMEOUT 1000
66 #define ENVY24HT_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE)
68 #define ENVY24HT_NAMELEN 32
70 struct envy24ht_sample {
71 volatile u_int32_t buffer;
74 typedef struct envy24ht_sample sample32_t;
76 /* channel registers */
78 struct snd_dbuf *buffer;
79 struct pcm_channel *channel;
80 struct sc_info *parent;
82 unsigned num; /* hw channel number */
84 /* channel information */
87 u_int32_t blk; /* hw block size(dword) */
89 /* format conversion structure */
91 unsigned int size; /* data buffer size(byte) */
92 int unit; /* sample size(byte) */
93 unsigned int offset; /* samples number offset */
94 void (*emldma)(struct sc_chinfo *);
100 /* codec interface entrys */
102 void *(*create)(device_t dev, void *devinfo, int dir, int num);
103 void (*destroy)(void *codec);
104 void (*init)(void *codec);
105 void (*reinit)(void *codec);
106 void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
107 void (*setrate)(void *codec, int which, int rate);
110 /* system configuration information */
113 u_int16_t subvendor, subdevice;
114 u_int8_t scfg, acl, i2s, spdif;
115 u_int32_t gpiomask, gpiostate, gpiodir;
116 u_int32_t cdti, cclk, cs;
117 u_int8_t cif, type, free;
118 struct codec_entry *codec;
121 /* device private data */
126 /* Control/Status registor */
130 bus_space_handle_t csh;
131 /* MultiTrack registor */
135 bus_space_handle_t mth;
139 struct resource *irq;
143 /* system configuration data */
144 struct cfg_info *cfg;
146 /* ADC/DAC number and info */
148 void *adc[4], *dac[4];
150 /* mixer control data */
152 u_int8_t left[ENVY24HT_CHAN_NUM];
153 u_int8_t right[ENVY24HT_CHAN_NUM];
155 /* Play/Record DMA fifo */
158 u_int32_t psize, rsize; /* DMA buffer size(byte) */
159 u_int16_t blk[2]; /* transfer check blocksize(dword) */
160 bus_dmamap_t pmap, rmap;
166 struct pcmchan_caps caps[2];
168 /* channel info table */
170 struct sc_chinfo chan[11];
173 /* -------------------------------------------------------------------- */
180 static void envy24ht_p8u(struct sc_chinfo *);
181 static void envy24ht_p16sl(struct sc_chinfo *);
182 static void envy24ht_p32sl(struct sc_chinfo *);
183 static void envy24ht_r16sl(struct sc_chinfo *);
184 static void envy24ht_r32sl(struct sc_chinfo *);
186 /* channel interface */
187 static void *envy24htchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
188 static int envy24htchan_setformat(kobj_t, void *, u_int32_t);
189 static int envy24htchan_setspeed(kobj_t, void *, u_int32_t);
190 static int envy24htchan_setblocksize(kobj_t, void *, u_int32_t);
191 static int envy24htchan_trigger(kobj_t, void *, int);
192 static int envy24htchan_getptr(kobj_t, void *);
193 static struct pcmchan_caps *envy24htchan_getcaps(kobj_t, void *);
195 /* mixer interface */
196 static int envy24htmixer_init(struct snd_mixer *);
197 static int envy24htmixer_reinit(struct snd_mixer *);
198 static int envy24htmixer_uninit(struct snd_mixer *);
199 static int envy24htmixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
200 static u_int32_t envy24htmixer_setrecsrc(struct snd_mixer *, u_int32_t);
202 /* SPI codec access interface */
203 static void *envy24ht_spi_create(device_t, void *, int, int);
204 static void envy24ht_spi_destroy(void *);
205 static void envy24ht_spi_init(void *);
206 static void envy24ht_spi_reinit(void *);
207 static void envy24ht_spi_setvolume(void *, int, unsigned int, unsigned int);
209 /* -------------------------------------------------------------------- */
212 system constant tables
215 /* API -> hardware channel map */
216 static unsigned envy24ht_chanmap[ENVY24HT_CHAN_NUM] = {
217 ENVY24HT_CHAN_PLAY_DAC1, /* 1 */
218 ENVY24HT_CHAN_PLAY_DAC2, /* 2 */
219 ENVY24HT_CHAN_PLAY_DAC3, /* 3 */
220 ENVY24HT_CHAN_PLAY_DAC4, /* 4 */
221 ENVY24HT_CHAN_PLAY_SPDIF, /* 0 */
222 ENVY24HT_CHAN_REC_MIX, /* 5 */
223 ENVY24HT_CHAN_REC_SPDIF, /* 6 */
224 ENVY24HT_CHAN_REC_ADC1, /* 7 */
225 ENVY24HT_CHAN_REC_ADC2, /* 8 */
226 ENVY24HT_CHAN_REC_ADC3, /* 9 */
227 ENVY24HT_CHAN_REC_ADC4, /* 10 */
230 /* mixer -> API channel map. see above */
231 static int envy24ht_mixmap[] = {
232 -1, /* Master output level. It is depend on codec support */
233 -1, /* Treble level of all output channels */
234 -1, /* Bass level of all output channels */
235 -1, /* Volume of synthesier input */
236 0, /* Output level for the audio device */
237 -1, /* Output level for the PC speaker */
238 7, /* line in jack */
239 -1, /* microphone jack */
240 -1, /* CD audio input */
241 -1, /* Recording monitor */
242 1, /* alternative codec */
243 -1, /* global recording level */
245 -1, /* Output gain */
246 8, /* Input source 1 */
247 9, /* Input source 2 */
248 10, /* Input source 3 */
249 6, /* Digital (input) 1 */
250 -1, /* Digital (input) 2 */
251 -1, /* Digital (input) 3 */
252 -1, /* Phone input */
253 -1, /* Phone output */
254 -1, /* Video/TV (audio) in */
256 -1, /* Monitor volume */
259 /* variable rate audio */
260 static u_int32_t envy24ht_speed[] = {
261 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
262 12000, 11025, 9600, 8000, 0
265 /* known boards configuration */
266 static struct codec_entry spi_codec = {
268 envy24ht_spi_destroy,
271 envy24ht_spi_setvolume,
275 static struct cfg_info cfg_table[] = {
277 "Envy24HT audio (Terratec Aureon 7.1 Space)",
279 0x0b, 0x80, 0xfc, 0xc3,
280 0x21efff, 0x7fffff, 0x5e1000,
281 0x40000, 0x80000, 0x1000, 0x00, 0x02,
286 "Envy24HT audio (Terratec Aureon 5.1 Sky)",
288 0x0a, 0x80, 0xfc, 0xc3,
289 0x21efff, 0x7fffff, 0x5e1000,
290 0x40000, 0x80000, 0x1000, 0x00, 0x02,
295 "Envy24HT audio (Terratec Aureon 7.1 Universe)",
297 0x0b, 0x80, 0xfc, 0xc3,
298 0x21efff, 0x7fffff, 0x5e1000,
299 0x40000, 0x80000, 0x1000, 0x00, 0x02,
304 "Envy24HT audio (AudioTrak Prodigy 7.1)",
306 0x0b, 0x80, 0xfc, 0xc3,
307 0x21efff, 0x7fffff, 0x5e1000,
308 0x40000, 0x80000, 0x1000, 0x00, 0x02,
313 "Envy24HT audio (Terratec PHASE 28)",
315 0x0b, 0x80, 0xfc, 0xc3,
316 0x21efff, 0x7fffff, 0x5e1000,
317 0x40000, 0x80000, 0x1000, 0x00, 0x02,
322 "Envy24HT-S audio (Terratec PHASE 22)",
324 0x10, 0x80, 0xf0, 0xc3,
325 0x7ffbc7, 0x7fffff, 0x438,
326 0x20, 0x10, 0x400, 0x00, 0x00,
331 "Envy24HT audio (AudioTrak Prodigy 7.1 LT)",
333 0x4b, 0x80, 0xfc, 0xc3,
334 0x7ff8ff, 0x7fffff, 0x700,
335 0x400, 0x200, 0x100, 0x00, 0x02,
340 "Envy24HT audio (AudioTrak Prodigy 7.1 XT)",
342 0x4b, 0x80, 0xfc, 0xc3,
343 0x7ff8ff, 0x7fffff, 0x700,
344 0x400, 0x200, 0x100, 0x00, 0x02,
349 "Envy24HT audio (M-Audio Revolution 7.1)",
351 0x43, 0x80, 0xf8, 0xc1,
352 0x3fff85, 0x72, 0x4000fa,
353 0x08, 0x02, 0x20, 0x00, 0x04,
358 "Envy24GT audio (M-Audio Revolution 5.1)",
360 0x42, 0x80, 0xf8, 0xc1,
361 0x3fff85, 0x72, 0x4000fa,
362 0x08, 0x02, 0x10, 0x00, 0x03,
367 "Envy24HT audio (M-Audio Audiophile 192)",
369 0x68, 0x80, 0xf8, 0xc3,
370 0x45, 0x4000b5, 0x7fffba,
371 0x08, 0x02, 0x10, 0x00, 0x03,
376 "Envy24HT audio (AudioTrak Prodigy HD2)",
378 0x68, 0x80, 0x78, 0xc3,
379 0xfff8ff, 0x200700, 0xdfffff,
380 0x400, 0x200, 0x100, 0x00, 0x05,
385 "Envy24HT audio (ESI Juli@)",
387 0x20, 0x80, 0xf8, 0xc3,
388 0x7fff9f, 0x8016, 0x7fff9f,
389 0x08, 0x02, 0x10, 0x00, 0x03,
394 "Envy24HT audio (Generic)",
396 0x0b, 0x80, 0xfc, 0xc3,
397 0x21efff, 0x7fffff, 0x5e1000,
398 0x40000, 0x80000, 0x1000, 0x00, 0x02,
400 &spi_codec, /* default codec routines */
404 static u_int32_t envy24ht_recfmt[] = {
405 AFMT_STEREO | AFMT_S16_LE,
406 AFMT_STEREO | AFMT_S32_LE,
409 static struct pcmchan_caps envy24ht_reccaps = {8000, 96000, envy24ht_recfmt, 0};
411 static u_int32_t envy24ht_playfmt[] = {
412 AFMT_STEREO | AFMT_U8,
413 AFMT_STEREO | AFMT_S16_LE,
414 AFMT_STEREO | AFMT_S32_LE,
418 static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0};
420 struct envy24ht_emldma {
422 void (*emldma)(struct sc_chinfo *);
426 static struct envy24ht_emldma envy24ht_pemltab[] = {
427 {AFMT_STEREO | AFMT_U8, envy24ht_p8u, 2},
428 {AFMT_STEREO | AFMT_S16_LE, envy24ht_p16sl, 4},
429 {AFMT_STEREO | AFMT_S32_LE, envy24ht_p32sl, 8},
433 static struct envy24ht_emldma envy24ht_remltab[] = {
434 {AFMT_STEREO | AFMT_S16_LE, envy24ht_r16sl, 4},
435 {AFMT_STEREO | AFMT_S32_LE, envy24ht_r32sl, 8},
439 /* -------------------------------------------------------------------- */
441 /* common routines */
443 envy24ht_rdcs(struct sc_info *sc, int regno, int size)
447 return bus_space_read_1(sc->cst, sc->csh, regno);
449 return bus_space_read_2(sc->cst, sc->csh, regno);
451 return bus_space_read_4(sc->cst, sc->csh, regno);
458 envy24ht_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
462 bus_space_write_1(sc->cst, sc->csh, regno, data);
465 bus_space_write_2(sc->cst, sc->csh, regno, data);
468 bus_space_write_4(sc->cst, sc->csh, regno, data);
474 envy24ht_rdmt(struct sc_info *sc, int regno, int size)
478 return bus_space_read_1(sc->mtt, sc->mth, regno);
480 return bus_space_read_2(sc->mtt, sc->mth, regno);
482 return bus_space_read_4(sc->mtt, sc->mth, regno);
489 envy24ht_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
493 bus_space_write_1(sc->mtt, sc->mth, regno, data);
496 bus_space_write_2(sc->mtt, sc->mth, regno, data);
499 bus_space_write_4(sc->mtt, sc->mth, regno, data);
504 /* -------------------------------------------------------------------- */
506 /* I2C port/E2PROM access routines */
509 envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
515 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
517 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
518 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
519 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
521 DELAY(32); /* 31.25kHz */
523 if (i == ENVY24HT_TIMEOUT) {
526 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
527 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
528 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_RD, 1);
529 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
530 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
531 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
533 DELAY(32); /* 31.25kHz */
535 if (i == ENVY24HT_TIMEOUT) {
538 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CDATA, 1);
541 device_printf(sc->dev, "envy24ht_rdi2c(): return 0x%x\n", data);
547 envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
553 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
555 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
556 tmp = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
557 if ((tmp & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
559 DELAY(32); /* 31.25kHz */
561 if (i == ENVY24HT_TIMEOUT) {
564 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
565 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDATA, data, 1);
566 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
567 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_WR, 1);
568 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
569 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
570 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
572 DELAY(32); /* 31.25kHz */
574 if (i == ENVY24HT_TIMEOUT) {
582 envy24ht_rdrom(struct sc_info *sc, u_int32_t addr)
587 device_printf(sc->dev, "envy24ht_rdrom(sc, 0x%02x)\n", addr);
589 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
590 if ((data & ENVY24HT_CCS_I2CSTAT_ROM) == 0) {
592 device_printf(sc->dev, "envy24ht_rdrom(): E2PROM not presented\n");
597 return envy24ht_rdi2c(sc, ENVY24HT_CCS_I2CDEV_ROM, addr);
600 static struct cfg_info *
601 envy24ht_rom2cfg(struct sc_info *sc)
603 struct cfg_info *buff;
608 device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n");
610 size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE);
611 if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) {
613 device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size);
615 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
618 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
624 /* no valid e2prom, using default values */
625 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
626 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
627 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
628 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
633 buff->gpiomask = 0x21efff;
634 buff->gpiostate = 0x7fffff;
635 buff->gpiodir = 0x5e1000;
636 buff->cdti = 0x40000;
637 buff->cclk = 0x80000;
642 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0;
644 if (cfg_table[i].subvendor == buff->subvendor &&
645 cfg_table[i].subdevice == buff->subdevice)
647 buff->name = cfg_table[i].name;
648 buff->codec = cfg_table[i].codec;
655 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
658 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
664 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
665 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
666 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
667 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
668 buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG);
669 buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL);
670 buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S);
671 buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF);
672 buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \
673 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \
674 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16;
675 buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \
676 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \
677 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16;
678 buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \
679 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \
680 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16;
682 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
683 if (cfg_table[i].subvendor == buff->subvendor &&
684 cfg_table[i].subdevice == buff->subdevice)
686 buff->name = cfg_table[i].name;
687 buff->codec = cfg_table[i].codec;
693 envy24ht_cfgfree(struct cfg_info *cfg) {
697 free(cfg, M_ENVY24HT);
701 /* -------------------------------------------------------------------- */
703 /* AC'97 codec access routines */
707 envy24ht_coldcd(struct sc_info *sc)
713 device_printf(sc->dev, "envy24ht_coldcd()\n");
715 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1);
717 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
719 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
720 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
721 if (data & ENVY24HT_MT_AC97CMD_RDY) {
730 envy24ht_slavecd(struct sc_info *sc)
736 device_printf(sc->dev, "envy24ht_slavecd()\n");
738 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD,
739 ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1);
741 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
743 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
744 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
745 if (data & ENVY24HT_MT_AC97CMD_RDY) {
754 envy24ht_rdcd(kobj_t obj, void *devinfo, int regno)
756 struct sc_info *sc = (struct sc_info *)devinfo;
761 device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno);
763 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
764 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1);
765 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
766 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
767 if ((data & ENVY24HT_MT_AC97CMD_RD) == 0)
770 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2);
773 device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data);
779 envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
781 struct sc_info *sc = (struct sc_info *)devinfo;
786 device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
788 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
789 envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2);
790 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1);
791 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
792 cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
793 if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0)
800 static kobj_method_t envy24ht_ac97_methods[] = {
801 KOBJMETHOD(ac97_read, envy24ht_rdcd),
802 KOBJMETHOD(ac97_write, envy24ht_wrcd),
805 AC97_DECLARE(envy24ht_ac97);
808 /* -------------------------------------------------------------------- */
810 /* GPIO access routines */
813 envy24ht_gpiord(struct sc_info *sc)
815 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
816 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2);
818 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2));
822 envy24ht_gpiowr(struct sc_info *sc, u_int32_t data)
825 device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF);
828 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2);
829 if (sc->cfg->subdevice != 0x1150)
830 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1);
836 envy24ht_gpiogetmask(struct sc_info *sc)
838 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2));
843 envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask)
845 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2);
846 if (sc->cfg->subdevice != 0x1150)
847 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1);
853 envy24ht_gpiogetdir(struct sc_info *sc)
855 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4);
860 envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir)
862 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
863 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2);
865 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4);
869 /* -------------------------------------------------------------------- */
871 /* SPI codec access interface routine */
873 struct envy24ht_spi_codec {
874 struct spicds_info *info;
875 struct sc_info *parent;
882 envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
885 struct envy24ht_spi_codec *ptr = codec;
888 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
890 data = envy24ht_gpiord(ptr->parent);
891 data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
892 if (cs) data += ptr->cs;
893 if (cclk) data += ptr->cclk;
894 if (cdti) data += ptr->cdti;
895 envy24ht_gpiowr(ptr->parent, data);
900 envy24ht_spi_create(device_t dev, void *info, int dir, int num)
902 struct sc_info *sc = info;
903 struct envy24ht_spi_codec *buff = NULL;
906 device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num);
909 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
913 if (dir == PCMDIR_REC && sc->adc[num] != NULL)
914 buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info;
915 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
916 buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info;
918 buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl);
919 if (buff->info == NULL) {
920 free(buff, M_ENVY24HT);
932 envy24ht_spi_destroy(void *codec)
934 struct envy24ht_spi_codec *ptr = codec;
938 device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n");
941 if (ptr->dir == PCMDIR_PLAY) {
942 if (ptr->parent->dac[ptr->num] != NULL)
943 spicds_destroy(ptr->info);
946 if (ptr->parent->adc[ptr->num] != NULL)
947 spicds_destroy(ptr->info);
950 free(codec, M_ENVY24HT);
954 envy24ht_spi_init(void *codec)
956 struct envy24ht_spi_codec *ptr = codec;
960 device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n");
962 ptr->cs = ptr->parent->cfg->cs;
963 ptr->cclk = ptr->parent->cfg->cclk;
964 ptr->cdti = ptr->parent->cfg->cdti;
965 spicds_settype(ptr->info, ptr->parent->cfg->type);
966 spicds_setcif(ptr->info, ptr->parent->cfg->cif);
967 if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \
968 ptr->parent->cfg->type == SPICDS_TYPE_AK4528) {
969 spicds_setformat(ptr->info,
970 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
971 spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
974 /* for the time being, init only first codec */
976 spicds_init(ptr->info);
980 envy24ht_spi_reinit(void *codec)
982 struct envy24ht_spi_codec *ptr = codec;
986 device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n");
989 spicds_reinit(ptr->info);
993 envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
995 struct envy24ht_spi_codec *ptr = codec;
999 device_printf(ptr->parent->dev, "envy24ht_spi_set()\n");
1002 spicds_set(ptr->info, dir, left, right);
1005 /* -------------------------------------------------------------------- */
1007 /* hardware access routeines */
1012 } envy24ht_speedtab[] = {
1013 {48000, ENVY24HT_MT_RATE_48000},
1014 {24000, ENVY24HT_MT_RATE_24000},
1015 {12000, ENVY24HT_MT_RATE_12000},
1016 {9600, ENVY24HT_MT_RATE_9600},
1017 {32000, ENVY24HT_MT_RATE_32000},
1018 {16000, ENVY24HT_MT_RATE_16000},
1019 {8000, ENVY24HT_MT_RATE_8000},
1020 {96000, ENVY24HT_MT_RATE_96000},
1021 {192000, ENVY24HT_MT_RATE_192000},
1022 {64000, ENVY24HT_MT_RATE_64000},
1023 {44100, ENVY24HT_MT_RATE_44100},
1024 {22050, ENVY24HT_MT_RATE_22050},
1025 {11025, ENVY24HT_MT_RATE_11025},
1026 {88200, ENVY24HT_MT_RATE_88200},
1027 {176400, ENVY24HT_MT_RATE_176400},
1032 envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) {
1033 u_int32_t code, i2sfmt;
1037 device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed);
1039 code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */
1040 envy24ht_slavecd(sc);
1044 for (i = 0; envy24ht_speedtab[i].speed != 0; i++) {
1045 if (envy24ht_speedtab[i].speed == speed)
1048 code = envy24ht_speedtab[i].code;
1051 device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code);
1054 envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1);
1055 if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \
1056 (code == ENVY24HT_MT_RATE_176400)) {
1057 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1058 i2sfmt |= ENVY24HT_MT_I2S_MLR128;
1059 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1062 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1063 i2sfmt &= ~ENVY24HT_MT_I2S_MLR128;
1064 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1066 code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1);
1067 code &= ENVY24HT_MT_RATE_MASK;
1068 for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) {
1069 if (envy24ht_speedtab[i].code == code)
1072 speed = envy24ht_speedtab[i].speed;
1078 device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed);
1084 envy24ht_setvolume(struct sc_info *sc, unsigned ch)
1087 device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch);
1088 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1089 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1090 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1091 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1096 envy24ht_mutevolume(struct sc_info *sc, unsigned ch)
1101 device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch);
1102 vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE;
1103 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1104 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1105 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1106 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1111 envy24ht_gethwptr(struct sc_info *sc, int dir)
1117 device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir);
1119 if (dir == PCMDIR_PLAY) {
1120 rtn = sc->psize / 4;
1121 unit = ENVY24HT_PLAY_BUFUNIT / 4;
1122 regno = ENVY24HT_MT_PCNT;
1125 rtn = sc->rsize / 4;
1126 unit = ENVY24HT_REC_BUFUNIT / 4;
1127 regno = ENVY24HT_MT_RCNT;
1130 ptr = envy24ht_rdmt(sc, regno, 2);
1135 device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn);
1141 envy24ht_updintr(struct sc_info *sc, int dir)
1143 int regptr, regintr;
1144 u_int32_t mask, intr;
1145 u_int32_t ptr, size, cnt;
1149 device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir);
1151 if (dir == PCMDIR_PLAY) {
1153 size = sc->psize / 4;
1154 regptr = ENVY24HT_MT_PCNT;
1155 regintr = ENVY24HT_MT_PTERM;
1156 mask = ~ENVY24HT_MT_INT_PMASK;
1160 size = sc->rsize / 4;
1161 regptr = ENVY24HT_MT_RCNT;
1162 regintr = ENVY24HT_MT_RTERM;
1163 mask = ~ENVY24HT_MT_INT_RMASK;
1166 ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1;
1168 cnt = blk - ptr % blk - 1;
1174 device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1176 envy24ht_wrmt(sc, regintr, cnt, 2);
1177 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1179 device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1181 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
1183 device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
1184 envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
1192 envy24ht_maskintr(struct sc_info *sc, int dir)
1194 u_int32_t mask, intr;
1197 device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
1199 if (dir == PCMDIR_PLAY)
1200 mask = ENVY24HT_MT_INT_PMASK;
1202 mask = ENVY24HT_MT_INT_RMASK;
1203 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
1204 envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
1211 envy24ht_checkintr(struct sc_info *sc, int dir)
1213 u_int32_t mask, stat, intr, rtn;
1216 device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
1218 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
1219 if (dir == PCMDIR_PLAY) {
1220 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
1221 mask = ~ENVY24HT_MT_INT_RSTAT;
1222 envy24ht_wrmt(sc, 0x1a, 0x01, 1);
1223 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);
1224 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1225 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
1229 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
1230 mask = ~ENVY24HT_MT_INT_PSTAT;
1232 stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
1234 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
1235 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1236 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
1244 envy24ht_start(struct sc_info *sc, int dir)
1249 device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
1251 if (dir == PCMDIR_PLAY)
1252 sw = ENVY24HT_MT_PCTL_PSTART;
1254 sw = ENVY24HT_MT_PCTL_RSTART;
1256 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1257 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
1260 device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
1261 device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
1268 envy24ht_stop(struct sc_info *sc, int dir)
1273 device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir);
1275 if (dir == PCMDIR_PLAY)
1276 sw = ~ENVY24HT_MT_PCTL_PSTART;
1278 sw = ~ENVY24HT_MT_PCTL_RSTART;
1280 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1281 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1);
1288 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1294 /* -------------------------------------------------------------------- */
1296 /* buffer copy routines */
1298 envy24ht_p32sl(struct sc_chinfo *ch)
1303 int src, dst, ssize, dsize, slot;
1306 length = sndbuf_getready(ch->buffer) / 8;
1307 dmabuf = ch->parent->pbuf;
1308 data = (u_int32_t *)ch->data;
1309 src = sndbuf_getreadyptr(ch->buffer) / 4;
1310 dst = src / 2 + ch->offset;
1311 ssize = ch->size / 4;
1312 dsize = ch->size / 8;
1315 for (i = 0; i < length; i++) {
1316 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
1317 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1328 envy24ht_p16sl(struct sc_chinfo *ch)
1333 int src, dst, ssize, dsize, slot;
1337 device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
1339 length = sndbuf_getready(ch->buffer) / 4;
1340 dmabuf = ch->parent->pbuf;
1341 data = (u_int16_t *)ch->data;
1342 src = sndbuf_getreadyptr(ch->buffer) / 2;
1343 dst = src / 2 + ch->offset;
1344 ssize = ch->size / 2;
1345 dsize = ch->size / 4;
1348 device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1351 for (i = 0; i < length; i++) {
1352 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1353 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1356 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
1357 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
1373 envy24ht_p8u(struct sc_chinfo *ch)
1378 int src, dst, ssize, dsize, slot;
1381 length = sndbuf_getready(ch->buffer) / 2;
1382 dmabuf = ch->parent->pbuf;
1383 data = (u_int8_t *)ch->data;
1384 src = sndbuf_getreadyptr(ch->buffer);
1385 dst = src / 2 + ch->offset;
1387 dsize = ch->size / 4;
1390 for (i = 0; i < length; i++) {
1391 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1392 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1403 envy24ht_r32sl(struct sc_chinfo *ch)
1408 int src, dst, ssize, dsize, slot;
1411 length = sndbuf_getfree(ch->buffer) / 8;
1412 dmabuf = ch->parent->rbuf;
1413 data = (u_int32_t *)ch->data;
1414 dst = sndbuf_getfreeptr(ch->buffer) / 4;
1415 src = dst / 2 + ch->offset;
1416 dsize = ch->size / 4;
1417 ssize = ch->size / 8;
1418 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1420 for (i = 0; i < length; i++) {
1421 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1422 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1433 envy24ht_r16sl(struct sc_chinfo *ch)
1438 int src, dst, ssize, dsize, slot;
1441 length = sndbuf_getfree(ch->buffer) / 4;
1442 dmabuf = ch->parent->rbuf;
1443 data = (u_int16_t *)ch->data;
1444 dst = sndbuf_getfreeptr(ch->buffer) / 2;
1445 src = dst / 2 + ch->offset;
1446 dsize = ch->size / 2;
1447 ssize = ch->size / 8;
1448 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1450 for (i = 0; i < length; i++) {
1451 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1452 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1462 /* -------------------------------------------------------------------- */
1464 /* channel interface */
1466 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1468 struct sc_info *sc = (struct sc_info *)devinfo;
1469 struct sc_chinfo *ch;
1473 device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
1475 snd_mtxlock(sc->lock);
1477 if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1478 (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1479 snd_mtxunlock(sc->lock);
1485 ch = &sc->chan[num];
1486 ch->size = 8 * ENVY24HT_SAMPLE_NUM;
1487 ch->data = malloc(ch->size, M_ENVY24HT, M_NOWAIT);
1488 if (ch->data == NULL) {
1497 /* set channel map */
1498 ch->num = envy24ht_chanmap[num];
1499 snd_mtxunlock(sc->lock);
1500 sndbuf_setup(ch->buffer, ch->data, ch->size);
1501 snd_mtxlock(sc->lock);
1502 /* these 2 values are dummy */
1506 snd_mtxunlock(sc->lock);
1512 envy24htchan_free(kobj_t obj, void *data)
1514 struct sc_chinfo *ch = data;
1515 struct sc_info *sc = ch->parent;
1518 device_printf(sc->dev, "envy24htchan_free()\n");
1520 snd_mtxlock(sc->lock);
1521 if (ch->data != NULL) {
1522 free(ch->data, M_ENVY24HT);
1525 snd_mtxunlock(sc->lock);
1531 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
1533 struct sc_chinfo *ch = data;
1534 struct sc_info *sc = ch->parent;
1535 struct envy24ht_emldma *emltab;
1536 /* unsigned int bcnt, bsize; */
1540 device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
1542 snd_mtxlock(sc->lock);
1543 /* check and get format related information */
1544 if (ch->dir == PCMDIR_PLAY)
1545 emltab = envy24ht_pemltab;
1547 emltab = envy24ht_remltab;
1548 if (emltab == NULL) {
1549 snd_mtxunlock(sc->lock);
1552 for (i = 0; emltab[i].format != 0; i++)
1553 if (emltab[i].format == format)
1555 if (emltab[i].format == 0) {
1556 snd_mtxunlock(sc->lock);
1560 /* set format information */
1561 ch->format = format;
1562 ch->emldma = emltab[i].emldma;
1563 if (ch->unit > emltab[i].unit)
1564 ch->blk *= ch->unit / emltab[i].unit;
1566 ch->blk /= emltab[i].unit / ch->unit;
1567 ch->unit = emltab[i].unit;
1569 /* set channel buffer information */
1570 ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
1572 if (ch->dir == PCMDIR_PLAY)
1573 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1575 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1577 bcnt = ch->size / bsize;
1578 sndbuf_resize(ch->buffer, bcnt, bsize);
1580 snd_mtxunlock(sc->lock);
1583 device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
1589 IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1590 of speed information value. And real hardware speed setting is done
1591 at start triggered(see envy24htchan_trigger()). So, at this function
1592 is called, any value that ENVY24 can use is able to set. But, at
1593 start triggerd, some other channel is running, and that channel's
1594 speed isn't same with, then trigger function will fail.
1597 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1599 struct sc_chinfo *ch = data;
1600 u_int32_t val, prev;
1604 device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
1607 for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
1608 if (abs(val - speed) < abs(prev - speed))
1616 device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
1622 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1624 struct sc_chinfo *ch = data;
1625 /* struct sc_info *sc = ch->parent; */
1626 u_int32_t size, prev;
1627 unsigned int bcnt, bsize;
1630 device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
1633 /* snd_mtxlock(sc->lock); */
1634 for (size = ch->size / 2; size > 0; size /= 2) {
1635 if (abs(size - blocksize) < abs(prev - blocksize))
1641 ch->blk = prev / ch->unit;
1642 if (ch->dir == PCMDIR_PLAY)
1643 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
1645 ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
1646 /* set channel buffer information */
1647 /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
1648 if (ch->dir == PCMDIR_PLAY)
1649 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1651 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1653 bcnt = ch->size / bsize;
1654 sndbuf_resize(ch->buffer, bcnt, bsize);
1655 /* snd_mtxunlock(sc->lock); */
1658 device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
1663 /* semantic note: must start at beginning of buffer */
1665 envy24htchan_trigger(kobj_t obj, void *data, int go)
1667 struct sc_chinfo *ch = data;
1668 struct sc_info *sc = ch->parent;
1674 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1676 snd_mtxlock(sc->lock);
1677 if (ch->dir == PCMDIR_PLAY)
1684 device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1686 /* check or set channel speed */
1687 if (sc->run[0] == 0 && sc->run[1] == 0) {
1688 sc->speed = envy24ht_setspeed(sc, ch->speed);
1689 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1690 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1692 else if (ch->speed != 0 && ch->speed != sc->speed)
1695 ch->channel->speed = sc->speed;
1696 /* start or enable channel */
1698 if (sc->run[slot] == 1) {
1701 sc->blk[slot] = ch->blk;
1704 ptr = envy24ht_gethwptr(sc, ch->dir);
1705 ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1706 (ch->size / 4)) * 4 / ch->unit;
1707 if (ch->blk < sc->blk[slot])
1708 sc->blk[slot] = ch->blk;
1710 if (ch->dir == PCMDIR_PLAY) {
1712 envy24ht_setvolume(sc, ch->num);
1714 envy24ht_updintr(sc, ch->dir);
1715 if (sc->run[slot] == 1)
1716 envy24ht_start(sc, ch->dir);
1719 case PCMTRIG_EMLDMAWR:
1721 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1727 case PCMTRIG_EMLDMARD:
1729 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1738 device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1742 if (ch->dir == PCMDIR_PLAY)
1743 envy24ht_mutevolume(sc, ch->num);
1744 if (sc->run[slot] == 0) {
1745 envy24ht_stop(sc, ch->dir);
1748 /* else if (ch->blk == sc->blk[slot]) {
1749 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1750 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1751 if (sc->chan[i].dir == ch->dir &&
1752 sc->chan[i].run == 1 &&
1753 sc->chan[i].blk < sc->blk[slot])
1754 sc->blk[slot] = sc->chan[i].blk;
1756 if (ch->blk != sc->blk[slot])
1757 envy24ht_updintr(sc, ch->dir);
1762 snd_mtxunlock(sc->lock);
1768 envy24htchan_getptr(kobj_t obj, void *data)
1770 struct sc_chinfo *ch = data;
1771 struct sc_info *sc = ch->parent;
1776 device_printf(sc->dev, "envy24htchan_getptr()\n");
1778 snd_mtxlock(sc->lock);
1779 ptr = envy24ht_gethwptr(sc, ch->dir);
1780 rtn = ptr * ch->unit;
1781 snd_mtxunlock(sc->lock);
1784 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1790 static struct pcmchan_caps *
1791 envy24htchan_getcaps(kobj_t obj, void *data)
1793 struct sc_chinfo *ch = data;
1794 struct sc_info *sc = ch->parent;
1795 struct pcmchan_caps *rtn;
1798 device_printf(sc->dev, "envy24htchan_getcaps()\n");
1800 snd_mtxlock(sc->lock);
1801 if (ch->dir == PCMDIR_PLAY) {
1802 if (sc->run[0] == 0)
1803 rtn = &envy24ht_playcaps;
1808 if (sc->run[1] == 0)
1809 rtn = &envy24ht_reccaps;
1813 snd_mtxunlock(sc->lock);
1818 static kobj_method_t envy24htchan_methods[] = {
1819 KOBJMETHOD(channel_init, envy24htchan_init),
1820 KOBJMETHOD(channel_free, envy24htchan_free),
1821 KOBJMETHOD(channel_setformat, envy24htchan_setformat),
1822 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed),
1823 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize),
1824 KOBJMETHOD(channel_trigger, envy24htchan_trigger),
1825 KOBJMETHOD(channel_getptr, envy24htchan_getptr),
1826 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps),
1829 CHANNEL_DECLARE(envy24htchan);
1831 /* -------------------------------------------------------------------- */
1833 /* mixer interface */
1836 envy24htmixer_init(struct snd_mixer *m)
1838 struct sc_info *sc = mix_getdevinfo(m);
1841 device_printf(sc->dev, "envy24htmixer_init()\n");
1846 /* set volume control rate */
1847 snd_mtxlock(sc->lock);
1849 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1852 pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1854 mix_setdevs(m, ENVY24HT_MIX_MASK);
1855 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1857 snd_mtxunlock(sc->lock);
1863 envy24htmixer_reinit(struct snd_mixer *m)
1865 struct sc_info *sc = mix_getdevinfo(m);
1870 device_printf(sc->dev, "envy24htmixer_reinit()\n");
1877 envy24htmixer_uninit(struct snd_mixer *m)
1879 struct sc_info *sc = mix_getdevinfo(m);
1884 device_printf(sc->dev, "envy24htmixer_uninit()\n");
1891 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1893 struct sc_info *sc = mix_getdevinfo(m);
1894 int ch = envy24ht_mixmap[dev];
1900 if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1902 if (dev != 0 && ch == -1)
1904 hwch = envy24ht_chanmap[ch];
1906 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1910 snd_mtxlock(sc->lock);
1912 for (i = 0; i < sc->dacn; i++) {
1913 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1917 /* set volume value for hardware */
1918 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1919 sc->left[hwch] = ENVY24HT_VOL_MUTE;
1920 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1921 sc->right[hwch] = ENVY24HT_VOL_MUTE;
1923 /* set volume for record channel and running play channel */
1924 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1925 envy24ht_setvolume(sc, hwch);
1927 snd_mtxunlock(sc->lock);
1929 return right << 8 | left;
1933 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1935 struct sc_info *sc = mix_getdevinfo(m);
1936 int ch = envy24ht_mixmap[src];
1938 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1941 if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1946 static kobj_method_t envy24htmixer_methods[] = {
1947 KOBJMETHOD(mixer_init, envy24htmixer_init),
1948 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit),
1949 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit),
1950 KOBJMETHOD(mixer_set, envy24htmixer_set),
1951 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc),
1954 MIXER_DECLARE(envy24htmixer);
1956 /* -------------------------------------------------------------------- */
1958 /* The interrupt handler */
1960 envy24ht_intr(void *p)
1962 struct sc_info *sc = (struct sc_info *)p;
1963 struct sc_chinfo *ch;
1964 u_int32_t ptr, dsize, feed;
1968 device_printf(sc->dev, "envy24ht_intr()\n");
1970 snd_mtxlock(sc->lock);
1971 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1973 device_printf(sc->dev, "envy24ht_intr(): play\n");
1975 dsize = sc->psize / 4;
1976 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
1978 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
1980 ptr -= ptr % sc->blk[0];
1981 feed = (ptr + dsize - sc->intr[0]) % dsize;
1983 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
1985 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
1989 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
1991 if (ch->run && ch->blk <= feed) {
1992 snd_mtxunlock(sc->lock);
1993 chn_intr(ch->channel);
1994 snd_mtxlock(sc->lock);
1998 envy24ht_updintr(sc, PCMDIR_PLAY);
2000 if (envy24ht_checkintr(sc, PCMDIR_REC)) {
2002 device_printf(sc->dev, "envy24ht_intr(): rec\n");
2004 dsize = sc->rsize / 4;
2005 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
2006 ptr -= ptr % sc->blk[1];
2007 feed = (ptr + dsize - sc->intr[1]) % dsize;
2008 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
2010 if (ch->run && ch->blk <= feed) {
2011 snd_mtxunlock(sc->lock);
2012 chn_intr(ch->channel);
2013 snd_mtxlock(sc->lock);
2017 envy24ht_updintr(sc, PCMDIR_REC);
2019 snd_mtxunlock(sc->lock);
2025 * Probe and attach the card
2029 envy24ht_pci_probe(device_t dev)
2035 printf("envy24ht_pci_probe()\n");
2037 if (pci_get_device(dev) == PCID_ENVY24HT &&
2038 pci_get_vendor(dev) == PCIV_ENVY24) {
2039 sv = pci_get_subvendor(dev);
2040 sd = pci_get_subdevice(dev);
2041 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2042 if (cfg_table[i].subvendor == sv &&
2043 cfg_table[i].subdevice == sd) {
2047 device_set_desc(dev, cfg_table[i].name);
2049 printf("envy24ht_pci_probe(): return 0\n");
2055 printf("envy24ht_pci_probe(): return ENXIO\n");
2062 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2064 /* struct sc_info *sc = (struct sc_info *)arg; */
2067 device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2069 printf("envy24ht(play): setmap %lx, %lx; ",
2070 (unsigned long)segs->ds_addr,
2071 (unsigned long)segs->ds_len);
2072 printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2078 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2080 /* struct sc_info *sc = (struct sc_info *)arg; */
2083 device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2085 printf("envy24ht(record): setmap %lx, %lx; ",
2086 (unsigned long)segs->ds_addr,
2087 (unsigned long)segs->ds_len);
2088 printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2094 envy24ht_dmafree(struct sc_info *sc)
2097 device_printf(sc->dev, "envy24ht_dmafree():");
2098 if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2099 else printf(" sc->rmap(null)");
2100 if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2101 else printf(" sc->pmap(null)");
2102 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2103 else printf(" sc->rbuf(null)");
2104 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2105 else printf(" sc->pbuf(null)\n");
2109 bus_dmamap_unload(sc->dmat, sc->rmap);
2111 bus_dmamap_unload(sc->dmat, sc->pmap);
2113 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2115 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2117 bus_dmamap_unload(sc->dmat, sc->rmap);
2118 bus_dmamap_unload(sc->dmat, sc->pmap);
2119 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2120 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2123 sc->rmap = sc->pmap = NULL;
2131 envy24ht_dmainit(struct sc_info *sc)
2136 device_printf(sc->dev, "envy24ht_dmainit()\n");
2139 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2140 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2143 sc->pmap = sc->rmap = NULL;
2144 sc->blk[0] = sc->blk[1] = 0;
2146 /* allocate DMA buffer */
2148 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2150 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2153 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2155 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2158 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2160 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, 0))
2163 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2165 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, 0))
2167 bzero(sc->pbuf, sc->psize);
2168 bzero(sc->rbuf, sc->rsize);
2170 /* set values to register */
2171 addr = vtophys(sc->pbuf);
2173 device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2175 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, addr, 4);
2177 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
2178 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2180 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, sc->psize / 4 - 1, 2);
2182 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
2184 addr = vtophys(sc->rbuf);
2185 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, addr, 4);
2186 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, sc->rsize / 4 - 1, 2);
2190 envy24ht_dmafree(sc);
2195 envy24ht_putcfg(struct sc_info *sc)
2197 device_printf(sc->dev, "system configuration\n");
2198 printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2199 sc->cfg->subvendor, sc->cfg->subdevice);
2200 printf(" XIN2 Clock Source: ");
2201 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2203 printf("24.576MHz(96kHz*256)\n");
2206 printf("49.152MHz(192kHz*256)\n");
2209 printf("reserved\n");
2212 printf("illeagal system setting\n");
2214 printf(" MPU-401 UART(s) #: ");
2215 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2218 printf("not implemented\n");
2222 printf("%d\n", sc->adcn);
2227 printf(" and SPDIF receiver connected\n");
2230 printf(" no physical inputs\n");
2233 printf("%d\n", sc->dacn);
2234 printf(" Multi-track converter type: ");
2235 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2236 printf("AC'97(SDATA_OUT:");
2237 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2245 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2246 printf("with volume, ");
2247 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2248 printf("192KHz support, ");
2250 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2251 printf("192KHz support, ");
2253 printf("48KHz support, ");
2254 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2255 case ENVY24HT_CCSM_I2S_16BIT:
2256 printf("16bit resolution, ");
2258 case ENVY24HT_CCSM_I2S_18BIT:
2259 printf("18bit resolution, ");
2261 case ENVY24HT_CCSM_I2S_20BIT:
2262 printf("20bit resolution, ");
2264 case ENVY24HT_CCSM_I2S_24BIT:
2265 printf("24bit resolution, ");
2268 printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2270 printf(" S/PDIF(IN/OUT): ");
2271 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2275 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2279 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2280 printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2281 printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2282 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2286 envy24ht_init(struct sc_info *sc)
2297 device_printf(sc->dev, "envy24ht_init()\n");
2302 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2304 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2307 /* legacy hardware disable */
2308 data = pci_read_config(sc->dev, PCIR_LAC, 2);
2309 data |= PCIM_LAC_DISABLE;
2310 pci_write_config(sc->dev, PCIR_LAC, data, 2);
2313 /* check system configuration */
2315 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2316 /* 1st: search configuration from table */
2317 sv = pci_get_subvendor(sc->dev);
2318 sd = pci_get_subdevice(sc->dev);
2319 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2321 device_printf(sc->dev, "Set configuration from table\n");
2323 sc->cfg = &cfg_table[i];
2327 if (sc->cfg == NULL) {
2328 /* 2nd: read configuration from table */
2329 sc->cfg = envy24ht_rom2cfg(sc);
2331 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2332 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2334 if (1 /* bootverbose */) {
2335 envy24ht_putcfg(sc);
2338 /* set system configuration */
2339 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2340 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2341 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2342 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2343 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2344 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2345 envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2347 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2348 envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2349 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2350 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2353 for (i = 0; i < sc->adcn; i++) {
2354 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2355 sc->cfg->codec->init(sc->adc[i]);
2357 for (i = 0; i < sc->dacn; i++) {
2358 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2359 sc->cfg->codec->init(sc->dac[i]);
2362 /* initialize DMA buffer */
2364 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2366 if (envy24ht_dmainit(sc))
2369 /* initialize status */
2370 sc->run[0] = sc->run[1] = 0;
2371 sc->intr[0] = sc->intr[1] = 0;
2373 sc->caps[0].fmtlist = envy24ht_playfmt;
2374 sc->caps[1].fmtlist = envy24ht_recfmt;
2376 /* set channel router */
2378 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2379 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2380 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2383 /* set macro interrupt mask */
2384 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2385 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2386 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2388 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2395 envy24ht_alloc_resource(struct sc_info *sc)
2397 /* allocate I/O port resource */
2398 sc->csid = PCIR_CCS;
2399 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2400 &sc->csid, 0, ~0, 1, RF_ACTIVE);
2401 sc->mtid = ENVY24HT_PCIR_MT;
2402 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2403 &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2404 if (!sc->cs || !sc->mt) {
2405 device_printf(sc->dev, "unable to map IO port space\n");
2408 sc->cst = rman_get_bustag(sc->cs);
2409 sc->csh = rman_get_bushandle(sc->cs);
2410 sc->mtt = rman_get_bustag(sc->mt);
2411 sc->mth = rman_get_bushandle(sc->mt);
2413 device_printf(sc->dev,
2414 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2415 pci_read_config(sc->dev, PCIR_CCS, 4),
2416 pci_read_config(sc->dev, PCIR_MT, 4));
2419 /* allocate interrupt resource */
2421 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2422 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2424 snd_setup_intr(sc->dev, sc->irq, 0, envy24ht_intr, sc, &sc->ih)) {
2425 device_printf(sc->dev, "unable to map interrupt\n");
2429 /* allocate DMA resource */
2430 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2433 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2434 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2435 /*filter*/NULL, /*filterarg*/NULL,
2436 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2437 /*nsegments*/1, /*maxsegsz*/0x3ffff,
2438 /*flags*/0, /*lockfunc*/busdma_lock_mutex,
2439 /*lockarg*/&Giant, &sc->dmat) != 0) {
2440 device_printf(sc->dev, "unable to create dma tag\n");
2448 envy24ht_pci_attach(device_t dev)
2452 char status[SND_STATUSLEN];
2457 device_printf(dev, "envy24ht_pci_attach()\n");
2459 /* get sc_info data area */
2460 if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) {
2461 device_printf(dev, "cannot allocate softc\n");
2465 bzero(sc, sizeof(*sc));
2466 sc->lock = snd_mtxcreate(device_get_nameunit(dev),
2467 "snd_envy24ht softc");
2470 /* initialize PCI interface */
2471 data = pci_read_config(dev, PCIR_COMMAND, 2);
2472 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2473 pci_write_config(dev, PCIR_COMMAND, data, 2);
2474 data = pci_read_config(dev, PCIR_COMMAND, 2);
2476 /* allocate resources */
2477 err = envy24ht_alloc_resource(sc);
2479 device_printf(dev, "unable to allocate system resources\n");
2483 /* initialize card */
2484 err = envy24ht_init(sc);
2486 device_printf(dev, "unable to initialize the card\n");
2490 /* set multi track mixer */
2491 mixer_init(dev, &envy24htmixer_class, sc);
2493 /* set channel information */
2494 /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
2495 err = pcm_register(dev, sc, 1, 2 + sc->adcn);
2499 /* for (i = 0; i < 5; i++) { */
2500 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
2503 for (i = 0; i < 2 + sc->adcn; i++) {
2504 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
2508 /* set status iformation */
2509 snprintf(status, SND_STATUSLEN,
2510 "at io 0x%lx:%ld,0x%lx:%ld irq %ld",
2511 rman_get_start(sc->cs),
2512 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2513 rman_get_start(sc->mt),
2514 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2515 rman_get_start(sc->irq));
2516 pcm_setstatus(dev, status);
2522 bus_teardown_intr(dev, sc->irq, sc->ih);
2524 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2525 envy24ht_dmafree(sc);
2527 bus_dma_tag_destroy(sc->dmat);
2528 if (sc->cfg->codec->destroy != NULL) {
2529 for (i = 0; i < sc->adcn; i++)
2530 sc->cfg->codec->destroy(sc->adc[i]);
2531 for (i = 0; i < sc->dacn; i++)
2532 sc->cfg->codec->destroy(sc->dac[i]);
2534 envy24ht_cfgfree(sc->cfg);
2536 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2538 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2540 snd_mtxfree(sc->lock);
2541 free(sc, M_ENVY24HT);
2546 envy24ht_pci_detach(device_t dev)
2553 device_printf(dev, "envy24ht_pci_detach()\n");
2555 sc = pcm_getdevinfo(dev);
2558 r = pcm_unregister(dev);
2562 envy24ht_dmafree(sc);
2563 if (sc->cfg->codec->destroy != NULL) {
2564 for (i = 0; i < sc->adcn; i++)
2565 sc->cfg->codec->destroy(sc->adc[i]);
2566 for (i = 0; i < sc->dacn; i++)
2567 sc->cfg->codec->destroy(sc->dac[i]);
2569 envy24ht_cfgfree(sc->cfg);
2570 bus_dma_tag_destroy(sc->dmat);
2571 bus_teardown_intr(dev, sc->irq, sc->ih);
2572 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2573 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2574 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2575 snd_mtxfree(sc->lock);
2576 free(sc, M_ENVY24HT);
2580 static device_method_t envy24ht_methods[] = {
2581 /* Device interface */
2582 DEVMETHOD(device_probe, envy24ht_pci_probe),
2583 DEVMETHOD(device_attach, envy24ht_pci_attach),
2584 DEVMETHOD(device_detach, envy24ht_pci_detach),
2588 static driver_t envy24ht_driver = {
2591 #if __FreeBSD_version > 500000
2594 sizeof(struct snddev_info),
2598 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0);
2599 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2600 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2601 MODULE_VERSION(snd_envy24ht, 1);