2 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
26 * $FreeBSD: src/sys/dev/sound/pci/envy24.c,v 1.11.2.2 2007/06/11 19:33:27 ariff Exp $
29 #include <dev/sound/pcm/sound.h>
30 #include <dev/sound/pcm/ac97.h>
31 #include <dev/sound/pci/spicds.h>
32 #include <dev/sound/pci/envy24.h>
34 #include <bus/pci/pcireg.h>
35 #include <bus/pci/pcivar.h>
39 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pci/envy24.c,v 1.3 2008/01/05 14:02:38 swildner Exp $");
41 MALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio");
43 /* -------------------------------------------------------------------- */
47 #define ENVY24_PLAY_CHNUM 10
48 #define ENVY24_REC_CHNUM 12
49 #define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */)
50 #define ENVY24_REC_BUFUNIT (4 /* byte/sample */ * 12 /* channel */)
51 #define ENVY24_SAMPLE_NUM 4096
53 #define ENVY24_TIMEOUT 1000
55 #define ENVY24_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE)
57 #define ENVY24_NAMELEN 32
62 #define abs(i) (i < 0 ? -i : i)
64 struct envy24_sample {
65 volatile u_int32_t buffer;
68 typedef struct envy24_sample sample32_t;
70 /* channel registers */
72 struct snd_dbuf *buffer;
73 struct pcm_channel *channel;
74 struct sc_info *parent;
76 unsigned num; /* hw channel number */
78 /* channel information */
81 u_int32_t blk; /* hw block size(dword) */
83 /* format conversion structure */
85 unsigned int size; /* data buffer size(byte) */
86 int unit; /* sample size(byte) */
87 unsigned int offset; /* samples number offset */
88 void (*emldma)(struct sc_chinfo *);
94 /* codec interface entrys */
96 void *(*create)(device_t dev, void *devinfo, int dir, int num);
97 void (*destroy)(void *codec);
98 void (*init)(void *codec);
99 void (*reinit)(void *codec);
100 void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
101 void (*setrate)(void *codec, int which, int rate);
104 /* system configuration information */
107 u_int16_t subvendor, subdevice;
108 u_int8_t scfg, acl, i2s, spdif;
109 u_int8_t gpiomask, gpiostate, gpiodir;
110 u_int8_t cdti, cclk, cs, cif, type;
112 struct codec_entry *codec;
115 /* device private data */
120 /* Control/Status registor */
124 bus_space_handle_t csh;
126 struct resource *ddma;
128 bus_space_tag_t ddmat;
129 bus_space_handle_t ddmah;
130 /* Consumer Section DMA Channel Registers */
134 bus_space_handle_t dsh;
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[ENVY24_CHAN_NUM];
157 u_int8_t right[ENVY24_CHAN_NUM];
159 /* Play/Record DMA fifo */
162 u_int32_t psize, rsize; /* DMA buffer size(byte) */
163 u_int16_t blk[2]; /* transfer check blocksize(dword) */
164 bus_dmamap_t pmap, rmap;
170 struct pcmchan_caps caps[2];
172 /* channel info table */
174 struct sc_chinfo chan[11];
177 /* -------------------------------------------------------------------- */
184 static void envy24_p8u(struct sc_chinfo *);
185 static void envy24_p16sl(struct sc_chinfo *);
186 static void envy24_p32sl(struct sc_chinfo *);
187 static void envy24_r16sl(struct sc_chinfo *);
188 static void envy24_r32sl(struct sc_chinfo *);
190 /* channel interface */
191 static void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
192 static int envy24chan_setformat(kobj_t, void *, u_int32_t);
193 static int envy24chan_setspeed(kobj_t, void *, u_int32_t);
194 static int envy24chan_setblocksize(kobj_t, void *, u_int32_t);
195 static int envy24chan_trigger(kobj_t, void *, int);
196 static int envy24chan_getptr(kobj_t, void *);
197 static struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *);
199 /* mixer interface */
200 static int envy24mixer_init(struct snd_mixer *);
201 static int envy24mixer_reinit(struct snd_mixer *);
202 static int envy24mixer_uninit(struct snd_mixer *);
203 static int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
204 static u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t);
206 /* M-Audio Delta series AK4524 access interface */
207 static void *envy24_delta_ak4524_create(device_t, void *, int, int);
208 static void envy24_delta_ak4524_destroy(void *);
209 static void envy24_delta_ak4524_init(void *);
210 static void envy24_delta_ak4524_reinit(void *);
211 static void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int);
213 /* -------------------------------------------------------------------- */
216 system constant tables
219 /* API -> hardware channel map */
220 static unsigned envy24_chanmap[ENVY24_CHAN_NUM] = {
221 ENVY24_CHAN_PLAY_SPDIF, /* 0 */
222 ENVY24_CHAN_PLAY_DAC1, /* 1 */
223 ENVY24_CHAN_PLAY_DAC2, /* 2 */
224 ENVY24_CHAN_PLAY_DAC3, /* 3 */
225 ENVY24_CHAN_PLAY_DAC4, /* 4 */
226 ENVY24_CHAN_REC_MIX, /* 5 */
227 ENVY24_CHAN_REC_SPDIF, /* 6 */
228 ENVY24_CHAN_REC_ADC1, /* 7 */
229 ENVY24_CHAN_REC_ADC2, /* 8 */
230 ENVY24_CHAN_REC_ADC3, /* 9 */
231 ENVY24_CHAN_REC_ADC4, /* 10 */
234 /* mixer -> API channel map. see above */
235 static int envy24_mixmap[] = {
236 -1, /* Master output level. It is depend on codec support */
237 -1, /* Treble level of all output channels */
238 -1, /* Bass level of all output channels */
239 -1, /* Volume of synthesier input */
240 0, /* Output level for the audio device */
241 -1, /* Output level for the PC speaker */
242 7, /* line in jack */
243 -1, /* microphone jack */
244 -1, /* CD audio input */
245 -1, /* Recording monitor */
246 1, /* alternative codec */
247 -1, /* global recording level */
249 -1, /* Output gain */
250 8, /* Input source 1 */
251 9, /* Input source 2 */
252 10, /* Input source 3 */
253 6, /* Digital (input) 1 */
254 -1, /* Digital (input) 2 */
255 -1, /* Digital (input) 3 */
256 -1, /* Phone input */
257 -1, /* Phone output */
258 -1, /* Video/TV (audio) in */
260 -1, /* Monitor volume */
263 /* variable rate audio */
264 static u_int32_t envy24_speed[] = {
265 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
266 12000, 11025, 9600, 8000, 0
269 /* known boards configuration */
270 static struct codec_entry delta_codec = {
271 envy24_delta_ak4524_create,
272 envy24_delta_ak4524_destroy,
273 envy24_delta_ak4524_init,
274 envy24_delta_ak4524_reinit,
275 envy24_delta_ak4524_setvolume,
279 static struct cfg_info cfg_table[] = {
281 "Envy24 audio (M Audio Delta Dio 2496)",
283 0x10, 0x80, 0xf0, 0x03,
285 0x10, 0x20, 0x40, 0x00, 0x00,
290 "Envy24 audio (Terratec DMX 6fire)",
292 0x2f, 0x80, 0xf0, 0x03,
294 0x10, 0x20, 0x01, 0x01, 0x00,
299 "Envy24 audio (M Audio Audiophile 2496)",
301 0x10, 0x80, 0x72, 0x03,
303 0x08, 0x02, 0x20, 0x00, 0x01,
308 "Envy24 audio (Generic)",
310 0x0f, 0x00, 0x01, 0x03,
312 0x10, 0x20, 0x40, 0x00, 0x00,
314 &delta_codec, /* default codec routines */
318 static u_int32_t envy24_recfmt[] = {
319 AFMT_STEREO | AFMT_S16_LE,
320 AFMT_STEREO | AFMT_S32_LE,
323 static struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0};
325 static u_int32_t envy24_playfmt[] = {
326 AFMT_STEREO | AFMT_U8,
327 AFMT_STEREO | AFMT_S16_LE,
328 AFMT_STEREO | AFMT_S32_LE,
332 static struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0};
334 struct envy24_emldma {
336 void (*emldma)(struct sc_chinfo *);
340 static struct envy24_emldma envy24_pemltab[] = {
341 {AFMT_STEREO | AFMT_U8, envy24_p8u, 2},
342 {AFMT_STEREO | AFMT_S16_LE, envy24_p16sl, 4},
343 {AFMT_STEREO | AFMT_S32_LE, envy24_p32sl, 8},
347 static struct envy24_emldma envy24_remltab[] = {
348 {AFMT_STEREO | AFMT_S16_LE, envy24_r16sl, 4},
349 {AFMT_STEREO | AFMT_S32_LE, envy24_r32sl, 8},
353 /* -------------------------------------------------------------------- */
355 /* common routines */
357 envy24_rdcs(struct sc_info *sc, int regno, int size)
361 return bus_space_read_1(sc->cst, sc->csh, regno);
363 return bus_space_read_2(sc->cst, sc->csh, regno);
365 return bus_space_read_4(sc->cst, sc->csh, regno);
372 envy24_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
376 bus_space_write_1(sc->cst, sc->csh, regno, data);
379 bus_space_write_2(sc->cst, sc->csh, regno, data);
382 bus_space_write_4(sc->cst, sc->csh, regno, data);
388 envy24_rdmt(struct sc_info *sc, int regno, int size)
392 return bus_space_read_1(sc->mtt, sc->mth, regno);
394 return bus_space_read_2(sc->mtt, sc->mth, regno);
396 return bus_space_read_4(sc->mtt, sc->mth, regno);
403 envy24_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
407 bus_space_write_1(sc->mtt, sc->mth, regno, data);
410 bus_space_write_2(sc->mtt, sc->mth, regno, data);
413 bus_space_write_4(sc->mtt, sc->mth, regno, data);
419 envy24_rdci(struct sc_info *sc, int regno)
421 envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
422 return envy24_rdcs(sc, ENVY24_CCS_DATA, 1);
426 envy24_wrci(struct sc_info *sc, int regno, u_int32_t data)
428 envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
429 envy24_wrcs(sc, ENVY24_CCS_DATA, data, 1);
432 /* -------------------------------------------------------------------- */
434 /* I2C port/E2PROM access routines */
437 envy24_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
443 device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
445 for (i = 0; i < ENVY24_TIMEOUT; i++) {
446 data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
447 if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
449 DELAY(32); /* 31.25kHz */
451 if (i == ENVY24_TIMEOUT) {
454 envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
455 envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
456 (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_RD, 1);
457 for (i = 0; i < ENVY24_TIMEOUT; i++) {
458 data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
459 if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
461 DELAY(32); /* 31.25kHz */
463 if (i == ENVY24_TIMEOUT) {
466 data = envy24_rdcs(sc, ENVY24_CCS_I2CDATA, 1);
469 device_printf(sc->dev, "envy24_rdi2c(): return 0x%x\n", data);
476 envy24_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
482 device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
484 for (i = 0; i < ENVY24_TIMEOUT; i++) {
485 tmp = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
486 if ((tmp & ENVY24_CCS_I2CSTAT_BSY) == 0)
488 DELAY(32); /* 31.25kHz */
490 if (i == ENVY24_TIMEOUT) {
493 envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
494 envy24_wrcs(sc, ENVY24_CCS_I2CDATA, data, 1);
495 envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
496 (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_WR, 1);
497 for (i = 0; i < ENVY24_TIMEOUT; i++) {
498 data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
499 if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
501 DELAY(32); /* 31.25kHz */
503 if (i == ENVY24_TIMEOUT) {
512 envy24_rdrom(struct sc_info *sc, u_int32_t addr)
517 device_printf(sc->dev, "envy24_rdrom(sc, 0x%02x)\n", addr);
519 data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
520 if ((data & ENVY24_CCS_I2CSTAT_ROM) == 0) {
522 device_printf(sc->dev, "envy24_rdrom(): E2PROM not presented\n");
527 return envy24_rdi2c(sc, ENVY24_CCS_I2CDEV_ROM, addr);
530 static struct cfg_info *
531 envy24_rom2cfg(struct sc_info *sc)
533 struct cfg_info *buff;
538 device_printf(sc->dev, "envy24_rom2cfg(sc)\n");
540 size = envy24_rdrom(sc, ENVY24_E2PROM_SIZE);
541 if (size < ENVY24_E2PROM_GPIODIR + 1) {
543 device_printf(sc->dev, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size);
547 buff = kmalloc(sizeof(*buff), M_ENVY24, M_WAITOK);
550 buff->subvendor = envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR) << 8;
551 buff->subvendor += envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR + 1);
552 buff->subdevice = envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE) << 8;
553 buff->subdevice += envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE + 1);
554 buff->scfg = envy24_rdrom(sc, ENVY24_E2PROM_SCFG);
555 buff->acl = envy24_rdrom(sc, ENVY24_E2PROM_ACL);
556 buff->i2s = envy24_rdrom(sc, ENVY24_E2PROM_I2S);
557 buff->spdif = envy24_rdrom(sc, ENVY24_E2PROM_SPDIF);
558 buff->gpiomask = envy24_rdrom(sc, ENVY24_E2PROM_GPIOMASK);
559 buff->gpiostate = envy24_rdrom(sc, ENVY24_E2PROM_GPIOSTATE);
560 buff->gpiodir = envy24_rdrom(sc, ENVY24_E2PROM_GPIODIR);
562 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
563 if (cfg_table[i].subvendor == buff->subvendor &&
564 cfg_table[i].subdevice == buff->subdevice)
566 buff->name = cfg_table[i].name;
567 buff->codec = cfg_table[i].codec;
573 envy24_cfgfree(struct cfg_info *cfg) {
577 kfree(cfg, M_ENVY24);
581 /* -------------------------------------------------------------------- */
583 /* AC'97 codec access routines */
587 envy24_coldcd(struct sc_info *sc)
593 device_printf(sc->dev, "envy24_coldcd()\n");
595 envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_CLD, 1);
597 envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
599 for (i = 0; i < ENVY24_TIMEOUT; i++) {
600 data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
601 if (data & ENVY24_MT_AC97CMD_RDY) {
611 envy24_slavecd(struct sc_info *sc)
617 device_printf(sc->dev, "envy24_slavecd()\n");
619 envy24_wrmt(sc, ENVY24_MT_AC97CMD,
620 ENVY24_MT_AC97CMD_CLD | ENVY24_MT_AC97CMD_WRM, 1);
622 envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
624 for (i = 0; i < ENVY24_TIMEOUT; i++) {
625 data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
626 if (data & ENVY24_MT_AC97CMD_RDY) {
636 envy24_rdcd(kobj_t obj, void *devinfo, int regno)
638 struct sc_info *sc = (struct sc_info *)devinfo;
643 device_printf(sc->dev, "envy24_rdcd(obj, sc, 0x%02x)\n", regno);
645 envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
646 envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_RD, 1);
647 for (i = 0; i < ENVY24_TIMEOUT; i++) {
648 data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
649 if ((data & ENVY24_MT_AC97CMD_RD) == 0)
652 data = envy24_rdmt(sc, ENVY24_MT_AC97DLO, 2);
655 device_printf(sc->dev, "envy24_rdcd(): return 0x%x\n", data);
661 envy24_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
663 struct sc_info *sc = (struct sc_info *)devinfo;
668 device_printf(sc->dev, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
670 envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
671 envy24_wrmt(sc, ENVY24_MT_AC97DLO, (u_int32_t)data, 2);
672 envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_WR, 1);
673 for (i = 0; i < ENVY24_TIMEOUT; i++) {
674 cmd = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
675 if ((cmd & ENVY24_MT_AC97CMD_WR) == 0)
682 static kobj_method_t envy24_ac97_methods[] = {
683 KOBJMETHOD(ac97_read, envy24_rdcd),
684 KOBJMETHOD(ac97_write, envy24_wrcd),
687 AC97_DECLARE(envy24_ac97);
690 /* -------------------------------------------------------------------- */
692 /* GPIO access routines */
695 envy24_gpiord(struct sc_info *sc)
697 return envy24_rdci(sc, ENVY24_CCI_GPIODAT);
701 envy24_gpiowr(struct sc_info *sc, u_int32_t data)
704 device_printf(sc->dev, "envy24_gpiowr(sc, 0x%02x)\n", data & 0xff);
707 envy24_wrci(sc, ENVY24_CCI_GPIODAT, data);
713 envy24_gpiogetmask(struct sc_info *sc)
715 return envy24_rdci(sc, ENVY24_CCI_GPIOMASK);
720 envy24_gpiosetmask(struct sc_info *sc, u_int32_t mask)
722 envy24_wrci(sc, ENVY24_CCI_GPIOMASK, mask);
728 envy24_gpiogetdir(struct sc_info *sc)
730 return envy24_rdci(sc, ENVY24_CCI_GPIOCTL);
735 envy24_gpiosetdir(struct sc_info *sc, u_int32_t dir)
737 envy24_wrci(sc, ENVY24_CCI_GPIOCTL, dir);
741 /* -------------------------------------------------------------------- */
743 /* Envy24 I2C through GPIO bit-banging */
745 struct envy24_delta_ak4524_codec {
746 struct spicds_info *info;
747 struct sc_info *parent;
754 envy24_gpio_i2c_ctl(void *codec, unsigned int scl, unsigned int sda)
757 struct envy24_delta_ak4524_codec *ptr = codec;
759 device_printf(ptr->parent->dev, "--> %d, %d\n", scl, sda);
761 data = envy24_gpiord(ptr->parent);
762 data &= ~(SDA_GPIO | SCL_GPIO);
763 if (scl) data += SCL_GPIO;
764 if (sda) data += SDA_GPIO;
765 envy24_gpiowr(ptr->parent, data);
770 i2c_wrbit(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), int bit)
772 struct envy24_delta_ak4524_codec *ptr = codec;
789 i2c_start(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
791 struct envy24_delta_ak4524_codec *ptr = codec;
802 i2c_stop(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
804 struct envy24_delta_ak4524_codec *ptr = codec;
815 i2c_ack(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
817 struct envy24_delta_ak4524_codec *ptr = codec;
823 /* dummy, need routine to change gpio direction */
829 i2c_wr(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), u_int32_t dev, int reg, u_int8_t val)
831 struct envy24_delta_ak4524_codec *ptr = codec;
834 i2c_start(ptr, ctrl);
836 for (mask = 0x80; mask != 0; mask >>= 1)
837 i2c_wrbit(ptr, ctrl, dev & mask);
841 for (mask = 0x80; mask != 0; mask >>= 1)
842 i2c_wrbit(ptr, ctrl, reg & mask);
846 for (mask = 0x80; mask != 0; mask >>= 1)
847 i2c_wrbit(ptr, ctrl, val & mask);
853 /* -------------------------------------------------------------------- */
855 /* M-Audio Delta series AK4524 access interface routine */
858 envy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
861 struct envy24_delta_ak4524_codec *ptr = codec;
864 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
866 data = envy24_gpiord(ptr->parent);
867 data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
868 if (cs) data += ptr->cs;
869 if (cclk) data += ptr->cclk;
870 if (cdti) data += ptr->cdti;
871 envy24_gpiowr(ptr->parent, data);
876 envy24_delta_ak4524_create(device_t dev, void *info, int dir, int num)
878 struct sc_info *sc = info;
879 struct envy24_delta_ak4524_codec *buff = NULL;
882 device_printf(sc->dev, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir, num);
885 buff = kmalloc(sizeof(*buff), M_ENVY24, M_WAITOK);
887 if (dir == PCMDIR_REC && sc->adc[num] != NULL)
888 buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info;
889 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
890 buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info;
892 buff->info = spicds_create(dev, buff, num, envy24_delta_ak4524_ctl);
893 if (buff->info == NULL) {
894 kfree(buff, M_ENVY24);
906 envy24_delta_ak4524_destroy(void *codec)
908 struct envy24_delta_ak4524_codec *ptr = codec;
912 device_printf(ptr->parent->dev, "envy24_delta_ak4524_destroy()\n");
915 if (ptr->dir == PCMDIR_PLAY) {
916 if (ptr->parent->dac[ptr->num] != NULL)
917 spicds_destroy(ptr->info);
920 if (ptr->parent->adc[ptr->num] != NULL)
921 spicds_destroy(ptr->info);
924 kfree(codec, M_ENVY24);
928 envy24_delta_ak4524_init(void *codec)
931 u_int32_t gpiomask, gpiodir;
933 struct envy24_delta_ak4524_codec *ptr = codec;
937 device_printf(ptr->parent->dev, "envy24_delta_ak4524_init()\n");
941 gpiomask = envy24_gpiogetmask(ptr->parent);
942 gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1);
943 envy24_gpiosetmask(ptr->parent, gpiomask);
944 gpiodir = envy24_gpiogetdir(ptr->parent);
945 gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1;
946 envy24_gpiosetdir(ptr->parent, gpiodir);
948 ptr->cs = ptr->parent->cfg->cs;
950 envy24_gpiosetmask(ptr->parent, ENVY24_GPIO_CS8414_STATUS);
951 envy24_gpiosetdir(ptr->parent, ~ENVY24_GPIO_CS8414_STATUS);
953 ptr->cs = ENVY24_GPIO_AK4524_CS0;
955 ptr->cs = ENVY24_GPIO_AK4524_CS1;
956 ptr->cclk = ENVY24_GPIO_AK4524_CCLK;
958 ptr->cclk = ptr->parent->cfg->cclk;
959 ptr->cdti = ptr->parent->cfg->cdti;
960 spicds_settype(ptr->info, ptr->parent->cfg->type);
961 spicds_setcif(ptr->info, ptr->parent->cfg->cif);
962 spicds_setformat(ptr->info,
963 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
964 spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
965 /* for the time being, init only first codec */
967 spicds_init(ptr->info);
969 /* 6fire rear input init test, set ptr->num to 1 for test */
970 if (ptr->parent->cfg->subvendor == 0x153b && \
971 ptr->parent->cfg->subdevice == 0x1138 && ptr->num == 100) {
973 spicds_init(ptr->info);
974 device_printf(ptr->parent->dev, "6fire rear input init\n");
975 i2c_wr(ptr, envy24_gpio_i2c_ctl, \
976 PCA9554_I2CDEV, PCA9554_DIR, 0x80);
977 i2c_wr(ptr, envy24_gpio_i2c_ctl, \
978 PCA9554_I2CDEV, PCA9554_OUT, 0x02);
983 envy24_delta_ak4524_reinit(void *codec)
985 struct envy24_delta_ak4524_codec *ptr = codec;
989 device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n");
992 spicds_reinit(ptr->info);
996 envy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
998 struct envy24_delta_ak4524_codec *ptr = codec;
1002 device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n");
1005 spicds_set(ptr->info, dir, left, right);
1009 There is no need for AK452[48] codec to set sample rate
1011 envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate)
1016 /* -------------------------------------------------------------------- */
1018 /* hardware access routeines */
1023 } envy24_speedtab[] = {
1024 {48000, ENVY24_MT_RATE_48000},
1025 {24000, ENVY24_MT_RATE_24000},
1026 {12000, ENVY24_MT_RATE_12000},
1027 {9600, ENVY24_MT_RATE_9600},
1028 {32000, ENVY24_MT_RATE_32000},
1029 {16000, ENVY24_MT_RATE_16000},
1030 {8000, ENVY24_MT_RATE_8000},
1031 {96000, ENVY24_MT_RATE_96000},
1032 {64000, ENVY24_MT_RATE_64000},
1033 {44100, ENVY24_MT_RATE_44100},
1034 {22050, ENVY24_MT_RATE_22050},
1035 {11025, ENVY24_MT_RATE_11025},
1036 {88200, ENVY24_MT_RATE_88200},
1041 envy24_setspeed(struct sc_info *sc, u_int32_t speed) {
1046 device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed);
1049 code = ENVY24_MT_RATE_SPDIF; /* external master clock */
1053 for (i = 0; envy24_speedtab[i].speed != 0; i++) {
1054 if (envy24_speedtab[i].speed == speed)
1057 code = envy24_speedtab[i].code;
1060 device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code);
1063 envy24_wrmt(sc, ENVY24_MT_RATE, code, 1);
1064 code = envy24_rdmt(sc, ENVY24_MT_RATE, 1);
1065 code &= ENVY24_MT_RATE_MASK;
1066 for (i = 0; envy24_speedtab[i].code < 0x10; i++) {
1067 if (envy24_speedtab[i].code == code)
1070 speed = envy24_speedtab[i].speed;
1076 device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed);
1082 envy24_setvolume(struct sc_info *sc, unsigned ch)
1085 device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch);
1087 if (sc->cfg->subvendor==0x153b && sc->cfg->subdevice==0x1138 ) {
1088 envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1);
1089 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1090 envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1);
1091 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1094 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1095 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1096 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1097 envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1101 envy24_mutevolume(struct sc_info *sc, unsigned ch)
1106 device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch);
1108 vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE;
1109 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1110 envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1111 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1112 envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1116 envy24_gethwptr(struct sc_info *sc, int dir)
1122 device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir);
1124 if (dir == PCMDIR_PLAY) {
1125 rtn = sc->psize / 4;
1126 unit = ENVY24_PLAY_BUFUNIT / 4;
1127 regno = ENVY24_MT_PCNT;
1130 rtn = sc->rsize / 4;
1131 unit = ENVY24_REC_BUFUNIT / 4;
1132 regno = ENVY24_MT_RCNT;
1135 ptr = envy24_rdmt(sc, regno, 2);
1140 device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn);
1146 envy24_updintr(struct sc_info *sc, int dir)
1148 int regptr, regintr;
1149 u_int32_t mask, intr;
1150 u_int32_t ptr, size, cnt;
1154 device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir);
1156 if (dir == PCMDIR_PLAY) {
1158 size = sc->psize / 4;
1159 regptr = ENVY24_MT_PCNT;
1160 regintr = ENVY24_MT_PTERM;
1161 mask = ~ENVY24_MT_INT_PMASK;
1165 size = sc->rsize / 4;
1166 regptr = ENVY24_MT_RCNT;
1167 regintr = ENVY24_MT_RTERM;
1168 mask = ~ENVY24_MT_INT_RMASK;
1171 ptr = size - envy24_rdmt(sc, regptr, 2) - 1;
1173 cnt = blk - ptr % blk - 1;
1179 device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1181 envy24_wrmt(sc, regintr, cnt, 2);
1182 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1184 device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1186 envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1);
1188 device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n",
1189 envy24_rdmt(sc, ENVY24_MT_INT, 1));
1197 envy24_maskintr(struct sc_info *sc, int dir)
1199 u_int32_t mask, intr;
1202 device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir);
1204 if (dir == PCMDIR_PLAY)
1205 mask = ENVY24_MT_INT_PMASK;
1207 mask = ENVY24_MT_INT_RMASK;
1208 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1209 envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1);
1216 envy24_checkintr(struct sc_info *sc, int dir)
1218 u_int32_t mask, stat, intr, rtn;
1221 device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir);
1223 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1224 if (dir == PCMDIR_PLAY) {
1225 if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) {
1226 mask = ~ENVY24_MT_INT_RSTAT;
1227 stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK;
1228 envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1232 if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) {
1233 mask = ~ENVY24_MT_INT_PSTAT;
1234 stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK;
1235 envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1243 envy24_start(struct sc_info *sc, int dir)
1248 device_printf(sc->dev, "envy24_start(sc, %d)\n", dir);
1250 if (dir == PCMDIR_PLAY)
1251 sw = ENVY24_MT_PCTL_PSTART;
1253 sw = ENVY24_MT_PCTL_RSTART;
1255 stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1256 envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1);
1259 device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
1260 device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
1267 envy24_stop(struct sc_info *sc, int dir)
1272 device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir);
1274 if (dir == PCMDIR_PLAY)
1275 sw = ~ENVY24_MT_PCTL_PSTART;
1277 sw = ~ENVY24_MT_PCTL_RSTART;
1279 stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1280 envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1);
1286 envy24_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1288 u_int32_t reg, mask;
1289 u_int32_t left, right;
1292 device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n",
1293 dac, class, adc, rev);
1295 /* parameter pattern check */
1296 if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac)
1298 if (class == ENVY24_ROUTE_CLASS_MIX &&
1299 (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF))
1302 left = ENVY24_ROUTE_RIGHT;
1303 right = ENVY24_ROUTE_LEFT;
1306 left = ENVY24_ROUTE_LEFT;
1307 right = ENVY24_ROUTE_RIGHT;
1310 if (dac == ENVY24_ROUTE_DAC_SPDIF) {
1311 reg = class | class << 2 |
1312 ((adc << 1 | left) | left << 3) << 8 |
1313 ((adc << 1 | right) | right << 3) << 12;
1315 device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg);
1317 envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2);
1320 mask = ~(0x0303 << dac * 2);
1321 reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2);
1322 reg = (reg & mask) | ((class | class << 8) << dac * 2);
1324 device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg);
1326 envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2);
1327 mask = ~(0xff << dac * 8);
1328 reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4);
1329 reg = (reg & mask) |
1330 (((adc << 1 | left) | left << 3) |
1331 ((adc << 1 | right) | right << 3) << 4) << dac * 8;
1333 device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg);
1335 envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4);
1337 /* 6fire rear input init test */
1338 envy24_wrmt(sc, ENVY24_MT_RECORD, 0x00, 4);
1344 /* -------------------------------------------------------------------- */
1346 /* buffer copy routines */
1348 envy24_p32sl(struct sc_chinfo *ch)
1353 int src, dst, ssize, dsize, slot;
1356 length = sndbuf_getready(ch->buffer) / 8;
1357 dmabuf = ch->parent->pbuf;
1358 data = (u_int32_t *)ch->data;
1359 src = sndbuf_getreadyptr(ch->buffer) / 4;
1360 dst = src / 2 + ch->offset;
1361 ssize = ch->size / 4;
1362 dsize = ch->size / 8;
1365 for (i = 0; i < length; i++) {
1366 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src];
1367 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1378 envy24_p16sl(struct sc_chinfo *ch)
1383 int src, dst, ssize, dsize, slot;
1387 device_printf(ch->parent->dev, "envy24_p16sl()\n");
1389 length = sndbuf_getready(ch->buffer) / 4;
1390 dmabuf = ch->parent->pbuf;
1391 data = (u_int16_t *)ch->data;
1392 src = sndbuf_getreadyptr(ch->buffer) / 2;
1393 dst = src / 2 + ch->offset;
1394 ssize = ch->size / 2;
1395 dsize = ch->size / 4;
1398 device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1401 for (i = 0; i < length; i++) {
1402 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1403 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1406 printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]);
1407 printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]);
1423 envy24_p8u(struct sc_chinfo *ch)
1428 int src, dst, ssize, dsize, slot;
1431 length = sndbuf_getready(ch->buffer) / 2;
1432 dmabuf = ch->parent->pbuf;
1434 src = sndbuf_getreadyptr(ch->buffer);
1435 dst = src / 2 + ch->offset;
1437 dsize = ch->size / 4;
1440 for (i = 0; i < length; i++) {
1441 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1442 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1453 envy24_r32sl(struct sc_chinfo *ch)
1458 int src, dst, ssize, dsize, slot;
1461 length = sndbuf_getfree(ch->buffer) / 8;
1462 dmabuf = ch->parent->rbuf;
1463 data = (u_int32_t *)ch->data;
1464 dst = sndbuf_getfreeptr(ch->buffer) / 4;
1465 src = dst / 2 + ch->offset;
1466 dsize = ch->size / 4;
1467 ssize = ch->size / 8;
1468 slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1470 for (i = 0; i < length; i++) {
1471 data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1472 data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1483 envy24_r16sl(struct sc_chinfo *ch)
1488 int src, dst, ssize, dsize, slot;
1491 length = sndbuf_getfree(ch->buffer) / 4;
1492 dmabuf = ch->parent->rbuf;
1493 data = (u_int16_t *)ch->data;
1494 dst = sndbuf_getfreeptr(ch->buffer) / 2;
1495 src = dst / 2 + ch->offset;
1496 dsize = ch->size / 2;
1497 ssize = ch->size / 8;
1498 slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1500 for (i = 0; i < length; i++) {
1501 data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1502 data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1512 /* -------------------------------------------------------------------- */
1514 /* channel interface */
1516 envy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1518 struct sc_info *sc = (struct sc_info *)devinfo;
1519 struct sc_chinfo *ch;
1523 device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir);
1525 snd_mtxlock(sc->lock);
1526 if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1527 (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1528 snd_mtxunlock(sc->lock);
1533 ch = &sc->chan[num];
1534 ch->size = 8 * ENVY24_SAMPLE_NUM;
1535 ch->data = kmalloc(ch->size, M_ENVY24, M_WAITOK);
1541 /* set channel map */
1542 ch->num = envy24_chanmap[num];
1543 snd_mtxunlock(sc->lock);
1544 sndbuf_setup(ch->buffer, ch->data, ch->size);
1545 snd_mtxlock(sc->lock);
1546 /* these 2 values are dummy */
1550 snd_mtxunlock(sc->lock);
1556 envy24chan_free(kobj_t obj, void *data)
1558 struct sc_chinfo *ch = data;
1559 struct sc_info *sc = ch->parent;
1562 device_printf(sc->dev, "envy24chan_free()\n");
1564 snd_mtxlock(sc->lock);
1565 if (ch->data != NULL) {
1566 kfree(ch->data, M_ENVY24);
1569 snd_mtxunlock(sc->lock);
1575 envy24chan_setformat(kobj_t obj, void *data, u_int32_t format)
1577 struct sc_chinfo *ch = data;
1578 struct sc_info *sc = ch->parent;
1579 struct envy24_emldma *emltab;
1580 /* unsigned int bcnt, bsize; */
1584 device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format);
1586 snd_mtxlock(sc->lock);
1587 /* check and get format related information */
1588 if (ch->dir == PCMDIR_PLAY)
1589 emltab = envy24_pemltab;
1591 emltab = envy24_remltab;
1592 if (emltab == NULL) {
1593 snd_mtxunlock(sc->lock);
1596 for (i = 0; emltab[i].format != 0; i++)
1597 if (emltab[i].format == format)
1599 if (emltab[i].format == 0) {
1600 snd_mtxunlock(sc->lock);
1604 /* set format information */
1605 ch->format = format;
1606 ch->emldma = emltab[i].emldma;
1607 if (ch->unit > emltab[i].unit)
1608 ch->blk *= ch->unit / emltab[i].unit;
1610 ch->blk /= emltab[i].unit / ch->unit;
1611 ch->unit = emltab[i].unit;
1613 /* set channel buffer information */
1614 ch->size = ch->unit * ENVY24_SAMPLE_NUM;
1616 if (ch->dir == PCMDIR_PLAY)
1617 bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1619 bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1621 bcnt = ch->size / bsize;
1622 sndbuf_resize(ch->buffer, bcnt, bsize);
1624 snd_mtxunlock(sc->lock);
1627 device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0);
1633 IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1634 of speed information value. And real hardware speed setting is done
1635 at start triggered(see envy24chan_trigger()). So, at this function
1636 is called, any value that ENVY24 can use is able to set. But, at
1637 start triggerd, some other channel is running, and that channel's
1638 speed isn't same with, then trigger function will fail.
1641 envy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1643 struct sc_chinfo *ch = data;
1644 u_int32_t val, prev;
1648 device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed);
1651 for (i = 0; (val = envy24_speed[i]) != 0; i++) {
1652 if (abs(val - speed) < abs(prev - speed))
1660 device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed);
1666 envy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1668 struct sc_chinfo *ch = data;
1669 /* struct sc_info *sc = ch->parent; */
1670 u_int32_t size, prev;
1671 unsigned int bcnt, bsize;
1674 device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize);
1677 /* snd_mtxlock(sc->lock); */
1678 for (size = ch->size / 2; size > 0; size /= 2) {
1679 if (abs(size - blocksize) < abs(prev - blocksize))
1685 ch->blk = prev / ch->unit;
1686 if (ch->dir == PCMDIR_PLAY)
1687 ch->blk *= ENVY24_PLAY_BUFUNIT / 4;
1689 ch->blk *= ENVY24_REC_BUFUNIT / 4;
1690 /* set channel buffer information */
1691 /* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */
1692 if (ch->dir == PCMDIR_PLAY)
1693 bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1695 bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1697 bcnt = ch->size / bsize;
1698 sndbuf_resize(ch->buffer, bcnt, bsize);
1699 /* snd_mtxunlock(sc->lock); */
1702 device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev);
1707 /* semantic note: must start at beginning of buffer */
1709 envy24chan_trigger(kobj_t obj, void *data, int go)
1711 struct sc_chinfo *ch = data;
1712 struct sc_info *sc = ch->parent;
1718 device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go);
1720 snd_mtxlock(sc->lock);
1721 if (ch->dir == PCMDIR_PLAY)
1728 device_printf(sc->dev, "envy24chan_trigger(): start\n");
1730 /* check or set channel speed */
1731 if (sc->run[0] == 0 && sc->run[1] == 0) {
1732 sc->speed = envy24_setspeed(sc, ch->speed);
1733 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1734 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1736 else if (ch->speed != 0 && ch->speed != sc->speed)
1739 ch->channel->speed = sc->speed;
1740 /* start or enable channel */
1742 if (sc->run[slot] == 1) {
1745 sc->blk[slot] = ch->blk;
1748 ptr = envy24_gethwptr(sc, ch->dir);
1749 ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1750 (ch->size / 4)) * 4 / ch->unit;
1751 if (ch->blk < sc->blk[slot])
1752 sc->blk[slot] = ch->blk;
1754 if (ch->dir == PCMDIR_PLAY) {
1756 envy24_setvolume(sc, ch->num);
1758 envy24_updintr(sc, ch->dir);
1759 if (sc->run[slot] == 1)
1760 envy24_start(sc, ch->dir);
1763 case PCMTRIG_EMLDMAWR:
1765 device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n");
1771 case PCMTRIG_EMLDMARD:
1773 device_printf(sc->dev, "envy24chan_trigger(): emldmard\n");
1782 device_printf(sc->dev, "envy24chan_trigger(): abort\n");
1786 if (ch->dir == PCMDIR_PLAY)
1787 envy24_mutevolume(sc, ch->num);
1788 if (sc->run[slot] == 0) {
1789 envy24_stop(sc, ch->dir);
1793 else if (ch->blk == sc->blk[slot]) {
1794 sc->blk[slot] = ENVY24_SAMPLE_NUM / 2;
1795 for (i = 0; i < ENVY24_CHAN_NUM; i++) {
1796 if (sc->chan[i].dir == ch->dir &&
1797 sc->chan[i].run == 1 &&
1798 sc->chan[i].blk < sc->blk[slot])
1799 sc->blk[slot] = sc->chan[i].blk;
1801 if (ch->blk != sc->blk[slot])
1802 envy24_updintr(sc, ch->dir);
1808 snd_mtxunlock(sc->lock);
1814 envy24chan_getptr(kobj_t obj, void *data)
1816 struct sc_chinfo *ch = data;
1817 struct sc_info *sc = ch->parent;
1822 device_printf(sc->dev, "envy24chan_getptr()\n");
1824 snd_mtxlock(sc->lock);
1825 ptr = envy24_gethwptr(sc, ch->dir);
1826 rtn = ptr * ch->unit;
1827 snd_mtxunlock(sc->lock);
1830 device_printf(sc->dev, "envy24chan_getptr(): return %d\n",
1836 static struct pcmchan_caps *
1837 envy24chan_getcaps(kobj_t obj, void *data)
1839 struct sc_chinfo *ch = data;
1840 struct sc_info *sc = ch->parent;
1841 struct pcmchan_caps *rtn;
1844 device_printf(sc->dev, "envy24chan_getcaps()\n");
1846 snd_mtxlock(sc->lock);
1847 if (ch->dir == PCMDIR_PLAY) {
1848 if (sc->run[0] == 0)
1849 rtn = &envy24_playcaps;
1854 if (sc->run[1] == 0)
1855 rtn = &envy24_reccaps;
1859 snd_mtxunlock(sc->lock);
1864 static kobj_method_t envy24chan_methods[] = {
1865 KOBJMETHOD(channel_init, envy24chan_init),
1866 KOBJMETHOD(channel_free, envy24chan_free),
1867 KOBJMETHOD(channel_setformat, envy24chan_setformat),
1868 KOBJMETHOD(channel_setspeed, envy24chan_setspeed),
1869 KOBJMETHOD(channel_setblocksize, envy24chan_setblocksize),
1870 KOBJMETHOD(channel_trigger, envy24chan_trigger),
1871 KOBJMETHOD(channel_getptr, envy24chan_getptr),
1872 KOBJMETHOD(channel_getcaps, envy24chan_getcaps),
1875 CHANNEL_DECLARE(envy24chan);
1877 /* -------------------------------------------------------------------- */
1879 /* mixer interface */
1882 envy24mixer_init(struct snd_mixer *m)
1884 struct sc_info *sc = mix_getdevinfo(m);
1887 device_printf(sc->dev, "envy24mixer_init()\n");
1892 /* set volume control rate */
1893 snd_mtxlock(sc->lock);
1894 envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1896 mix_setdevs(m, ENVY24_MIX_MASK);
1897 mix_setrecdevs(m, ENVY24_MIX_REC_MASK);
1898 snd_mtxunlock(sc->lock);
1904 envy24mixer_reinit(struct snd_mixer *m)
1906 struct sc_info *sc = mix_getdevinfo(m);
1911 device_printf(sc->dev, "envy24mixer_reinit()\n");
1918 envy24mixer_uninit(struct snd_mixer *m)
1920 struct sc_info *sc = mix_getdevinfo(m);
1925 device_printf(sc->dev, "envy24mixer_uninit()\n");
1932 envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1934 struct sc_info *sc = mix_getdevinfo(m);
1935 int ch = envy24_mixmap[dev];
1941 if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1943 if (dev != 0 && ch == -1)
1945 hwch = envy24_chanmap[ch];
1947 device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n",
1951 snd_mtxlock(sc->lock);
1953 for (i = 0; i < sc->dacn; i++) {
1954 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1958 /* set volume value for hardware */
1959 if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN)
1960 sc->left[hwch] = ENVY24_VOL_MUTE;
1961 if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN)
1962 sc->right[hwch] = ENVY24_VOL_MUTE;
1964 /* set volume for record channel and running play channel */
1965 if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1966 envy24_setvolume(sc, hwch);
1968 snd_mtxunlock(sc->lock);
1970 return right << 8 | left;
1974 envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1976 struct sc_info *sc = mix_getdevinfo(m);
1977 int ch = envy24_mixmap[src];
1979 device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src);
1982 if (ch > ENVY24_CHAN_PLAY_SPDIF)
1987 static kobj_method_t envy24mixer_methods[] = {
1988 KOBJMETHOD(mixer_init, envy24mixer_init),
1989 KOBJMETHOD(mixer_reinit, envy24mixer_reinit),
1990 KOBJMETHOD(mixer_uninit, envy24mixer_uninit),
1991 KOBJMETHOD(mixer_set, envy24mixer_set),
1992 KOBJMETHOD(mixer_setrecsrc, envy24mixer_setrecsrc),
1995 MIXER_DECLARE(envy24mixer);
1997 /* -------------------------------------------------------------------- */
1999 /* The interrupt handler */
2001 envy24_intr(void *p)
2003 struct sc_info *sc = (struct sc_info *)p;
2004 struct sc_chinfo *ch;
2005 u_int32_t ptr, dsize, feed;
2009 device_printf(sc->dev, "envy24_intr()\n");
2011 snd_mtxlock(sc->lock);
2012 if (envy24_checkintr(sc, PCMDIR_PLAY)) {
2014 device_printf(sc->dev, "envy24_intr(): play\n");
2016 dsize = sc->psize / 4;
2017 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1;
2019 device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr);
2021 ptr -= ptr % sc->blk[0];
2022 feed = (ptr + dsize - sc->intr[0]) % dsize;
2024 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2026 for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) {
2030 device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk);
2032 if (ch->run && ch->blk <= feed) {
2033 snd_mtxunlock(sc->lock);
2034 chn_intr(ch->channel);
2035 snd_mtxlock(sc->lock);
2039 envy24_updintr(sc, PCMDIR_PLAY);
2041 if (envy24_checkintr(sc, PCMDIR_REC)) {
2043 device_printf(sc->dev, "envy24_intr(): rec\n");
2045 dsize = sc->rsize / 4;
2046 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1;
2047 ptr -= ptr % sc->blk[1];
2048 feed = (ptr + dsize - sc->intr[1]) % dsize;
2049 for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) {
2051 if (ch->run && ch->blk <= feed) {
2052 snd_mtxunlock(sc->lock);
2053 chn_intr(ch->channel);
2054 snd_mtxlock(sc->lock);
2058 envy24_updintr(sc, PCMDIR_REC);
2060 snd_mtxunlock(sc->lock);
2066 * Probe and attach the card
2070 envy24_pci_probe(device_t dev)
2076 printf("envy24_pci_probe()\n");
2078 if (pci_get_device(dev) == PCID_ENVY24 &&
2079 pci_get_vendor(dev) == PCIV_ENVY24) {
2080 sv = pci_get_subvendor(dev);
2081 sd = pci_get_subdevice(dev);
2082 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2083 if (cfg_table[i].subvendor == sv &&
2084 cfg_table[i].subdevice == sd) {
2088 device_set_desc(dev, cfg_table[i].name);
2090 printf("envy24_pci_probe(): return 0\n");
2096 printf("envy24_pci_probe(): return ENXIO\n");
2103 envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2105 /* struct sc_info *sc = (struct sc_info *)arg; */
2108 device_printf(sc->dev, "envy24_dmapsetmap()\n");
2110 printf("envy24(play): setmap %lx, %lx; ",
2111 (unsigned long)segs->ds_addr,
2112 (unsigned long)segs->ds_len);
2113 printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2119 envy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2121 /* struct sc_info *sc = (struct sc_info *)arg; */
2124 device_printf(sc->dev, "envy24_dmarsetmap()\n");
2126 printf("envy24(record): setmap %lx, %lx; ",
2127 (unsigned long)segs->ds_addr,
2128 (unsigned long)segs->ds_len);
2129 printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2135 envy24_dmafree(struct sc_info *sc)
2138 device_printf(sc->dev, "envy24_dmafree():");
2139 if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2140 else printf(" sc->rmap(null)");
2141 if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2142 else printf(" sc->pmap(null)");
2143 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2144 else printf(" sc->rbuf(null)");
2145 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2146 else printf(" sc->pbuf(null)\n");
2150 bus_dmamap_unload(sc->dmat, sc->rmap);
2152 bus_dmamap_unload(sc->dmat, sc->pmap);
2154 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2156 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2158 bus_dmamap_unload(sc->dmat, sc->rmap);
2159 bus_dmamap_unload(sc->dmat, sc->pmap);
2160 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2161 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2164 sc->rmap = sc->pmap = NULL;
2172 envy24_dmainit(struct sc_info *sc)
2177 device_printf(sc->dev, "envy24_dmainit()\n");
2180 sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM;
2181 sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM;
2184 sc->pmap = sc->rmap = NULL;
2185 sc->blk[0] = sc->blk[1] = 0;
2187 /* allocate DMA buffer */
2189 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2191 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2194 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2196 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2199 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2201 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0))
2204 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2206 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0))
2208 bzero(sc->pbuf, sc->psize);
2209 bzero(sc->rbuf, sc->rsize);
2211 /* set values to register */
2212 addr = vtophys(sc->pbuf);
2214 device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2216 envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4);
2218 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
2219 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2221 envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2);
2223 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
2225 addr = vtophys(sc->rbuf);
2226 envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4);
2227 envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2);
2236 envy24_putcfg(struct sc_info *sc)
2238 device_printf(sc->dev, "system configuration\n");
2239 kprintf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2240 sc->cfg->subvendor, sc->cfg->subdevice);
2241 kprintf(" XIN2 Clock Source: ");
2242 switch (sc->cfg->scfg & PCIM_SCFG_XIN2) {
2244 kprintf("22.5792MHz(44.1kHz*512)\n");
2247 kprintf("16.9344MHz(44.1kHz*384)\n");
2250 kprintf("from external clock synthesizer chip\n");
2253 kprintf("illegal system setting\n");
2255 kprintf(" MPU-401 UART(s) #: ");
2256 if (sc->cfg->scfg & PCIM_SCFG_MPU)
2260 kprintf(" AC'97 codec: ");
2261 if (sc->cfg->scfg & PCIM_SCFG_AC97)
2262 kprintf("not exist\n");
2265 kprintf(" ADC #: ");
2266 kprintf("%d\n", sc->adcn);
2267 kprintf(" DAC #: ");
2268 kprintf("%d\n", sc->dacn);
2269 kprintf(" Multi-track converter type: ");
2270 if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) {
2271 kprintf("AC'97(SDATA_OUT:");
2272 if (sc->cfg->acl & PCIM_ACL_OMODE)
2276 kprintf("|SDATA_IN:");
2277 if (sc->cfg->acl & PCIM_ACL_IMODE)
2285 if (sc->cfg->i2s & PCIM_I2S_VOL)
2286 kprintf("with volume, ");
2287 if (sc->cfg->i2s & PCIM_I2S_96KHZ)
2288 kprintf("96KHz support, ");
2289 switch (sc->cfg->i2s & PCIM_I2S_RES) {
2290 case PCIM_I2S_16BIT:
2291 kprintf("16bit resolution, ");
2293 case PCIM_I2S_18BIT:
2294 kprintf("18bit resolution, ");
2296 case PCIM_I2S_20BIT:
2297 kprintf("20bit resolution, ");
2299 case PCIM_I2S_24BIT:
2300 kprintf("24bit resolution, ");
2303 kprintf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID);
2305 kprintf(" S/PDIF(IN/OUT): ");
2306 if (sc->cfg->spdif & PCIM_SPDIF_IN)
2310 if (sc->cfg->spdif & PCIM_SPDIF_OUT)
2314 if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT))
2315 kprintf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2);
2316 kprintf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2317 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2321 envy24_init(struct sc_info *sc)
2332 device_printf(sc->dev, "envy24_init()\n");
2336 envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1);
2338 envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1);
2341 /* legacy hardware disable */
2342 data = pci_read_config(sc->dev, PCIR_LAC, 2);
2343 data |= PCIM_LAC_DISABLE;
2344 pci_write_config(sc->dev, PCIR_LAC, data, 2);
2346 /* check system configuration */
2348 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2349 /* 1st: search configuration from table */
2350 sv = pci_get_subvendor(sc->dev);
2351 sd = pci_get_subdevice(sc->dev);
2352 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2354 device_printf(sc->dev, "Set configuration from table\n");
2356 sc->cfg = &cfg_table[i];
2360 if (sc->cfg == NULL) {
2361 /* 2nd: read configuration from table */
2362 sc->cfg = envy24_rom2cfg(sc);
2364 sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1;
2365 sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1;
2367 if (1 /* bootverbose */) {
2371 /* set system configuration */
2372 pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1);
2373 pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1);
2374 pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1);
2375 pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1);
2376 envy24_gpiosetmask(sc, sc->cfg->gpiomask);
2377 envy24_gpiosetdir(sc, sc->cfg->gpiodir);
2378 envy24_gpiowr(sc, sc->cfg->gpiostate);
2379 for (i = 0; i < sc->adcn; i++) {
2380 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2381 sc->cfg->codec->init(sc->adc[i]);
2383 for (i = 0; i < sc->dacn; i++) {
2384 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2385 sc->cfg->codec->init(sc->dac[i]);
2388 /* initialize DMA buffer */
2390 device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n");
2392 if (envy24_dmainit(sc))
2395 /* initialize status */
2396 sc->run[0] = sc->run[1] = 0;
2397 sc->intr[0] = sc->intr[1] = 0;
2399 sc->caps[0].fmtlist = envy24_playfmt;
2400 sc->caps[1].fmtlist = envy24_recfmt;
2402 /* set channel router */
2403 envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0);
2404 envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0);
2405 /* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2407 /* set macro interrupt mask */
2408 data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2409 envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1);
2410 data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2412 device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data);
2419 envy24_alloc_resource(struct sc_info *sc)
2421 /* allocate I/O port resource */
2422 sc->csid = PCIR_CCS;
2423 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2424 &sc->csid, 0, ~0, 1, RF_ACTIVE);
2425 sc->ddmaid = PCIR_DDMA;
2426 sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2427 &sc->ddmaid, 0, ~0, 1, RF_ACTIVE);
2429 sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2430 &sc->dsid, 0, ~0, 1, RF_ACTIVE);
2432 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2433 &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2434 if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) {
2435 device_printf(sc->dev, "unable to map IO port space\n");
2438 sc->cst = rman_get_bustag(sc->cs);
2439 sc->csh = rman_get_bushandle(sc->cs);
2440 sc->ddmat = rman_get_bustag(sc->ddma);
2441 sc->ddmah = rman_get_bushandle(sc->ddma);
2442 sc->dst = rman_get_bustag(sc->ds);
2443 sc->dsh = rman_get_bushandle(sc->ds);
2444 sc->mtt = rman_get_bustag(sc->mt);
2445 sc->mth = rman_get_bushandle(sc->mt);
2447 device_printf(sc->dev,
2448 "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2449 pci_read_config(sc->dev, PCIR_CCS, 4),
2450 pci_read_config(sc->dev, PCIR_DDMA, 4),
2451 pci_read_config(sc->dev, PCIR_DS, 4),
2452 pci_read_config(sc->dev, PCIR_MT, 4));
2455 /* allocate interupt resource */
2457 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2458 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2460 snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) {
2461 device_printf(sc->dev, "unable to map interrupt\n");
2465 /* allocate DMA resource */
2466 if (bus_dma_tag_create(/*parent*/NULL,
2469 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2470 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2471 /*filter*/NULL, /*filterarg*/NULL,
2472 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2473 /*nsegments*/1, /*maxsegsz*/0x3ffff,
2474 /*flags*/0, &sc->dmat) != 0) {
2475 device_printf(sc->dev, "unable to create dma tag\n");
2483 envy24_pci_attach(device_t dev)
2487 char status[SND_STATUSLEN];
2492 device_printf(dev, "envy24_pci_attach()\n");
2494 /* get sc_info data area */
2495 sc = kmalloc(sizeof(*sc), M_ENVY24, M_WAITOK | M_ZERO);
2496 sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_envy24 softc");
2499 /* initialize PCI interface */
2500 data = pci_read_config(dev, PCIR_COMMAND, 2);
2501 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2502 pci_write_config(dev, PCIR_COMMAND, data, 2);
2503 data = pci_read_config(dev, PCIR_COMMAND, 2);
2505 /* allocate resources */
2506 err = envy24_alloc_resource(sc);
2508 device_printf(dev, "unable to allocate system resources\n");
2512 /* initialize card */
2513 err = envy24_init(sc);
2515 device_printf(dev, "unable to initialize the card\n");
2519 /* set multi track mixer */
2520 mixer_init(dev, &envy24mixer_class, sc);
2522 /* set channel information */
2523 err = pcm_register(dev, sc, 5, 2 + sc->adcn);
2527 for (i = 0; i < 5; i++) {
2528 pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
2531 for (i = 0; i < 2 + sc->adcn; i++) {
2532 pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc);
2536 /* set status iformation */
2537 ksnprintf(status, SND_STATUSLEN,
2538 "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
2539 rman_get_start(sc->cs),
2540 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2541 rman_get_start(sc->ddma),
2542 rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1,
2543 rman_get_start(sc->ds),
2544 rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1,
2545 rman_get_start(sc->mt),
2546 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2547 rman_get_start(sc->irq));
2548 pcm_setstatus(dev, status);
2554 bus_teardown_intr(dev, sc->irq, sc->ih);
2556 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2559 bus_dma_tag_destroy(sc->dmat);
2560 if (sc->cfg->codec->destroy != NULL) {
2561 for (i = 0; i < sc->adcn; i++)
2562 sc->cfg->codec->destroy(sc->adc[i]);
2563 for (i = 0; i < sc->dacn; i++)
2564 sc->cfg->codec->destroy(sc->dac[i]);
2566 envy24_cfgfree(sc->cfg);
2568 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2570 bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2572 bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2574 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2576 snd_mtxfree(sc->lock);
2577 kfree(sc, M_ENVY24);
2582 envy24_pci_detach(device_t dev)
2589 device_printf(dev, "envy24_pci_detach()\n");
2591 sc = pcm_getdevinfo(dev);
2594 r = pcm_unregister(dev);
2599 if (sc->cfg->codec->destroy != NULL) {
2600 for (i = 0; i < sc->adcn; i++)
2601 sc->cfg->codec->destroy(sc->adc[i]);
2602 for (i = 0; i < sc->dacn; i++)
2603 sc->cfg->codec->destroy(sc->dac[i]);
2605 envy24_cfgfree(sc->cfg);
2606 bus_dma_tag_destroy(sc->dmat);
2607 bus_teardown_intr(dev, sc->irq, sc->ih);
2608 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2609 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2610 bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2611 bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2612 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2613 snd_mtxfree(sc->lock);
2614 kfree(sc, M_ENVY24);
2618 static device_method_t envy24_methods[] = {
2619 /* Device interface */
2620 DEVMETHOD(device_probe, envy24_pci_probe),
2621 DEVMETHOD(device_attach, envy24_pci_attach),
2622 DEVMETHOD(device_detach, envy24_pci_detach),
2626 static driver_t envy24_driver = {
2629 #if __FreeBSD_version > 500000
2632 sizeof(struct snddev_info),
2636 DRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, NULL, NULL);
2637 MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2638 MODULE_DEPEND(snd_envy24, snd_spicds, 1, 1, 1);
2639 MODULE_VERSION(snd_envy24, 1);