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 #ifdef HAVE_KERNEL_OPTION_HEADERS
44 #include <dev/sound/pcm/sound.h>
45 #include <dev/sound/pcm/ac97.h>
46 #include <dev/sound/pci/spicds.h>
47 #include <dev/sound/pci/envy24ht.h>
49 #include <dev/pci/pcireg.h>
50 #include <dev/pci/pcivar.h>
54 SND_DECLARE_FILE("$FreeBSD$");
56 MALLOC_DEFINE(M_ENVY24HT, "envy24ht", "envy24ht audio");
58 /* -------------------------------------------------------------------- */
62 #define ENVY24HT_PLAY_CHNUM 8
63 #define ENVY24HT_REC_CHNUM 2
64 #define ENVY24HT_PLAY_BUFUNIT (4 /* byte/sample */ * 8 /* channel */)
65 #define ENVY24HT_REC_BUFUNIT (4 /* byte/sample */ * 2 /* channel */)
66 #define ENVY24HT_SAMPLE_NUM 4096
68 #define ENVY24HT_TIMEOUT 1000
70 #define ENVY24HT_DEFAULT_FORMAT SND_FORMAT(AFMT_S16_LE, 2, 0)
72 #define ENVY24HT_NAMELEN 32
74 struct envy24ht_sample {
75 volatile u_int32_t buffer;
78 typedef struct envy24ht_sample sample32_t;
80 /* channel registers */
82 struct snd_dbuf *buffer;
83 struct pcm_channel *channel;
84 struct sc_info *parent;
86 unsigned num; /* hw channel number */
88 /* channel information */
91 u_int32_t blk; /* hw block size(dword) */
93 /* format conversion structure */
95 unsigned int size; /* data buffer size(byte) */
96 int unit; /* sample size(byte) */
97 unsigned int offset; /* samples number offset */
98 void (*emldma)(struct sc_chinfo *);
104 /* codec interface entrys */
106 void *(*create)(device_t dev, void *devinfo, int dir, int num);
107 void (*destroy)(void *codec);
108 void (*init)(void *codec);
109 void (*reinit)(void *codec);
110 void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
111 void (*setrate)(void *codec, int which, int rate);
114 /* system configuration information */
117 u_int16_t subvendor, subdevice;
118 u_int8_t scfg, acl, i2s, spdif;
119 u_int32_t gpiomask, gpiostate, gpiodir;
120 u_int32_t cdti, cclk, cs;
121 u_int8_t cif, type, free;
122 struct codec_entry *codec;
125 /* device private data */
130 /* Control/Status registor */
134 bus_space_handle_t csh;
135 /* MultiTrack registor */
139 bus_space_handle_t mth;
143 struct resource *irq;
147 /* system configuration data */
148 struct cfg_info *cfg;
150 /* ADC/DAC number and info */
152 void *adc[4], *dac[4];
154 /* mixer control data */
156 u_int8_t left[ENVY24HT_CHAN_NUM];
157 u_int8_t right[ENVY24HT_CHAN_NUM];
159 /* Play/Record DMA fifo */
162 u_int32_t psize, rsize; /* DMA buffer size(byte) */
163 u_int16_t blk[2]; /* transfer check blocksize(dword) */
164 bus_dmamap_t pmap, rmap;
170 struct pcmchan_caps caps[2];
172 /* channel info table */
174 struct sc_chinfo chan[11];
177 /* -------------------------------------------------------------------- */
184 static void envy24ht_p8u(struct sc_chinfo *);
185 static void envy24ht_p16sl(struct sc_chinfo *);
186 static void envy24ht_p32sl(struct sc_chinfo *);
187 static void envy24ht_r16sl(struct sc_chinfo *);
188 static void envy24ht_r32sl(struct sc_chinfo *);
190 /* channel interface */
191 static void *envy24htchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
192 static int envy24htchan_setformat(kobj_t, void *, u_int32_t);
193 static u_int32_t envy24htchan_setspeed(kobj_t, void *, u_int32_t);
194 static u_int32_t envy24htchan_setblocksize(kobj_t, void *, u_int32_t);
195 static int envy24htchan_trigger(kobj_t, void *, int);
196 static u_int32_t envy24htchan_getptr(kobj_t, void *);
197 static struct pcmchan_caps *envy24htchan_getcaps(kobj_t, void *);
199 /* mixer interface */
200 static int envy24htmixer_init(struct snd_mixer *);
201 static int envy24htmixer_reinit(struct snd_mixer *);
202 static int envy24htmixer_uninit(struct snd_mixer *);
203 static int envy24htmixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
204 static u_int32_t envy24htmixer_setrecsrc(struct snd_mixer *, u_int32_t);
206 /* SPI codec access interface */
207 static void *envy24ht_spi_create(device_t, void *, int, int);
208 static void envy24ht_spi_destroy(void *);
209 static void envy24ht_spi_init(void *);
210 static void envy24ht_spi_reinit(void *);
211 static void envy24ht_spi_setvolume(void *, int, unsigned int, unsigned int);
213 /* -------------------------------------------------------------------- */
216 system constant tables
219 /* API -> hardware channel map */
220 static unsigned envy24ht_chanmap[ENVY24HT_CHAN_NUM] = {
221 ENVY24HT_CHAN_PLAY_DAC1, /* 1 */
222 ENVY24HT_CHAN_PLAY_DAC2, /* 2 */
223 ENVY24HT_CHAN_PLAY_DAC3, /* 3 */
224 ENVY24HT_CHAN_PLAY_DAC4, /* 4 */
225 ENVY24HT_CHAN_PLAY_SPDIF, /* 0 */
226 ENVY24HT_CHAN_REC_MIX, /* 5 */
227 ENVY24HT_CHAN_REC_SPDIF, /* 6 */
228 ENVY24HT_CHAN_REC_ADC1, /* 7 */
229 ENVY24HT_CHAN_REC_ADC2, /* 8 */
230 ENVY24HT_CHAN_REC_ADC3, /* 9 */
231 ENVY24HT_CHAN_REC_ADC4, /* 10 */
234 /* mixer -> API channel map. see above */
235 static int envy24ht_mixmap[] = {
236 -1, /* Master output level. It is depend on codec support */
237 -1, /* Treble level of all output channels */
238 -1, /* Bass level of all output channels */
239 -1, /* Volume of synthesier input */
240 0, /* Output level for the audio device */
241 -1, /* Output level for the PC speaker */
242 7, /* line in jack */
243 -1, /* microphone jack */
244 -1, /* CD audio input */
245 -1, /* Recording monitor */
246 1, /* alternative codec */
247 -1, /* global recording level */
249 -1, /* Output gain */
250 8, /* Input source 1 */
251 9, /* Input source 2 */
252 10, /* Input source 3 */
253 6, /* Digital (input) 1 */
254 -1, /* Digital (input) 2 */
255 -1, /* Digital (input) 3 */
256 -1, /* Phone input */
257 -1, /* Phone output */
258 -1, /* Video/TV (audio) in */
260 -1, /* Monitor volume */
263 /* variable rate audio */
264 static u_int32_t envy24ht_speed[] = {
265 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
266 12000, 11025, 9600, 8000, 0
269 /* known boards configuration */
270 static struct codec_entry spi_codec = {
272 envy24ht_spi_destroy,
275 envy24ht_spi_setvolume,
279 static struct cfg_info cfg_table[] = {
281 "Envy24HT audio (Terratec Aureon 7.1 Space)",
283 0x0b, 0x80, 0xfc, 0xc3,
284 0x21efff, 0x7fffff, 0x5e1000,
285 0x40000, 0x80000, 0x1000, 0x00, 0x02,
290 "Envy24HT audio (Terratec Aureon 5.1 Sky)",
292 0x0a, 0x80, 0xfc, 0xc3,
293 0x21efff, 0x7fffff, 0x5e1000,
294 0x40000, 0x80000, 0x1000, 0x00, 0x02,
299 "Envy24HT audio (Terratec Aureon 7.1 Universe)",
301 0x0b, 0x80, 0xfc, 0xc3,
302 0x21efff, 0x7fffff, 0x5e1000,
303 0x40000, 0x80000, 0x1000, 0x00, 0x02,
308 "Envy24HT audio (AudioTrak Prodigy 7.1)",
310 0x0b, 0x80, 0xfc, 0xc3,
311 0x21efff, 0x7fffff, 0x5e1000,
312 0x40000, 0x80000, 0x1000, 0x00, 0x02,
317 "Envy24HT audio (Terratec PHASE 28)",
319 0x0b, 0x80, 0xfc, 0xc3,
320 0x21efff, 0x7fffff, 0x5e1000,
321 0x40000, 0x80000, 0x1000, 0x00, 0x02,
326 "Envy24HT-S audio (Terratec PHASE 22)",
328 0x10, 0x80, 0xf0, 0xc3,
329 0x7ffbc7, 0x7fffff, 0x438,
330 0x10, 0x20, 0x400, 0x01, 0x00,
335 "Envy24HT audio (AudioTrak Prodigy 7.1 LT)",
337 0x4b, 0x80, 0xfc, 0xc3,
338 0x7ff8ff, 0x7fffff, 0x700,
339 0x400, 0x200, 0x100, 0x00, 0x02,
344 "Envy24HT audio (AudioTrak Prodigy 7.1 XT)",
346 0x4b, 0x80, 0xfc, 0xc3,
347 0x7ff8ff, 0x7fffff, 0x700,
348 0x400, 0x200, 0x100, 0x00, 0x02,
353 "Envy24HT audio (M-Audio Revolution 7.1)",
355 0x43, 0x80, 0xf8, 0xc1,
356 0x3fff85, 0x400072, 0x4000fa,
357 0x08, 0x02, 0x20, 0x00, 0x04,
362 "Envy24GT audio (M-Audio Revolution 5.1)",
364 0x42, 0x80, 0xf8, 0xc1,
365 0x3fff05, 0x4000f0, 0x4000fa,
366 0x08, 0x02, 0x10, 0x00, 0x03,
371 "Envy24HT audio (M-Audio Audiophile 192)",
373 0x68, 0x80, 0xf8, 0xc3,
374 0x45, 0x4000b5, 0x7fffba,
375 0x08, 0x02, 0x10, 0x00, 0x03,
380 "Envy24HT audio (AudioTrak Prodigy HD2)",
382 0x68, 0x80, 0x78, 0xc3,
383 0xfff8ff, 0x200700, 0xdfffff,
384 0x400, 0x200, 0x100, 0x00, 0x05,
389 "Envy24HT audio (ESI Juli@)",
391 0x20, 0x80, 0xf8, 0xc3,
392 0x7fff9f, 0x8016, 0x7fff9f,
393 0x08, 0x02, 0x10, 0x00, 0x03,
398 "Envy24HT-S audio (Terrasoniq TS22PCI)",
400 0x10, 0x80, 0xf0, 0xc3,
401 0x7ffbc7, 0x7fffff, 0x438,
402 0x10, 0x20, 0x400, 0x01, 0x00,
407 "Envy24HT audio (Generic)",
409 0x0b, 0x80, 0xfc, 0xc3,
410 0x21efff, 0x7fffff, 0x5e1000,
411 0x40000, 0x80000, 0x1000, 0x00, 0x02,
413 &spi_codec, /* default codec routines */
417 static u_int32_t envy24ht_recfmt[] = {
418 SND_FORMAT(AFMT_S16_LE, 2, 0),
419 SND_FORMAT(AFMT_S32_LE, 2, 0),
422 static struct pcmchan_caps envy24ht_reccaps = {8000, 96000, envy24ht_recfmt, 0};
424 static u_int32_t envy24ht_playfmt[] = {
425 SND_FORMAT(AFMT_U8, 2, 0),
426 SND_FORMAT(AFMT_S16_LE, 2, 0),
427 SND_FORMAT(AFMT_S32_LE, 2, 0),
431 static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0};
433 struct envy24ht_emldma {
435 void (*emldma)(struct sc_chinfo *);
439 static struct envy24ht_emldma envy24ht_pemltab[] = {
440 {SND_FORMAT(AFMT_U8, 2, 0), envy24ht_p8u, 2},
441 {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_p16sl, 4},
442 {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_p32sl, 8},
446 static struct envy24ht_emldma envy24ht_remltab[] = {
447 {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_r16sl, 4},
448 {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_r32sl, 8},
452 /* -------------------------------------------------------------------- */
454 /* common routines */
456 envy24ht_rdcs(struct sc_info *sc, int regno, int size)
460 return bus_space_read_1(sc->cst, sc->csh, regno);
462 return bus_space_read_2(sc->cst, sc->csh, regno);
464 return bus_space_read_4(sc->cst, sc->csh, regno);
471 envy24ht_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
475 bus_space_write_1(sc->cst, sc->csh, regno, data);
478 bus_space_write_2(sc->cst, sc->csh, regno, data);
481 bus_space_write_4(sc->cst, sc->csh, regno, data);
487 envy24ht_rdmt(struct sc_info *sc, int regno, int size)
491 return bus_space_read_1(sc->mtt, sc->mth, regno);
493 return bus_space_read_2(sc->mtt, sc->mth, regno);
495 return bus_space_read_4(sc->mtt, sc->mth, regno);
502 envy24ht_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
506 bus_space_write_1(sc->mtt, sc->mth, regno, data);
509 bus_space_write_2(sc->mtt, sc->mth, regno, data);
512 bus_space_write_4(sc->mtt, sc->mth, regno, data);
517 /* -------------------------------------------------------------------- */
519 /* I2C port/E2PROM access routines */
522 envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
528 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
530 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
531 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
532 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
534 DELAY(32); /* 31.25kHz */
536 if (i == ENVY24HT_TIMEOUT) {
539 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
540 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
541 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_RD, 1);
542 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
543 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
544 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
546 DELAY(32); /* 31.25kHz */
548 if (i == ENVY24HT_TIMEOUT) {
551 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CDATA, 1);
554 device_printf(sc->dev, "envy24ht_rdi2c(): return 0x%x\n", data);
560 envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
566 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
568 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
569 tmp = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
570 if ((tmp & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
572 DELAY(32); /* 31.25kHz */
574 if (i == ENVY24HT_TIMEOUT) {
577 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
578 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDATA, data, 1);
579 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
580 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_WR, 1);
581 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
582 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
583 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
585 DELAY(32); /* 31.25kHz */
587 if (i == ENVY24HT_TIMEOUT) {
595 envy24ht_rdrom(struct sc_info *sc, u_int32_t addr)
600 device_printf(sc->dev, "envy24ht_rdrom(sc, 0x%02x)\n", addr);
602 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
603 if ((data & ENVY24HT_CCS_I2CSTAT_ROM) == 0) {
605 device_printf(sc->dev, "envy24ht_rdrom(): E2PROM not presented\n");
610 return envy24ht_rdi2c(sc, ENVY24HT_CCS_I2CDEV_ROM, addr);
613 static struct cfg_info *
614 envy24ht_rom2cfg(struct sc_info *sc)
616 struct cfg_info *buff;
621 device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n");
623 size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE);
624 if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) {
626 device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size);
628 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
631 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
637 /* no valid e2prom, using default values */
638 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
639 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
640 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
641 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
646 buff->gpiomask = 0x21efff;
647 buff->gpiostate = 0x7fffff;
648 buff->gpiodir = 0x5e1000;
649 buff->cdti = 0x40000;
650 buff->cclk = 0x80000;
655 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0;
657 if (cfg_table[i].subvendor == buff->subvendor &&
658 cfg_table[i].subdevice == buff->subdevice)
660 buff->name = cfg_table[i].name;
661 buff->codec = cfg_table[i].codec;
668 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
671 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
677 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
678 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
679 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
680 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
681 buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG);
682 buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL);
683 buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S);
684 buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF);
685 buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \
686 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \
687 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16;
688 buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \
689 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \
690 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16;
691 buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \
692 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \
693 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16;
695 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
696 if (cfg_table[i].subvendor == buff->subvendor &&
697 cfg_table[i].subdevice == buff->subdevice)
699 buff->name = cfg_table[i].name;
700 buff->codec = cfg_table[i].codec;
706 envy24ht_cfgfree(struct cfg_info *cfg) {
710 free(cfg, M_ENVY24HT);
714 /* -------------------------------------------------------------------- */
716 /* AC'97 codec access routines */
720 envy24ht_coldcd(struct sc_info *sc)
726 device_printf(sc->dev, "envy24ht_coldcd()\n");
728 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1);
730 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
732 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
733 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
734 if (data & ENVY24HT_MT_AC97CMD_RDY) {
743 envy24ht_slavecd(struct sc_info *sc)
749 device_printf(sc->dev, "envy24ht_slavecd()\n");
751 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD,
752 ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1);
754 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
756 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
757 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
758 if (data & ENVY24HT_MT_AC97CMD_RDY) {
767 envy24ht_rdcd(kobj_t obj, void *devinfo, int regno)
769 struct sc_info *sc = (struct sc_info *)devinfo;
774 device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno);
776 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
777 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1);
778 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
779 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
780 if ((data & ENVY24HT_MT_AC97CMD_RD) == 0)
783 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2);
786 device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data);
792 envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
794 struct sc_info *sc = (struct sc_info *)devinfo;
799 device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
801 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
802 envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2);
803 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1);
804 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
805 cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
806 if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0)
813 static kobj_method_t envy24ht_ac97_methods[] = {
814 KOBJMETHOD(ac97_read, envy24ht_rdcd),
815 KOBJMETHOD(ac97_write, envy24ht_wrcd),
818 AC97_DECLARE(envy24ht_ac97);
821 /* -------------------------------------------------------------------- */
823 /* GPIO access routines */
826 envy24ht_gpiord(struct sc_info *sc)
828 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
829 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2);
831 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2));
835 envy24ht_gpiowr(struct sc_info *sc, u_int32_t data)
838 device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF);
841 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2);
842 if (sc->cfg->subdevice != 0x1150)
843 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1);
849 envy24ht_gpiogetmask(struct sc_info *sc)
851 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2));
856 envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask)
858 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2);
859 if (sc->cfg->subdevice != 0x1150)
860 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1);
866 envy24ht_gpiogetdir(struct sc_info *sc)
868 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4);
873 envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir)
875 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
876 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2);
878 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4);
882 /* -------------------------------------------------------------------- */
884 /* SPI codec access interface routine */
886 struct envy24ht_spi_codec {
887 struct spicds_info *info;
888 struct sc_info *parent;
895 envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
898 struct envy24ht_spi_codec *ptr = codec;
901 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
903 data = envy24ht_gpiord(ptr->parent);
904 data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
905 if (cs) data += ptr->cs;
906 if (cclk) data += ptr->cclk;
907 if (cdti) data += ptr->cdti;
908 envy24ht_gpiowr(ptr->parent, data);
913 envy24ht_spi_create(device_t dev, void *info, int dir, int num)
915 struct sc_info *sc = info;
916 struct envy24ht_spi_codec *buff = NULL;
919 device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num);
922 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
926 if (dir == PCMDIR_REC && sc->adc[num] != NULL)
927 buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info;
928 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
929 buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info;
931 buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl);
932 if (buff->info == NULL) {
933 free(buff, M_ENVY24HT);
945 envy24ht_spi_destroy(void *codec)
947 struct envy24ht_spi_codec *ptr = codec;
951 device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n");
954 if (ptr->dir == PCMDIR_PLAY) {
955 if (ptr->parent->dac[ptr->num] != NULL)
956 spicds_destroy(ptr->info);
959 if (ptr->parent->adc[ptr->num] != NULL)
960 spicds_destroy(ptr->info);
963 free(codec, M_ENVY24HT);
967 envy24ht_spi_init(void *codec)
969 struct envy24ht_spi_codec *ptr = codec;
973 device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n");
975 ptr->cs = ptr->parent->cfg->cs;
976 ptr->cclk = ptr->parent->cfg->cclk;
977 ptr->cdti = ptr->parent->cfg->cdti;
978 spicds_settype(ptr->info, ptr->parent->cfg->type);
979 spicds_setcif(ptr->info, ptr->parent->cfg->cif);
980 if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \
981 ptr->parent->cfg->type == SPICDS_TYPE_AK4528) {
982 spicds_setformat(ptr->info,
983 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
984 spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
987 /* for the time being, init only first codec */
989 spicds_init(ptr->info);
993 envy24ht_spi_reinit(void *codec)
995 struct envy24ht_spi_codec *ptr = codec;
999 device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n");
1002 spicds_reinit(ptr->info);
1006 envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
1008 struct envy24ht_spi_codec *ptr = codec;
1012 device_printf(ptr->parent->dev, "envy24ht_spi_set()\n");
1015 spicds_set(ptr->info, dir, left, right);
1018 /* -------------------------------------------------------------------- */
1020 /* hardware access routeines */
1025 } envy24ht_speedtab[] = {
1026 {48000, ENVY24HT_MT_RATE_48000},
1027 {24000, ENVY24HT_MT_RATE_24000},
1028 {12000, ENVY24HT_MT_RATE_12000},
1029 {9600, ENVY24HT_MT_RATE_9600},
1030 {32000, ENVY24HT_MT_RATE_32000},
1031 {16000, ENVY24HT_MT_RATE_16000},
1032 {8000, ENVY24HT_MT_RATE_8000},
1033 {96000, ENVY24HT_MT_RATE_96000},
1034 {192000, ENVY24HT_MT_RATE_192000},
1035 {64000, ENVY24HT_MT_RATE_64000},
1036 {44100, ENVY24HT_MT_RATE_44100},
1037 {22050, ENVY24HT_MT_RATE_22050},
1038 {11025, ENVY24HT_MT_RATE_11025},
1039 {88200, ENVY24HT_MT_RATE_88200},
1040 {176400, ENVY24HT_MT_RATE_176400},
1045 envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) {
1046 u_int32_t code, i2sfmt;
1050 device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed);
1052 code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */
1053 envy24ht_slavecd(sc);
1057 for (i = 0; envy24ht_speedtab[i].speed != 0; i++) {
1058 if (envy24ht_speedtab[i].speed == speed)
1061 code = envy24ht_speedtab[i].code;
1064 device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code);
1067 envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1);
1068 if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \
1069 (code == ENVY24HT_MT_RATE_176400)) {
1070 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1071 i2sfmt |= ENVY24HT_MT_I2S_MLR128;
1072 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1075 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1076 i2sfmt &= ~ENVY24HT_MT_I2S_MLR128;
1077 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1079 code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1);
1080 code &= ENVY24HT_MT_RATE_MASK;
1081 for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) {
1082 if (envy24ht_speedtab[i].code == code)
1085 speed = envy24ht_speedtab[i].speed;
1091 device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed);
1097 envy24ht_setvolume(struct sc_info *sc, unsigned ch)
1100 device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch);
1101 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1102 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1103 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1104 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1109 envy24ht_mutevolume(struct sc_info *sc, unsigned ch)
1114 device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch);
1115 vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE;
1116 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1117 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1118 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1119 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1124 envy24ht_gethwptr(struct sc_info *sc, int dir)
1130 device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir);
1132 if (dir == PCMDIR_PLAY) {
1133 rtn = sc->psize / 4;
1134 unit = ENVY24HT_PLAY_BUFUNIT / 4;
1135 regno = ENVY24HT_MT_PCNT;
1138 rtn = sc->rsize / 4;
1139 unit = ENVY24HT_REC_BUFUNIT / 4;
1140 regno = ENVY24HT_MT_RCNT;
1143 ptr = envy24ht_rdmt(sc, regno, 2);
1148 device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn);
1154 envy24ht_updintr(struct sc_info *sc, int dir)
1156 int regptr, regintr;
1157 u_int32_t mask, intr;
1158 u_int32_t ptr, size, cnt;
1162 device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir);
1164 if (dir == PCMDIR_PLAY) {
1166 size = sc->psize / 4;
1167 regptr = ENVY24HT_MT_PCNT;
1168 regintr = ENVY24HT_MT_PTERM;
1169 mask = ~ENVY24HT_MT_INT_PMASK;
1173 size = sc->rsize / 4;
1174 regptr = ENVY24HT_MT_RCNT;
1175 regintr = ENVY24HT_MT_RTERM;
1176 mask = ~ENVY24HT_MT_INT_RMASK;
1179 ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1;
1181 cnt = blk - ptr % blk - 1;
1187 device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1189 envy24ht_wrmt(sc, regintr, cnt, 2);
1190 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1192 device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1194 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
1196 device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
1197 envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
1205 envy24ht_maskintr(struct sc_info *sc, int dir)
1207 u_int32_t mask, intr;
1210 device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
1212 if (dir == PCMDIR_PLAY)
1213 mask = ENVY24HT_MT_INT_PMASK;
1215 mask = ENVY24HT_MT_INT_RMASK;
1216 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
1217 envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
1224 envy24ht_checkintr(struct sc_info *sc, int dir)
1226 u_int32_t mask, stat, intr, rtn;
1229 device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
1231 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
1232 if (dir == PCMDIR_PLAY) {
1233 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
1234 mask = ~ENVY24HT_MT_INT_RSTAT;
1235 envy24ht_wrmt(sc, 0x1a, 0x01, 1);
1236 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);
1237 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1238 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
1242 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
1243 mask = ~ENVY24HT_MT_INT_PSTAT;
1245 stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
1247 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
1248 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1249 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
1257 envy24ht_start(struct sc_info *sc, int dir)
1262 device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
1264 if (dir == PCMDIR_PLAY)
1265 sw = ENVY24HT_MT_PCTL_PSTART;
1267 sw = ENVY24HT_MT_PCTL_RSTART;
1269 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1270 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
1273 device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
1274 device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
1281 envy24ht_stop(struct sc_info *sc, int dir)
1286 device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir);
1288 if (dir == PCMDIR_PLAY)
1289 sw = ~ENVY24HT_MT_PCTL_PSTART;
1291 sw = ~ENVY24HT_MT_PCTL_RSTART;
1293 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1294 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1);
1301 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1307 /* -------------------------------------------------------------------- */
1309 /* buffer copy routines */
1311 envy24ht_p32sl(struct sc_chinfo *ch)
1316 int src, dst, ssize, dsize, slot;
1319 length = sndbuf_getready(ch->buffer) / 8;
1320 dmabuf = ch->parent->pbuf;
1321 data = (u_int32_t *)ch->data;
1322 src = sndbuf_getreadyptr(ch->buffer) / 4;
1323 dst = src / 2 + ch->offset;
1324 ssize = ch->size / 4;
1325 dsize = ch->size / 8;
1328 for (i = 0; i < length; i++) {
1329 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
1330 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1341 envy24ht_p16sl(struct sc_chinfo *ch)
1346 int src, dst, ssize, dsize, slot;
1350 device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
1352 length = sndbuf_getready(ch->buffer) / 4;
1353 dmabuf = ch->parent->pbuf;
1354 data = (u_int16_t *)ch->data;
1355 src = sndbuf_getreadyptr(ch->buffer) / 2;
1356 dst = src / 2 + ch->offset;
1357 ssize = ch->size / 2;
1358 dsize = ch->size / 4;
1361 device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1364 for (i = 0; i < length; i++) {
1365 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1366 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1369 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
1370 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
1386 envy24ht_p8u(struct sc_chinfo *ch)
1391 int src, dst, ssize, dsize, slot;
1394 length = sndbuf_getready(ch->buffer) / 2;
1395 dmabuf = ch->parent->pbuf;
1396 data = (u_int8_t *)ch->data;
1397 src = sndbuf_getreadyptr(ch->buffer);
1398 dst = src / 2 + ch->offset;
1400 dsize = ch->size / 4;
1403 for (i = 0; i < length; i++) {
1404 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1405 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1416 envy24ht_r32sl(struct sc_chinfo *ch)
1421 int src, dst, ssize, dsize, slot;
1424 length = sndbuf_getfree(ch->buffer) / 8;
1425 dmabuf = ch->parent->rbuf;
1426 data = (u_int32_t *)ch->data;
1427 dst = sndbuf_getfreeptr(ch->buffer) / 4;
1428 src = dst / 2 + ch->offset;
1429 dsize = ch->size / 4;
1430 ssize = ch->size / 8;
1431 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1433 for (i = 0; i < length; i++) {
1434 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1435 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1446 envy24ht_r16sl(struct sc_chinfo *ch)
1451 int src, dst, ssize, dsize, slot;
1454 length = sndbuf_getfree(ch->buffer) / 4;
1455 dmabuf = ch->parent->rbuf;
1456 data = (u_int16_t *)ch->data;
1457 dst = sndbuf_getfreeptr(ch->buffer) / 2;
1458 src = dst / 2 + ch->offset;
1459 dsize = ch->size / 2;
1460 ssize = ch->size / 8;
1461 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1463 for (i = 0; i < length; i++) {
1464 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1465 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1475 /* -------------------------------------------------------------------- */
1477 /* channel interface */
1479 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1481 struct sc_info *sc = (struct sc_info *)devinfo;
1482 struct sc_chinfo *ch;
1486 device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
1488 snd_mtxlock(sc->lock);
1490 if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1491 (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1492 snd_mtxunlock(sc->lock);
1498 ch = &sc->chan[num];
1499 ch->size = 8 * ENVY24HT_SAMPLE_NUM;
1500 ch->data = malloc(ch->size, M_ENVY24HT, M_NOWAIT);
1501 if (ch->data == NULL) {
1510 /* set channel map */
1511 ch->num = envy24ht_chanmap[num];
1512 snd_mtxunlock(sc->lock);
1513 sndbuf_setup(ch->buffer, ch->data, ch->size);
1514 snd_mtxlock(sc->lock);
1515 /* these 2 values are dummy */
1519 snd_mtxunlock(sc->lock);
1525 envy24htchan_free(kobj_t obj, void *data)
1527 struct sc_chinfo *ch = data;
1528 struct sc_info *sc = ch->parent;
1531 device_printf(sc->dev, "envy24htchan_free()\n");
1533 snd_mtxlock(sc->lock);
1534 if (ch->data != NULL) {
1535 free(ch->data, M_ENVY24HT);
1538 snd_mtxunlock(sc->lock);
1544 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
1546 struct sc_chinfo *ch = data;
1547 struct sc_info *sc = ch->parent;
1548 struct envy24ht_emldma *emltab;
1549 /* unsigned int bcnt, bsize; */
1553 device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
1555 snd_mtxlock(sc->lock);
1556 /* check and get format related information */
1557 if (ch->dir == PCMDIR_PLAY)
1558 emltab = envy24ht_pemltab;
1560 emltab = envy24ht_remltab;
1561 if (emltab == NULL) {
1562 snd_mtxunlock(sc->lock);
1565 for (i = 0; emltab[i].format != 0; i++)
1566 if (emltab[i].format == format)
1568 if (emltab[i].format == 0) {
1569 snd_mtxunlock(sc->lock);
1573 /* set format information */
1574 ch->format = format;
1575 ch->emldma = emltab[i].emldma;
1576 if (ch->unit > emltab[i].unit)
1577 ch->blk *= ch->unit / emltab[i].unit;
1579 ch->blk /= emltab[i].unit / ch->unit;
1580 ch->unit = emltab[i].unit;
1582 /* set channel buffer information */
1583 ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
1585 if (ch->dir == PCMDIR_PLAY)
1586 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1588 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1590 bcnt = ch->size / bsize;
1591 sndbuf_resize(ch->buffer, bcnt, bsize);
1593 snd_mtxunlock(sc->lock);
1596 device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
1602 IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1603 of speed information value. And real hardware speed setting is done
1604 at start triggered(see envy24htchan_trigger()). So, at this function
1605 is called, any value that ENVY24 can use is able to set. But, at
1606 start triggerd, some other channel is running, and that channel's
1607 speed isn't same with, then trigger function will fail.
1610 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1612 struct sc_chinfo *ch = data;
1613 u_int32_t val, prev;
1617 device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
1620 for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
1621 if (abs(val - speed) < abs(prev - speed))
1629 device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
1635 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1637 struct sc_chinfo *ch = data;
1638 /* struct sc_info *sc = ch->parent; */
1639 u_int32_t size, prev;
1640 unsigned int bcnt, bsize;
1643 device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
1646 /* snd_mtxlock(sc->lock); */
1647 for (size = ch->size / 2; size > 0; size /= 2) {
1648 if (abs(size - blocksize) < abs(prev - blocksize))
1654 ch->blk = prev / ch->unit;
1655 if (ch->dir == PCMDIR_PLAY)
1656 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
1658 ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
1659 /* set channel buffer information */
1660 /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
1661 if (ch->dir == PCMDIR_PLAY)
1662 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1664 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1666 bcnt = ch->size / bsize;
1667 sndbuf_resize(ch->buffer, bcnt, bsize);
1668 /* snd_mtxunlock(sc->lock); */
1671 device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
1676 /* semantic note: must start at beginning of buffer */
1678 envy24htchan_trigger(kobj_t obj, void *data, int go)
1680 struct sc_chinfo *ch = data;
1681 struct sc_info *sc = ch->parent;
1688 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1690 snd_mtxlock(sc->lock);
1691 if (ch->dir == PCMDIR_PLAY)
1698 device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1700 /* check or set channel speed */
1701 if (sc->run[0] == 0 && sc->run[1] == 0) {
1702 sc->speed = envy24ht_setspeed(sc, ch->speed);
1703 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1704 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1706 else if (ch->speed != 0 && ch->speed != sc->speed) {
1711 ch->channel->speed = sc->speed;
1712 /* start or enable channel */
1714 if (sc->run[slot] == 1) {
1717 sc->blk[slot] = ch->blk;
1720 ptr = envy24ht_gethwptr(sc, ch->dir);
1721 ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1722 (ch->size / 4)) * 4 / ch->unit;
1723 if (ch->blk < sc->blk[slot])
1724 sc->blk[slot] = ch->blk;
1726 if (ch->dir == PCMDIR_PLAY) {
1728 envy24ht_setvolume(sc, ch->num);
1730 envy24ht_updintr(sc, ch->dir);
1731 if (sc->run[slot] == 1)
1732 envy24ht_start(sc, ch->dir);
1735 case PCMTRIG_EMLDMAWR:
1737 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1745 case PCMTRIG_EMLDMARD:
1747 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1758 device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1762 if (ch->dir == PCMDIR_PLAY)
1763 envy24ht_mutevolume(sc, ch->num);
1764 if (sc->run[slot] == 0) {
1765 envy24ht_stop(sc, ch->dir);
1768 /* else if (ch->blk == sc->blk[slot]) {
1769 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1770 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1771 if (sc->chan[i].dir == ch->dir &&
1772 sc->chan[i].run == 1 &&
1773 sc->chan[i].blk < sc->blk[slot])
1774 sc->blk[slot] = sc->chan[i].blk;
1776 if (ch->blk != sc->blk[slot])
1777 envy24ht_updintr(sc, ch->dir);
1783 snd_mtxunlock(sc->lock);
1788 envy24htchan_getptr(kobj_t obj, void *data)
1790 struct sc_chinfo *ch = data;
1791 struct sc_info *sc = ch->parent;
1795 device_printf(sc->dev, "envy24htchan_getptr()\n");
1797 snd_mtxlock(sc->lock);
1798 ptr = envy24ht_gethwptr(sc, ch->dir);
1799 rtn = ptr * ch->unit;
1800 snd_mtxunlock(sc->lock);
1803 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1809 static struct pcmchan_caps *
1810 envy24htchan_getcaps(kobj_t obj, void *data)
1812 struct sc_chinfo *ch = data;
1813 struct sc_info *sc = ch->parent;
1814 struct pcmchan_caps *rtn;
1817 device_printf(sc->dev, "envy24htchan_getcaps()\n");
1819 snd_mtxlock(sc->lock);
1820 if (ch->dir == PCMDIR_PLAY) {
1821 if (sc->run[0] == 0)
1822 rtn = &envy24ht_playcaps;
1827 if (sc->run[1] == 0)
1828 rtn = &envy24ht_reccaps;
1832 snd_mtxunlock(sc->lock);
1837 static kobj_method_t envy24htchan_methods[] = {
1838 KOBJMETHOD(channel_init, envy24htchan_init),
1839 KOBJMETHOD(channel_free, envy24htchan_free),
1840 KOBJMETHOD(channel_setformat, envy24htchan_setformat),
1841 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed),
1842 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize),
1843 KOBJMETHOD(channel_trigger, envy24htchan_trigger),
1844 KOBJMETHOD(channel_getptr, envy24htchan_getptr),
1845 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps),
1848 CHANNEL_DECLARE(envy24htchan);
1850 /* -------------------------------------------------------------------- */
1852 /* mixer interface */
1855 envy24htmixer_init(struct snd_mixer *m)
1857 struct sc_info *sc = mix_getdevinfo(m);
1860 device_printf(sc->dev, "envy24htmixer_init()\n");
1865 /* set volume control rate */
1866 snd_mtxlock(sc->lock);
1868 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1871 pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1873 mix_setdevs(m, ENVY24HT_MIX_MASK);
1874 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1876 snd_mtxunlock(sc->lock);
1882 envy24htmixer_reinit(struct snd_mixer *m)
1884 struct sc_info *sc = mix_getdevinfo(m);
1889 device_printf(sc->dev, "envy24htmixer_reinit()\n");
1896 envy24htmixer_uninit(struct snd_mixer *m)
1898 struct sc_info *sc = mix_getdevinfo(m);
1903 device_printf(sc->dev, "envy24htmixer_uninit()\n");
1910 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1912 struct sc_info *sc = mix_getdevinfo(m);
1913 int ch = envy24ht_mixmap[dev];
1919 if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1921 if (dev != 0 && ch == -1)
1923 hwch = envy24ht_chanmap[ch];
1925 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1929 snd_mtxlock(sc->lock);
1931 for (i = 0; i < sc->dacn; i++) {
1932 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1936 /* set volume value for hardware */
1937 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1938 sc->left[hwch] = ENVY24HT_VOL_MUTE;
1939 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1940 sc->right[hwch] = ENVY24HT_VOL_MUTE;
1942 /* set volume for record channel and running play channel */
1943 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1944 envy24ht_setvolume(sc, hwch);
1946 snd_mtxunlock(sc->lock);
1948 return right << 8 | left;
1952 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1954 struct sc_info *sc = mix_getdevinfo(m);
1955 int ch = envy24ht_mixmap[src];
1957 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1960 if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1965 static kobj_method_t envy24htmixer_methods[] = {
1966 KOBJMETHOD(mixer_init, envy24htmixer_init),
1967 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit),
1968 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit),
1969 KOBJMETHOD(mixer_set, envy24htmixer_set),
1970 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc),
1973 MIXER_DECLARE(envy24htmixer);
1975 /* -------------------------------------------------------------------- */
1977 /* The interrupt handler */
1979 envy24ht_intr(void *p)
1981 struct sc_info *sc = (struct sc_info *)p;
1982 struct sc_chinfo *ch;
1983 u_int32_t ptr, dsize, feed;
1987 device_printf(sc->dev, "envy24ht_intr()\n");
1989 snd_mtxlock(sc->lock);
1990 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1992 device_printf(sc->dev, "envy24ht_intr(): play\n");
1994 dsize = sc->psize / 4;
1995 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
1997 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
1999 ptr -= ptr % sc->blk[0];
2000 feed = (ptr + dsize - sc->intr[0]) % dsize;
2002 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2004 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
2008 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
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_PLAY);
2019 if (envy24ht_checkintr(sc, PCMDIR_REC)) {
2021 device_printf(sc->dev, "envy24ht_intr(): rec\n");
2023 dsize = sc->rsize / 4;
2024 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
2025 ptr -= ptr % sc->blk[1];
2026 feed = (ptr + dsize - sc->intr[1]) % dsize;
2027 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
2029 if (ch->run && ch->blk <= feed) {
2030 snd_mtxunlock(sc->lock);
2031 chn_intr(ch->channel);
2032 snd_mtxlock(sc->lock);
2036 envy24ht_updintr(sc, PCMDIR_REC);
2038 snd_mtxunlock(sc->lock);
2044 * Probe and attach the card
2048 envy24ht_pci_probe(device_t dev)
2054 printf("envy24ht_pci_probe()\n");
2056 if (pci_get_device(dev) == PCID_ENVY24HT &&
2057 pci_get_vendor(dev) == PCIV_ENVY24) {
2058 sv = pci_get_subvendor(dev);
2059 sd = pci_get_subdevice(dev);
2060 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2061 if (cfg_table[i].subvendor == sv &&
2062 cfg_table[i].subdevice == sd) {
2066 device_set_desc(dev, cfg_table[i].name);
2068 printf("envy24ht_pci_probe(): return 0\n");
2074 printf("envy24ht_pci_probe(): return ENXIO\n");
2081 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2083 /* struct sc_info *sc = (struct sc_info *)arg; */
2086 device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2088 printf("envy24ht(play): setmap %lx, %lx; ",
2089 (unsigned long)segs->ds_addr,
2090 (unsigned long)segs->ds_len);
2091 printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2097 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2099 /* struct sc_info *sc = (struct sc_info *)arg; */
2102 device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2104 printf("envy24ht(record): setmap %lx, %lx; ",
2105 (unsigned long)segs->ds_addr,
2106 (unsigned long)segs->ds_len);
2107 printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2113 envy24ht_dmafree(struct sc_info *sc)
2116 device_printf(sc->dev, "envy24ht_dmafree():");
2117 if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2118 else printf(" sc->rmap(null)");
2119 if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2120 else printf(" sc->pmap(null)");
2121 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2122 else printf(" sc->rbuf(null)");
2123 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2124 else printf(" sc->pbuf(null)\n");
2128 bus_dmamap_unload(sc->dmat, sc->rmap);
2130 bus_dmamap_unload(sc->dmat, sc->pmap);
2132 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2134 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2136 bus_dmamap_unload(sc->dmat, sc->rmap);
2137 bus_dmamap_unload(sc->dmat, sc->pmap);
2138 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2139 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2142 sc->rmap = sc->pmap = NULL;
2150 envy24ht_dmainit(struct sc_info *sc)
2155 device_printf(sc->dev, "envy24ht_dmainit()\n");
2158 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2159 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2162 sc->pmap = sc->rmap = NULL;
2163 sc->blk[0] = sc->blk[1] = 0;
2165 /* allocate DMA buffer */
2167 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2169 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2172 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2174 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2177 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2179 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, 0))
2182 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2184 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, 0))
2186 bzero(sc->pbuf, sc->psize);
2187 bzero(sc->rbuf, sc->rsize);
2189 /* set values to register */
2190 addr = vtophys(sc->pbuf);
2192 device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2194 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, addr, 4);
2196 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
2197 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2199 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, sc->psize / 4 - 1, 2);
2201 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
2203 addr = vtophys(sc->rbuf);
2204 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, addr, 4);
2205 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, sc->rsize / 4 - 1, 2);
2209 envy24ht_dmafree(sc);
2214 envy24ht_putcfg(struct sc_info *sc)
2216 device_printf(sc->dev, "system configuration\n");
2217 printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2218 sc->cfg->subvendor, sc->cfg->subdevice);
2219 printf(" XIN2 Clock Source: ");
2220 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2222 printf("24.576MHz(96kHz*256)\n");
2225 printf("49.152MHz(192kHz*256)\n");
2228 printf("reserved\n");
2231 printf("illeagal system setting\n");
2233 printf(" MPU-401 UART(s) #: ");
2234 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2237 printf("not implemented\n");
2242 printf("%d\n", sc->adcn);
2247 printf(" and SPDIF receiver connected\n");
2250 printf(" no physical inputs\n");
2253 printf("%d\n", sc->dacn);
2254 printf(" Multi-track converter type: ");
2255 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2256 printf("AC'97(SDATA_OUT:");
2257 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2265 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2266 printf("with volume, ");
2267 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2268 printf("192KHz support, ");
2270 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2271 printf("192KHz support, ");
2273 printf("48KHz support, ");
2274 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2275 case ENVY24HT_CCSM_I2S_16BIT:
2276 printf("16bit resolution, ");
2278 case ENVY24HT_CCSM_I2S_18BIT:
2279 printf("18bit resolution, ");
2281 case ENVY24HT_CCSM_I2S_20BIT:
2282 printf("20bit resolution, ");
2284 case ENVY24HT_CCSM_I2S_24BIT:
2285 printf("24bit resolution, ");
2288 printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2290 printf(" S/PDIF(IN/OUT): ");
2291 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2295 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2299 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2300 printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2301 printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2302 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2306 envy24ht_init(struct sc_info *sc)
2317 device_printf(sc->dev, "envy24ht_init()\n");
2322 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2324 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2327 /* legacy hardware disable */
2328 data = pci_read_config(sc->dev, PCIR_LAC, 2);
2329 data |= PCIM_LAC_DISABLE;
2330 pci_write_config(sc->dev, PCIR_LAC, data, 2);
2333 /* check system configuration */
2335 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2336 /* 1st: search configuration from table */
2337 sv = pci_get_subvendor(sc->dev);
2338 sd = pci_get_subdevice(sc->dev);
2339 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2341 device_printf(sc->dev, "Set configuration from table\n");
2343 sc->cfg = &cfg_table[i];
2347 if (sc->cfg == NULL) {
2348 /* 2nd: read configuration from table */
2349 sc->cfg = envy24ht_rom2cfg(sc);
2351 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2352 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2354 if (1 /* bootverbose */) {
2355 envy24ht_putcfg(sc);
2358 /* set system configuration */
2359 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2360 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2361 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2362 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2363 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2364 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2365 envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2367 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2368 envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2369 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2370 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2373 for (i = 0; i < sc->adcn; i++) {
2374 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2375 sc->cfg->codec->init(sc->adc[i]);
2377 for (i = 0; i < sc->dacn; i++) {
2378 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2379 sc->cfg->codec->init(sc->dac[i]);
2382 /* initialize DMA buffer */
2384 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2386 if (envy24ht_dmainit(sc))
2389 /* initialize status */
2390 sc->run[0] = sc->run[1] = 0;
2391 sc->intr[0] = sc->intr[1] = 0;
2393 sc->caps[0].fmtlist = envy24ht_playfmt;
2394 sc->caps[1].fmtlist = envy24ht_recfmt;
2396 /* set channel router */
2398 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2399 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2400 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2403 /* set macro interrupt mask */
2404 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2405 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2406 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2408 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2415 envy24ht_alloc_resource(struct sc_info *sc)
2417 /* allocate I/O port resource */
2418 sc->csid = PCIR_CCS;
2419 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2420 &sc->csid, 0, ~0, 1, RF_ACTIVE);
2421 sc->mtid = ENVY24HT_PCIR_MT;
2422 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2423 &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2424 if (!sc->cs || !sc->mt) {
2425 device_printf(sc->dev, "unable to map IO port space\n");
2428 sc->cst = rman_get_bustag(sc->cs);
2429 sc->csh = rman_get_bushandle(sc->cs);
2430 sc->mtt = rman_get_bustag(sc->mt);
2431 sc->mth = rman_get_bushandle(sc->mt);
2433 device_printf(sc->dev,
2434 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2435 pci_read_config(sc->dev, PCIR_CCS, 4),
2436 pci_read_config(sc->dev, PCIR_MT, 4));
2439 /* allocate interrupt resource */
2441 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2442 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2444 snd_setup_intr(sc->dev, sc->irq, 0, envy24ht_intr, sc, &sc->ih)) {
2445 device_printf(sc->dev, "unable to map interrupt\n");
2449 /* allocate DMA resource */
2450 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2453 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2454 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2455 /*filter*/NULL, /*filterarg*/NULL,
2456 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2457 /*nsegments*/1, /*maxsegsz*/0x3ffff,
2458 /*flags*/0, /*lockfunc*/busdma_lock_mutex,
2459 /*lockarg*/&Giant, &sc->dmat) != 0) {
2460 device_printf(sc->dev, "unable to create dma tag\n");
2468 envy24ht_pci_attach(device_t dev)
2472 char status[SND_STATUSLEN];
2477 device_printf(dev, "envy24ht_pci_attach()\n");
2479 /* get sc_info data area */
2480 if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) {
2481 device_printf(dev, "cannot allocate softc\n");
2485 bzero(sc, sizeof(*sc));
2486 sc->lock = snd_mtxcreate(device_get_nameunit(dev),
2487 "snd_envy24ht softc");
2490 /* initialize PCI interface */
2491 data = pci_read_config(dev, PCIR_COMMAND, 2);
2492 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2493 pci_write_config(dev, PCIR_COMMAND, data, 2);
2494 data = pci_read_config(dev, PCIR_COMMAND, 2);
2496 /* allocate resources */
2497 err = envy24ht_alloc_resource(sc);
2499 device_printf(dev, "unable to allocate system resources\n");
2503 /* initialize card */
2504 err = envy24ht_init(sc);
2506 device_printf(dev, "unable to initialize the card\n");
2510 /* set multi track mixer */
2511 mixer_init(dev, &envy24htmixer_class, sc);
2513 /* set channel information */
2514 /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
2515 err = pcm_register(dev, sc, 1, 2 + sc->adcn);
2519 /* for (i = 0; i < 5; i++) { */
2520 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
2523 for (i = 0; i < 2 + sc->adcn; i++) {
2524 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
2528 /* set status iformation */
2529 snprintf(status, SND_STATUSLEN,
2530 "at io 0x%lx:%ld,0x%lx:%ld irq %ld",
2531 rman_get_start(sc->cs),
2532 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2533 rman_get_start(sc->mt),
2534 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2535 rman_get_start(sc->irq));
2536 pcm_setstatus(dev, status);
2542 bus_teardown_intr(dev, sc->irq, sc->ih);
2544 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2545 envy24ht_dmafree(sc);
2547 bus_dma_tag_destroy(sc->dmat);
2548 if (sc->cfg->codec->destroy != NULL) {
2549 for (i = 0; i < sc->adcn; i++)
2550 sc->cfg->codec->destroy(sc->adc[i]);
2551 for (i = 0; i < sc->dacn; i++)
2552 sc->cfg->codec->destroy(sc->dac[i]);
2554 envy24ht_cfgfree(sc->cfg);
2556 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2558 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2560 snd_mtxfree(sc->lock);
2561 free(sc, M_ENVY24HT);
2566 envy24ht_pci_detach(device_t dev)
2573 device_printf(dev, "envy24ht_pci_detach()\n");
2575 sc = pcm_getdevinfo(dev);
2578 r = pcm_unregister(dev);
2582 envy24ht_dmafree(sc);
2583 if (sc->cfg->codec->destroy != NULL) {
2584 for (i = 0; i < sc->adcn; i++)
2585 sc->cfg->codec->destroy(sc->adc[i]);
2586 for (i = 0; i < sc->dacn; i++)
2587 sc->cfg->codec->destroy(sc->dac[i]);
2589 envy24ht_cfgfree(sc->cfg);
2590 bus_dma_tag_destroy(sc->dmat);
2591 bus_teardown_intr(dev, sc->irq, sc->ih);
2592 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2593 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2594 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2595 snd_mtxfree(sc->lock);
2596 free(sc, M_ENVY24HT);
2600 static device_method_t envy24ht_methods[] = {
2601 /* Device interface */
2602 DEVMETHOD(device_probe, envy24ht_pci_probe),
2603 DEVMETHOD(device_attach, envy24ht_pci_attach),
2604 DEVMETHOD(device_detach, envy24ht_pci_detach),
2608 static driver_t envy24ht_driver = {
2611 #if __FreeBSD_version > 500000
2614 sizeof(struct snddev_info),
2618 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0);
2619 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2620 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2621 MODULE_VERSION(snd_envy24ht, 1);