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 <bus/pci/pcireg.h>
50 #include <bus/pci/pcivar.h>
54 SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/envy24ht.c 274035 2014-11-03 11:11:45Z bapt $");
56 static 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;
165 bus_addr_t paddr, raddr;
171 struct pcmchan_caps caps[2];
173 /* channel info table */
175 struct sc_chinfo chan[11];
178 /* -------------------------------------------------------------------- */
185 static void envy24ht_p8u(struct sc_chinfo *);
186 static void envy24ht_p16sl(struct sc_chinfo *);
187 static void envy24ht_p32sl(struct sc_chinfo *);
188 static void envy24ht_r16sl(struct sc_chinfo *);
189 static void envy24ht_r32sl(struct sc_chinfo *);
191 /* channel interface */
192 static void *envy24htchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
193 static int envy24htchan_setformat(kobj_t, void *, u_int32_t);
194 static u_int32_t envy24htchan_setspeed(kobj_t, void *, u_int32_t);
195 static u_int32_t envy24htchan_setblocksize(kobj_t, void *, u_int32_t);
196 static int envy24htchan_trigger(kobj_t, void *, int);
197 static u_int32_t envy24htchan_getptr(kobj_t, void *);
198 static struct pcmchan_caps *envy24htchan_getcaps(kobj_t, void *);
200 /* mixer interface */
201 static int envy24htmixer_init(struct snd_mixer *);
202 static int envy24htmixer_reinit(struct snd_mixer *);
203 static int envy24htmixer_uninit(struct snd_mixer *);
204 static int envy24htmixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
205 static u_int32_t envy24htmixer_setrecsrc(struct snd_mixer *, u_int32_t);
207 /* SPI codec access interface */
208 static void *envy24ht_spi_create(device_t, void *, int, int);
209 static void envy24ht_spi_destroy(void *);
210 static void envy24ht_spi_init(void *);
211 static void envy24ht_spi_reinit(void *);
212 static void envy24ht_spi_setvolume(void *, int, unsigned int, unsigned int);
214 /* -------------------------------------------------------------------- */
217 system constant tables
220 /* API -> hardware channel map */
221 static unsigned envy24ht_chanmap[ENVY24HT_CHAN_NUM] = {
222 ENVY24HT_CHAN_PLAY_DAC1, /* 1 */
223 ENVY24HT_CHAN_PLAY_DAC2, /* 2 */
224 ENVY24HT_CHAN_PLAY_DAC3, /* 3 */
225 ENVY24HT_CHAN_PLAY_DAC4, /* 4 */
226 ENVY24HT_CHAN_PLAY_SPDIF, /* 0 */
227 ENVY24HT_CHAN_REC_MIX, /* 5 */
228 ENVY24HT_CHAN_REC_SPDIF, /* 6 */
229 ENVY24HT_CHAN_REC_ADC1, /* 7 */
230 ENVY24HT_CHAN_REC_ADC2, /* 8 */
231 ENVY24HT_CHAN_REC_ADC3, /* 9 */
232 ENVY24HT_CHAN_REC_ADC4, /* 10 */
235 /* mixer -> API channel map. see above */
236 static int envy24ht_mixmap[] = {
237 -1, /* Master output level. It is depend on codec support */
238 -1, /* Treble level of all output channels */
239 -1, /* Bass level of all output channels */
240 -1, /* Volume of synthesier input */
241 0, /* Output level for the audio device */
242 -1, /* Output level for the PC speaker */
243 7, /* line in jack */
244 -1, /* microphone jack */
245 -1, /* CD audio input */
246 -1, /* Recording monitor */
247 1, /* alternative codec */
248 -1, /* global recording level */
250 -1, /* Output gain */
251 8, /* Input source 1 */
252 9, /* Input source 2 */
253 10, /* Input source 3 */
254 6, /* Digital (input) 1 */
255 -1, /* Digital (input) 2 */
256 -1, /* Digital (input) 3 */
257 -1, /* Phone input */
258 -1, /* Phone output */
259 -1, /* Video/TV (audio) in */
261 -1, /* Monitor volume */
264 /* variable rate audio */
265 static u_int32_t envy24ht_speed[] = {
266 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
267 12000, 11025, 9600, 8000, 0
270 /* known boards configuration */
271 static struct codec_entry spi_codec = {
273 envy24ht_spi_destroy,
276 envy24ht_spi_setvolume,
280 static struct cfg_info cfg_table[] = {
282 "Envy24HT audio (Terratec Aureon 7.1 Space)",
284 0x0b, 0x80, 0xfc, 0xc3,
285 0x21efff, 0x7fffff, 0x5e1000,
286 0x40000, 0x80000, 0x1000, 0x00, 0x02,
291 "Envy24HT audio (Terratec Aureon 5.1 Sky)",
293 0x0a, 0x80, 0xfc, 0xc3,
294 0x21efff, 0x7fffff, 0x5e1000,
295 0x40000, 0x80000, 0x1000, 0x00, 0x02,
300 "Envy24HT audio (Terratec Aureon 7.1 Universe)",
302 0x0b, 0x80, 0xfc, 0xc3,
303 0x21efff, 0x7fffff, 0x5e1000,
304 0x40000, 0x80000, 0x1000, 0x00, 0x02,
309 "Envy24HT audio (AudioTrak Prodigy 7.1)",
311 0x0b, 0x80, 0xfc, 0xc3,
312 0x21efff, 0x7fffff, 0x5e1000,
313 0x40000, 0x80000, 0x1000, 0x00, 0x02,
318 "Envy24HT audio (Terratec PHASE 28)",
320 0x0b, 0x80, 0xfc, 0xc3,
321 0x21efff, 0x7fffff, 0x5e1000,
322 0x40000, 0x80000, 0x1000, 0x00, 0x02,
327 "Envy24HT-S audio (Terratec PHASE 22)",
329 0x10, 0x80, 0xf0, 0xc3,
330 0x7ffbc7, 0x7fffff, 0x438,
331 0x10, 0x20, 0x400, 0x01, 0x00,
336 "Envy24HT audio (AudioTrak Prodigy 7.1 LT)",
338 0x4b, 0x80, 0xfc, 0xc3,
339 0x7ff8ff, 0x7fffff, 0x700,
340 0x400, 0x200, 0x100, 0x00, 0x02,
345 "Envy24HT audio (AudioTrak Prodigy 7.1 XT)",
347 0x4b, 0x80, 0xfc, 0xc3,
348 0x7ff8ff, 0x7fffff, 0x700,
349 0x400, 0x200, 0x100, 0x00, 0x02,
354 "Envy24HT audio (M-Audio Revolution 7.1)",
356 0x43, 0x80, 0xf8, 0xc1,
357 0x3fff85, 0x400072, 0x4000fa,
358 0x08, 0x02, 0x20, 0x00, 0x04,
363 "Envy24GT audio (M-Audio Revolution 5.1)",
365 0x42, 0x80, 0xf8, 0xc1,
366 0x3fff05, 0x4000f0, 0x4000fa,
367 0x08, 0x02, 0x10, 0x00, 0x03,
372 "Envy24HT audio (M-Audio Audiophile 192)",
374 0x68, 0x80, 0xf8, 0xc3,
375 0x45, 0x4000b5, 0x7fffba,
376 0x08, 0x02, 0x10, 0x00, 0x03,
381 "Envy24HT audio (AudioTrak Prodigy HD2)",
383 0x68, 0x80, 0x78, 0xc3,
384 0xfff8ff, 0x200700, 0xdfffff,
385 0x400, 0x200, 0x100, 0x00, 0x05,
390 "Envy24HT audio (ESI Juli@)",
392 0x20, 0x80, 0xf8, 0xc3,
393 0x7fff9f, 0x8016, 0x7fff9f,
394 0x08, 0x02, 0x10, 0x00, 0x03,
399 "Envy24HT-S audio (Terrasoniq TS22PCI)",
401 0x10, 0x80, 0xf0, 0xc3,
402 0x7ffbc7, 0x7fffff, 0x438,
403 0x10, 0x20, 0x400, 0x01, 0x00,
408 "Envy24HT audio (Generic)",
410 0x0b, 0x80, 0xfc, 0xc3,
411 0x21efff, 0x7fffff, 0x5e1000,
412 0x40000, 0x80000, 0x1000, 0x00, 0x02,
414 &spi_codec, /* default codec routines */
418 static u_int32_t envy24ht_recfmt[] = {
419 SND_FORMAT(AFMT_S16_LE, 2, 0),
420 SND_FORMAT(AFMT_S32_LE, 2, 0),
423 static struct pcmchan_caps envy24ht_reccaps = {8000, 96000, envy24ht_recfmt, 0};
425 static u_int32_t envy24ht_playfmt[] = {
426 SND_FORMAT(AFMT_U8, 2, 0),
427 SND_FORMAT(AFMT_S16_LE, 2, 0),
428 SND_FORMAT(AFMT_S32_LE, 2, 0),
432 static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0};
434 struct envy24ht_emldma {
436 void (*emldma)(struct sc_chinfo *);
440 static struct envy24ht_emldma envy24ht_pemltab[] = {
441 {SND_FORMAT(AFMT_U8, 2, 0), envy24ht_p8u, 2},
442 {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_p16sl, 4},
443 {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_p32sl, 8},
447 static struct envy24ht_emldma envy24ht_remltab[] = {
448 {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_r16sl, 4},
449 {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_r32sl, 8},
453 /* -------------------------------------------------------------------- */
455 /* common routines */
457 envy24ht_rdcs(struct sc_info *sc, int regno, int size)
461 return bus_space_read_1(sc->cst, sc->csh, regno);
463 return bus_space_read_2(sc->cst, sc->csh, regno);
465 return bus_space_read_4(sc->cst, sc->csh, regno);
472 envy24ht_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
476 bus_space_write_1(sc->cst, sc->csh, regno, data);
479 bus_space_write_2(sc->cst, sc->csh, regno, data);
482 bus_space_write_4(sc->cst, sc->csh, regno, data);
488 envy24ht_rdmt(struct sc_info *sc, int regno, int size)
492 return bus_space_read_1(sc->mtt, sc->mth, regno);
494 return bus_space_read_2(sc->mtt, sc->mth, regno);
496 return bus_space_read_4(sc->mtt, sc->mth, regno);
503 envy24ht_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
507 bus_space_write_1(sc->mtt, sc->mth, regno, data);
510 bus_space_write_2(sc->mtt, sc->mth, regno, data);
513 bus_space_write_4(sc->mtt, sc->mth, regno, data);
518 /* -------------------------------------------------------------------- */
520 /* I2C port/E2PROM access routines */
523 envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
529 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
531 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
532 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
533 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
535 DELAY(32); /* 31.25kHz */
537 if (i == ENVY24HT_TIMEOUT) {
540 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
541 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
542 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_RD, 1);
543 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
544 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
545 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
547 DELAY(32); /* 31.25kHz */
549 if (i == ENVY24HT_TIMEOUT) {
552 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CDATA, 1);
555 device_printf(sc->dev, "envy24ht_rdi2c(): return 0x%x\n", data);
561 envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
567 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
569 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
570 tmp = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
571 if ((tmp & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
573 DELAY(32); /* 31.25kHz */
575 if (i == ENVY24HT_TIMEOUT) {
578 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
579 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDATA, data, 1);
580 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
581 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_WR, 1);
582 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
583 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
584 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
586 DELAY(32); /* 31.25kHz */
588 if (i == ENVY24HT_TIMEOUT) {
596 envy24ht_rdrom(struct sc_info *sc, u_int32_t addr)
601 device_printf(sc->dev, "envy24ht_rdrom(sc, 0x%02x)\n", addr);
603 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
604 if ((data & ENVY24HT_CCS_I2CSTAT_ROM) == 0) {
606 device_printf(sc->dev, "envy24ht_rdrom(): E2PROM not presented\n");
611 return envy24ht_rdi2c(sc, ENVY24HT_CCS_I2CDEV_ROM, addr);
614 static struct cfg_info *
615 envy24ht_rom2cfg(struct sc_info *sc)
617 struct cfg_info *buff;
622 device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n");
624 size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE);
625 if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) {
627 device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size);
629 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
632 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
638 /* no valid e2prom, using default values */
639 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
640 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
641 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
642 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
647 buff->gpiomask = 0x21efff;
648 buff->gpiostate = 0x7fffff;
649 buff->gpiodir = 0x5e1000;
650 buff->cdti = 0x40000;
651 buff->cclk = 0x80000;
656 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0;
658 if (cfg_table[i].subvendor == buff->subvendor &&
659 cfg_table[i].subdevice == buff->subdevice)
661 buff->name = cfg_table[i].name;
662 buff->codec = cfg_table[i].codec;
669 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
672 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
678 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
679 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
680 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
681 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
682 buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG);
683 buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL);
684 buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S);
685 buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF);
686 buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \
687 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \
688 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16;
689 buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \
690 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \
691 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16;
692 buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \
693 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \
694 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16;
696 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
697 if (cfg_table[i].subvendor == buff->subvendor &&
698 cfg_table[i].subdevice == buff->subdevice)
700 buff->name = cfg_table[i].name;
701 buff->codec = cfg_table[i].codec;
707 envy24ht_cfgfree(struct cfg_info *cfg) {
711 kfree(cfg, M_ENVY24HT);
715 /* -------------------------------------------------------------------- */
717 /* AC'97 codec access routines */
721 envy24ht_coldcd(struct sc_info *sc)
727 device_printf(sc->dev, "envy24ht_coldcd()\n");
729 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1);
731 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
733 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
734 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
735 if (data & ENVY24HT_MT_AC97CMD_RDY) {
744 envy24ht_slavecd(struct sc_info *sc)
750 device_printf(sc->dev, "envy24ht_slavecd()\n");
752 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD,
753 ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1);
755 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
757 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
758 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
759 if (data & ENVY24HT_MT_AC97CMD_RDY) {
768 envy24ht_rdcd(kobj_t obj, void *devinfo, int regno)
770 struct sc_info *sc = (struct sc_info *)devinfo;
775 device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno);
777 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
778 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1);
779 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
780 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
781 if ((data & ENVY24HT_MT_AC97CMD_RD) == 0)
784 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2);
787 device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data);
793 envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
795 struct sc_info *sc = (struct sc_info *)devinfo;
800 device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
802 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
803 envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2);
804 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1);
805 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
806 cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
807 if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0)
814 static kobj_method_t envy24ht_ac97_methods[] = {
815 KOBJMETHOD(ac97_read, envy24ht_rdcd),
816 KOBJMETHOD(ac97_write, envy24ht_wrcd),
819 AC97_DECLARE(envy24ht_ac97);
822 /* -------------------------------------------------------------------- */
824 /* GPIO access routines */
827 envy24ht_gpiord(struct sc_info *sc)
829 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
830 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2);
832 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2));
836 envy24ht_gpiowr(struct sc_info *sc, u_int32_t data)
839 device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF);
842 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2);
843 if (sc->cfg->subdevice != 0x1150)
844 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1);
850 envy24ht_gpiogetmask(struct sc_info *sc)
852 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2));
857 envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask)
859 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2);
860 if (sc->cfg->subdevice != 0x1150)
861 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1);
867 envy24ht_gpiogetdir(struct sc_info *sc)
869 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4);
874 envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir)
876 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
877 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2);
879 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4);
883 /* -------------------------------------------------------------------- */
885 /* SPI codec access interface routine */
887 struct envy24ht_spi_codec {
888 struct spicds_info *info;
889 struct sc_info *parent;
896 envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
899 struct envy24ht_spi_codec *ptr = codec;
902 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
904 data = envy24ht_gpiord(ptr->parent);
905 data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
906 if (cs) data += ptr->cs;
907 if (cclk) data += ptr->cclk;
908 if (cdti) data += ptr->cdti;
909 envy24ht_gpiowr(ptr->parent, data);
914 envy24ht_spi_create(device_t dev, void *info, int dir, int num)
916 struct sc_info *sc = info;
917 struct envy24ht_spi_codec *buff = NULL;
920 device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num);
923 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
927 if (dir == PCMDIR_REC && sc->adc[num] != NULL)
928 buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info;
929 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
930 buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info;
932 buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl);
933 if (buff->info == NULL) {
934 kfree(buff, M_ENVY24HT);
946 envy24ht_spi_destroy(void *codec)
948 struct envy24ht_spi_codec *ptr = codec;
952 device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n");
955 if (ptr->dir == PCMDIR_PLAY) {
956 if (ptr->parent->dac[ptr->num] != NULL)
957 spicds_destroy(ptr->info);
960 if (ptr->parent->adc[ptr->num] != NULL)
961 spicds_destroy(ptr->info);
964 kfree(codec, M_ENVY24HT);
968 envy24ht_spi_init(void *codec)
970 struct envy24ht_spi_codec *ptr = codec;
974 device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n");
976 ptr->cs = ptr->parent->cfg->cs;
977 ptr->cclk = ptr->parent->cfg->cclk;
978 ptr->cdti = ptr->parent->cfg->cdti;
979 spicds_settype(ptr->info, ptr->parent->cfg->type);
980 spicds_setcif(ptr->info, ptr->parent->cfg->cif);
981 if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \
982 ptr->parent->cfg->type == SPICDS_TYPE_AK4528) {
983 spicds_setformat(ptr->info,
984 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
985 spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
988 /* for the time being, init only first codec */
990 spicds_init(ptr->info);
994 envy24ht_spi_reinit(void *codec)
996 struct envy24ht_spi_codec *ptr = codec;
1000 device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n");
1003 spicds_reinit(ptr->info);
1007 envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
1009 struct envy24ht_spi_codec *ptr = codec;
1013 device_printf(ptr->parent->dev, "envy24ht_spi_set()\n");
1016 spicds_set(ptr->info, dir, left, right);
1019 /* -------------------------------------------------------------------- */
1021 /* hardware access routeines */
1026 } envy24ht_speedtab[] = {
1027 {48000, ENVY24HT_MT_RATE_48000},
1028 {24000, ENVY24HT_MT_RATE_24000},
1029 {12000, ENVY24HT_MT_RATE_12000},
1030 {9600, ENVY24HT_MT_RATE_9600},
1031 {32000, ENVY24HT_MT_RATE_32000},
1032 {16000, ENVY24HT_MT_RATE_16000},
1033 {8000, ENVY24HT_MT_RATE_8000},
1034 {96000, ENVY24HT_MT_RATE_96000},
1035 {192000, ENVY24HT_MT_RATE_192000},
1036 {64000, ENVY24HT_MT_RATE_64000},
1037 {44100, ENVY24HT_MT_RATE_44100},
1038 {22050, ENVY24HT_MT_RATE_22050},
1039 {11025, ENVY24HT_MT_RATE_11025},
1040 {88200, ENVY24HT_MT_RATE_88200},
1041 {176400, ENVY24HT_MT_RATE_176400},
1046 envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) {
1047 u_int32_t code, i2sfmt;
1051 device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed);
1053 code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */
1054 envy24ht_slavecd(sc);
1058 for (i = 0; envy24ht_speedtab[i].speed != 0; i++) {
1059 if (envy24ht_speedtab[i].speed == speed)
1062 code = envy24ht_speedtab[i].code;
1065 device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code);
1068 envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1);
1069 if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \
1070 (code == ENVY24HT_MT_RATE_176400)) {
1071 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1072 i2sfmt |= ENVY24HT_MT_I2S_MLR128;
1073 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1076 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1077 i2sfmt &= ~ENVY24HT_MT_I2S_MLR128;
1078 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1080 code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1);
1081 code &= ENVY24HT_MT_RATE_MASK;
1082 for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) {
1083 if (envy24ht_speedtab[i].code == code)
1086 speed = envy24ht_speedtab[i].speed;
1092 device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed);
1098 envy24ht_setvolume(struct sc_info *sc, unsigned ch)
1101 device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch);
1102 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1103 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1104 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1105 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1110 envy24ht_mutevolume(struct sc_info *sc, unsigned ch)
1115 device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch);
1116 vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE;
1117 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1118 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1119 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1120 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1125 envy24ht_gethwptr(struct sc_info *sc, int dir)
1131 device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir);
1133 if (dir == PCMDIR_PLAY) {
1134 rtn = sc->psize / 4;
1135 unit = ENVY24HT_PLAY_BUFUNIT / 4;
1136 regno = ENVY24HT_MT_PCNT;
1139 rtn = sc->rsize / 4;
1140 unit = ENVY24HT_REC_BUFUNIT / 4;
1141 regno = ENVY24HT_MT_RCNT;
1144 ptr = envy24ht_rdmt(sc, regno, 2);
1149 device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn);
1155 envy24ht_updintr(struct sc_info *sc, int dir)
1157 int regptr, regintr;
1158 u_int32_t mask, intr;
1159 u_int32_t ptr, size, cnt;
1163 device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir);
1165 if (dir == PCMDIR_PLAY) {
1167 size = sc->psize / 4;
1168 regptr = ENVY24HT_MT_PCNT;
1169 regintr = ENVY24HT_MT_PTERM;
1170 mask = ~ENVY24HT_MT_INT_PMASK;
1174 size = sc->rsize / 4;
1175 regptr = ENVY24HT_MT_RCNT;
1176 regintr = ENVY24HT_MT_RTERM;
1177 mask = ~ENVY24HT_MT_INT_RMASK;
1180 ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1;
1182 cnt = blk - ptr % blk - 1;
1188 device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1190 envy24ht_wrmt(sc, regintr, cnt, 2);
1191 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1193 device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1195 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
1197 device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
1198 envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
1206 envy24ht_maskintr(struct sc_info *sc, int dir)
1208 u_int32_t mask, intr;
1211 device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
1213 if (dir == PCMDIR_PLAY)
1214 mask = ENVY24HT_MT_INT_PMASK;
1216 mask = ENVY24HT_MT_INT_RMASK;
1217 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
1218 envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
1225 envy24ht_checkintr(struct sc_info *sc, int dir)
1227 u_int32_t mask, stat, intr, rtn;
1230 device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
1232 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
1233 if (dir == PCMDIR_PLAY) {
1234 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
1235 mask = ~ENVY24HT_MT_INT_RSTAT;
1236 envy24ht_wrmt(sc, 0x1a, 0x01, 1);
1237 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);
1238 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1239 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
1243 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
1244 mask = ~ENVY24HT_MT_INT_PSTAT;
1246 stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
1248 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
1249 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1250 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
1258 envy24ht_start(struct sc_info *sc, int dir)
1263 device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
1265 if (dir == PCMDIR_PLAY)
1266 sw = ENVY24HT_MT_PCTL_PSTART;
1268 sw = ENVY24HT_MT_PCTL_RSTART;
1270 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1271 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
1274 device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
1275 device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
1282 envy24ht_stop(struct sc_info *sc, int dir)
1287 device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir);
1289 if (dir == PCMDIR_PLAY)
1290 sw = ~ENVY24HT_MT_PCTL_PSTART;
1292 sw = ~ENVY24HT_MT_PCTL_RSTART;
1294 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1295 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1);
1302 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1308 /* -------------------------------------------------------------------- */
1310 /* buffer copy routines */
1312 envy24ht_p32sl(struct sc_chinfo *ch)
1317 int src, dst, ssize, dsize, slot;
1320 length = sndbuf_getready(ch->buffer) / 8;
1321 dmabuf = ch->parent->pbuf;
1322 data = (u_int32_t *)ch->data;
1323 src = sndbuf_getreadyptr(ch->buffer) / 4;
1324 dst = src / 2 + ch->offset;
1325 ssize = ch->size / 4;
1326 dsize = ch->size / 8;
1329 for (i = 0; i < length; i++) {
1330 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
1331 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1342 envy24ht_p16sl(struct sc_chinfo *ch)
1347 int src, dst, ssize, dsize, slot;
1351 device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
1353 length = sndbuf_getready(ch->buffer) / 4;
1354 dmabuf = ch->parent->pbuf;
1355 data = (u_int16_t *)ch->data;
1356 src = sndbuf_getreadyptr(ch->buffer) / 2;
1357 dst = src / 2 + ch->offset;
1358 ssize = ch->size / 2;
1359 dsize = ch->size / 4;
1362 device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1365 for (i = 0; i < length; i++) {
1366 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1367 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1370 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
1371 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
1387 envy24ht_p8u(struct sc_chinfo *ch)
1392 int src, dst, ssize, dsize, slot;
1395 length = sndbuf_getready(ch->buffer) / 2;
1396 dmabuf = ch->parent->pbuf;
1397 data = (u_int8_t *)ch->data;
1398 src = sndbuf_getreadyptr(ch->buffer);
1399 dst = src / 2 + ch->offset;
1401 dsize = ch->size / 4;
1404 for (i = 0; i < length; i++) {
1405 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1406 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1417 envy24ht_r32sl(struct sc_chinfo *ch)
1422 int src, dst, ssize, dsize, slot;
1425 length = sndbuf_getfree(ch->buffer) / 8;
1426 dmabuf = ch->parent->rbuf;
1427 data = (u_int32_t *)ch->data;
1428 dst = sndbuf_getfreeptr(ch->buffer) / 4;
1429 src = dst / 2 + ch->offset;
1430 dsize = ch->size / 4;
1431 ssize = ch->size / 8;
1432 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1434 for (i = 0; i < length; i++) {
1435 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1436 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1447 envy24ht_r16sl(struct sc_chinfo *ch)
1452 int src, dst, ssize, dsize, slot;
1455 length = sndbuf_getfree(ch->buffer) / 4;
1456 dmabuf = ch->parent->rbuf;
1457 data = (u_int16_t *)ch->data;
1458 dst = sndbuf_getfreeptr(ch->buffer) / 2;
1459 src = dst / 2 + ch->offset;
1460 dsize = ch->size / 2;
1461 ssize = ch->size / 8;
1462 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1464 for (i = 0; i < length; i++) {
1465 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1466 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1476 /* -------------------------------------------------------------------- */
1478 /* channel interface */
1480 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1482 struct sc_info *sc = (struct sc_info *)devinfo;
1483 struct sc_chinfo *ch;
1487 device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
1489 snd_mtxlock(sc->lock);
1491 if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1492 (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1493 snd_mtxunlock(sc->lock);
1499 ch = &sc->chan[num];
1500 ch->size = 8 * ENVY24HT_SAMPLE_NUM;
1501 ch->data = kmalloc(ch->size, M_ENVY24HT, M_WAITOK | M_ZERO);
1502 if (ch->data == NULL) {
1511 /* set channel map */
1512 ch->num = envy24ht_chanmap[num];
1513 snd_mtxunlock(sc->lock);
1514 sndbuf_setup(ch->buffer, ch->data, ch->size);
1515 snd_mtxlock(sc->lock);
1516 /* these 2 values are dummy */
1520 snd_mtxunlock(sc->lock);
1526 envy24htchan_free(kobj_t obj, void *data)
1528 struct sc_chinfo *ch = data;
1529 struct sc_info *sc = ch->parent;
1532 device_printf(sc->dev, "envy24htchan_free()\n");
1534 snd_mtxlock(sc->lock);
1535 if (ch->data != NULL) {
1536 kfree(ch->data, M_ENVY24HT);
1539 snd_mtxunlock(sc->lock);
1545 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
1547 struct sc_chinfo *ch = data;
1548 struct sc_info *sc = ch->parent;
1549 struct envy24ht_emldma *emltab;
1550 /* unsigned int bcnt, bsize; */
1554 device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
1556 snd_mtxlock(sc->lock);
1557 /* check and get format related information */
1558 if (ch->dir == PCMDIR_PLAY)
1559 emltab = envy24ht_pemltab;
1561 emltab = envy24ht_remltab;
1562 if (emltab == NULL) {
1563 snd_mtxunlock(sc->lock);
1566 for (i = 0; emltab[i].format != 0; i++)
1567 if (emltab[i].format == format)
1569 if (emltab[i].format == 0) {
1570 snd_mtxunlock(sc->lock);
1574 /* set format information */
1575 ch->format = format;
1576 ch->emldma = emltab[i].emldma;
1577 if (ch->unit > emltab[i].unit)
1578 ch->blk *= ch->unit / emltab[i].unit;
1580 ch->blk /= emltab[i].unit / ch->unit;
1581 ch->unit = emltab[i].unit;
1583 /* set channel buffer information */
1584 ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
1586 if (ch->dir == PCMDIR_PLAY)
1587 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1589 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1591 bcnt = ch->size / bsize;
1592 sndbuf_resize(ch->buffer, bcnt, bsize);
1594 snd_mtxunlock(sc->lock);
1597 device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
1603 IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1604 of speed information value. And real hardware speed setting is done
1605 at start triggered(see envy24htchan_trigger()). So, at this function
1606 is called, any value that ENVY24 can use is able to set. But, at
1607 start triggerd, some other channel is running, and that channel's
1608 speed isn't same with, then trigger function will fail.
1611 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1613 struct sc_chinfo *ch = data;
1614 u_int32_t val, prev;
1618 device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
1621 for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
1622 if (abs(val - speed) < abs(prev - speed))
1630 device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
1636 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1638 struct sc_chinfo *ch = data;
1639 /* struct sc_info *sc = ch->parent; */
1640 u_int32_t size, prev;
1641 unsigned int bcnt, bsize;
1644 device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
1647 /* snd_mtxlock(sc->lock); */
1648 for (size = ch->size / 2; size > 0; size /= 2) {
1649 if (abs(size - blocksize) < abs(prev - blocksize))
1655 ch->blk = prev / ch->unit;
1656 if (ch->dir == PCMDIR_PLAY)
1657 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
1659 ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
1660 /* set channel buffer information */
1661 /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
1662 if (ch->dir == PCMDIR_PLAY)
1663 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1665 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1667 bcnt = ch->size / bsize;
1668 sndbuf_resize(ch->buffer, bcnt, bsize);
1669 /* snd_mtxunlock(sc->lock); */
1672 device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
1677 /* semantic note: must start at beginning of buffer */
1679 envy24htchan_trigger(kobj_t obj, void *data, int go)
1681 struct sc_chinfo *ch = data;
1682 struct sc_info *sc = ch->parent;
1689 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1691 snd_mtxlock(sc->lock);
1692 if (ch->dir == PCMDIR_PLAY)
1699 device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1701 /* check or set channel speed */
1702 if (sc->run[0] == 0 && sc->run[1] == 0) {
1703 sc->speed = envy24ht_setspeed(sc, ch->speed);
1704 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1705 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1707 else if (ch->speed != 0 && ch->speed != sc->speed) {
1712 ch->channel->speed = sc->speed;
1713 /* start or enable channel */
1715 if (sc->run[slot] == 1) {
1718 sc->blk[slot] = ch->blk;
1721 ptr = envy24ht_gethwptr(sc, ch->dir);
1722 ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1723 (ch->size / 4)) * 4 / ch->unit;
1724 if (ch->blk < sc->blk[slot])
1725 sc->blk[slot] = ch->blk;
1727 if (ch->dir == PCMDIR_PLAY) {
1729 envy24ht_setvolume(sc, ch->num);
1731 envy24ht_updintr(sc, ch->dir);
1732 if (sc->run[slot] == 1)
1733 envy24ht_start(sc, ch->dir);
1736 case PCMTRIG_EMLDMAWR:
1738 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1746 case PCMTRIG_EMLDMARD:
1748 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1759 device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1763 if (ch->dir == PCMDIR_PLAY)
1764 envy24ht_mutevolume(sc, ch->num);
1765 if (sc->run[slot] == 0) {
1766 envy24ht_stop(sc, ch->dir);
1769 /* else if (ch->blk == sc->blk[slot]) {
1770 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1771 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1772 if (sc->chan[i].dir == ch->dir &&
1773 sc->chan[i].run == 1 &&
1774 sc->chan[i].blk < sc->blk[slot])
1775 sc->blk[slot] = sc->chan[i].blk;
1777 if (ch->blk != sc->blk[slot])
1778 envy24ht_updintr(sc, ch->dir);
1784 snd_mtxunlock(sc->lock);
1789 envy24htchan_getptr(kobj_t obj, void *data)
1791 struct sc_chinfo *ch = data;
1792 struct sc_info *sc = ch->parent;
1796 device_printf(sc->dev, "envy24htchan_getptr()\n");
1798 snd_mtxlock(sc->lock);
1799 ptr = envy24ht_gethwptr(sc, ch->dir);
1800 rtn = ptr * ch->unit;
1801 snd_mtxunlock(sc->lock);
1804 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1810 static struct pcmchan_caps *
1811 envy24htchan_getcaps(kobj_t obj, void *data)
1813 struct sc_chinfo *ch = data;
1814 struct sc_info *sc = ch->parent;
1815 struct pcmchan_caps *rtn;
1818 device_printf(sc->dev, "envy24htchan_getcaps()\n");
1820 snd_mtxlock(sc->lock);
1821 if (ch->dir == PCMDIR_PLAY) {
1822 if (sc->run[0] == 0)
1823 rtn = &envy24ht_playcaps;
1828 if (sc->run[1] == 0)
1829 rtn = &envy24ht_reccaps;
1833 snd_mtxunlock(sc->lock);
1838 static kobj_method_t envy24htchan_methods[] = {
1839 KOBJMETHOD(channel_init, envy24htchan_init),
1840 KOBJMETHOD(channel_free, envy24htchan_free),
1841 KOBJMETHOD(channel_setformat, envy24htchan_setformat),
1842 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed),
1843 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize),
1844 KOBJMETHOD(channel_trigger, envy24htchan_trigger),
1845 KOBJMETHOD(channel_getptr, envy24htchan_getptr),
1846 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps),
1849 CHANNEL_DECLARE(envy24htchan);
1851 /* -------------------------------------------------------------------- */
1853 /* mixer interface */
1856 envy24htmixer_init(struct snd_mixer *m)
1858 struct sc_info *sc = mix_getdevinfo(m);
1861 device_printf(sc->dev, "envy24htmixer_init()\n");
1866 /* set volume control rate */
1867 snd_mtxlock(sc->lock);
1869 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1872 pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1874 mix_setdevs(m, ENVY24HT_MIX_MASK);
1875 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1877 snd_mtxunlock(sc->lock);
1883 envy24htmixer_reinit(struct snd_mixer *m)
1885 struct sc_info *sc = mix_getdevinfo(m);
1890 device_printf(sc->dev, "envy24htmixer_reinit()\n");
1897 envy24htmixer_uninit(struct snd_mixer *m)
1899 struct sc_info *sc = mix_getdevinfo(m);
1904 device_printf(sc->dev, "envy24htmixer_uninit()\n");
1911 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1913 struct sc_info *sc = mix_getdevinfo(m);
1914 int ch = envy24ht_mixmap[dev];
1920 if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1922 if (dev != 0 && ch == -1)
1924 hwch = envy24ht_chanmap[ch];
1926 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1930 snd_mtxlock(sc->lock);
1932 for (i = 0; i < sc->dacn; i++) {
1933 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1937 /* set volume value for hardware */
1938 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1939 sc->left[hwch] = ENVY24HT_VOL_MUTE;
1940 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1941 sc->right[hwch] = ENVY24HT_VOL_MUTE;
1943 /* set volume for record channel and running play channel */
1944 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1945 envy24ht_setvolume(sc, hwch);
1947 snd_mtxunlock(sc->lock);
1949 return right << 8 | left;
1953 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1955 struct sc_info *sc = mix_getdevinfo(m);
1956 int ch = envy24ht_mixmap[src];
1958 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1961 if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1966 static kobj_method_t envy24htmixer_methods[] = {
1967 KOBJMETHOD(mixer_init, envy24htmixer_init),
1968 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit),
1969 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit),
1970 KOBJMETHOD(mixer_set, envy24htmixer_set),
1971 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc),
1974 MIXER_DECLARE(envy24htmixer);
1976 /* -------------------------------------------------------------------- */
1978 /* The interrupt handler */
1980 envy24ht_intr(void *p)
1982 struct sc_info *sc = (struct sc_info *)p;
1983 struct sc_chinfo *ch;
1984 u_int32_t ptr, dsize, feed;
1988 device_printf(sc->dev, "envy24ht_intr()\n");
1990 snd_mtxlock(sc->lock);
1991 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1993 device_printf(sc->dev, "envy24ht_intr(): play\n");
1995 dsize = sc->psize / 4;
1996 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
1998 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
2000 ptr -= ptr % sc->blk[0];
2001 feed = (ptr + dsize - sc->intr[0]) % dsize;
2003 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2005 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
2009 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
2011 if (ch->run && ch->blk <= feed) {
2012 snd_mtxunlock(sc->lock);
2013 chn_intr(ch->channel);
2014 snd_mtxlock(sc->lock);
2018 envy24ht_updintr(sc, PCMDIR_PLAY);
2020 if (envy24ht_checkintr(sc, PCMDIR_REC)) {
2022 device_printf(sc->dev, "envy24ht_intr(): rec\n");
2024 dsize = sc->rsize / 4;
2025 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
2026 ptr -= ptr % sc->blk[1];
2027 feed = (ptr + dsize - sc->intr[1]) % dsize;
2028 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
2030 if (ch->run && ch->blk <= feed) {
2031 snd_mtxunlock(sc->lock);
2032 chn_intr(ch->channel);
2033 snd_mtxlock(sc->lock);
2037 envy24ht_updintr(sc, PCMDIR_REC);
2039 snd_mtxunlock(sc->lock);
2045 * Probe and attach the card
2049 envy24ht_pci_probe(device_t dev)
2055 printf("envy24ht_pci_probe()\n");
2057 if (pci_get_device(dev) == PCID_ENVY24HT &&
2058 pci_get_vendor(dev) == PCIV_ENVY24) {
2059 sv = pci_get_subvendor(dev);
2060 sd = pci_get_subdevice(dev);
2061 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2062 if (cfg_table[i].subvendor == sv &&
2063 cfg_table[i].subdevice == sd) {
2067 device_set_desc(dev, cfg_table[i].name);
2069 printf("envy24ht_pci_probe(): return 0\n");
2075 printf("envy24ht_pci_probe(): return ENXIO\n");
2082 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2084 struct sc_info *sc = arg;
2086 sc->paddr = segs->ds_addr;
2088 device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2090 printf("envy24ht(play): setmap %lx, %lx; ",
2091 (unsigned long)segs->ds_addr,
2092 (unsigned long)segs->ds_len);
2095 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, (uint32_t)segs->ds_addr, 4);
2096 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2100 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2102 struct sc_info *sc = arg;
2104 sc->raddr = segs->ds_addr;
2106 device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2108 printf("envy24ht(record): setmap %lx, %lx; ",
2109 (unsigned long)segs->ds_addr,
2110 (unsigned long)segs->ds_len);
2113 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, (uint32_t)segs->ds_addr, 4);
2114 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2118 envy24ht_dmafree(struct sc_info *sc)
2121 device_printf(sc->dev, "envy24ht_dmafree():");
2122 printf(" sc->raddr(0x%08x)", (u_int32_t)sc->raddr);
2123 printf(" sc->paddr(0x%08x)", (u_int32_t)sc->paddr);
2124 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2125 else printf(" sc->rbuf(null)");
2126 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2127 else printf(" sc->pbuf(null)\n");
2131 bus_dmamap_unload(sc->dmat, sc->rmap);
2133 bus_dmamap_unload(sc->dmat, sc->pmap);
2135 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2137 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2139 bus_dmamap_unload(sc->dmat, sc->rmap);
2140 bus_dmamap_unload(sc->dmat, sc->pmap);
2141 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2142 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2145 sc->raddr = sc->paddr = 0;
2153 envy24ht_dmainit(struct sc_info *sc)
2157 device_printf(sc->dev, "envy24ht_dmainit()\n");
2160 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2161 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2164 sc->paddr = sc->raddr = 0;
2165 sc->blk[0] = sc->blk[1] = 0;
2167 /* allocate DMA buffer */
2169 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2171 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2174 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2176 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2179 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2181 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, BUS_DMA_NOWAIT))
2184 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2186 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, BUS_DMA_NOWAIT))
2188 bzero(sc->pbuf, sc->psize);
2189 bzero(sc->rbuf, sc->rsize);
2193 envy24ht_dmafree(sc);
2198 envy24ht_putcfg(struct sc_info *sc)
2200 device_printf(sc->dev, "system configuration\n");
2201 kprintf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2202 sc->cfg->subvendor, sc->cfg->subdevice);
2203 kprintf(" XIN2 Clock Source: ");
2204 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2206 kprintf("24.576MHz(96kHz*256)\n");
2209 kprintf("49.152MHz(192kHz*256)\n");
2212 kprintf("reserved\n");
2215 kprintf("illegal system setting\n");
2217 kprintf(" MPU-401 UART(s) #: ");
2218 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2221 kprintf("not implemented\n");
2225 kprintf(" ADC #: ");
2226 kprintf("%d\n", sc->adcn);
2229 kprintf(" ADC #: ");
2231 kprintf(" and SPDIF receiver connected\n");
2234 kprintf(" no physical inputs\n");
2236 kprintf(" DAC #: ");
2237 kprintf("%d\n", sc->dacn);
2238 kprintf(" Multi-track converter type: ");
2239 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2240 kprintf("AC'97(SDATA_OUT:");
2241 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2249 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2250 kprintf("with volume, ");
2251 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2252 kprintf("192KHz support, ");
2254 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2255 kprintf("192KHz support, ");
2257 kprintf("48KHz support, ");
2258 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2259 case ENVY24HT_CCSM_I2S_16BIT:
2260 kprintf("16bit resolution, ");
2262 case ENVY24HT_CCSM_I2S_18BIT:
2263 kprintf("18bit resolution, ");
2265 case ENVY24HT_CCSM_I2S_20BIT:
2266 kprintf("20bit resolution, ");
2268 case ENVY24HT_CCSM_I2S_24BIT:
2269 kprintf("24bit resolution, ");
2272 kprintf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2274 kprintf(" S/PDIF(IN/OUT): ");
2275 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2279 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2283 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2284 kprintf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2285 kprintf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2286 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2290 envy24ht_init(struct sc_info *sc)
2301 device_printf(sc->dev, "envy24ht_init()\n");
2306 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2308 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2311 /* legacy hardware disable */
2312 data = pci_read_config(sc->dev, PCIR_LAC, 2);
2313 data |= PCIM_LAC_DISABLE;
2314 pci_write_config(sc->dev, PCIR_LAC, data, 2);
2317 /* check system configuration */
2319 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2320 /* 1st: search configuration from table */
2321 sv = pci_get_subvendor(sc->dev);
2322 sd = pci_get_subdevice(sc->dev);
2323 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2325 device_printf(sc->dev, "Set configuration from table\n");
2327 sc->cfg = &cfg_table[i];
2331 if (sc->cfg == NULL) {
2332 /* 2nd: read configuration from table */
2333 sc->cfg = envy24ht_rom2cfg(sc);
2335 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2336 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2338 if (1 /* bootverbose */) {
2339 envy24ht_putcfg(sc);
2342 /* set system configuration */
2343 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2344 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2345 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2346 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2347 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2348 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2349 envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2351 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2352 envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2353 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2354 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2357 for (i = 0; i < sc->adcn; i++) {
2358 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2359 sc->cfg->codec->init(sc->adc[i]);
2361 for (i = 0; i < sc->dacn; i++) {
2362 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2363 sc->cfg->codec->init(sc->dac[i]);
2366 /* initialize DMA buffer */
2368 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2370 if (envy24ht_dmainit(sc))
2373 /* initialize status */
2374 sc->run[0] = sc->run[1] = 0;
2375 sc->intr[0] = sc->intr[1] = 0;
2377 sc->caps[0].fmtlist = envy24ht_playfmt;
2378 sc->caps[1].fmtlist = envy24ht_recfmt;
2380 /* set channel router */
2382 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2383 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2384 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2387 /* set macro interrupt mask */
2388 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2389 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2390 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2392 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2399 envy24ht_alloc_resource(struct sc_info *sc)
2401 /* allocate I/O port resource */
2402 sc->csid = PCIR_CCS;
2403 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2404 &sc->csid, 0, ~0, 1, RF_ACTIVE);
2405 sc->mtid = ENVY24HT_PCIR_MT;
2406 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2407 &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2408 if (!sc->cs || !sc->mt) {
2409 device_printf(sc->dev, "unable to map IO port space\n");
2412 sc->cst = rman_get_bustag(sc->cs);
2413 sc->csh = rman_get_bushandle(sc->cs);
2414 sc->mtt = rman_get_bustag(sc->mt);
2415 sc->mth = rman_get_bushandle(sc->mt);
2417 device_printf(sc->dev,
2418 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2419 pci_read_config(sc->dev, PCIR_CCS, 4),
2420 pci_read_config(sc->dev, PCIR_MT, 4));
2423 /* allocate interrupt resource */
2425 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2426 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2428 snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24ht_intr, sc, &sc->ih)) {
2429 device_printf(sc->dev, "unable to map interrupt\n");
2433 /* allocate DMA resource */
2434 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2437 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
2438 /*highaddr*/BUS_SPACE_MAXADDR,
2439 /*filter*/NULL, /*filterarg*/NULL,
2440 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2441 /*nsegments*/1, /*maxsegsz*/0x3ffff,
2444 device_printf(sc->dev, "unable to create dma tag\n");
2452 envy24ht_pci_attach(device_t dev)
2455 char status[SND_STATUSLEN];
2460 device_printf(dev, "envy24ht_pci_attach()\n");
2462 /* get sc_info data area */
2463 if ((sc = kmalloc(sizeof(*sc), M_ENVY24HT, M_WAITOK | M_ZERO)) == NULL) {
2464 device_printf(dev, "cannot allocate softc\n");
2468 bzero(sc, sizeof(*sc));
2469 sc->lock = snd_mtxcreate(device_get_nameunit(dev),
2470 "snd_envy24ht softc");
2473 /* initialize PCI interface */
2474 pci_enable_busmaster(dev);
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 ksnprintf(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 kfree(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 kfree(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 = {
2594 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0);
2595 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2596 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2597 MODULE_VERSION(snd_envy24ht, 1);