2 * Copyright (c) 2006 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
3 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $FreeBSD: src/sys/dev/sound/pci/envy24ht.c,v 1.11.2.2 2007/06/11 19:33:27 ariff Exp $
31 * Konstantin Dimitrov's thanks list:
33 * A huge thanks goes to Spas Filipov for his friendship, support and his
34 * generous gift - an 'Audiotrak Prodigy HD2' audio card! I also want to
35 * thank Keiichi Iwasaki and his parents, because they helped Spas to get
36 * the card from Japan! Having hardware sample of Prodigy HD2 made adding
37 * support for that great card very easy and real fun and pleasure.
41 #include <dev/sound/pcm/sound.h>
42 #include <dev/sound/pcm/ac97.h>
43 #include <dev/sound/pci/spicds.h>
44 #include <dev/sound/pci/envy24ht.h>
46 #include <bus/pci/pcireg.h>
47 #include <bus/pci/pcivar.h>
51 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pci/envy24ht.c,v 1.3 2008/01/05 14:02:38 swildner Exp $");
53 MALLOC_DEFINE(M_ENVY24HT, "envy24ht", "envy24ht audio");
55 /* -------------------------------------------------------------------- */
59 #define ENVY24HT_PLAY_CHNUM 8
60 #define ENVY24HT_REC_CHNUM 2
61 #define ENVY24HT_PLAY_BUFUNIT (4 /* byte/sample */ * 8 /* channel */)
62 #define ENVY24HT_REC_BUFUNIT (4 /* byte/sample */ * 2 /* channel */)
63 #define ENVY24HT_SAMPLE_NUM 4096
65 #define ENVY24HT_TIMEOUT 1000
67 #define ENVY24HT_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE)
69 #define ENVY24HT_NAMELEN 32
71 #define abs(i) (i < 0 ? -i : i)
73 struct envy24ht_sample {
74 volatile u_int32_t buffer;
77 typedef struct envy24ht_sample sample32_t;
79 /* channel registers */
81 struct snd_dbuf *buffer;
82 struct pcm_channel *channel;
83 struct sc_info *parent;
85 unsigned num; /* hw channel number */
87 /* channel information */
90 u_int32_t blk; /* hw block size(dword) */
92 /* format conversion structure */
94 unsigned int size; /* data buffer size(byte) */
95 int unit; /* sample size(byte) */
96 unsigned int offset; /* samples number offset */
97 void (*emldma)(struct sc_chinfo *);
103 /* codec interface entrys */
105 void *(*create)(device_t dev, void *devinfo, int dir, int num);
106 void (*destroy)(void *codec);
107 void (*init)(void *codec);
108 void (*reinit)(void *codec);
109 void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
110 void (*setrate)(void *codec, int which, int rate);
113 /* system configuration information */
116 u_int16_t subvendor, subdevice;
117 u_int8_t scfg, acl, i2s, spdif;
118 u_int32_t gpiomask, gpiostate, gpiodir;
119 u_int32_t cdti, cclk, cs;
120 u_int8_t cif, type, free;
121 struct codec_entry *codec;
124 /* device private data */
129 /* Control/Status registor */
133 bus_space_handle_t csh;
134 /* MultiTrack registor */
138 bus_space_handle_t mth;
142 struct resource *irq;
146 /* system configuration data */
147 struct cfg_info *cfg;
149 /* ADC/DAC number and info */
151 void *adc[4], *dac[4];
153 /* mixer control data */
155 u_int8_t left[ENVY24HT_CHAN_NUM];
156 u_int8_t right[ENVY24HT_CHAN_NUM];
158 /* Play/Record DMA fifo */
161 u_int32_t psize, rsize; /* DMA buffer size(byte) */
162 u_int16_t blk[2]; /* transfer check blocksize(dword) */
163 bus_dmamap_t pmap, rmap;
169 struct pcmchan_caps caps[2];
171 /* channel info table */
173 struct sc_chinfo chan[11];
176 /* -------------------------------------------------------------------- */
183 static void envy24ht_p8u(struct sc_chinfo *);
184 static void envy24ht_p16sl(struct sc_chinfo *);
185 static void envy24ht_p32sl(struct sc_chinfo *);
186 static void envy24ht_r16sl(struct sc_chinfo *);
187 static void envy24ht_r32sl(struct sc_chinfo *);
189 /* channel interface */
190 static void *envy24htchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
191 static int envy24htchan_setformat(kobj_t, void *, u_int32_t);
192 static int envy24htchan_setspeed(kobj_t, void *, u_int32_t);
193 static int envy24htchan_setblocksize(kobj_t, void *, u_int32_t);
194 static int envy24htchan_trigger(kobj_t, void *, int);
195 static int envy24htchan_getptr(kobj_t, void *);
196 static struct pcmchan_caps *envy24htchan_getcaps(kobj_t, void *);
198 /* mixer interface */
199 static int envy24htmixer_init(struct snd_mixer *);
200 static int envy24htmixer_reinit(struct snd_mixer *);
201 static int envy24htmixer_uninit(struct snd_mixer *);
202 static int envy24htmixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
203 static u_int32_t envy24htmixer_setrecsrc(struct snd_mixer *, u_int32_t);
205 /* SPI codec access interface */
206 static void *envy24ht_spi_create(device_t, void *, int, int);
207 static void envy24ht_spi_destroy(void *);
208 static void envy24ht_spi_init(void *);
209 static void envy24ht_spi_reinit(void *);
210 static void envy24ht_spi_setvolume(void *, int, unsigned int, unsigned int);
212 /* -------------------------------------------------------------------- */
215 system constant tables
218 /* API -> hardware channel map */
219 static unsigned envy24ht_chanmap[ENVY24HT_CHAN_NUM] = {
220 ENVY24HT_CHAN_PLAY_DAC1, /* 1 */
221 ENVY24HT_CHAN_PLAY_DAC2, /* 2 */
222 ENVY24HT_CHAN_PLAY_DAC3, /* 3 */
223 ENVY24HT_CHAN_PLAY_DAC4, /* 4 */
224 ENVY24HT_CHAN_PLAY_SPDIF, /* 0 */
225 ENVY24HT_CHAN_REC_MIX, /* 5 */
226 ENVY24HT_CHAN_REC_SPDIF, /* 6 */
227 ENVY24HT_CHAN_REC_ADC1, /* 7 */
228 ENVY24HT_CHAN_REC_ADC2, /* 8 */
229 ENVY24HT_CHAN_REC_ADC3, /* 9 */
230 ENVY24HT_CHAN_REC_ADC4, /* 10 */
233 /* mixer -> API channel map. see above */
234 static int envy24ht_mixmap[] = {
235 -1, /* Master output level. It is depend on codec support */
236 -1, /* Treble level of all output channels */
237 -1, /* Bass level of all output channels */
238 -1, /* Volume of synthesier input */
239 0, /* Output level for the audio device */
240 -1, /* Output level for the PC speaker */
241 7, /* line in jack */
242 -1, /* microphone jack */
243 -1, /* CD audio input */
244 -1, /* Recording monitor */
245 1, /* alternative codec */
246 -1, /* global recording level */
248 -1, /* Output gain */
249 8, /* Input source 1 */
250 9, /* Input source 2 */
251 10, /* Input source 3 */
252 6, /* Digital (input) 1 */
253 -1, /* Digital (input) 2 */
254 -1, /* Digital (input) 3 */
255 -1, /* Phone input */
256 -1, /* Phone output */
257 -1, /* Video/TV (audio) in */
259 -1, /* Monitor volume */
262 /* variable rate audio */
263 static u_int32_t envy24ht_speed[] = {
264 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
265 12000, 11025, 9600, 8000, 0
268 /* known boards configuration */
269 static struct codec_entry spi_codec = {
271 envy24ht_spi_destroy,
274 envy24ht_spi_setvolume,
278 static struct cfg_info cfg_table[] = {
280 "Envy24HT audio (Terratec Aureon 7.1 Space)",
282 0x0b, 0x80, 0xfc, 0xc3,
283 0x21efff, 0x7fffff, 0x5e1000,
284 0x40000, 0x80000, 0x1000, 0x00, 0x02,
289 "Envy24HT audio (Terratec Aureon 5.1 Sky)",
291 0x0a, 0x80, 0xfc, 0xc3,
292 0x21efff, 0x7fffff, 0x5e1000,
293 0x40000, 0x80000, 0x1000, 0x00, 0x02,
298 "Envy24HT audio (Terratec Aureon 7.1 Universe)",
300 0x0b, 0x80, 0xfc, 0xc3,
301 0x21efff, 0x7fffff, 0x5e1000,
302 0x40000, 0x80000, 0x1000, 0x00, 0x02,
307 "Envy24HT audio (AudioTrak Prodigy 7.1)",
309 0x0b, 0x80, 0xfc, 0xc3,
310 0x21efff, 0x7fffff, 0x5e1000,
311 0x40000, 0x80000, 0x1000, 0x00, 0x02,
316 "Envy24HT audio (Terratec PHASE 28)",
318 0x0b, 0x80, 0xfc, 0xc3,
319 0x21efff, 0x7fffff, 0x5e1000,
320 0x40000, 0x80000, 0x1000, 0x00, 0x02,
325 "Envy24HT-S audio (Terratec PHASE 22)",
327 0x10, 0x80, 0xf0, 0xc3,
328 0x7ffbc7, 0x7fffff, 0x438,
329 0x20, 0x10, 0x400, 0x00, 0x00,
334 "Envy24HT audio (AudioTrak Prodigy 7.1 LT)",
336 0x4b, 0x80, 0xfc, 0xc3,
337 0x7ff8ff, 0x7fffff, 0x700,
338 0x400, 0x200, 0x100, 0x00, 0x02,
343 "Envy24HT audio (AudioTrak Prodigy 7.1 XT)",
345 0x4b, 0x80, 0xfc, 0xc3,
346 0x7ff8ff, 0x7fffff, 0x700,
347 0x400, 0x200, 0x100, 0x00, 0x02,
352 "Envy24HT audio (M-Audio Revolution 7.1)",
354 0x43, 0x80, 0xf8, 0xc1,
355 0x3fff85, 0x72, 0x4000fa,
356 0x08, 0x02, 0x20, 0x00, 0x04,
361 "Envy24GT audio (M-Audio Revolution 5.1)",
363 0x42, 0x80, 0xf8, 0xc1,
364 0x3fff85, 0x72, 0x4000fa,
365 0x08, 0x02, 0x10, 0x00, 0x03,
370 "Envy24HT audio (M-Audio Audiophile 192)",
372 0x68, 0x80, 0xf8, 0xc3,
373 0x45, 0x4000b5, 0x7fffba,
374 0x08, 0x02, 0x10, 0x00, 0x03,
379 "Envy24HT audio (AudioTrak Prodigy HD2)",
381 0x68, 0x80, 0x78, 0xc3,
382 0xfff8ff, 0x200700, 0xdfffff,
383 0x400, 0x200, 0x100, 0x00, 0x05,
388 "Envy24HT audio (ESI Juli@)",
390 0x20, 0x80, 0xf8, 0xc3,
391 0x7fff9f, 0x8016, 0x7fff9f,
392 0x08, 0x02, 0x10, 0x00, 0x03,
397 "Envy24HT audio (Generic)",
399 0x0b, 0x80, 0xfc, 0xc3,
400 0x21efff, 0x7fffff, 0x5e1000,
401 0x40000, 0x80000, 0x1000, 0x00, 0x02,
403 &spi_codec, /* default codec routines */
407 static u_int32_t envy24ht_recfmt[] = {
408 AFMT_STEREO | AFMT_S16_LE,
409 AFMT_STEREO | AFMT_S32_LE,
412 static struct pcmchan_caps envy24ht_reccaps = {8000, 96000, envy24ht_recfmt, 0};
414 static u_int32_t envy24ht_playfmt[] = {
415 AFMT_STEREO | AFMT_U8,
416 AFMT_STEREO | AFMT_S16_LE,
417 AFMT_STEREO | AFMT_S32_LE,
421 static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0};
423 struct envy24ht_emldma {
425 void (*emldma)(struct sc_chinfo *);
429 static struct envy24ht_emldma envy24ht_pemltab[] = {
430 {AFMT_STEREO | AFMT_U8, envy24ht_p8u, 2},
431 {AFMT_STEREO | AFMT_S16_LE, envy24ht_p16sl, 4},
432 {AFMT_STEREO | AFMT_S32_LE, envy24ht_p32sl, 8},
436 static struct envy24ht_emldma envy24ht_remltab[] = {
437 {AFMT_STEREO | AFMT_S16_LE, envy24ht_r16sl, 4},
438 {AFMT_STEREO | AFMT_S32_LE, envy24ht_r32sl, 8},
442 /* -------------------------------------------------------------------- */
444 /* common routines */
446 envy24ht_rdcs(struct sc_info *sc, int regno, int size)
450 return bus_space_read_1(sc->cst, sc->csh, regno);
452 return bus_space_read_2(sc->cst, sc->csh, regno);
454 return bus_space_read_4(sc->cst, sc->csh, regno);
461 envy24ht_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
465 bus_space_write_1(sc->cst, sc->csh, regno, data);
468 bus_space_write_2(sc->cst, sc->csh, regno, data);
471 bus_space_write_4(sc->cst, sc->csh, regno, data);
477 envy24ht_rdmt(struct sc_info *sc, int regno, int size)
481 return bus_space_read_1(sc->mtt, sc->mth, regno);
483 return bus_space_read_2(sc->mtt, sc->mth, regno);
485 return bus_space_read_4(sc->mtt, sc->mth, regno);
492 envy24ht_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
496 bus_space_write_1(sc->mtt, sc->mth, regno, data);
499 bus_space_write_2(sc->mtt, sc->mth, regno, data);
502 bus_space_write_4(sc->mtt, sc->mth, regno, data);
507 /* -------------------------------------------------------------------- */
509 /* I2C port/E2PROM access routines */
512 envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
518 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
520 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
521 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
522 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
524 DELAY(32); /* 31.25kHz */
526 if (i == ENVY24HT_TIMEOUT) {
529 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
530 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
531 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_RD, 1);
532 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
533 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
534 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
536 DELAY(32); /* 31.25kHz */
538 if (i == ENVY24HT_TIMEOUT) {
541 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CDATA, 1);
544 device_printf(sc->dev, "envy24ht_rdi2c(): return 0x%x\n", data);
550 envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
556 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
558 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
559 tmp = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
560 if ((tmp & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
562 DELAY(32); /* 31.25kHz */
564 if (i == ENVY24HT_TIMEOUT) {
567 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
568 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDATA, data, 1);
569 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
570 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_WR, 1);
571 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
572 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
573 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
575 DELAY(32); /* 31.25kHz */
577 if (i == ENVY24HT_TIMEOUT) {
585 envy24ht_rdrom(struct sc_info *sc, u_int32_t addr)
590 device_printf(sc->dev, "envy24ht_rdrom(sc, 0x%02x)\n", addr);
592 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
593 if ((data & ENVY24HT_CCS_I2CSTAT_ROM) == 0) {
595 device_printf(sc->dev, "envy24ht_rdrom(): E2PROM not presented\n");
600 return envy24ht_rdi2c(sc, ENVY24HT_CCS_I2CDEV_ROM, addr);
603 static struct cfg_info *
604 envy24ht_rom2cfg(struct sc_info *sc)
606 struct cfg_info *buff;
611 device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n");
613 size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE);
614 if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) {
616 device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size);
618 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK);
621 /* no valid e2prom, using default values */
622 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
623 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
624 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
625 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
630 buff->gpiomask = 0x21efff;
631 buff->gpiostate = 0x7fffff;
632 buff->gpiodir = 0x5e1000;
633 buff->cdti = 0x40000;
634 buff->cclk = 0x80000;
639 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0;
641 if (cfg_table[i].subvendor == buff->subvendor &&
642 cfg_table[i].subdevice == buff->subdevice)
644 buff->name = cfg_table[i].name;
645 buff->codec = cfg_table[i].codec;
652 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK);
655 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
656 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
657 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
658 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
659 buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG);
660 buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL);
661 buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S);
662 buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF);
663 buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \
664 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \
665 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16;
666 buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \
667 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \
668 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16;
669 buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \
670 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \
671 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16;
673 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
674 if (cfg_table[i].subvendor == buff->subvendor &&
675 cfg_table[i].subdevice == buff->subdevice)
677 buff->name = cfg_table[i].name;
678 buff->codec = cfg_table[i].codec;
684 envy24ht_cfgfree(struct cfg_info *cfg) {
688 kfree(cfg, M_ENVY24HT);
692 /* -------------------------------------------------------------------- */
694 /* AC'97 codec access routines */
698 envy24ht_coldcd(struct sc_info *sc)
704 device_printf(sc->dev, "envy24ht_coldcd()\n");
706 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1);
708 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
710 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
711 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
712 if (data & ENVY24HT_MT_AC97CMD_RDY) {
721 envy24ht_slavecd(struct sc_info *sc)
727 device_printf(sc->dev, "envy24ht_slavecd()\n");
729 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD,
730 ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1);
732 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
734 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
735 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
736 if (data & ENVY24HT_MT_AC97CMD_RDY) {
745 envy24ht_rdcd(kobj_t obj, void *devinfo, int regno)
747 struct sc_info *sc = (struct sc_info *)devinfo;
752 device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno);
754 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
755 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1);
756 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
757 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
758 if ((data & ENVY24HT_MT_AC97CMD_RD) == 0)
761 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2);
764 device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data);
770 envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
772 struct sc_info *sc = (struct sc_info *)devinfo;
777 device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
779 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
780 envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2);
781 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1);
782 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
783 cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
784 if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0)
791 static kobj_method_t envy24ht_ac97_methods[] = {
792 KOBJMETHOD(ac97_read, envy24ht_rdcd),
793 KOBJMETHOD(ac97_write, envy24ht_wrcd),
796 AC97_DECLARE(envy24ht_ac97);
799 /* -------------------------------------------------------------------- */
801 /* GPIO access routines */
804 envy24ht_gpiord(struct sc_info *sc)
806 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
807 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2);
809 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2));
813 envy24ht_gpiowr(struct sc_info *sc, u_int32_t data)
816 device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF);
819 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2);
820 if (sc->cfg->subdevice != 0x1150)
821 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1);
827 envy24ht_gpiogetmask(struct sc_info *sc)
829 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2));
834 envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask)
836 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2);
837 if (sc->cfg->subdevice != 0x1150)
838 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1);
844 envy24ht_gpiogetdir(struct sc_info *sc)
846 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4);
851 envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir)
853 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
854 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2);
856 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4);
860 /* -------------------------------------------------------------------- */
862 /* SPI codec access interface routine */
864 struct envy24ht_spi_codec {
865 struct spicds_info *info;
866 struct sc_info *parent;
873 envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
876 struct envy24ht_spi_codec *ptr = codec;
879 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
881 data = envy24ht_gpiord(ptr->parent);
882 data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
883 if (cs) data += ptr->cs;
884 if (cclk) data += ptr->cclk;
885 if (cdti) data += ptr->cdti;
886 envy24ht_gpiowr(ptr->parent, data);
891 envy24ht_spi_create(device_t dev, void *info, int dir, int num)
893 struct sc_info *sc = info;
894 struct envy24ht_spi_codec *buff = NULL;
897 device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num);
900 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK);
902 if (dir == PCMDIR_REC && sc->adc[num] != NULL)
903 buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info;
904 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
905 buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info;
907 buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl);
908 if (buff->info == NULL) {
909 kfree(buff, M_ENVY24HT);
921 envy24ht_spi_destroy(void *codec)
923 struct envy24ht_spi_codec *ptr = codec;
927 device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n");
930 if (ptr->dir == PCMDIR_PLAY) {
931 if (ptr->parent->dac[ptr->num] != NULL)
932 spicds_destroy(ptr->info);
935 if (ptr->parent->adc[ptr->num] != NULL)
936 spicds_destroy(ptr->info);
939 kfree(codec, M_ENVY24HT);
943 envy24ht_spi_init(void *codec)
945 struct envy24ht_spi_codec *ptr = codec;
949 device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n");
951 ptr->cs = ptr->parent->cfg->cs;
952 ptr->cclk = ptr->parent->cfg->cclk;
953 ptr->cdti = ptr->parent->cfg->cdti;
954 spicds_settype(ptr->info, ptr->parent->cfg->type);
955 spicds_setcif(ptr->info, ptr->parent->cfg->cif);
956 if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \
957 ptr->parent->cfg->type == SPICDS_TYPE_AK4528) {
958 spicds_setformat(ptr->info,
959 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
960 spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
963 /* for the time being, init only first codec */
965 spicds_init(ptr->info);
969 envy24ht_spi_reinit(void *codec)
971 struct envy24ht_spi_codec *ptr = codec;
975 device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n");
978 spicds_reinit(ptr->info);
982 envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
984 struct envy24ht_spi_codec *ptr = codec;
988 device_printf(ptr->parent->dev, "envy24ht_spi_set()\n");
991 spicds_set(ptr->info, dir, left, right);
994 /* -------------------------------------------------------------------- */
996 /* hardware access routeines */
1001 } envy24ht_speedtab[] = {
1002 {48000, ENVY24HT_MT_RATE_48000},
1003 {24000, ENVY24HT_MT_RATE_24000},
1004 {12000, ENVY24HT_MT_RATE_12000},
1005 {9600, ENVY24HT_MT_RATE_9600},
1006 {32000, ENVY24HT_MT_RATE_32000},
1007 {16000, ENVY24HT_MT_RATE_16000},
1008 {8000, ENVY24HT_MT_RATE_8000},
1009 {96000, ENVY24HT_MT_RATE_96000},
1010 {192000, ENVY24HT_MT_RATE_192000},
1011 {64000, ENVY24HT_MT_RATE_64000},
1012 {44100, ENVY24HT_MT_RATE_44100},
1013 {22050, ENVY24HT_MT_RATE_22050},
1014 {11025, ENVY24HT_MT_RATE_11025},
1015 {88200, ENVY24HT_MT_RATE_88200},
1016 {176400, ENVY24HT_MT_RATE_176400},
1021 envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) {
1022 u_int32_t code, i2sfmt;
1026 device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed);
1028 code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */
1029 envy24ht_slavecd(sc);
1033 for (i = 0; envy24ht_speedtab[i].speed != 0; i++) {
1034 if (envy24ht_speedtab[i].speed == speed)
1037 code = envy24ht_speedtab[i].code;
1040 device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code);
1043 envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1);
1044 if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \
1045 (code == ENVY24HT_MT_RATE_176400)) {
1046 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1047 i2sfmt |= ENVY24HT_MT_I2S_MLR128;
1048 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1051 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1052 i2sfmt &= ~ENVY24HT_MT_I2S_MLR128;
1053 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1055 code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1);
1056 code &= ENVY24HT_MT_RATE_MASK;
1057 for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) {
1058 if (envy24ht_speedtab[i].code == code)
1061 speed = envy24ht_speedtab[i].speed;
1067 device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed);
1073 envy24ht_setvolume(struct sc_info *sc, unsigned ch)
1076 device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch);
1077 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1078 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1079 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1080 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1085 envy24ht_mutevolume(struct sc_info *sc, unsigned ch)
1090 device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch);
1091 vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE;
1092 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1093 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1094 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1095 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1100 envy24ht_gethwptr(struct sc_info *sc, int dir)
1106 device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir);
1108 if (dir == PCMDIR_PLAY) {
1109 rtn = sc->psize / 4;
1110 unit = ENVY24HT_PLAY_BUFUNIT / 4;
1111 regno = ENVY24HT_MT_PCNT;
1114 rtn = sc->rsize / 4;
1115 unit = ENVY24HT_REC_BUFUNIT / 4;
1116 regno = ENVY24HT_MT_RCNT;
1119 ptr = envy24ht_rdmt(sc, regno, 2);
1124 device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn);
1130 envy24ht_updintr(struct sc_info *sc, int dir)
1132 int regptr, regintr;
1133 u_int32_t mask, intr;
1134 u_int32_t ptr, size, cnt;
1138 device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir);
1140 if (dir == PCMDIR_PLAY) {
1142 size = sc->psize / 4;
1143 regptr = ENVY24HT_MT_PCNT;
1144 regintr = ENVY24HT_MT_PTERM;
1145 mask = ~ENVY24HT_MT_INT_PMASK;
1149 size = sc->rsize / 4;
1150 regptr = ENVY24HT_MT_RCNT;
1151 regintr = ENVY24HT_MT_RTERM;
1152 mask = ~ENVY24HT_MT_INT_RMASK;
1155 ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1;
1157 cnt = blk - ptr % blk - 1;
1163 device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1165 envy24ht_wrmt(sc, regintr, cnt, 2);
1166 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1168 device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1170 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
1172 device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
1173 envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
1181 envy24ht_maskintr(struct sc_info *sc, int dir)
1183 u_int32_t mask, intr;
1186 device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
1188 if (dir == PCMDIR_PLAY)
1189 mask = ENVY24HT_MT_INT_PMASK;
1191 mask = ENVY24HT_MT_INT_RMASK;
1192 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
1193 envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
1200 envy24ht_checkintr(struct sc_info *sc, int dir)
1202 u_int32_t mask, stat, intr, rtn;
1205 device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
1207 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
1208 if (dir == PCMDIR_PLAY) {
1209 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
1210 mask = ~ENVY24HT_MT_INT_RSTAT;
1211 envy24ht_wrmt(sc, 0x1a, 0x01, 1);
1212 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);
1213 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1214 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
1218 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
1219 mask = ~ENVY24HT_MT_INT_PSTAT;
1221 stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
1223 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
1224 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1225 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
1233 envy24ht_start(struct sc_info *sc, int dir)
1238 device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
1240 if (dir == PCMDIR_PLAY)
1241 sw = ENVY24HT_MT_PCTL_PSTART;
1243 sw = ENVY24HT_MT_PCTL_RSTART;
1245 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1246 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
1249 device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
1250 device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
1257 envy24ht_stop(struct sc_info *sc, int dir)
1262 device_printf(sc->dev, "envy24ht_stop(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);
1277 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1283 /* -------------------------------------------------------------------- */
1285 /* buffer copy routines */
1287 envy24ht_p32sl(struct sc_chinfo *ch)
1292 int src, dst, ssize, dsize, slot;
1295 length = sndbuf_getready(ch->buffer) / 8;
1296 dmabuf = ch->parent->pbuf;
1297 data = (u_int32_t *)ch->data;
1298 src = sndbuf_getreadyptr(ch->buffer) / 4;
1299 dst = src / 2 + ch->offset;
1300 ssize = ch->size / 4;
1301 dsize = ch->size / 8;
1304 for (i = 0; i < length; i++) {
1305 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
1306 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1317 envy24ht_p16sl(struct sc_chinfo *ch)
1322 int src, dst, ssize, dsize, slot;
1326 device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
1328 length = sndbuf_getready(ch->buffer) / 4;
1329 dmabuf = ch->parent->pbuf;
1330 data = (u_int16_t *)ch->data;
1331 src = sndbuf_getreadyptr(ch->buffer) / 2;
1332 dst = src / 2 + ch->offset;
1333 ssize = ch->size / 2;
1334 dsize = ch->size / 4;
1337 device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1340 for (i = 0; i < length; i++) {
1341 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1342 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1345 kprintf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
1346 kprintf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
1362 envy24ht_p8u(struct sc_chinfo *ch)
1367 int src, dst, ssize, dsize, slot;
1370 length = sndbuf_getready(ch->buffer) / 2;
1371 dmabuf = ch->parent->pbuf;
1373 src = sndbuf_getreadyptr(ch->buffer);
1374 dst = src / 2 + ch->offset;
1376 dsize = ch->size / 4;
1379 for (i = 0; i < length; i++) {
1380 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1381 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1392 envy24ht_r32sl(struct sc_chinfo *ch)
1397 int src, dst, ssize, dsize, slot;
1400 length = sndbuf_getfree(ch->buffer) / 8;
1401 dmabuf = ch->parent->rbuf;
1402 data = (u_int32_t *)ch->data;
1403 dst = sndbuf_getfreeptr(ch->buffer) / 4;
1404 src = dst / 2 + ch->offset;
1405 dsize = ch->size / 4;
1406 ssize = ch->size / 8;
1407 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1409 for (i = 0; i < length; i++) {
1410 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1411 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1422 envy24ht_r16sl(struct sc_chinfo *ch)
1427 int src, dst, ssize, dsize, slot;
1430 length = sndbuf_getfree(ch->buffer) / 4;
1431 dmabuf = ch->parent->rbuf;
1432 data = (u_int16_t *)ch->data;
1433 dst = sndbuf_getfreeptr(ch->buffer) / 2;
1434 src = dst / 2 + ch->offset;
1435 dsize = ch->size / 2;
1436 ssize = ch->size / 8;
1437 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1439 for (i = 0; i < length; i++) {
1440 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1441 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1451 /* -------------------------------------------------------------------- */
1453 /* channel interface */
1455 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1457 struct sc_info *sc = (struct sc_info *)devinfo;
1458 struct sc_chinfo *ch;
1462 device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
1464 snd_mtxlock(sc->lock);
1466 if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1467 (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1468 snd_mtxunlock(sc->lock);
1474 ch = &sc->chan[num];
1475 ch->size = 8 * ENVY24HT_SAMPLE_NUM;
1476 ch->data = kmalloc(ch->size, M_ENVY24HT, M_WAITOK);
1482 /* set channel map */
1483 ch->num = envy24ht_chanmap[num];
1484 snd_mtxunlock(sc->lock);
1485 sndbuf_setup(ch->buffer, ch->data, ch->size);
1486 snd_mtxlock(sc->lock);
1487 /* these 2 values are dummy */
1491 snd_mtxunlock(sc->lock);
1497 envy24htchan_free(kobj_t obj, void *data)
1499 struct sc_chinfo *ch = data;
1500 struct sc_info *sc = ch->parent;
1503 device_printf(sc->dev, "envy24htchan_free()\n");
1505 snd_mtxlock(sc->lock);
1506 if (ch->data != NULL) {
1507 kfree(ch->data, M_ENVY24HT);
1510 snd_mtxunlock(sc->lock);
1516 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
1518 struct sc_chinfo *ch = data;
1519 struct sc_info *sc = ch->parent;
1520 struct envy24ht_emldma *emltab;
1521 /* unsigned int bcnt, bsize; */
1525 device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
1527 snd_mtxlock(sc->lock);
1528 /* check and get format related information */
1529 if (ch->dir == PCMDIR_PLAY)
1530 emltab = envy24ht_pemltab;
1532 emltab = envy24ht_remltab;
1533 if (emltab == NULL) {
1534 snd_mtxunlock(sc->lock);
1537 for (i = 0; emltab[i].format != 0; i++)
1538 if (emltab[i].format == format)
1540 if (emltab[i].format == 0) {
1541 snd_mtxunlock(sc->lock);
1545 /* set format information */
1546 ch->format = format;
1547 ch->emldma = emltab[i].emldma;
1548 if (ch->unit > emltab[i].unit)
1549 ch->blk *= ch->unit / emltab[i].unit;
1551 ch->blk /= emltab[i].unit / ch->unit;
1552 ch->unit = emltab[i].unit;
1554 /* set channel buffer information */
1555 ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
1557 if (ch->dir == PCMDIR_PLAY)
1558 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1560 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1562 bcnt = ch->size / bsize;
1563 sndbuf_resize(ch->buffer, bcnt, bsize);
1565 snd_mtxunlock(sc->lock);
1568 device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
1574 IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1575 of speed information value. And real hardware speed setting is done
1576 at start triggered(see envy24htchan_trigger()). So, at this function
1577 is called, any value that ENVY24 can use is able to set. But, at
1578 start triggerd, some other channel is running, and that channel's
1579 speed isn't same with, then trigger function will fail.
1582 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1584 struct sc_chinfo *ch = data;
1585 u_int32_t val, prev;
1589 device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
1592 for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
1593 if (abs(val - speed) < abs(prev - speed))
1601 device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
1607 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1609 struct sc_chinfo *ch = data;
1610 /* struct sc_info *sc = ch->parent; */
1611 u_int32_t size, prev;
1612 unsigned int bcnt, bsize;
1615 device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
1618 /* snd_mtxlock(sc->lock); */
1619 for (size = ch->size / 2; size > 0; size /= 2) {
1620 if (abs(size - blocksize) < abs(prev - blocksize))
1626 ch->blk = prev / ch->unit;
1627 if (ch->dir == PCMDIR_PLAY)
1628 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
1630 ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
1631 /* set channel buffer information */
1632 /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
1633 if (ch->dir == PCMDIR_PLAY)
1634 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1636 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1638 bcnt = ch->size / bsize;
1639 sndbuf_resize(ch->buffer, bcnt, bsize);
1640 /* snd_mtxunlock(sc->lock); */
1643 device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
1648 /* semantic note: must start at beginning of buffer */
1650 envy24htchan_trigger(kobj_t obj, void *data, int go)
1652 struct sc_chinfo *ch = data;
1653 struct sc_info *sc = ch->parent;
1659 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1661 snd_mtxlock(sc->lock);
1662 if (ch->dir == PCMDIR_PLAY)
1669 device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1671 /* check or set channel speed */
1672 if (sc->run[0] == 0 && sc->run[1] == 0) {
1673 sc->speed = envy24ht_setspeed(sc, ch->speed);
1674 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1675 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1677 else if (ch->speed != 0 && ch->speed != sc->speed)
1680 ch->channel->speed = sc->speed;
1681 /* start or enable channel */
1683 if (sc->run[slot] == 1) {
1686 sc->blk[slot] = ch->blk;
1689 ptr = envy24ht_gethwptr(sc, ch->dir);
1690 ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1691 (ch->size / 4)) * 4 / ch->unit;
1692 if (ch->blk < sc->blk[slot])
1693 sc->blk[slot] = ch->blk;
1695 if (ch->dir == PCMDIR_PLAY) {
1697 envy24ht_setvolume(sc, ch->num);
1699 envy24ht_updintr(sc, ch->dir);
1700 if (sc->run[slot] == 1)
1701 envy24ht_start(sc, ch->dir);
1704 case PCMTRIG_EMLDMAWR:
1706 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1712 case PCMTRIG_EMLDMARD:
1714 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1723 device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1727 if (ch->dir == PCMDIR_PLAY)
1728 envy24ht_mutevolume(sc, ch->num);
1729 if (sc->run[slot] == 0) {
1730 envy24ht_stop(sc, ch->dir);
1733 /* else if (ch->blk == sc->blk[slot]) {
1734 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1735 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1736 if (sc->chan[i].dir == ch->dir &&
1737 sc->chan[i].run == 1 &&
1738 sc->chan[i].blk < sc->blk[slot])
1739 sc->blk[slot] = sc->chan[i].blk;
1741 if (ch->blk != sc->blk[slot])
1742 envy24ht_updintr(sc, ch->dir);
1747 snd_mtxunlock(sc->lock);
1753 envy24htchan_getptr(kobj_t obj, void *data)
1755 struct sc_chinfo *ch = data;
1756 struct sc_info *sc = ch->parent;
1761 device_printf(sc->dev, "envy24htchan_getptr()\n");
1763 snd_mtxlock(sc->lock);
1764 ptr = envy24ht_gethwptr(sc, ch->dir);
1765 rtn = ptr * ch->unit;
1766 snd_mtxunlock(sc->lock);
1769 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1775 static struct pcmchan_caps *
1776 envy24htchan_getcaps(kobj_t obj, void *data)
1778 struct sc_chinfo *ch = data;
1779 struct sc_info *sc = ch->parent;
1780 struct pcmchan_caps *rtn;
1783 device_printf(sc->dev, "envy24htchan_getcaps()\n");
1785 snd_mtxlock(sc->lock);
1786 if (ch->dir == PCMDIR_PLAY) {
1787 if (sc->run[0] == 0)
1788 rtn = &envy24ht_playcaps;
1793 if (sc->run[1] == 0)
1794 rtn = &envy24ht_reccaps;
1798 snd_mtxunlock(sc->lock);
1803 static kobj_method_t envy24htchan_methods[] = {
1804 KOBJMETHOD(channel_init, envy24htchan_init),
1805 KOBJMETHOD(channel_free, envy24htchan_free),
1806 KOBJMETHOD(channel_setformat, envy24htchan_setformat),
1807 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed),
1808 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize),
1809 KOBJMETHOD(channel_trigger, envy24htchan_trigger),
1810 KOBJMETHOD(channel_getptr, envy24htchan_getptr),
1811 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps),
1814 CHANNEL_DECLARE(envy24htchan);
1816 /* -------------------------------------------------------------------- */
1818 /* mixer interface */
1821 envy24htmixer_init(struct snd_mixer *m)
1823 struct sc_info *sc = mix_getdevinfo(m);
1826 device_printf(sc->dev, "envy24htmixer_init()\n");
1831 /* set volume control rate */
1832 snd_mtxlock(sc->lock);
1834 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1837 pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1839 mix_setdevs(m, ENVY24HT_MIX_MASK);
1840 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1842 snd_mtxunlock(sc->lock);
1848 envy24htmixer_reinit(struct snd_mixer *m)
1850 struct sc_info *sc = mix_getdevinfo(m);
1855 device_printf(sc->dev, "envy24htmixer_reinit()\n");
1862 envy24htmixer_uninit(struct snd_mixer *m)
1864 struct sc_info *sc = mix_getdevinfo(m);
1869 device_printf(sc->dev, "envy24htmixer_uninit()\n");
1876 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1878 struct sc_info *sc = mix_getdevinfo(m);
1879 int ch = envy24ht_mixmap[dev];
1885 if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1887 if (dev != 0 && ch == -1)
1889 hwch = envy24ht_chanmap[ch];
1891 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1895 snd_mtxlock(sc->lock);
1897 for (i = 0; i < sc->dacn; i++) {
1898 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1902 /* set volume value for hardware */
1903 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1904 sc->left[hwch] = ENVY24HT_VOL_MUTE;
1905 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1906 sc->right[hwch] = ENVY24HT_VOL_MUTE;
1908 /* set volume for record channel and running play channel */
1909 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1910 envy24ht_setvolume(sc, hwch);
1912 snd_mtxunlock(sc->lock);
1914 return right << 8 | left;
1918 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1920 struct sc_info *sc = mix_getdevinfo(m);
1921 int ch = envy24ht_mixmap[src];
1923 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1926 if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1931 static kobj_method_t envy24htmixer_methods[] = {
1932 KOBJMETHOD(mixer_init, envy24htmixer_init),
1933 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit),
1934 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit),
1935 KOBJMETHOD(mixer_set, envy24htmixer_set),
1936 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc),
1939 MIXER_DECLARE(envy24htmixer);
1941 /* -------------------------------------------------------------------- */
1943 /* The interrupt handler */
1945 envy24ht_intr(void *p)
1947 struct sc_info *sc = (struct sc_info *)p;
1948 struct sc_chinfo *ch;
1949 u_int32_t ptr, dsize, feed;
1953 device_printf(sc->dev, "envy24ht_intr()\n");
1955 snd_mtxlock(sc->lock);
1956 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1958 device_printf(sc->dev, "envy24ht_intr(): play\n");
1960 dsize = sc->psize / 4;
1961 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
1963 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
1965 ptr -= ptr % sc->blk[0];
1966 feed = (ptr + dsize - sc->intr[0]) % dsize;
1968 kprintf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
1970 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
1974 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
1976 if (ch->run && ch->blk <= feed) {
1977 snd_mtxunlock(sc->lock);
1978 chn_intr(ch->channel);
1979 snd_mtxlock(sc->lock);
1983 envy24ht_updintr(sc, PCMDIR_PLAY);
1985 if (envy24ht_checkintr(sc, PCMDIR_REC)) {
1987 device_printf(sc->dev, "envy24ht_intr(): rec\n");
1989 dsize = sc->rsize / 4;
1990 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
1991 ptr -= ptr % sc->blk[1];
1992 feed = (ptr + dsize - sc->intr[1]) % dsize;
1993 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
1995 if (ch->run && ch->blk <= feed) {
1996 snd_mtxunlock(sc->lock);
1997 chn_intr(ch->channel);
1998 snd_mtxlock(sc->lock);
2002 envy24ht_updintr(sc, PCMDIR_REC);
2004 snd_mtxunlock(sc->lock);
2010 * Probe and attach the card
2014 envy24ht_pci_probe(device_t dev)
2020 kprintf("envy24ht_pci_probe()\n");
2022 if (pci_get_device(dev) == PCID_ENVY24HT &&
2023 pci_get_vendor(dev) == PCIV_ENVY24) {
2024 sv = pci_get_subvendor(dev);
2025 sd = pci_get_subdevice(dev);
2026 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2027 if (cfg_table[i].subvendor == sv &&
2028 cfg_table[i].subdevice == sd) {
2032 device_set_desc(dev, cfg_table[i].name);
2034 kprintf("envy24ht_pci_probe(): return 0\n");
2040 kprintf("envy24ht_pci_probe(): return ENXIO\n");
2047 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2049 /* struct sc_info *sc = (struct sc_info *)arg; */
2052 device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2054 kprintf("envy24ht(play): setmap %lx, %lx; ",
2055 (unsigned long)segs->ds_addr,
2056 (unsigned long)segs->ds_len);
2057 kprintf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2063 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2065 /* struct sc_info *sc = (struct sc_info *)arg; */
2068 device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2070 kprintf("envy24ht(record): setmap %lx, %lx; ",
2071 (unsigned long)segs->ds_addr,
2072 (unsigned long)segs->ds_len);
2073 kprintf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2079 envy24ht_dmafree(struct sc_info *sc)
2082 device_printf(sc->dev, "envy24ht_dmafree():");
2083 if (sc->rmap) kprintf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2084 else kprintf(" sc->rmap(null)");
2085 if (sc->pmap) kprintf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2086 else kprintf(" sc->pmap(null)");
2087 if (sc->rbuf) kprintf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2088 else kprintf(" sc->rbuf(null)");
2089 if (sc->pbuf) kprintf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2090 else kprintf(" sc->pbuf(null)\n");
2094 bus_dmamap_unload(sc->dmat, sc->rmap);
2096 bus_dmamap_unload(sc->dmat, sc->pmap);
2098 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2100 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2102 bus_dmamap_unload(sc->dmat, sc->rmap);
2103 bus_dmamap_unload(sc->dmat, sc->pmap);
2104 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2105 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2108 sc->rmap = sc->pmap = NULL;
2116 envy24ht_dmainit(struct sc_info *sc)
2121 device_printf(sc->dev, "envy24ht_dmainit()\n");
2124 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2125 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2128 sc->pmap = sc->rmap = NULL;
2129 sc->blk[0] = sc->blk[1] = 0;
2131 /* allocate DMA buffer */
2133 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2135 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2138 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2140 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2143 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2145 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, 0))
2148 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2150 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, 0))
2152 bzero(sc->pbuf, sc->psize);
2153 bzero(sc->rbuf, sc->rsize);
2155 /* set values to register */
2156 addr = vtophys(sc->pbuf);
2158 device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2160 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, addr, 4);
2162 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
2163 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2165 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, sc->psize / 4 - 1, 2);
2167 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
2169 addr = vtophys(sc->rbuf);
2170 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, addr, 4);
2171 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, sc->rsize / 4 - 1, 2);
2175 envy24ht_dmafree(sc);
2180 envy24ht_putcfg(struct sc_info *sc)
2182 device_printf(sc->dev, "system configuration\n");
2183 kprintf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2184 sc->cfg->subvendor, sc->cfg->subdevice);
2185 kprintf(" XIN2 Clock Source: ");
2186 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2188 kprintf("24.576MHz(96kHz*256)\n");
2191 kprintf("49.152MHz(192kHz*256)\n");
2194 kprintf("reserved\n");
2197 kprintf("illegal system setting\n");
2199 kprintf(" MPU-401 UART(s) #: ");
2200 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2203 kprintf("not implemented\n");
2207 kprintf(" ADC #: ");
2208 kprintf("%d\n", sc->adcn);
2211 kprintf(" ADC #: ");
2213 kprintf(" and SPDIF receiver connected\n");
2216 kprintf(" no physical inputs\n");
2218 kprintf(" DAC #: ");
2219 kprintf("%d\n", sc->dacn);
2220 kprintf(" Multi-track converter type: ");
2221 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2222 kprintf("AC'97(SDATA_OUT:");
2223 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2231 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2232 kprintf("with volume, ");
2233 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2234 kprintf("192KHz support, ");
2236 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2237 kprintf("192KHz support, ");
2239 kprintf("48KHz support, ");
2240 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2241 case ENVY24HT_CCSM_I2S_16BIT:
2242 kprintf("16bit resolution, ");
2244 case ENVY24HT_CCSM_I2S_18BIT:
2245 kprintf("18bit resolution, ");
2247 case ENVY24HT_CCSM_I2S_20BIT:
2248 kprintf("20bit resolution, ");
2250 case ENVY24HT_CCSM_I2S_24BIT:
2251 kprintf("24bit resolution, ");
2254 kprintf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2256 kprintf(" S/PDIF(IN/OUT): ");
2257 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2261 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2265 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2266 kprintf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2267 kprintf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2268 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2272 envy24ht_init(struct sc_info *sc)
2283 device_printf(sc->dev, "envy24ht_init()\n");
2288 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2290 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2293 /* legacy hardware disable */
2294 data = pci_read_config(sc->dev, PCIR_LAC, 2);
2295 data |= PCIM_LAC_DISABLE;
2296 pci_write_config(sc->dev, PCIR_LAC, data, 2);
2299 /* check system configuration */
2301 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2302 /* 1st: search configuration from table */
2303 sv = pci_get_subvendor(sc->dev);
2304 sd = pci_get_subdevice(sc->dev);
2305 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2307 device_printf(sc->dev, "Set configuration from table\n");
2309 sc->cfg = &cfg_table[i];
2313 if (sc->cfg == NULL) {
2314 /* 2nd: read configuration from table */
2315 sc->cfg = envy24ht_rom2cfg(sc);
2317 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2318 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2320 if (1 /* bootverbose */) {
2321 envy24ht_putcfg(sc);
2324 /* set system configuration */
2325 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2326 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2327 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2328 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2329 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2330 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2331 envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2333 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2334 envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2335 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2336 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2339 for (i = 0; i < sc->adcn; i++) {
2340 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2341 sc->cfg->codec->init(sc->adc[i]);
2343 for (i = 0; i < sc->dacn; i++) {
2344 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2345 sc->cfg->codec->init(sc->dac[i]);
2348 /* initialize DMA buffer */
2350 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2352 if (envy24ht_dmainit(sc))
2355 /* initialize status */
2356 sc->run[0] = sc->run[1] = 0;
2357 sc->intr[0] = sc->intr[1] = 0;
2359 sc->caps[0].fmtlist = envy24ht_playfmt;
2360 sc->caps[1].fmtlist = envy24ht_recfmt;
2362 /* set channel router */
2364 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2365 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2366 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2369 /* set macro interrupt mask */
2370 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2371 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2372 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2374 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2381 envy24ht_alloc_resource(struct sc_info *sc)
2383 /* allocate I/O port resource */
2384 sc->csid = PCIR_CCS;
2385 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2386 &sc->csid, 0, ~0, 1, RF_ACTIVE);
2387 sc->mtid = ENVY24HT_PCIR_MT;
2388 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2389 &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2390 if (!sc->cs || !sc->mt) {
2391 device_printf(sc->dev, "unable to map IO port space\n");
2394 sc->cst = rman_get_bustag(sc->cs);
2395 sc->csh = rman_get_bushandle(sc->cs);
2396 sc->mtt = rman_get_bustag(sc->mt);
2397 sc->mth = rman_get_bushandle(sc->mt);
2399 device_printf(sc->dev,
2400 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2401 pci_read_config(sc->dev, PCIR_CCS, 4),
2402 pci_read_config(sc->dev, PCIR_MT, 4));
2405 /* allocate interupt resource */
2407 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2408 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2410 snd_setup_intr(sc->dev, sc->irq, 0, envy24ht_intr, sc, &sc->ih)) {
2411 device_printf(sc->dev, "unable to map interrupt\n");
2415 /* allocate DMA resource */
2416 if (bus_dma_tag_create(/*parent*/NULL,
2419 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2420 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2421 /*filter*/NULL, /*filterarg*/NULL,
2422 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2423 /*nsegments*/1, /*maxsegsz*/0x3ffff,
2424 /*flags*/0 , &sc->dmat) != 0) {
2425 device_printf(sc->dev, "unable to create dma tag\n");
2433 envy24ht_pci_attach(device_t dev)
2437 char status[SND_STATUSLEN];
2442 device_printf(dev, "envy24ht_pci_attach()\n");
2444 /* get sc_info data area */
2445 sc = kmalloc(sizeof(*sc), M_ENVY24HT, M_WAITOK | M_ZERO);
2446 sc->lock = snd_mtxcreate(device_get_nameunit(dev),
2447 "snd_envy24ht softc");
2450 /* initialize PCI interface */
2451 data = pci_read_config(dev, PCIR_COMMAND, 2);
2452 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2453 pci_write_config(dev, PCIR_COMMAND, data, 2);
2454 data = pci_read_config(dev, PCIR_COMMAND, 2);
2456 /* allocate resources */
2457 err = envy24ht_alloc_resource(sc);
2459 device_printf(dev, "unable to allocate system resources\n");
2463 /* initialize card */
2464 err = envy24ht_init(sc);
2466 device_printf(dev, "unable to initialize the card\n");
2470 /* set multi track mixer */
2471 mixer_init(dev, &envy24htmixer_class, sc);
2473 /* set channel information */
2474 /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
2475 err = pcm_register(dev, sc, 1, 2 + sc->adcn);
2479 /* for (i = 0; i < 5; i++) { */
2480 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
2483 for (i = 0; i < 2 + sc->adcn; i++) {
2484 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
2488 /* set status iformation */
2489 ksnprintf(status, SND_STATUSLEN,
2490 "at io 0x%lx:%ld,0x%lx:%ld irq %ld",
2491 rman_get_start(sc->cs),
2492 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2493 rman_get_start(sc->mt),
2494 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2495 rman_get_start(sc->irq));
2496 pcm_setstatus(dev, status);
2502 bus_teardown_intr(dev, sc->irq, sc->ih);
2504 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2505 envy24ht_dmafree(sc);
2507 bus_dma_tag_destroy(sc->dmat);
2508 if (sc->cfg->codec->destroy != NULL) {
2509 for (i = 0; i < sc->adcn; i++)
2510 sc->cfg->codec->destroy(sc->adc[i]);
2511 for (i = 0; i < sc->dacn; i++)
2512 sc->cfg->codec->destroy(sc->dac[i]);
2514 envy24ht_cfgfree(sc->cfg);
2516 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2518 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2520 snd_mtxfree(sc->lock);
2521 kfree(sc, M_ENVY24HT);
2526 envy24ht_pci_detach(device_t dev)
2533 device_printf(dev, "envy24ht_pci_detach()\n");
2535 sc = pcm_getdevinfo(dev);
2538 r = pcm_unregister(dev);
2542 envy24ht_dmafree(sc);
2543 if (sc->cfg->codec->destroy != NULL) {
2544 for (i = 0; i < sc->adcn; i++)
2545 sc->cfg->codec->destroy(sc->adc[i]);
2546 for (i = 0; i < sc->dacn; i++)
2547 sc->cfg->codec->destroy(sc->dac[i]);
2549 envy24ht_cfgfree(sc->cfg);
2550 bus_dma_tag_destroy(sc->dmat);
2551 bus_teardown_intr(dev, sc->irq, sc->ih);
2552 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2553 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2554 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2555 snd_mtxfree(sc->lock);
2556 kfree(sc, M_ENVY24HT);
2560 static device_method_t envy24ht_methods[] = {
2561 /* Device interface */
2562 DEVMETHOD(device_probe, envy24ht_pci_probe),
2563 DEVMETHOD(device_attach, envy24ht_pci_attach),
2564 DEVMETHOD(device_detach, envy24ht_pci_detach),
2568 static driver_t envy24ht_driver = {
2571 #if __FreeBSD_version > 500000
2574 sizeof(struct snddev_info),
2578 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, NULL, NULL);
2579 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2580 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2581 MODULE_VERSION(snd_envy24ht, 1);