rc.conf: Add and document the missing root_rw_mount=YES
[dragonfly.git] / sys / dev / sound / pci / envy24ht.c
blob82f28cd67a7a37a4635f474f06b1babba4c1490d
1 /*-
2 * Copyright (c) 2006 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
3 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
25 * SUCH DAMAGE.
30 * Konstantin Dimitrov's thanks list:
32 * A huge thanks goes to Spas Filipov for his friendship, support and his
33 * generous gift - an 'Audiotrak Prodigy HD2' audio card! I also want to
34 * thank Keiichi Iwasaki and his parents, because they helped Spas to get
35 * the card from Japan! Having hardware sample of Prodigy HD2 made adding
36 * support for that great card very easy and real fun and pleasure.
40 #ifdef HAVE_KERNEL_OPTION_HEADERS
41 #include "opt_snd.h"
42 #endif
44 #include <dev/sound/pcm/sound.h>
45 #include <dev/sound/pcm/ac97.h>
46 #include <dev/sound/pci/spicds.h>
47 #include <dev/sound/pci/envy24ht.h>
49 #include <bus/pci/pcireg.h>
50 #include <bus/pci/pcivar.h>
52 #include "mixer_if.h"
54 SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/envy24ht.c 274035 2014-11-03 11:11:45Z bapt $");
56 static MALLOC_DEFINE(M_ENVY24HT, "envy24ht", "envy24ht audio");
58 /* -------------------------------------------------------------------- */
60 struct sc_info;
62 #define ENVY24HT_PLAY_CHNUM 8
63 #define ENVY24HT_REC_CHNUM 2
64 #define ENVY24HT_PLAY_BUFUNIT (4 /* byte/sample */ * 8 /* channel */)
65 #define ENVY24HT_REC_BUFUNIT (4 /* byte/sample */ * 2 /* channel */)
66 #define ENVY24HT_SAMPLE_NUM 4096
68 #define ENVY24HT_TIMEOUT 1000
70 #define ENVY24HT_DEFAULT_FORMAT SND_FORMAT(AFMT_S16_LE, 2, 0)
72 #define ENVY24HT_NAMELEN 32
74 struct envy24ht_sample {
75 volatile u_int32_t buffer;
78 typedef struct envy24ht_sample sample32_t;
80 /* channel registers */
81 struct sc_chinfo {
82 struct snd_dbuf *buffer;
83 struct pcm_channel *channel;
84 struct sc_info *parent;
85 int dir;
86 unsigned num; /* hw channel number */
88 /* channel information */
89 u_int32_t format;
90 u_int32_t speed;
91 u_int32_t blk; /* hw block size(dword) */
93 /* format conversion structure */
94 u_int8_t *data;
95 unsigned int size; /* data buffer size(byte) */
96 int unit; /* sample size(byte) */
97 unsigned int offset; /* samples number offset */
98 void (*emldma)(struct sc_chinfo *);
100 /* flags */
101 int run;
104 /* codec interface entrys */
105 struct codec_entry {
106 void *(*create)(device_t dev, void *devinfo, int dir, int num);
107 void (*destroy)(void *codec);
108 void (*init)(void *codec);
109 void (*reinit)(void *codec);
110 void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
111 void (*setrate)(void *codec, int which, int rate);
114 /* system configuration information */
115 struct cfg_info {
116 char *name;
117 u_int16_t subvendor, subdevice;
118 u_int8_t scfg, acl, i2s, spdif;
119 u_int32_t gpiomask, gpiostate, gpiodir;
120 u_int32_t cdti, cclk, cs;
121 u_int8_t cif, type, free;
122 struct codec_entry *codec;
125 /* device private data */
126 struct sc_info {
127 device_t dev;
128 struct lock *lock;
130 /* Control/Status registor */
131 struct resource *cs;
132 int csid;
133 bus_space_tag_t cst;
134 bus_space_handle_t csh;
135 /* MultiTrack registor */
136 struct resource *mt;
137 int mtid;
138 bus_space_tag_t mtt;
139 bus_space_handle_t mth;
140 /* DMA tag */
141 bus_dma_tag_t dmat;
142 /* IRQ resource */
143 struct resource *irq;
144 int irqid;
145 void *ih;
147 /* system configuration data */
148 struct cfg_info *cfg;
150 /* ADC/DAC number and info */
151 int adcn, dacn;
152 void *adc[4], *dac[4];
154 /* mixer control data */
155 u_int32_t src;
156 u_int8_t left[ENVY24HT_CHAN_NUM];
157 u_int8_t right[ENVY24HT_CHAN_NUM];
159 /* Play/Record DMA fifo */
160 sample32_t *pbuf;
161 sample32_t *rbuf;
162 u_int32_t psize, rsize; /* DMA buffer size(byte) */
163 u_int16_t blk[2]; /* transfer check blocksize(dword) */
164 bus_dmamap_t pmap, rmap;
165 bus_addr_t paddr, raddr;
167 /* current status */
168 u_int32_t speed;
169 int run[2];
170 u_int16_t intr[2];
171 struct pcmchan_caps caps[2];
173 /* channel info table */
174 unsigned chnum;
175 struct sc_chinfo chan[11];
178 /* -------------------------------------------------------------------- */
181 * prototypes
184 /* DMA emulator */
185 static void envy24ht_p8u(struct sc_chinfo *);
186 static void envy24ht_p16sl(struct sc_chinfo *);
187 static void envy24ht_p32sl(struct sc_chinfo *);
188 static void envy24ht_r16sl(struct sc_chinfo *);
189 static void envy24ht_r32sl(struct sc_chinfo *);
191 /* channel interface */
192 static void *envy24htchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
193 static int envy24htchan_setformat(kobj_t, void *, u_int32_t);
194 static u_int32_t envy24htchan_setspeed(kobj_t, void *, u_int32_t);
195 static u_int32_t envy24htchan_setblocksize(kobj_t, void *, u_int32_t);
196 static int envy24htchan_trigger(kobj_t, void *, int);
197 static u_int32_t envy24htchan_getptr(kobj_t, void *);
198 static struct pcmchan_caps *envy24htchan_getcaps(kobj_t, void *);
200 /* mixer interface */
201 static int envy24htmixer_init(struct snd_mixer *);
202 static int envy24htmixer_reinit(struct snd_mixer *);
203 static int envy24htmixer_uninit(struct snd_mixer *);
204 static int envy24htmixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
205 static u_int32_t envy24htmixer_setrecsrc(struct snd_mixer *, u_int32_t);
207 /* SPI codec access interface */
208 static void *envy24ht_spi_create(device_t, void *, int, int);
209 static void envy24ht_spi_destroy(void *);
210 static void envy24ht_spi_init(void *);
211 static void envy24ht_spi_reinit(void *);
212 static void envy24ht_spi_setvolume(void *, int, unsigned int, unsigned int);
214 /* -------------------------------------------------------------------- */
217 system constant tables
220 /* API -> hardware channel map */
221 static unsigned envy24ht_chanmap[ENVY24HT_CHAN_NUM] = {
222 ENVY24HT_CHAN_PLAY_DAC1, /* 1 */
223 ENVY24HT_CHAN_PLAY_DAC2, /* 2 */
224 ENVY24HT_CHAN_PLAY_DAC3, /* 3 */
225 ENVY24HT_CHAN_PLAY_DAC4, /* 4 */
226 ENVY24HT_CHAN_PLAY_SPDIF, /* 0 */
227 ENVY24HT_CHAN_REC_MIX, /* 5 */
228 ENVY24HT_CHAN_REC_SPDIF, /* 6 */
229 ENVY24HT_CHAN_REC_ADC1, /* 7 */
230 ENVY24HT_CHAN_REC_ADC2, /* 8 */
231 ENVY24HT_CHAN_REC_ADC3, /* 9 */
232 ENVY24HT_CHAN_REC_ADC4, /* 10 */
235 /* mixer -> API channel map. see above */
236 static int envy24ht_mixmap[] = {
237 -1, /* Master output level. It is depend on codec support */
238 -1, /* Treble level of all output channels */
239 -1, /* Bass level of all output channels */
240 -1, /* Volume of synthesier input */
241 0, /* Output level for the audio device */
242 -1, /* Output level for the PC speaker */
243 7, /* line in jack */
244 -1, /* microphone jack */
245 -1, /* CD audio input */
246 -1, /* Recording monitor */
247 1, /* alternative codec */
248 -1, /* global recording level */
249 -1, /* Input gain */
250 -1, /* Output gain */
251 8, /* Input source 1 */
252 9, /* Input source 2 */
253 10, /* Input source 3 */
254 6, /* Digital (input) 1 */
255 -1, /* Digital (input) 2 */
256 -1, /* Digital (input) 3 */
257 -1, /* Phone input */
258 -1, /* Phone output */
259 -1, /* Video/TV (audio) in */
260 -1, /* Radio in */
261 -1, /* Monitor volume */
264 /* variable rate audio */
265 static u_int32_t envy24ht_speed[] = {
266 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
267 12000, 11025, 9600, 8000, 0
270 /* known boards configuration */
271 static struct codec_entry spi_codec = {
272 envy24ht_spi_create,
273 envy24ht_spi_destroy,
274 envy24ht_spi_init,
275 envy24ht_spi_reinit,
276 envy24ht_spi_setvolume,
277 NULL, /* setrate */
280 static struct cfg_info cfg_table[] = {
282 "Envy24HT audio (Terratec Aureon 7.1 Space)",
283 0x153b, 0x1145,
284 0x0b, 0x80, 0xfc, 0xc3,
285 0x21efff, 0x7fffff, 0x5e1000,
286 0x40000, 0x80000, 0x1000, 0x00, 0x02,
288 &spi_codec,
291 "Envy24HT audio (Terratec Aureon 5.1 Sky)",
292 0x153b, 0x1147,
293 0x0a, 0x80, 0xfc, 0xc3,
294 0x21efff, 0x7fffff, 0x5e1000,
295 0x40000, 0x80000, 0x1000, 0x00, 0x02,
297 &spi_codec,
300 "Envy24HT audio (Terratec Aureon 7.1 Universe)",
301 0x153b, 0x1153,
302 0x0b, 0x80, 0xfc, 0xc3,
303 0x21efff, 0x7fffff, 0x5e1000,
304 0x40000, 0x80000, 0x1000, 0x00, 0x02,
306 &spi_codec,
309 "Envy24HT audio (AudioTrak Prodigy 7.1)",
310 0x4933, 0x4553,
311 0x0b, 0x80, 0xfc, 0xc3,
312 0x21efff, 0x7fffff, 0x5e1000,
313 0x40000, 0x80000, 0x1000, 0x00, 0x02,
315 &spi_codec,
318 "Envy24HT audio (Terratec PHASE 28)",
319 0x153b, 0x1149,
320 0x0b, 0x80, 0xfc, 0xc3,
321 0x21efff, 0x7fffff, 0x5e1000,
322 0x40000, 0x80000, 0x1000, 0x00, 0x02,
324 &spi_codec,
327 "Envy24HT-S audio (Terratec PHASE 22)",
328 0x153b, 0x1150,
329 0x10, 0x80, 0xf0, 0xc3,
330 0x7ffbc7, 0x7fffff, 0x438,
331 0x10, 0x20, 0x400, 0x01, 0x00,
333 &spi_codec,
336 "Envy24HT audio (AudioTrak Prodigy 7.1 LT)",
337 0x3132, 0x4154,
338 0x4b, 0x80, 0xfc, 0xc3,
339 0x7ff8ff, 0x7fffff, 0x700,
340 0x400, 0x200, 0x100, 0x00, 0x02,
342 &spi_codec,
345 "Envy24HT audio (AudioTrak Prodigy 7.1 XT)",
346 0x3136, 0x4154,
347 0x4b, 0x80, 0xfc, 0xc3,
348 0x7ff8ff, 0x7fffff, 0x700,
349 0x400, 0x200, 0x100, 0x00, 0x02,
351 &spi_codec,
354 "Envy24HT audio (M-Audio Revolution 7.1)",
355 0x1412, 0x3630,
356 0x43, 0x80, 0xf8, 0xc1,
357 0x3fff85, 0x400072, 0x4000fa,
358 0x08, 0x02, 0x20, 0x00, 0x04,
360 &spi_codec,
363 "Envy24GT audio (M-Audio Revolution 5.1)",
364 0x1412, 0x3631,
365 0x42, 0x80, 0xf8, 0xc1,
366 0x3fff05, 0x4000f0, 0x4000fa,
367 0x08, 0x02, 0x10, 0x00, 0x03,
369 &spi_codec,
372 "Envy24HT audio (M-Audio Audiophile 192)",
373 0x1412, 0x3632,
374 0x68, 0x80, 0xf8, 0xc3,
375 0x45, 0x4000b5, 0x7fffba,
376 0x08, 0x02, 0x10, 0x00, 0x03,
378 &spi_codec,
381 "Envy24HT audio (AudioTrak Prodigy HD2)",
382 0x3137, 0x4154,
383 0x68, 0x80, 0x78, 0xc3,
384 0xfff8ff, 0x200700, 0xdfffff,
385 0x400, 0x200, 0x100, 0x00, 0x05,
387 &spi_codec,
390 "Envy24HT audio (ESI Juli@)",
391 0x3031, 0x4553,
392 0x20, 0x80, 0xf8, 0xc3,
393 0x7fff9f, 0x8016, 0x7fff9f,
394 0x08, 0x02, 0x10, 0x00, 0x03,
396 &spi_codec,
399 "Envy24HT-S audio (Terrasoniq TS22PCI)",
400 0x153b, 0x117b,
401 0x10, 0x80, 0xf0, 0xc3,
402 0x7ffbc7, 0x7fffff, 0x438,
403 0x10, 0x20, 0x400, 0x01, 0x00,
405 &spi_codec,
408 "Envy24HT audio (Generic)",
409 0, 0,
410 0x0b, 0x80, 0xfc, 0xc3,
411 0x21efff, 0x7fffff, 0x5e1000,
412 0x40000, 0x80000, 0x1000, 0x00, 0x02,
414 &spi_codec, /* default codec routines */
418 static u_int32_t envy24ht_recfmt[] = {
419 SND_FORMAT(AFMT_S16_LE, 2, 0),
420 SND_FORMAT(AFMT_S32_LE, 2, 0),
423 static struct pcmchan_caps envy24ht_reccaps = {8000, 96000, envy24ht_recfmt, 0};
425 static u_int32_t envy24ht_playfmt[] = {
426 SND_FORMAT(AFMT_U8, 2, 0),
427 SND_FORMAT(AFMT_S16_LE, 2, 0),
428 SND_FORMAT(AFMT_S32_LE, 2, 0),
432 static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0};
434 struct envy24ht_emldma {
435 u_int32_t format;
436 void (*emldma)(struct sc_chinfo *);
437 int unit;
440 static struct envy24ht_emldma envy24ht_pemltab[] = {
441 {SND_FORMAT(AFMT_U8, 2, 0), envy24ht_p8u, 2},
442 {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_p16sl, 4},
443 {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_p32sl, 8},
444 {0, NULL, 0}
447 static struct envy24ht_emldma envy24ht_remltab[] = {
448 {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_r16sl, 4},
449 {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_r32sl, 8},
450 {0, NULL, 0}
453 /* -------------------------------------------------------------------- */
455 /* common routines */
456 static u_int32_t
457 envy24ht_rdcs(struct sc_info *sc, int regno, int size)
459 switch (size) {
460 case 1:
461 return bus_space_read_1(sc->cst, sc->csh, regno);
462 case 2:
463 return bus_space_read_2(sc->cst, sc->csh, regno);
464 case 4:
465 return bus_space_read_4(sc->cst, sc->csh, regno);
466 default:
467 return 0xffffffff;
471 static void
472 envy24ht_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
474 switch (size) {
475 case 1:
476 bus_space_write_1(sc->cst, sc->csh, regno, data);
477 break;
478 case 2:
479 bus_space_write_2(sc->cst, sc->csh, regno, data);
480 break;
481 case 4:
482 bus_space_write_4(sc->cst, sc->csh, regno, data);
483 break;
487 static u_int32_t
488 envy24ht_rdmt(struct sc_info *sc, int regno, int size)
490 switch (size) {
491 case 1:
492 return bus_space_read_1(sc->mtt, sc->mth, regno);
493 case 2:
494 return bus_space_read_2(sc->mtt, sc->mth, regno);
495 case 4:
496 return bus_space_read_4(sc->mtt, sc->mth, regno);
497 default:
498 return 0xffffffff;
502 static void
503 envy24ht_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
505 switch (size) {
506 case 1:
507 bus_space_write_1(sc->mtt, sc->mth, regno, data);
508 break;
509 case 2:
510 bus_space_write_2(sc->mtt, sc->mth, regno, data);
511 break;
512 case 4:
513 bus_space_write_4(sc->mtt, sc->mth, regno, data);
514 break;
518 /* -------------------------------------------------------------------- */
520 /* I2C port/E2PROM access routines */
522 static int
523 envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
525 u_int32_t data;
526 int i;
528 #if(0)
529 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
530 #endif
531 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
532 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
533 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
534 break;
535 DELAY(32); /* 31.25kHz */
537 if (i == ENVY24HT_TIMEOUT) {
538 return -1;
540 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
541 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
542 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_RD, 1);
543 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
544 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
545 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
546 break;
547 DELAY(32); /* 31.25kHz */
549 if (i == ENVY24HT_TIMEOUT) {
550 return -1;
552 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CDATA, 1);
554 #if(0)
555 device_printf(sc->dev, "envy24ht_rdi2c(): return 0x%x\n", data);
556 #endif
557 return (int)data;
560 static int
561 envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
563 u_int32_t tmp;
564 int i;
566 #if(0)
567 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
568 #endif
569 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
570 tmp = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
571 if ((tmp & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
572 break;
573 DELAY(32); /* 31.25kHz */
575 if (i == ENVY24HT_TIMEOUT) {
576 return -1;
578 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
579 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDATA, data, 1);
580 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
581 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_WR, 1);
582 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
583 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
584 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
585 break;
586 DELAY(32); /* 31.25kHz */
588 if (i == ENVY24HT_TIMEOUT) {
589 return -1;
592 return 0;
595 static int
596 envy24ht_rdrom(struct sc_info *sc, u_int32_t addr)
598 u_int32_t data;
600 #if(0)
601 device_printf(sc->dev, "envy24ht_rdrom(sc, 0x%02x)\n", addr);
602 #endif
603 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
604 if ((data & ENVY24HT_CCS_I2CSTAT_ROM) == 0) {
605 #if(0)
606 device_printf(sc->dev, "envy24ht_rdrom(): E2PROM not presented\n");
607 #endif
608 return -1;
611 return envy24ht_rdi2c(sc, ENVY24HT_CCS_I2CDEV_ROM, addr);
614 static struct cfg_info *
615 envy24ht_rom2cfg(struct sc_info *sc)
617 struct cfg_info *buff;
618 int size;
619 int i;
621 #if(0)
622 device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n");
623 #endif
624 size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE);
625 if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) {
626 #if(0)
627 device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size);
628 #endif
629 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
630 if (buff == NULL) {
631 #if(0)
632 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
633 #endif
634 return NULL;
636 buff->free = 1;
638 /* no valid e2prom, using default values */
639 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
640 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
641 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
642 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
643 buff->scfg = 0x0b;
644 buff->acl = 0x80;
645 buff->i2s = 0xfc;
646 buff->spdif = 0xc3;
647 buff->gpiomask = 0x21efff;
648 buff->gpiostate = 0x7fffff;
649 buff->gpiodir = 0x5e1000;
650 buff->cdti = 0x40000;
651 buff->cclk = 0x80000;
652 buff->cs = 0x1000;
653 buff->cif = 0x00;
654 buff->type = 0x02;
656 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0;
657 i++)
658 if (cfg_table[i].subvendor == buff->subvendor &&
659 cfg_table[i].subdevice == buff->subdevice)
660 break;
661 buff->name = cfg_table[i].name;
662 buff->codec = cfg_table[i].codec;
664 return buff;
665 #if 0
666 return NULL;
667 #endif
669 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
670 if (buff == NULL) {
671 #if(0)
672 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
673 #endif
674 return NULL;
676 buff->free = 1;
678 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
679 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
680 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
681 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
682 buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG);
683 buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL);
684 buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S);
685 buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF);
686 buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \
687 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \
688 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16;
689 buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \
690 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \
691 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16;
692 buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \
693 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \
694 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16;
696 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
697 if (cfg_table[i].subvendor == buff->subvendor &&
698 cfg_table[i].subdevice == buff->subdevice)
699 break;
700 buff->name = cfg_table[i].name;
701 buff->codec = cfg_table[i].codec;
703 return buff;
706 static void
707 envy24ht_cfgfree(struct cfg_info *cfg) {
708 if (cfg == NULL)
709 return;
710 if (cfg->free)
711 kfree(cfg, M_ENVY24HT);
712 return;
715 /* -------------------------------------------------------------------- */
717 /* AC'97 codec access routines */
719 #if 0
720 static int
721 envy24ht_coldcd(struct sc_info *sc)
723 u_int32_t data;
724 int i;
726 #if(0)
727 device_printf(sc->dev, "envy24ht_coldcd()\n");
728 #endif
729 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1);
730 DELAY(10);
731 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
732 DELAY(1000);
733 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
734 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
735 if (data & ENVY24HT_MT_AC97CMD_RDY) {
736 return 0;
740 return -1;
743 static int
744 envy24ht_slavecd(struct sc_info *sc)
746 u_int32_t data;
747 int i;
749 #if(0)
750 device_printf(sc->dev, "envy24ht_slavecd()\n");
751 #endif
752 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD,
753 ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1);
754 DELAY(10);
755 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
756 DELAY(1000);
757 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
758 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
759 if (data & ENVY24HT_MT_AC97CMD_RDY) {
760 return 0;
764 return -1;
767 static int
768 envy24ht_rdcd(kobj_t obj, void *devinfo, int regno)
770 struct sc_info *sc = (struct sc_info *)devinfo;
771 u_int32_t data;
772 int i;
774 #if(0)
775 device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno);
776 #endif
777 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
778 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1);
779 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
780 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
781 if ((data & ENVY24HT_MT_AC97CMD_RD) == 0)
782 break;
784 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2);
786 #if(0)
787 device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data);
788 #endif
789 return (int)data;
792 static int
793 envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
795 struct sc_info *sc = (struct sc_info *)devinfo;
796 u_int32_t cmd;
797 int i;
799 #if(0)
800 device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
801 #endif
802 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
803 envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2);
804 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1);
805 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
806 cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
807 if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0)
808 break;
811 return 0;
814 static kobj_method_t envy24ht_ac97_methods[] = {
815 KOBJMETHOD(ac97_read, envy24ht_rdcd),
816 KOBJMETHOD(ac97_write, envy24ht_wrcd),
817 KOBJMETHOD_END
819 AC97_DECLARE(envy24ht_ac97);
820 #endif
822 /* -------------------------------------------------------------------- */
824 /* GPIO access routines */
826 static u_int32_t
827 envy24ht_gpiord(struct sc_info *sc)
829 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
830 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2);
831 else
832 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2));
835 static void
836 envy24ht_gpiowr(struct sc_info *sc, u_int32_t data)
838 #if(0)
839 device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF);
840 return;
841 #endif
842 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2);
843 if (sc->cfg->subdevice != 0x1150)
844 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1);
845 return;
848 #if 0
849 static u_int32_t
850 envy24ht_gpiogetmask(struct sc_info *sc)
852 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2));
854 #endif
856 static void
857 envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask)
859 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2);
860 if (sc->cfg->subdevice != 0x1150)
861 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1);
862 return;
865 #if 0
866 static u_int32_t
867 envy24ht_gpiogetdir(struct sc_info *sc)
869 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4);
871 #endif
873 static void
874 envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir)
876 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
877 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2);
878 else
879 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4);
880 return;
883 /* -------------------------------------------------------------------- */
885 /* SPI codec access interface routine */
887 struct envy24ht_spi_codec {
888 struct spicds_info *info;
889 struct sc_info *parent;
890 int dir;
891 int num;
892 int cs, cclk, cdti;
895 static void
896 envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
898 u_int32_t data = 0;
899 struct envy24ht_spi_codec *ptr = codec;
901 #if(0)
902 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
903 #endif
904 data = envy24ht_gpiord(ptr->parent);
905 data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
906 if (cs) data += ptr->cs;
907 if (cclk) data += ptr->cclk;
908 if (cdti) data += ptr->cdti;
909 envy24ht_gpiowr(ptr->parent, data);
910 return;
913 static void *
914 envy24ht_spi_create(device_t dev, void *info, int dir, int num)
916 struct sc_info *sc = info;
917 struct envy24ht_spi_codec *buff = NULL;
919 #if(0)
920 device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num);
921 #endif
923 buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
924 if (buff == NULL)
925 return NULL;
927 if (dir == PCMDIR_REC && sc->adc[num] != NULL)
928 buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info;
929 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
930 buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info;
931 else
932 buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl);
933 if (buff->info == NULL) {
934 kfree(buff, M_ENVY24HT);
935 return NULL;
938 buff->parent = sc;
939 buff->dir = dir;
940 buff->num = num;
942 return (void *)buff;
945 static void
946 envy24ht_spi_destroy(void *codec)
948 struct envy24ht_spi_codec *ptr = codec;
949 if (ptr == NULL)
950 return;
951 #if(0)
952 device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n");
953 #endif
955 if (ptr->dir == PCMDIR_PLAY) {
956 if (ptr->parent->dac[ptr->num] != NULL)
957 spicds_destroy(ptr->info);
959 else {
960 if (ptr->parent->adc[ptr->num] != NULL)
961 spicds_destroy(ptr->info);
964 kfree(codec, M_ENVY24HT);
967 static void
968 envy24ht_spi_init(void *codec)
970 struct envy24ht_spi_codec *ptr = codec;
971 if (ptr == NULL)
972 return;
973 #if(0)
974 device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n");
975 #endif
976 ptr->cs = ptr->parent->cfg->cs;
977 ptr->cclk = ptr->parent->cfg->cclk;
978 ptr->cdti = ptr->parent->cfg->cdti;
979 spicds_settype(ptr->info, ptr->parent->cfg->type);
980 spicds_setcif(ptr->info, ptr->parent->cfg->cif);
981 if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \
982 ptr->parent->cfg->type == SPICDS_TYPE_AK4528) {
983 spicds_setformat(ptr->info,
984 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
985 spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
988 /* for the time being, init only first codec */
989 if (ptr->num == 0)
990 spicds_init(ptr->info);
993 static void
994 envy24ht_spi_reinit(void *codec)
996 struct envy24ht_spi_codec *ptr = codec;
997 if (ptr == NULL)
998 return;
999 #if(0)
1000 device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n");
1001 #endif
1003 spicds_reinit(ptr->info);
1006 static void
1007 envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
1009 struct envy24ht_spi_codec *ptr = codec;
1010 if (ptr == NULL)
1011 return;
1012 #if(0)
1013 device_printf(ptr->parent->dev, "envy24ht_spi_set()\n");
1014 #endif
1016 spicds_set(ptr->info, dir, left, right);
1019 /* -------------------------------------------------------------------- */
1021 /* hardware access routeines */
1023 static struct {
1024 u_int32_t speed;
1025 u_int32_t code;
1026 } envy24ht_speedtab[] = {
1027 {48000, ENVY24HT_MT_RATE_48000},
1028 {24000, ENVY24HT_MT_RATE_24000},
1029 {12000, ENVY24HT_MT_RATE_12000},
1030 {9600, ENVY24HT_MT_RATE_9600},
1031 {32000, ENVY24HT_MT_RATE_32000},
1032 {16000, ENVY24HT_MT_RATE_16000},
1033 {8000, ENVY24HT_MT_RATE_8000},
1034 {96000, ENVY24HT_MT_RATE_96000},
1035 {192000, ENVY24HT_MT_RATE_192000},
1036 {64000, ENVY24HT_MT_RATE_64000},
1037 {44100, ENVY24HT_MT_RATE_44100},
1038 {22050, ENVY24HT_MT_RATE_22050},
1039 {11025, ENVY24HT_MT_RATE_11025},
1040 {88200, ENVY24HT_MT_RATE_88200},
1041 {176400, ENVY24HT_MT_RATE_176400},
1042 {0, 0x10}
1045 static u_int32_t
1046 envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) {
1047 u_int32_t code, i2sfmt;
1048 int i = 0;
1050 #if(0)
1051 device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed);
1052 if (speed == 0) {
1053 code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */
1054 envy24ht_slavecd(sc);
1056 else {
1057 #endif
1058 for (i = 0; envy24ht_speedtab[i].speed != 0; i++) {
1059 if (envy24ht_speedtab[i].speed == speed)
1060 break;
1062 code = envy24ht_speedtab[i].code;
1063 #if 0
1065 device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code);
1066 #endif
1067 if (code < 0x10) {
1068 envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1);
1069 if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \
1070 (code == ENVY24HT_MT_RATE_176400)) {
1071 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1072 i2sfmt |= ENVY24HT_MT_I2S_MLR128;
1073 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1075 else {
1076 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1077 i2sfmt &= ~ENVY24HT_MT_I2S_MLR128;
1078 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1080 code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1);
1081 code &= ENVY24HT_MT_RATE_MASK;
1082 for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) {
1083 if (envy24ht_speedtab[i].code == code)
1084 break;
1086 speed = envy24ht_speedtab[i].speed;
1088 else
1089 speed = 0;
1091 #if(0)
1092 device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed);
1093 #endif
1094 return speed;
1097 static void
1098 envy24ht_setvolume(struct sc_info *sc, unsigned ch)
1100 #if(0)
1101 device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch);
1102 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1103 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1104 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1105 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1106 #endif
1109 static void
1110 envy24ht_mutevolume(struct sc_info *sc, unsigned ch)
1112 #if 0
1113 u_int32_t vol;
1115 device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch);
1116 vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE;
1117 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1118 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1119 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1120 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1121 #endif
1124 static u_int32_t
1125 envy24ht_gethwptr(struct sc_info *sc, int dir)
1127 int unit, regno;
1128 u_int32_t ptr, rtn;
1130 #if(0)
1131 device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir);
1132 #endif
1133 if (dir == PCMDIR_PLAY) {
1134 rtn = sc->psize / 4;
1135 unit = ENVY24HT_PLAY_BUFUNIT / 4;
1136 regno = ENVY24HT_MT_PCNT;
1138 else {
1139 rtn = sc->rsize / 4;
1140 unit = ENVY24HT_REC_BUFUNIT / 4;
1141 regno = ENVY24HT_MT_RCNT;
1144 ptr = envy24ht_rdmt(sc, regno, 2);
1145 rtn -= (ptr + 1);
1146 rtn /= unit;
1148 #if(0)
1149 device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn);
1150 #endif
1151 return rtn;
1154 static void
1155 envy24ht_updintr(struct sc_info *sc, int dir)
1157 int regptr, regintr;
1158 u_int32_t mask, intr;
1159 u_int32_t ptr, size, cnt;
1160 u_int16_t blk;
1162 #if(0)
1163 device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir);
1164 #endif
1165 if (dir == PCMDIR_PLAY) {
1166 blk = sc->blk[0];
1167 size = sc->psize / 4;
1168 regptr = ENVY24HT_MT_PCNT;
1169 regintr = ENVY24HT_MT_PTERM;
1170 mask = ~ENVY24HT_MT_INT_PMASK;
1172 else {
1173 blk = sc->blk[1];
1174 size = sc->rsize / 4;
1175 regptr = ENVY24HT_MT_RCNT;
1176 regintr = ENVY24HT_MT_RTERM;
1177 mask = ~ENVY24HT_MT_INT_RMASK;
1180 ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1;
1182 cnt = blk - ptr % blk - 1;
1183 if (cnt == 0)
1184 cnt = blk - 1;
1186 cnt = blk - 1;
1187 #if(0)
1188 device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1189 #endif
1190 envy24ht_wrmt(sc, regintr, cnt, 2);
1191 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1192 #if(0)
1193 device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1194 #endif
1195 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
1196 #if(0)
1197 device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
1198 envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
1199 #endif
1201 return;
1204 #if 0
1205 static void
1206 envy24ht_maskintr(struct sc_info *sc, int dir)
1208 u_int32_t mask, intr;
1210 #if(0)
1211 device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
1212 #endif
1213 if (dir == PCMDIR_PLAY)
1214 mask = ENVY24HT_MT_INT_PMASK;
1215 else
1216 mask = ENVY24HT_MT_INT_RMASK;
1217 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
1218 envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
1220 return;
1222 #endif
1224 static int
1225 envy24ht_checkintr(struct sc_info *sc, int dir)
1227 u_int32_t mask, stat, intr, rtn;
1229 #if(0)
1230 device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
1231 #endif
1232 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
1233 if (dir == PCMDIR_PLAY) {
1234 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
1235 mask = ~ENVY24HT_MT_INT_RSTAT;
1236 envy24ht_wrmt(sc, 0x1a, 0x01, 1);
1237 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);
1238 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1239 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
1242 else {
1243 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
1244 mask = ~ENVY24HT_MT_INT_PSTAT;
1245 #if 0
1246 stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
1247 #endif
1248 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
1249 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1250 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
1254 return rtn;
1257 static void
1258 envy24ht_start(struct sc_info *sc, int dir)
1260 u_int32_t stat, sw;
1262 #if(0)
1263 device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
1264 #endif
1265 if (dir == PCMDIR_PLAY)
1266 sw = ENVY24HT_MT_PCTL_PSTART;
1267 else
1268 sw = ENVY24HT_MT_PCTL_RSTART;
1270 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1271 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
1272 #if(0)
1273 DELAY(100);
1274 device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
1275 device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
1276 #endif
1278 return;
1281 static void
1282 envy24ht_stop(struct sc_info *sc, int dir)
1284 u_int32_t stat, sw;
1286 #if(0)
1287 device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir);
1288 #endif
1289 if (dir == PCMDIR_PLAY)
1290 sw = ~ENVY24HT_MT_PCTL_PSTART;
1291 else
1292 sw = ~ENVY24HT_MT_PCTL_RSTART;
1294 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1295 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1);
1297 return;
1300 #if 0
1301 static int
1302 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1304 return 0;
1306 #endif
1308 /* -------------------------------------------------------------------- */
1310 /* buffer copy routines */
1311 static void
1312 envy24ht_p32sl(struct sc_chinfo *ch)
1314 int length;
1315 sample32_t *dmabuf;
1316 u_int32_t *data;
1317 int src, dst, ssize, dsize, slot;
1318 int i;
1320 length = sndbuf_getready(ch->buffer) / 8;
1321 dmabuf = ch->parent->pbuf;
1322 data = (u_int32_t *)ch->data;
1323 src = sndbuf_getreadyptr(ch->buffer) / 4;
1324 dst = src / 2 + ch->offset;
1325 ssize = ch->size / 4;
1326 dsize = ch->size / 8;
1327 slot = ch->num * 2;
1329 for (i = 0; i < length; i++) {
1330 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
1331 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1332 dst++;
1333 dst %= dsize;
1334 src += 2;
1335 src %= ssize;
1338 return;
1341 static void
1342 envy24ht_p16sl(struct sc_chinfo *ch)
1344 int length;
1345 sample32_t *dmabuf;
1346 u_int16_t *data;
1347 int src, dst, ssize, dsize, slot;
1348 int i;
1350 #if(0)
1351 device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
1352 #endif
1353 length = sndbuf_getready(ch->buffer) / 4;
1354 dmabuf = ch->parent->pbuf;
1355 data = (u_int16_t *)ch->data;
1356 src = sndbuf_getreadyptr(ch->buffer) / 2;
1357 dst = src / 2 + ch->offset;
1358 ssize = ch->size / 2;
1359 dsize = ch->size / 4;
1360 slot = ch->num * 2;
1361 #if(0)
1362 device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1363 #endif
1365 for (i = 0; i < length; i++) {
1366 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1367 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1368 #if(0)
1369 if (i < 16) {
1370 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
1371 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
1373 #endif
1374 dst++;
1375 dst %= dsize;
1376 src += 2;
1377 src %= ssize;
1379 #if(0)
1380 printf("\n");
1381 #endif
1383 return;
1386 static void
1387 envy24ht_p8u(struct sc_chinfo *ch)
1389 int length;
1390 sample32_t *dmabuf;
1391 u_int8_t *data;
1392 int src, dst, ssize, dsize, slot;
1393 int i;
1395 length = sndbuf_getready(ch->buffer) / 2;
1396 dmabuf = ch->parent->pbuf;
1397 data = (u_int8_t *)ch->data;
1398 src = sndbuf_getreadyptr(ch->buffer);
1399 dst = src / 2 + ch->offset;
1400 ssize = ch->size;
1401 dsize = ch->size / 4;
1402 slot = ch->num * 2;
1404 for (i = 0; i < length; i++) {
1405 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1406 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1407 dst++;
1408 dst %= dsize;
1409 src += 2;
1410 src %= ssize;
1413 return;
1416 static void
1417 envy24ht_r32sl(struct sc_chinfo *ch)
1419 int length;
1420 sample32_t *dmabuf;
1421 u_int32_t *data;
1422 int src, dst, ssize, dsize, slot;
1423 int i;
1425 length = sndbuf_getfree(ch->buffer) / 8;
1426 dmabuf = ch->parent->rbuf;
1427 data = (u_int32_t *)ch->data;
1428 dst = sndbuf_getfreeptr(ch->buffer) / 4;
1429 src = dst / 2 + ch->offset;
1430 dsize = ch->size / 4;
1431 ssize = ch->size / 8;
1432 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1434 for (i = 0; i < length; i++) {
1435 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1436 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1437 dst += 2;
1438 dst %= dsize;
1439 src++;
1440 src %= ssize;
1443 return;
1446 static void
1447 envy24ht_r16sl(struct sc_chinfo *ch)
1449 int length;
1450 sample32_t *dmabuf;
1451 u_int16_t *data;
1452 int src, dst, ssize, dsize, slot;
1453 int i;
1455 length = sndbuf_getfree(ch->buffer) / 4;
1456 dmabuf = ch->parent->rbuf;
1457 data = (u_int16_t *)ch->data;
1458 dst = sndbuf_getfreeptr(ch->buffer) / 2;
1459 src = dst / 2 + ch->offset;
1460 dsize = ch->size / 2;
1461 ssize = ch->size / 8;
1462 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1464 for (i = 0; i < length; i++) {
1465 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1466 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1467 dst += 2;
1468 dst %= dsize;
1469 src++;
1470 src %= ssize;
1473 return;
1476 /* -------------------------------------------------------------------- */
1478 /* channel interface */
1479 static void *
1480 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1482 struct sc_info *sc = (struct sc_info *)devinfo;
1483 struct sc_chinfo *ch;
1484 unsigned num;
1486 #if(0)
1487 device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
1488 #endif
1489 snd_mtxlock(sc->lock);
1490 #if 0
1491 if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1492 (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1493 snd_mtxunlock(sc->lock);
1494 return NULL;
1496 #endif
1497 num = sc->chnum;
1499 ch = &sc->chan[num];
1500 ch->size = 8 * ENVY24HT_SAMPLE_NUM;
1501 ch->data = kmalloc(ch->size, M_ENVY24HT, M_WAITOK | M_ZERO);
1502 if (ch->data == NULL) {
1503 ch->size = 0;
1504 ch = NULL;
1506 else {
1507 ch->buffer = b;
1508 ch->channel = c;
1509 ch->parent = sc;
1510 ch->dir = dir;
1511 /* set channel map */
1512 ch->num = envy24ht_chanmap[num];
1513 snd_mtxunlock(sc->lock);
1514 sndbuf_setup(ch->buffer, ch->data, ch->size);
1515 snd_mtxlock(sc->lock);
1516 /* these 2 values are dummy */
1517 ch->unit = 4;
1518 ch->blk = 10240;
1520 snd_mtxunlock(sc->lock);
1522 return ch;
1525 static int
1526 envy24htchan_free(kobj_t obj, void *data)
1528 struct sc_chinfo *ch = data;
1529 struct sc_info *sc = ch->parent;
1531 #if(0)
1532 device_printf(sc->dev, "envy24htchan_free()\n");
1533 #endif
1534 snd_mtxlock(sc->lock);
1535 if (ch->data != NULL) {
1536 kfree(ch->data, M_ENVY24HT);
1537 ch->data = NULL;
1539 snd_mtxunlock(sc->lock);
1541 return 0;
1544 static int
1545 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
1547 struct sc_chinfo *ch = data;
1548 struct sc_info *sc = ch->parent;
1549 struct envy24ht_emldma *emltab;
1550 /* unsigned int bcnt, bsize; */
1551 int i;
1553 #if(0)
1554 device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
1555 #endif
1556 snd_mtxlock(sc->lock);
1557 /* check and get format related information */
1558 if (ch->dir == PCMDIR_PLAY)
1559 emltab = envy24ht_pemltab;
1560 else
1561 emltab = envy24ht_remltab;
1562 if (emltab == NULL) {
1563 snd_mtxunlock(sc->lock);
1564 return -1;
1566 for (i = 0; emltab[i].format != 0; i++)
1567 if (emltab[i].format == format)
1568 break;
1569 if (emltab[i].format == 0) {
1570 snd_mtxunlock(sc->lock);
1571 return -1;
1574 /* set format information */
1575 ch->format = format;
1576 ch->emldma = emltab[i].emldma;
1577 if (ch->unit > emltab[i].unit)
1578 ch->blk *= ch->unit / emltab[i].unit;
1579 else
1580 ch->blk /= emltab[i].unit / ch->unit;
1581 ch->unit = emltab[i].unit;
1583 /* set channel buffer information */
1584 ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
1585 #if 0
1586 if (ch->dir == PCMDIR_PLAY)
1587 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1588 else
1589 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1590 bsize *= ch->unit;
1591 bcnt = ch->size / bsize;
1592 sndbuf_resize(ch->buffer, bcnt, bsize);
1593 #endif
1594 snd_mtxunlock(sc->lock);
1596 #if(0)
1597 device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
1598 #endif
1599 return 0;
1603 IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1604 of speed information value. And real hardware speed setting is done
1605 at start triggered(see envy24htchan_trigger()). So, at this function
1606 is called, any value that ENVY24 can use is able to set. But, at
1607 start triggerd, some other channel is running, and that channel's
1608 speed isn't same with, then trigger function will fail.
1610 static u_int32_t
1611 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1613 struct sc_chinfo *ch = data;
1614 u_int32_t val, prev;
1615 int i;
1617 #if(0)
1618 device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
1619 #endif
1620 prev = 0x7fffffff;
1621 for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
1622 if (abs(val - speed) < abs(prev - speed))
1623 prev = val;
1624 else
1625 break;
1627 ch->speed = prev;
1629 #if(0)
1630 device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
1631 #endif
1632 return ch->speed;
1635 static u_int32_t
1636 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1638 struct sc_chinfo *ch = data;
1639 /* struct sc_info *sc = ch->parent; */
1640 u_int32_t size, prev;
1641 unsigned int bcnt, bsize;
1643 #if(0)
1644 device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
1645 #endif
1646 prev = 0x7fffffff;
1647 /* snd_mtxlock(sc->lock); */
1648 for (size = ch->size / 2; size > 0; size /= 2) {
1649 if (abs(size - blocksize) < abs(prev - blocksize))
1650 prev = size;
1651 else
1652 break;
1655 ch->blk = prev / ch->unit;
1656 if (ch->dir == PCMDIR_PLAY)
1657 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
1658 else
1659 ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
1660 /* set channel buffer information */
1661 /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
1662 if (ch->dir == PCMDIR_PLAY)
1663 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1664 else
1665 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1666 bsize *= ch->unit;
1667 bcnt = ch->size / bsize;
1668 sndbuf_resize(ch->buffer, bcnt, bsize);
1669 /* snd_mtxunlock(sc->lock); */
1671 #if(0)
1672 device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
1673 #endif
1674 return prev;
1677 /* semantic note: must start at beginning of buffer */
1678 static int
1679 envy24htchan_trigger(kobj_t obj, void *data, int go)
1681 struct sc_chinfo *ch = data;
1682 struct sc_info *sc = ch->parent;
1683 u_int32_t ptr;
1684 int slot;
1685 int error = 0;
1686 #if 0
1687 int i;
1689 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1690 #endif
1691 snd_mtxlock(sc->lock);
1692 if (ch->dir == PCMDIR_PLAY)
1693 slot = 0;
1694 else
1695 slot = 1;
1696 switch (go) {
1697 case PCMTRIG_START:
1698 #if(0)
1699 device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1700 #endif
1701 /* check or set channel speed */
1702 if (sc->run[0] == 0 && sc->run[1] == 0) {
1703 sc->speed = envy24ht_setspeed(sc, ch->speed);
1704 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1705 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1707 else if (ch->speed != 0 && ch->speed != sc->speed) {
1708 error = -1;
1709 goto fail;
1711 if (ch->speed == 0)
1712 ch->channel->speed = sc->speed;
1713 /* start or enable channel */
1714 sc->run[slot]++;
1715 if (sc->run[slot] == 1) {
1716 /* first channel */
1717 ch->offset = 0;
1718 sc->blk[slot] = ch->blk;
1720 else {
1721 ptr = envy24ht_gethwptr(sc, ch->dir);
1722 ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1723 (ch->size / 4)) * 4 / ch->unit;
1724 if (ch->blk < sc->blk[slot])
1725 sc->blk[slot] = ch->blk;
1727 if (ch->dir == PCMDIR_PLAY) {
1728 ch->emldma(ch);
1729 envy24ht_setvolume(sc, ch->num);
1731 envy24ht_updintr(sc, ch->dir);
1732 if (sc->run[slot] == 1)
1733 envy24ht_start(sc, ch->dir);
1734 ch->run = 1;
1735 break;
1736 case PCMTRIG_EMLDMAWR:
1737 #if(0)
1738 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1739 #endif
1740 if (ch->run != 1) {
1741 error = -1;
1742 goto fail;
1744 ch->emldma(ch);
1745 break;
1746 case PCMTRIG_EMLDMARD:
1747 #if(0)
1748 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1749 #endif
1750 if (ch->run != 1) {
1751 error = -1;
1752 goto fail;
1754 ch->emldma(ch);
1755 break;
1756 case PCMTRIG_ABORT:
1757 if (ch->run) {
1758 #if(0)
1759 device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1760 #endif
1761 ch->run = 0;
1762 sc->run[slot]--;
1763 if (ch->dir == PCMDIR_PLAY)
1764 envy24ht_mutevolume(sc, ch->num);
1765 if (sc->run[slot] == 0) {
1766 envy24ht_stop(sc, ch->dir);
1767 sc->intr[slot] = 0;
1769 /* else if (ch->blk == sc->blk[slot]) {
1770 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1771 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1772 if (sc->chan[i].dir == ch->dir &&
1773 sc->chan[i].run == 1 &&
1774 sc->chan[i].blk < sc->blk[slot])
1775 sc->blk[slot] = sc->chan[i].blk;
1777 if (ch->blk != sc->blk[slot])
1778 envy24ht_updintr(sc, ch->dir);
1781 break;
1783 fail:
1784 snd_mtxunlock(sc->lock);
1785 return (error);
1788 static u_int32_t
1789 envy24htchan_getptr(kobj_t obj, void *data)
1791 struct sc_chinfo *ch = data;
1792 struct sc_info *sc = ch->parent;
1793 u_int32_t ptr, rtn;
1795 #if(0)
1796 device_printf(sc->dev, "envy24htchan_getptr()\n");
1797 #endif
1798 snd_mtxlock(sc->lock);
1799 ptr = envy24ht_gethwptr(sc, ch->dir);
1800 rtn = ptr * ch->unit;
1801 snd_mtxunlock(sc->lock);
1803 #if(0)
1804 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1805 rtn);
1806 #endif
1807 return rtn;
1810 static struct pcmchan_caps *
1811 envy24htchan_getcaps(kobj_t obj, void *data)
1813 struct sc_chinfo *ch = data;
1814 struct sc_info *sc = ch->parent;
1815 struct pcmchan_caps *rtn;
1817 #if(0)
1818 device_printf(sc->dev, "envy24htchan_getcaps()\n");
1819 #endif
1820 snd_mtxlock(sc->lock);
1821 if (ch->dir == PCMDIR_PLAY) {
1822 if (sc->run[0] == 0)
1823 rtn = &envy24ht_playcaps;
1824 else
1825 rtn = &sc->caps[0];
1827 else {
1828 if (sc->run[1] == 0)
1829 rtn = &envy24ht_reccaps;
1830 else
1831 rtn = &sc->caps[1];
1833 snd_mtxunlock(sc->lock);
1835 return rtn;
1838 static kobj_method_t envy24htchan_methods[] = {
1839 KOBJMETHOD(channel_init, envy24htchan_init),
1840 KOBJMETHOD(channel_free, envy24htchan_free),
1841 KOBJMETHOD(channel_setformat, envy24htchan_setformat),
1842 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed),
1843 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize),
1844 KOBJMETHOD(channel_trigger, envy24htchan_trigger),
1845 KOBJMETHOD(channel_getptr, envy24htchan_getptr),
1846 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps),
1847 KOBJMETHOD_END
1849 CHANNEL_DECLARE(envy24htchan);
1851 /* -------------------------------------------------------------------- */
1853 /* mixer interface */
1855 static int
1856 envy24htmixer_init(struct snd_mixer *m)
1858 struct sc_info *sc = mix_getdevinfo(m);
1860 #if(0)
1861 device_printf(sc->dev, "envy24htmixer_init()\n");
1862 #endif
1863 if (sc == NULL)
1864 return -1;
1866 /* set volume control rate */
1867 snd_mtxlock(sc->lock);
1868 #if 0
1869 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1870 #endif
1872 pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1874 mix_setdevs(m, ENVY24HT_MIX_MASK);
1875 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1877 snd_mtxunlock(sc->lock);
1879 return 0;
1882 static int
1883 envy24htmixer_reinit(struct snd_mixer *m)
1885 struct sc_info *sc = mix_getdevinfo(m);
1887 if (sc == NULL)
1888 return -1;
1889 #if(0)
1890 device_printf(sc->dev, "envy24htmixer_reinit()\n");
1891 #endif
1893 return 0;
1896 static int
1897 envy24htmixer_uninit(struct snd_mixer *m)
1899 struct sc_info *sc = mix_getdevinfo(m);
1901 if (sc == NULL)
1902 return -1;
1903 #if(0)
1904 device_printf(sc->dev, "envy24htmixer_uninit()\n");
1905 #endif
1907 return 0;
1910 static int
1911 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1913 struct sc_info *sc = mix_getdevinfo(m);
1914 int ch = envy24ht_mixmap[dev];
1915 int hwch;
1916 int i;
1918 if (sc == NULL)
1919 return -1;
1920 if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1921 return -1;
1922 if (dev != 0 && ch == -1)
1923 return -1;
1924 hwch = envy24ht_chanmap[ch];
1925 #if(0)
1926 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1927 dev, left, right);
1928 #endif
1930 snd_mtxlock(sc->lock);
1931 if (dev == 0) {
1932 for (i = 0; i < sc->dacn; i++) {
1933 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1936 else {
1937 /* set volume value for hardware */
1938 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1939 sc->left[hwch] = ENVY24HT_VOL_MUTE;
1940 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1941 sc->right[hwch] = ENVY24HT_VOL_MUTE;
1943 /* set volume for record channel and running play channel */
1944 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1945 envy24ht_setvolume(sc, hwch);
1947 snd_mtxunlock(sc->lock);
1949 return right << 8 | left;
1952 static u_int32_t
1953 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1955 struct sc_info *sc = mix_getdevinfo(m);
1956 int ch = envy24ht_mixmap[src];
1957 #if(0)
1958 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1959 #endif
1961 if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1962 sc->src = ch;
1963 return src;
1966 static kobj_method_t envy24htmixer_methods[] = {
1967 KOBJMETHOD(mixer_init, envy24htmixer_init),
1968 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit),
1969 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit),
1970 KOBJMETHOD(mixer_set, envy24htmixer_set),
1971 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc),
1972 KOBJMETHOD_END
1974 MIXER_DECLARE(envy24htmixer);
1976 /* -------------------------------------------------------------------- */
1978 /* The interrupt handler */
1979 static void
1980 envy24ht_intr(void *p)
1982 struct sc_info *sc = (struct sc_info *)p;
1983 struct sc_chinfo *ch;
1984 u_int32_t ptr, dsize, feed;
1985 int i;
1987 #if(0)
1988 device_printf(sc->dev, "envy24ht_intr()\n");
1989 #endif
1990 snd_mtxlock(sc->lock);
1991 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1992 #if(0)
1993 device_printf(sc->dev, "envy24ht_intr(): play\n");
1994 #endif
1995 dsize = sc->psize / 4;
1996 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
1997 #if(0)
1998 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
1999 #endif
2000 ptr -= ptr % sc->blk[0];
2001 feed = (ptr + dsize - sc->intr[0]) % dsize;
2002 #if(0)
2003 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2004 #endif
2005 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
2006 ch = &sc->chan[i];
2007 #if(0)
2008 if (ch->run)
2009 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
2010 #endif
2011 if (ch->run && ch->blk <= feed) {
2012 snd_mtxunlock(sc->lock);
2013 chn_intr(ch->channel);
2014 snd_mtxlock(sc->lock);
2017 sc->intr[0] = ptr;
2018 envy24ht_updintr(sc, PCMDIR_PLAY);
2020 if (envy24ht_checkintr(sc, PCMDIR_REC)) {
2021 #if(0)
2022 device_printf(sc->dev, "envy24ht_intr(): rec\n");
2023 #endif
2024 dsize = sc->rsize / 4;
2025 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
2026 ptr -= ptr % sc->blk[1];
2027 feed = (ptr + dsize - sc->intr[1]) % dsize;
2028 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
2029 ch = &sc->chan[i];
2030 if (ch->run && ch->blk <= feed) {
2031 snd_mtxunlock(sc->lock);
2032 chn_intr(ch->channel);
2033 snd_mtxlock(sc->lock);
2036 sc->intr[1] = ptr;
2037 envy24ht_updintr(sc, PCMDIR_REC);
2039 snd_mtxunlock(sc->lock);
2041 return;
2045 * Probe and attach the card
2048 static int
2049 envy24ht_pci_probe(device_t dev)
2051 u_int16_t sv, sd;
2052 int i;
2054 #if(0)
2055 printf("envy24ht_pci_probe()\n");
2056 #endif
2057 if (pci_get_device(dev) == PCID_ENVY24HT &&
2058 pci_get_vendor(dev) == PCIV_ENVY24) {
2059 sv = pci_get_subvendor(dev);
2060 sd = pci_get_subdevice(dev);
2061 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2062 if (cfg_table[i].subvendor == sv &&
2063 cfg_table[i].subdevice == sd) {
2064 break;
2067 device_set_desc(dev, cfg_table[i].name);
2068 #if(0)
2069 printf("envy24ht_pci_probe(): return 0\n");
2070 #endif
2071 return 0;
2073 else {
2074 #if(0)
2075 printf("envy24ht_pci_probe(): return ENXIO\n");
2076 #endif
2077 return ENXIO;
2081 static void
2082 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2084 struct sc_info *sc = arg;
2086 sc->paddr = segs->ds_addr;
2087 #if(0)
2088 device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2089 if (bootverbose) {
2090 printf("envy24ht(play): setmap %lx, %lx; ",
2091 (unsigned long)segs->ds_addr,
2092 (unsigned long)segs->ds_len);
2094 #endif
2095 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, (uint32_t)segs->ds_addr, 4);
2096 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2099 static void
2100 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2102 struct sc_info *sc = arg;
2104 sc->raddr = segs->ds_addr;
2105 #if(0)
2106 device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2107 if (bootverbose) {
2108 printf("envy24ht(record): setmap %lx, %lx; ",
2109 (unsigned long)segs->ds_addr,
2110 (unsigned long)segs->ds_len);
2112 #endif
2113 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, (uint32_t)segs->ds_addr, 4);
2114 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2117 static void
2118 envy24ht_dmafree(struct sc_info *sc)
2120 #if(0)
2121 device_printf(sc->dev, "envy24ht_dmafree():");
2122 printf(" sc->raddr(0x%08x)", (u_int32_t)sc->raddr);
2123 printf(" sc->paddr(0x%08x)", (u_int32_t)sc->paddr);
2124 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2125 else printf(" sc->rbuf(null)");
2126 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2127 else printf(" sc->pbuf(null)\n");
2128 #endif
2129 #if(0)
2130 if (sc->raddr)
2131 bus_dmamap_unload(sc->dmat, sc->rmap);
2132 if (sc->paddr)
2133 bus_dmamap_unload(sc->dmat, sc->pmap);
2134 if (sc->rbuf)
2135 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2136 if (sc->pbuf)
2137 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2138 #else
2139 bus_dmamap_unload(sc->dmat, sc->rmap);
2140 bus_dmamap_unload(sc->dmat, sc->pmap);
2141 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2142 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2143 #endif
2145 sc->raddr = sc->paddr = 0;
2146 sc->pbuf = NULL;
2147 sc->rbuf = NULL;
2149 return;
2152 static int
2153 envy24ht_dmainit(struct sc_info *sc)
2156 #if(0)
2157 device_printf(sc->dev, "envy24ht_dmainit()\n");
2158 #endif
2159 /* init values */
2160 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2161 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2162 sc->pbuf = NULL;
2163 sc->rbuf = NULL;
2164 sc->paddr = sc->raddr = 0;
2165 sc->blk[0] = sc->blk[1] = 0;
2167 /* allocate DMA buffer */
2168 #if(0)
2169 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2170 #endif
2171 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2172 goto bad;
2173 #if(0)
2174 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2175 #endif
2176 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2177 goto bad;
2178 #if(0)
2179 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2180 #endif
2181 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, BUS_DMA_NOWAIT))
2182 goto bad;
2183 #if(0)
2184 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2185 #endif
2186 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, BUS_DMA_NOWAIT))
2187 goto bad;
2188 bzero(sc->pbuf, sc->psize);
2189 bzero(sc->rbuf, sc->rsize);
2191 return 0;
2192 bad:
2193 envy24ht_dmafree(sc);
2194 return ENOSPC;
2197 static void
2198 envy24ht_putcfg(struct sc_info *sc)
2200 device_printf(sc->dev, "system configuration\n");
2201 kprintf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2202 sc->cfg->subvendor, sc->cfg->subdevice);
2203 kprintf(" XIN2 Clock Source: ");
2204 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2205 case 0x00:
2206 kprintf("24.576MHz(96kHz*256)\n");
2207 break;
2208 case 0x40:
2209 kprintf("49.152MHz(192kHz*256)\n");
2210 break;
2211 case 0x80:
2212 kprintf("reserved\n");
2213 break;
2214 default:
2215 kprintf("illegal system setting\n");
2217 kprintf(" MPU-401 UART(s) #: ");
2218 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2219 kprintf("1\n");
2220 else
2221 kprintf("not implemented\n");
2222 switch (sc->adcn) {
2223 case 0x01:
2224 case 0x02:
2225 kprintf(" ADC #: ");
2226 kprintf("%d\n", sc->adcn);
2227 break;
2228 case 0x03:
2229 kprintf(" ADC #: ");
2230 kprintf("%d", 1);
2231 kprintf(" and SPDIF receiver connected\n");
2232 break;
2233 default:
2234 kprintf(" no physical inputs\n");
2236 kprintf(" DAC #: ");
2237 kprintf("%d\n", sc->dacn);
2238 kprintf(" Multi-track converter type: ");
2239 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2240 kprintf("AC'97(SDATA_OUT:");
2241 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2242 kprintf("packed");
2243 else
2244 kprintf("split");
2245 kprintf(")\n");
2247 else {
2248 kprintf("I2S(");
2249 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2250 kprintf("with volume, ");
2251 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2252 kprintf("192KHz support, ");
2253 else
2254 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2255 kprintf("192KHz support, ");
2256 else
2257 kprintf("48KHz support, ");
2258 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2259 case ENVY24HT_CCSM_I2S_16BIT:
2260 kprintf("16bit resolution, ");
2261 break;
2262 case ENVY24HT_CCSM_I2S_18BIT:
2263 kprintf("18bit resolution, ");
2264 break;
2265 case ENVY24HT_CCSM_I2S_20BIT:
2266 kprintf("20bit resolution, ");
2267 break;
2268 case ENVY24HT_CCSM_I2S_24BIT:
2269 kprintf("24bit resolution, ");
2270 break;
2272 kprintf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2274 kprintf(" S/PDIF(IN/OUT): ");
2275 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2276 kprintf("1/");
2277 else
2278 kprintf("0/");
2279 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2280 kprintf("1 ");
2281 else
2282 kprintf("0 ");
2283 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2284 kprintf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2285 kprintf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2286 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2289 static int
2290 envy24ht_init(struct sc_info *sc)
2292 u_int32_t data;
2293 #if(0)
2294 int rtn;
2295 #endif
2296 int i;
2297 u_int32_t sv, sd;
2300 #if(0)
2301 device_printf(sc->dev, "envy24ht_init()\n");
2302 #endif
2304 /* reset chip */
2305 #if 0
2306 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2307 DELAY(200);
2308 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2309 DELAY(200);
2311 /* legacy hardware disable */
2312 data = pci_read_config(sc->dev, PCIR_LAC, 2);
2313 data |= PCIM_LAC_DISABLE;
2314 pci_write_config(sc->dev, PCIR_LAC, data, 2);
2315 #endif
2317 /* check system configuration */
2318 sc->cfg = NULL;
2319 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2320 /* 1st: search configuration from table */
2321 sv = pci_get_subvendor(sc->dev);
2322 sd = pci_get_subdevice(sc->dev);
2323 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2324 #if(0)
2325 device_printf(sc->dev, "Set configuration from table\n");
2326 #endif
2327 sc->cfg = &cfg_table[i];
2328 break;
2331 if (sc->cfg == NULL) {
2332 /* 2nd: read configuration from table */
2333 sc->cfg = envy24ht_rom2cfg(sc);
2335 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2336 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2338 if (1 /* bootverbose */) {
2339 envy24ht_putcfg(sc);
2342 /* set system configuration */
2343 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2344 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2345 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2346 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2347 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2348 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2349 envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2351 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2352 envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2353 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2354 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2357 for (i = 0; i < sc->adcn; i++) {
2358 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2359 sc->cfg->codec->init(sc->adc[i]);
2361 for (i = 0; i < sc->dacn; i++) {
2362 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2363 sc->cfg->codec->init(sc->dac[i]);
2366 /* initialize DMA buffer */
2367 #if(0)
2368 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2369 #endif
2370 if (envy24ht_dmainit(sc))
2371 return ENOSPC;
2373 /* initialize status */
2374 sc->run[0] = sc->run[1] = 0;
2375 sc->intr[0] = sc->intr[1] = 0;
2376 sc->speed = 0;
2377 sc->caps[0].fmtlist = envy24ht_playfmt;
2378 sc->caps[1].fmtlist = envy24ht_recfmt;
2380 /* set channel router */
2381 #if 0
2382 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2383 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2384 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2385 #endif
2387 /* set macro interrupt mask */
2388 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2389 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2390 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2391 #if(0)
2392 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2393 #endif
2395 return 0;
2398 static int
2399 envy24ht_alloc_resource(struct sc_info *sc)
2401 /* allocate I/O port resource */
2402 sc->csid = PCIR_CCS;
2403 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2404 &sc->csid, 0, ~0, 1, RF_ACTIVE);
2405 sc->mtid = ENVY24HT_PCIR_MT;
2406 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2407 &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2408 if (!sc->cs || !sc->mt) {
2409 device_printf(sc->dev, "unable to map IO port space\n");
2410 return ENXIO;
2412 sc->cst = rman_get_bustag(sc->cs);
2413 sc->csh = rman_get_bushandle(sc->cs);
2414 sc->mtt = rman_get_bustag(sc->mt);
2415 sc->mth = rman_get_bushandle(sc->mt);
2416 #if(0)
2417 device_printf(sc->dev,
2418 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2419 pci_read_config(sc->dev, PCIR_CCS, 4),
2420 pci_read_config(sc->dev, PCIR_MT, 4));
2421 #endif
2423 /* allocate interrupt resource */
2424 sc->irqid = 0;
2425 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2426 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2427 if (!sc->irq ||
2428 snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24ht_intr, sc, &sc->ih)) {
2429 device_printf(sc->dev, "unable to map interrupt\n");
2430 return ENXIO;
2433 /* allocate DMA resource */
2434 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2435 /*alignment*/4,
2436 /*boundary*/0,
2437 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
2438 /*highaddr*/BUS_SPACE_MAXADDR,
2439 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2440 /*nsegments*/1, /*maxsegsz*/0x3ffff,
2441 /*flags*/0,
2442 &sc->dmat) != 0) {
2443 device_printf(sc->dev, "unable to create dma tag\n");
2444 return ENXIO;
2447 return 0;
2450 static int
2451 envy24ht_pci_attach(device_t dev)
2453 struct sc_info *sc;
2454 char status[SND_STATUSLEN];
2455 int err = 0;
2456 int i;
2458 #if(0)
2459 device_printf(dev, "envy24ht_pci_attach()\n");
2460 #endif
2461 /* get sc_info data area */
2462 if ((sc = kmalloc(sizeof(*sc), M_ENVY24HT, M_WAITOK | M_ZERO)) == NULL) {
2463 device_printf(dev, "cannot allocate softc\n");
2464 return ENXIO;
2467 bzero(sc, sizeof(*sc));
2468 sc->lock = snd_mtxcreate(device_get_nameunit(dev),
2469 "snd_envy24ht softc");
2470 sc->dev = dev;
2472 /* initialize PCI interface */
2473 pci_enable_busmaster(dev);
2475 /* allocate resources */
2476 err = envy24ht_alloc_resource(sc);
2477 if (err) {
2478 device_printf(dev, "unable to allocate system resources\n");
2479 goto bad;
2482 /* initialize card */
2483 err = envy24ht_init(sc);
2484 if (err) {
2485 device_printf(dev, "unable to initialize the card\n");
2486 goto bad;
2489 /* set multi track mixer */
2490 mixer_init(dev, &envy24htmixer_class, sc);
2492 /* set channel information */
2493 /* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
2494 err = pcm_register(dev, sc, 1, 2 + sc->adcn);
2495 if (err)
2496 goto bad;
2497 sc->chnum = 0;
2498 /* for (i = 0; i < 5; i++) { */
2499 pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
2500 sc->chnum++;
2501 /* } */
2502 for (i = 0; i < 2 + sc->adcn; i++) {
2503 pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
2504 sc->chnum++;
2507 /* set status iformation */
2508 ksnprintf(status, SND_STATUSLEN,
2509 "at io 0x%lx:%ld,0x%lx:%ld irq %ld",
2510 rman_get_start(sc->cs),
2511 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2512 rman_get_start(sc->mt),
2513 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2514 rman_get_start(sc->irq));
2515 pcm_setstatus(dev, status);
2517 return 0;
2519 bad:
2520 if (sc->ih)
2521 bus_teardown_intr(dev, sc->irq, sc->ih);
2522 if (sc->irq)
2523 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2524 envy24ht_dmafree(sc);
2525 if (sc->dmat)
2526 bus_dma_tag_destroy(sc->dmat);
2527 if (sc->cfg->codec->destroy != NULL) {
2528 for (i = 0; i < sc->adcn; i++)
2529 sc->cfg->codec->destroy(sc->adc[i]);
2530 for (i = 0; i < sc->dacn; i++)
2531 sc->cfg->codec->destroy(sc->dac[i]);
2533 envy24ht_cfgfree(sc->cfg);
2534 if (sc->cs)
2535 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2536 if (sc->mt)
2537 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2538 if (sc->lock)
2539 snd_mtxfree(sc->lock);
2540 kfree(sc, M_ENVY24HT);
2541 return err;
2544 static int
2545 envy24ht_pci_detach(device_t dev)
2547 struct sc_info *sc;
2548 int r;
2549 int i;
2551 #if(0)
2552 device_printf(dev, "envy24ht_pci_detach()\n");
2553 #endif
2554 sc = pcm_getdevinfo(dev);
2555 if (sc == NULL)
2556 return 0;
2557 r = pcm_unregister(dev);
2558 if (r)
2559 return r;
2561 envy24ht_dmafree(sc);
2562 if (sc->cfg->codec->destroy != NULL) {
2563 for (i = 0; i < sc->adcn; i++)
2564 sc->cfg->codec->destroy(sc->adc[i]);
2565 for (i = 0; i < sc->dacn; i++)
2566 sc->cfg->codec->destroy(sc->dac[i]);
2568 envy24ht_cfgfree(sc->cfg);
2569 bus_dma_tag_destroy(sc->dmat);
2570 bus_teardown_intr(dev, sc->irq, sc->ih);
2571 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2572 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2573 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2574 snd_mtxfree(sc->lock);
2575 kfree(sc, M_ENVY24HT);
2576 return 0;
2579 static device_method_t envy24ht_methods[] = {
2580 /* Device interface */
2581 DEVMETHOD(device_probe, envy24ht_pci_probe),
2582 DEVMETHOD(device_attach, envy24ht_pci_attach),
2583 DEVMETHOD(device_detach, envy24ht_pci_detach),
2584 { 0, 0 }
2587 static driver_t envy24ht_driver = {
2588 "pcm",
2589 envy24ht_methods,
2590 PCM_SOFTC_SIZE,
2593 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, NULL, NULL);
2594 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2595 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2596 MODULE_VERSION(snd_envy24ht, 1);