- Add codec id for Realtek ALC268.
[dragonfly.git] / sys / dev / sound / pci / envy24.c
blob035c5be40f8d2dcf17cb22e0a92ced3c4e1e059c
1 /*
2 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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
24 * SUCH DAMAGE.
26 * $FreeBSD: src/sys/dev/sound/pci/envy24.c,v 1.11.2.2 2007/06/11 19:33:27 ariff Exp $
27 * $DragonFly: src/sys/dev/sound/pci/envy24.c,v 1.2 2007/06/16 20:07:19 dillon Exp $
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/pcm/ac97.h>
32 #include <dev/sound/pci/spicds.h>
33 #include <dev/sound/pci/envy24.h>
35 #include <bus/pci/pcireg.h>
36 #include <bus/pci/pcivar.h>
38 #include "mixer_if.h"
40 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pci/envy24.c,v 1.2 2007/06/16 20:07:19 dillon Exp $");
42 MALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio");
44 /* -------------------------------------------------------------------- */
46 struct sc_info;
48 #define ENVY24_PLAY_CHNUM 10
49 #define ENVY24_REC_CHNUM 12
50 #define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */)
51 #define ENVY24_REC_BUFUNIT (4 /* byte/sample */ * 12 /* channel */)
52 #define ENVY24_SAMPLE_NUM 4096
54 #define ENVY24_TIMEOUT 1000
56 #define ENVY24_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE)
58 #define ENVY24_NAMELEN 32
60 #define SDA_GPIO 0x10
61 #define SCL_GPIO 0x20
63 #define abs(i) (i < 0 ? -i : i)
65 struct envy24_sample {
66 volatile u_int32_t buffer;
69 typedef struct envy24_sample sample32_t;
71 /* channel registers */
72 struct sc_chinfo {
73 struct snd_dbuf *buffer;
74 struct pcm_channel *channel;
75 struct sc_info *parent;
76 int dir;
77 unsigned num; /* hw channel number */
79 /* channel information */
80 u_int32_t format;
81 u_int32_t speed;
82 u_int32_t blk; /* hw block size(dword) */
84 /* format conversion structure */
85 u_int8_t *data;
86 unsigned int size; /* data buffer size(byte) */
87 int unit; /* sample size(byte) */
88 unsigned int offset; /* samples number offset */
89 void (*emldma)(struct sc_chinfo *);
91 /* flags */
92 int run;
95 /* codec interface entrys */
96 struct codec_entry {
97 void *(*create)(device_t dev, void *devinfo, int dir, int num);
98 void (*destroy)(void *codec);
99 void (*init)(void *codec);
100 void (*reinit)(void *codec);
101 void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
102 void (*setrate)(void *codec, int which, int rate);
105 /* system configuration information */
106 struct cfg_info {
107 char *name;
108 u_int16_t subvendor, subdevice;
109 u_int8_t scfg, acl, i2s, spdif;
110 u_int8_t gpiomask, gpiostate, gpiodir;
111 u_int8_t cdti, cclk, cs, cif, type;
112 u_int8_t free;
113 struct codec_entry *codec;
116 /* device private data */
117 struct sc_info {
118 device_t dev;
119 sndlock_t lock;
121 /* Control/Status registor */
122 struct resource *cs;
123 int csid;
124 bus_space_tag_t cst;
125 bus_space_handle_t csh;
126 /* DDMA registor */
127 struct resource *ddma;
128 int ddmaid;
129 bus_space_tag_t ddmat;
130 bus_space_handle_t ddmah;
131 /* Consumer Section DMA Channel Registers */
132 struct resource *ds;
133 int dsid;
134 bus_space_tag_t dst;
135 bus_space_handle_t dsh;
136 /* MultiTrack registor */
137 struct resource *mt;
138 int mtid;
139 bus_space_tag_t mtt;
140 bus_space_handle_t mth;
141 /* DMA tag */
142 bus_dma_tag_t dmat;
143 /* IRQ resource */
144 struct resource *irq;
145 int irqid;
146 void *ih;
148 /* system configuration data */
149 struct cfg_info *cfg;
151 /* ADC/DAC number and info */
152 int adcn, dacn;
153 void *adc[4], *dac[4];
155 /* mixer control data */
156 u_int32_t src;
157 u_int8_t left[ENVY24_CHAN_NUM];
158 u_int8_t right[ENVY24_CHAN_NUM];
160 /* Play/Record DMA fifo */
161 sample32_t *pbuf;
162 sample32_t *rbuf;
163 u_int32_t psize, rsize; /* DMA buffer size(byte) */
164 u_int16_t blk[2]; /* transfer check blocksize(dword) */
165 bus_dmamap_t pmap, rmap;
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 envy24_p8u(struct sc_chinfo *);
186 static void envy24_p16sl(struct sc_chinfo *);
187 static void envy24_p32sl(struct sc_chinfo *);
188 static void envy24_r16sl(struct sc_chinfo *);
189 static void envy24_r32sl(struct sc_chinfo *);
191 /* channel interface */
192 static void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
193 static int envy24chan_setformat(kobj_t, void *, u_int32_t);
194 static int envy24chan_setspeed(kobj_t, void *, u_int32_t);
195 static int envy24chan_setblocksize(kobj_t, void *, u_int32_t);
196 static int envy24chan_trigger(kobj_t, void *, int);
197 static int envy24chan_getptr(kobj_t, void *);
198 static struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *);
200 /* mixer interface */
201 static int envy24mixer_init(struct snd_mixer *);
202 static int envy24mixer_reinit(struct snd_mixer *);
203 static int envy24mixer_uninit(struct snd_mixer *);
204 static int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
205 static u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t);
207 /* M-Audio Delta series AK4524 access interface */
208 static void *envy24_delta_ak4524_create(device_t, void *, int, int);
209 static void envy24_delta_ak4524_destroy(void *);
210 static void envy24_delta_ak4524_init(void *);
211 static void envy24_delta_ak4524_reinit(void *);
212 static void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int);
214 /* -------------------------------------------------------------------- */
217 system constant tables
220 /* API -> hardware channel map */
221 static unsigned envy24_chanmap[ENVY24_CHAN_NUM] = {
222 ENVY24_CHAN_PLAY_SPDIF, /* 0 */
223 ENVY24_CHAN_PLAY_DAC1, /* 1 */
224 ENVY24_CHAN_PLAY_DAC2, /* 2 */
225 ENVY24_CHAN_PLAY_DAC3, /* 3 */
226 ENVY24_CHAN_PLAY_DAC4, /* 4 */
227 ENVY24_CHAN_REC_MIX, /* 5 */
228 ENVY24_CHAN_REC_SPDIF, /* 6 */
229 ENVY24_CHAN_REC_ADC1, /* 7 */
230 ENVY24_CHAN_REC_ADC2, /* 8 */
231 ENVY24_CHAN_REC_ADC3, /* 9 */
232 ENVY24_CHAN_REC_ADC4, /* 10 */
235 /* mixer -> API channel map. see above */
236 static int envy24_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 envy24_speed[] = {
266 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
267 12000, 11025, 9600, 8000, 0
270 /* known boards configuration */
271 static struct codec_entry delta_codec = {
272 envy24_delta_ak4524_create,
273 envy24_delta_ak4524_destroy,
274 envy24_delta_ak4524_init,
275 envy24_delta_ak4524_reinit,
276 envy24_delta_ak4524_setvolume,
277 NULL, /* setrate */
280 static struct cfg_info cfg_table[] = {
282 "Envy24 audio (M Audio Delta Dio 2496)",
283 0x1412, 0xd631,
284 0x10, 0x80, 0xf0, 0x03,
285 0xff, 0x00, 0x00,
286 0x10, 0x20, 0x40, 0x00, 0x00,
287 0x00,
288 &delta_codec,
291 "Envy24 audio (Terratec DMX 6fire)",
292 0x153b, 0x1138,
293 0x2f, 0x80, 0xf0, 0x03,
294 0xc0, 0xff, 0x7f,
295 0x10, 0x20, 0x01, 0x01, 0x00,
296 0x00,
297 &delta_codec,
300 "Envy24 audio (M Audio Audiophile 2496)",
301 0x1412, 0xd634,
302 0x10, 0x80, 0x72, 0x03,
303 0x04, 0xfe, 0xfb,
304 0x08, 0x02, 0x20, 0x00, 0x01,
305 0x00,
306 &delta_codec,
309 "Envy24 audio (Generic)",
310 0, 0,
311 0x0f, 0x00, 0x01, 0x03,
312 0xff, 0x00, 0x00,
313 0x10, 0x20, 0x40, 0x00, 0x00,
314 0x00,
315 &delta_codec, /* default codec routines */
319 static u_int32_t envy24_recfmt[] = {
320 AFMT_STEREO | AFMT_S16_LE,
321 AFMT_STEREO | AFMT_S32_LE,
324 static struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0};
326 static u_int32_t envy24_playfmt[] = {
327 AFMT_STEREO | AFMT_U8,
328 AFMT_STEREO | AFMT_S16_LE,
329 AFMT_STEREO | AFMT_S32_LE,
333 static struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0};
335 struct envy24_emldma {
336 u_int32_t format;
337 void (*emldma)(struct sc_chinfo *);
338 int unit;
341 static struct envy24_emldma envy24_pemltab[] = {
342 {AFMT_STEREO | AFMT_U8, envy24_p8u, 2},
343 {AFMT_STEREO | AFMT_S16_LE, envy24_p16sl, 4},
344 {AFMT_STEREO | AFMT_S32_LE, envy24_p32sl, 8},
345 {0, NULL, 0}
348 static struct envy24_emldma envy24_remltab[] = {
349 {AFMT_STEREO | AFMT_S16_LE, envy24_r16sl, 4},
350 {AFMT_STEREO | AFMT_S32_LE, envy24_r32sl, 8},
351 {0, NULL, 0}
354 /* -------------------------------------------------------------------- */
356 /* common routines */
357 static u_int32_t
358 envy24_rdcs(struct sc_info *sc, int regno, int size)
360 switch (size) {
361 case 1:
362 return bus_space_read_1(sc->cst, sc->csh, regno);
363 case 2:
364 return bus_space_read_2(sc->cst, sc->csh, regno);
365 case 4:
366 return bus_space_read_4(sc->cst, sc->csh, regno);
367 default:
368 return 0xffffffff;
372 static void
373 envy24_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
375 switch (size) {
376 case 1:
377 bus_space_write_1(sc->cst, sc->csh, regno, data);
378 break;
379 case 2:
380 bus_space_write_2(sc->cst, sc->csh, regno, data);
381 break;
382 case 4:
383 bus_space_write_4(sc->cst, sc->csh, regno, data);
384 break;
388 static u_int32_t
389 envy24_rdmt(struct sc_info *sc, int regno, int size)
391 switch (size) {
392 case 1:
393 return bus_space_read_1(sc->mtt, sc->mth, regno);
394 case 2:
395 return bus_space_read_2(sc->mtt, sc->mth, regno);
396 case 4:
397 return bus_space_read_4(sc->mtt, sc->mth, regno);
398 default:
399 return 0xffffffff;
403 static void
404 envy24_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
406 switch (size) {
407 case 1:
408 bus_space_write_1(sc->mtt, sc->mth, regno, data);
409 break;
410 case 2:
411 bus_space_write_2(sc->mtt, sc->mth, regno, data);
412 break;
413 case 4:
414 bus_space_write_4(sc->mtt, sc->mth, regno, data);
415 break;
419 static u_int32_t
420 envy24_rdci(struct sc_info *sc, int regno)
422 envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
423 return envy24_rdcs(sc, ENVY24_CCS_DATA, 1);
426 static void
427 envy24_wrci(struct sc_info *sc, int regno, u_int32_t data)
429 envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
430 envy24_wrcs(sc, ENVY24_CCS_DATA, data, 1);
433 /* -------------------------------------------------------------------- */
435 /* I2C port/E2PROM access routines */
437 static int
438 envy24_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
440 u_int32_t data;
441 int i;
443 #if(0)
444 device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
445 #endif
446 for (i = 0; i < ENVY24_TIMEOUT; i++) {
447 data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
448 if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
449 break;
450 DELAY(32); /* 31.25kHz */
452 if (i == ENVY24_TIMEOUT) {
453 return -1;
455 envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
456 envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
457 (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_RD, 1);
458 for (i = 0; i < ENVY24_TIMEOUT; i++) {
459 data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
460 if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
461 break;
462 DELAY(32); /* 31.25kHz */
464 if (i == ENVY24_TIMEOUT) {
465 return -1;
467 data = envy24_rdcs(sc, ENVY24_CCS_I2CDATA, 1);
469 #if(0)
470 device_printf(sc->dev, "envy24_rdi2c(): return 0x%x\n", data);
471 #endif
472 return (int)data;
475 #if 0
476 static int
477 envy24_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
479 u_int32_t tmp;
480 int i;
482 #if(0)
483 device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
484 #endif
485 for (i = 0; i < ENVY24_TIMEOUT; i++) {
486 tmp = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
487 if ((tmp & ENVY24_CCS_I2CSTAT_BSY) == 0)
488 break;
489 DELAY(32); /* 31.25kHz */
491 if (i == ENVY24_TIMEOUT) {
492 return -1;
494 envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
495 envy24_wrcs(sc, ENVY24_CCS_I2CDATA, data, 1);
496 envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
497 (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_WR, 1);
498 for (i = 0; i < ENVY24_TIMEOUT; i++) {
499 data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
500 if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
501 break;
502 DELAY(32); /* 31.25kHz */
504 if (i == ENVY24_TIMEOUT) {
505 return -1;
508 return 0;
510 #endif
512 static int
513 envy24_rdrom(struct sc_info *sc, u_int32_t addr)
515 u_int32_t data;
517 #if(0)
518 device_printf(sc->dev, "envy24_rdrom(sc, 0x%02x)\n", addr);
519 #endif
520 data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
521 if ((data & ENVY24_CCS_I2CSTAT_ROM) == 0) {
522 #if(0)
523 device_printf(sc->dev, "envy24_rdrom(): E2PROM not presented\n");
524 #endif
525 return -1;
528 return envy24_rdi2c(sc, ENVY24_CCS_I2CDEV_ROM, addr);
531 static struct cfg_info *
532 envy24_rom2cfg(struct sc_info *sc)
534 struct cfg_info *buff;
535 int size;
536 int i;
538 #if(0)
539 device_printf(sc->dev, "envy24_rom2cfg(sc)\n");
540 #endif
541 size = envy24_rdrom(sc, ENVY24_E2PROM_SIZE);
542 if (size < ENVY24_E2PROM_GPIODIR + 1) {
543 #if(0)
544 device_printf(sc->dev, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size);
545 #endif
546 return NULL;
548 buff = kmalloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
549 if (buff == NULL) {
550 #if(0)
551 device_printf(sc->dev, "envy24_rom2cfg(): malloc()\n");
552 #endif
553 return NULL;
555 buff->free = 1;
557 buff->subvendor = envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR) << 8;
558 buff->subvendor += envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR + 1);
559 buff->subdevice = envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE) << 8;
560 buff->subdevice += envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE + 1);
561 buff->scfg = envy24_rdrom(sc, ENVY24_E2PROM_SCFG);
562 buff->acl = envy24_rdrom(sc, ENVY24_E2PROM_ACL);
563 buff->i2s = envy24_rdrom(sc, ENVY24_E2PROM_I2S);
564 buff->spdif = envy24_rdrom(sc, ENVY24_E2PROM_SPDIF);
565 buff->gpiomask = envy24_rdrom(sc, ENVY24_E2PROM_GPIOMASK);
566 buff->gpiostate = envy24_rdrom(sc, ENVY24_E2PROM_GPIOSTATE);
567 buff->gpiodir = envy24_rdrom(sc, ENVY24_E2PROM_GPIODIR);
569 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
570 if (cfg_table[i].subvendor == buff->subvendor &&
571 cfg_table[i].subdevice == buff->subdevice)
572 break;
573 buff->name = cfg_table[i].name;
574 buff->codec = cfg_table[i].codec;
576 return buff;
579 static void
580 envy24_cfgfree(struct cfg_info *cfg) {
581 if (cfg == NULL)
582 return;
583 if (cfg->free)
584 kfree(cfg, M_ENVY24);
585 return;
588 /* -------------------------------------------------------------------- */
590 /* AC'97 codec access routines */
592 #if 0
593 static int
594 envy24_coldcd(struct sc_info *sc)
596 u_int32_t data;
597 int i;
599 #if(0)
600 device_printf(sc->dev, "envy24_coldcd()\n");
601 #endif
602 envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_CLD, 1);
603 DELAY(10);
604 envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
605 DELAY(1000);
606 for (i = 0; i < ENVY24_TIMEOUT; i++) {
607 data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
608 if (data & ENVY24_MT_AC97CMD_RDY) {
609 return 0;
613 return -1;
615 #endif
617 static int
618 envy24_slavecd(struct sc_info *sc)
620 u_int32_t data;
621 int i;
623 #if(0)
624 device_printf(sc->dev, "envy24_slavecd()\n");
625 #endif
626 envy24_wrmt(sc, ENVY24_MT_AC97CMD,
627 ENVY24_MT_AC97CMD_CLD | ENVY24_MT_AC97CMD_WRM, 1);
628 DELAY(10);
629 envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
630 DELAY(1000);
631 for (i = 0; i < ENVY24_TIMEOUT; i++) {
632 data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
633 if (data & ENVY24_MT_AC97CMD_RDY) {
634 return 0;
638 return -1;
641 #if 0
642 static int
643 envy24_rdcd(kobj_t obj, void *devinfo, int regno)
645 struct sc_info *sc = (struct sc_info *)devinfo;
646 u_int32_t data;
647 int i;
649 #if(0)
650 device_printf(sc->dev, "envy24_rdcd(obj, sc, 0x%02x)\n", regno);
651 #endif
652 envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
653 envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_RD, 1);
654 for (i = 0; i < ENVY24_TIMEOUT; i++) {
655 data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
656 if ((data & ENVY24_MT_AC97CMD_RD) == 0)
657 break;
659 data = envy24_rdmt(sc, ENVY24_MT_AC97DLO, 2);
661 #if(0)
662 device_printf(sc->dev, "envy24_rdcd(): return 0x%x\n", data);
663 #endif
664 return (int)data;
667 static int
668 envy24_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
670 struct sc_info *sc = (struct sc_info *)devinfo;
671 u_int32_t cmd;
672 int i;
674 #if(0)
675 device_printf(sc->dev, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
676 #endif
677 envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
678 envy24_wrmt(sc, ENVY24_MT_AC97DLO, (u_int32_t)data, 2);
679 envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_WR, 1);
680 for (i = 0; i < ENVY24_TIMEOUT; i++) {
681 cmd = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
682 if ((cmd & ENVY24_MT_AC97CMD_WR) == 0)
683 break;
686 return 0;
689 static kobj_method_t envy24_ac97_methods[] = {
690 KOBJMETHOD(ac97_read, envy24_rdcd),
691 KOBJMETHOD(ac97_write, envy24_wrcd),
692 {0, 0}
694 AC97_DECLARE(envy24_ac97);
695 #endif
697 /* -------------------------------------------------------------------- */
699 /* GPIO access routines */
701 static u_int32_t
702 envy24_gpiord(struct sc_info *sc)
704 return envy24_rdci(sc, ENVY24_CCI_GPIODAT);
707 static void
708 envy24_gpiowr(struct sc_info *sc, u_int32_t data)
710 #if(0)
711 device_printf(sc->dev, "envy24_gpiowr(sc, 0x%02x)\n", data & 0xff);
712 return;
713 #endif
714 envy24_wrci(sc, ENVY24_CCI_GPIODAT, data);
715 return;
718 #if 0
719 static u_int32_t
720 envy24_gpiogetmask(struct sc_info *sc)
722 return envy24_rdci(sc, ENVY24_CCI_GPIOMASK);
724 #endif
726 static void
727 envy24_gpiosetmask(struct sc_info *sc, u_int32_t mask)
729 envy24_wrci(sc, ENVY24_CCI_GPIOMASK, mask);
730 return;
733 #if 0
734 static u_int32_t
735 envy24_gpiogetdir(struct sc_info *sc)
737 return envy24_rdci(sc, ENVY24_CCI_GPIOCTL);
739 #endif
741 static void
742 envy24_gpiosetdir(struct sc_info *sc, u_int32_t dir)
744 envy24_wrci(sc, ENVY24_CCI_GPIOCTL, dir);
745 return;
748 /* -------------------------------------------------------------------- */
750 /* Envy24 I2C through GPIO bit-banging */
752 struct envy24_delta_ak4524_codec {
753 struct spicds_info *info;
754 struct sc_info *parent;
755 int dir;
756 int num;
757 int cs, cclk, cdti;
760 static void
761 envy24_gpio_i2c_ctl(void *codec, unsigned int scl, unsigned int sda)
763 u_int32_t data = 0;
764 struct envy24_delta_ak4524_codec *ptr = codec;
765 #if(0)
766 device_printf(ptr->parent->dev, "--> %d, %d\n", scl, sda);
767 #endif
768 data = envy24_gpiord(ptr->parent);
769 data &= ~(SDA_GPIO | SCL_GPIO);
770 if (scl) data += SCL_GPIO;
771 if (sda) data += SDA_GPIO;
772 envy24_gpiowr(ptr->parent, data);
773 return;
776 static void
777 i2c_wrbit(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), int bit)
779 struct envy24_delta_ak4524_codec *ptr = codec;
780 unsigned int sda;
782 if (bit)
783 sda = 1;
784 else
785 sda = 0;
787 ctrl(ptr, 0, sda);
788 DELAY(I2C_DELAY);
789 ctrl(ptr, 1, sda);
790 DELAY(I2C_DELAY);
791 ctrl(ptr, 0, sda);
792 DELAY(I2C_DELAY);
795 static void
796 i2c_start(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
798 struct envy24_delta_ak4524_codec *ptr = codec;
800 ctrl(ptr, 1, 1);
801 DELAY(I2C_DELAY);
802 ctrl(ptr, 1, 0);
803 DELAY(I2C_DELAY);
804 ctrl(ptr, 0, 0);
805 DELAY(I2C_DELAY);
808 static void
809 i2c_stop(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
811 struct envy24_delta_ak4524_codec *ptr = codec;
813 ctrl(ptr, 0, 0);
814 DELAY(I2C_DELAY);
815 ctrl(ptr, 1, 0);
816 DELAY(I2C_DELAY);
817 ctrl(ptr, 1, 1);
818 DELAY(I2C_DELAY);
821 static void
822 i2c_ack(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
824 struct envy24_delta_ak4524_codec *ptr = codec;
826 ctrl(ptr, 0, 1);
827 DELAY(I2C_DELAY);
828 ctrl(ptr, 1, 1);
829 DELAY(I2C_DELAY);
830 /* dummy, need routine to change gpio direction */
831 ctrl(ptr, 0, 1);
832 DELAY(I2C_DELAY);
835 static void
836 i2c_wr(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), u_int32_t dev, int reg, u_int8_t val)
838 struct envy24_delta_ak4524_codec *ptr = codec;
839 int mask;
841 i2c_start(ptr, ctrl);
843 for (mask = 0x80; mask != 0; mask >>= 1)
844 i2c_wrbit(ptr, ctrl, dev & mask);
845 i2c_ack(ptr, ctrl);
847 if (reg != 0xff) {
848 for (mask = 0x80; mask != 0; mask >>= 1)
849 i2c_wrbit(ptr, ctrl, reg & mask);
850 i2c_ack(ptr, ctrl);
853 for (mask = 0x80; mask != 0; mask >>= 1)
854 i2c_wrbit(ptr, ctrl, val & mask);
855 i2c_ack(ptr, ctrl);
857 i2c_stop(ptr, ctrl);
860 /* -------------------------------------------------------------------- */
862 /* M-Audio Delta series AK4524 access interface routine */
864 static void
865 envy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
867 u_int32_t data = 0;
868 struct envy24_delta_ak4524_codec *ptr = codec;
870 #if(0)
871 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
872 #endif
873 data = envy24_gpiord(ptr->parent);
874 data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
875 if (cs) data += ptr->cs;
876 if (cclk) data += ptr->cclk;
877 if (cdti) data += ptr->cdti;
878 envy24_gpiowr(ptr->parent, data);
879 return;
882 static void *
883 envy24_delta_ak4524_create(device_t dev, void *info, int dir, int num)
885 struct sc_info *sc = info;
886 struct envy24_delta_ak4524_codec *buff = NULL;
888 #if(0)
889 device_printf(sc->dev, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir, num);
890 #endif
892 buff = kmalloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
893 if (buff == NULL)
894 return NULL;
896 if (dir == PCMDIR_REC && sc->adc[num] != NULL)
897 buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info;
898 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
899 buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info;
900 else
901 buff->info = spicds_create(dev, buff, num, envy24_delta_ak4524_ctl);
902 if (buff->info == NULL) {
903 kfree(buff, M_ENVY24);
904 return NULL;
907 buff->parent = sc;
908 buff->dir = dir;
909 buff->num = num;
911 return (void *)buff;
914 static void
915 envy24_delta_ak4524_destroy(void *codec)
917 struct envy24_delta_ak4524_codec *ptr = codec;
918 if (ptr == NULL)
919 return;
920 #if(0)
921 device_printf(ptr->parent->dev, "envy24_delta_ak4524_destroy()\n");
922 #endif
924 if (ptr->dir == PCMDIR_PLAY) {
925 if (ptr->parent->dac[ptr->num] != NULL)
926 spicds_destroy(ptr->info);
928 else {
929 if (ptr->parent->adc[ptr->num] != NULL)
930 spicds_destroy(ptr->info);
933 kfree(codec, M_ENVY24);
936 static void
937 envy24_delta_ak4524_init(void *codec)
939 #if 0
940 u_int32_t gpiomask, gpiodir;
941 #endif
942 struct envy24_delta_ak4524_codec *ptr = codec;
943 if (ptr == NULL)
944 return;
945 #if(0)
946 device_printf(ptr->parent->dev, "envy24_delta_ak4524_init()\n");
947 #endif
950 gpiomask = envy24_gpiogetmask(ptr->parent);
951 gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1);
952 envy24_gpiosetmask(ptr->parent, gpiomask);
953 gpiodir = envy24_gpiogetdir(ptr->parent);
954 gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1;
955 envy24_gpiosetdir(ptr->parent, gpiodir);
957 ptr->cs = ptr->parent->cfg->cs;
958 #if 0
959 envy24_gpiosetmask(ptr->parent, ENVY24_GPIO_CS8414_STATUS);
960 envy24_gpiosetdir(ptr->parent, ~ENVY24_GPIO_CS8414_STATUS);
961 if (ptr->num == 0)
962 ptr->cs = ENVY24_GPIO_AK4524_CS0;
963 else
964 ptr->cs = ENVY24_GPIO_AK4524_CS1;
965 ptr->cclk = ENVY24_GPIO_AK4524_CCLK;
966 #endif
967 ptr->cclk = ptr->parent->cfg->cclk;
968 ptr->cdti = ptr->parent->cfg->cdti;
969 spicds_settype(ptr->info, ptr->parent->cfg->type);
970 spicds_setcif(ptr->info, ptr->parent->cfg->cif);
971 spicds_setformat(ptr->info,
972 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
973 spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
974 /* for the time being, init only first codec */
975 if (ptr->num == 0)
976 spicds_init(ptr->info);
978 /* 6fire rear input init test, set ptr->num to 1 for test */
979 if (ptr->parent->cfg->subvendor == 0x153b && \
980 ptr->parent->cfg->subdevice == 0x1138 && ptr->num == 100) {
981 ptr->cs = 0x02;
982 spicds_init(ptr->info);
983 device_printf(ptr->parent->dev, "6fire rear input init\n");
984 i2c_wr(ptr, envy24_gpio_i2c_ctl, \
985 PCA9554_I2CDEV, PCA9554_DIR, 0x80);
986 i2c_wr(ptr, envy24_gpio_i2c_ctl, \
987 PCA9554_I2CDEV, PCA9554_OUT, 0x02);
991 static void
992 envy24_delta_ak4524_reinit(void *codec)
994 struct envy24_delta_ak4524_codec *ptr = codec;
995 if (ptr == NULL)
996 return;
997 #if(0)
998 device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n");
999 #endif
1001 spicds_reinit(ptr->info);
1004 static void
1005 envy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
1007 struct envy24_delta_ak4524_codec *ptr = codec;
1008 if (ptr == NULL)
1009 return;
1010 #if(0)
1011 device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n");
1012 #endif
1014 spicds_set(ptr->info, dir, left, right);
1018 There is no need for AK452[48] codec to set sample rate
1019 static void
1020 envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate)
1025 /* -------------------------------------------------------------------- */
1027 /* hardware access routeines */
1029 static struct {
1030 u_int32_t speed;
1031 u_int32_t code;
1032 } envy24_speedtab[] = {
1033 {48000, ENVY24_MT_RATE_48000},
1034 {24000, ENVY24_MT_RATE_24000},
1035 {12000, ENVY24_MT_RATE_12000},
1036 {9600, ENVY24_MT_RATE_9600},
1037 {32000, ENVY24_MT_RATE_32000},
1038 {16000, ENVY24_MT_RATE_16000},
1039 {8000, ENVY24_MT_RATE_8000},
1040 {96000, ENVY24_MT_RATE_96000},
1041 {64000, ENVY24_MT_RATE_64000},
1042 {44100, ENVY24_MT_RATE_44100},
1043 {22050, ENVY24_MT_RATE_22050},
1044 {11025, ENVY24_MT_RATE_11025},
1045 {88200, ENVY24_MT_RATE_88200},
1046 {0, 0x10}
1049 static int
1050 envy24_setspeed(struct sc_info *sc, u_int32_t speed) {
1051 u_int32_t code;
1052 int i = 0;
1054 #if(0)
1055 device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed);
1056 #endif
1057 if (speed == 0) {
1058 code = ENVY24_MT_RATE_SPDIF; /* external master clock */
1059 envy24_slavecd(sc);
1061 else {
1062 for (i = 0; envy24_speedtab[i].speed != 0; i++) {
1063 if (envy24_speedtab[i].speed == speed)
1064 break;
1066 code = envy24_speedtab[i].code;
1068 #if(0)
1069 device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code);
1070 #endif
1071 if (code < 0x10) {
1072 envy24_wrmt(sc, ENVY24_MT_RATE, code, 1);
1073 code = envy24_rdmt(sc, ENVY24_MT_RATE, 1);
1074 code &= ENVY24_MT_RATE_MASK;
1075 for (i = 0; envy24_speedtab[i].code < 0x10; i++) {
1076 if (envy24_speedtab[i].code == code)
1077 break;
1079 speed = envy24_speedtab[i].speed;
1081 else
1082 speed = 0;
1084 #if(0)
1085 device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed);
1086 #endif
1087 return speed;
1090 static void
1091 envy24_setvolume(struct sc_info *sc, unsigned ch)
1093 #if(0)
1094 device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch);
1095 #endif
1096 if (sc->cfg->subvendor==0x153b && sc->cfg->subdevice==0x1138 ) {
1097 envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1);
1098 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1099 envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1);
1100 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1103 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1104 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1105 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1106 envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1109 static void
1110 envy24_mutevolume(struct sc_info *sc, unsigned ch)
1112 u_int32_t vol;
1114 #if(0)
1115 device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch);
1116 #endif
1117 vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE;
1118 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1119 envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1120 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1121 envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1124 static u_int32_t
1125 envy24_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, "envy24_gethwptr(sc, %d)\n", dir);
1132 #endif
1133 if (dir == PCMDIR_PLAY) {
1134 rtn = sc->psize / 4;
1135 unit = ENVY24_PLAY_BUFUNIT / 4;
1136 regno = ENVY24_MT_PCNT;
1138 else {
1139 rtn = sc->rsize / 4;
1140 unit = ENVY24_REC_BUFUNIT / 4;
1141 regno = ENVY24_MT_RCNT;
1144 ptr = envy24_rdmt(sc, regno, 2);
1145 rtn -= (ptr + 1);
1146 rtn /= unit;
1148 #if(0)
1149 device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn);
1150 #endif
1151 return rtn;
1154 static void
1155 envy24_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, "envy24_updintr(sc, %d)\n", dir);
1164 #endif
1165 if (dir == PCMDIR_PLAY) {
1166 blk = sc->blk[0];
1167 size = sc->psize / 4;
1168 regptr = ENVY24_MT_PCNT;
1169 regintr = ENVY24_MT_PTERM;
1170 mask = ~ENVY24_MT_INT_PMASK;
1172 else {
1173 blk = sc->blk[1];
1174 size = sc->rsize / 4;
1175 regptr = ENVY24_MT_RCNT;
1176 regintr = ENVY24_MT_RTERM;
1177 mask = ~ENVY24_MT_INT_RMASK;
1180 ptr = size - envy24_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, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1189 #endif
1190 envy24_wrmt(sc, regintr, cnt, 2);
1191 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1192 #if(0)
1193 device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1194 #endif
1195 envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1);
1196 #if(0)
1197 device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n",
1198 envy24_rdmt(sc, ENVY24_MT_INT, 1));
1199 #endif
1201 return;
1204 #if 0
1205 static void
1206 envy24_maskintr(struct sc_info *sc, int dir)
1208 u_int32_t mask, intr;
1210 #if(0)
1211 device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir);
1212 #endif
1213 if (dir == PCMDIR_PLAY)
1214 mask = ENVY24_MT_INT_PMASK;
1215 else
1216 mask = ENVY24_MT_INT_RMASK;
1217 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1218 envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1);
1220 return;
1222 #endif
1224 static int
1225 envy24_checkintr(struct sc_info *sc, int dir)
1227 u_int32_t mask, stat, intr, rtn;
1229 #if(0)
1230 device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir);
1231 #endif
1232 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1233 if (dir == PCMDIR_PLAY) {
1234 if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) {
1235 mask = ~ENVY24_MT_INT_RSTAT;
1236 stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK;
1237 envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1240 else {
1241 if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) {
1242 mask = ~ENVY24_MT_INT_PSTAT;
1243 stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK;
1244 envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1248 return rtn;
1251 static void
1252 envy24_start(struct sc_info *sc, int dir)
1254 u_int32_t stat, sw;
1256 #if(0)
1257 device_printf(sc->dev, "envy24_start(sc, %d)\n", dir);
1258 #endif
1259 if (dir == PCMDIR_PLAY)
1260 sw = ENVY24_MT_PCTL_PSTART;
1261 else
1262 sw = ENVY24_MT_PCTL_RSTART;
1264 stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1265 envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1);
1266 #if(0)
1267 DELAY(100);
1268 device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
1269 device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
1270 #endif
1272 return;
1275 static void
1276 envy24_stop(struct sc_info *sc, int dir)
1278 u_int32_t stat, sw;
1280 #if(0)
1281 device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir);
1282 #endif
1283 if (dir == PCMDIR_PLAY)
1284 sw = ~ENVY24_MT_PCTL_PSTART;
1285 else
1286 sw = ~ENVY24_MT_PCTL_RSTART;
1288 stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1289 envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1);
1291 return;
1294 static int
1295 envy24_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1297 u_int32_t reg, mask;
1298 u_int32_t left, right;
1300 #if(0)
1301 device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n",
1302 dac, class, adc, rev);
1303 #endif
1304 /* parameter pattern check */
1305 if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac)
1306 return -1;
1307 if (class == ENVY24_ROUTE_CLASS_MIX &&
1308 (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF))
1309 return -1;
1310 if (rev) {
1311 left = ENVY24_ROUTE_RIGHT;
1312 right = ENVY24_ROUTE_LEFT;
1314 else {
1315 left = ENVY24_ROUTE_LEFT;
1316 right = ENVY24_ROUTE_RIGHT;
1319 if (dac == ENVY24_ROUTE_DAC_SPDIF) {
1320 reg = class | class << 2 |
1321 ((adc << 1 | left) | left << 3) << 8 |
1322 ((adc << 1 | right) | right << 3) << 12;
1323 #if(0)
1324 device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg);
1325 #endif
1326 envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2);
1328 else {
1329 mask = ~(0x0303 << dac * 2);
1330 reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2);
1331 reg = (reg & mask) | ((class | class << 8) << dac * 2);
1332 #if(0)
1333 device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg);
1334 #endif
1335 envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2);
1336 mask = ~(0xff << dac * 8);
1337 reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4);
1338 reg = (reg & mask) |
1339 (((adc << 1 | left) | left << 3) |
1340 ((adc << 1 | right) | right << 3) << 4) << dac * 8;
1341 #if(0)
1342 device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg);
1343 #endif
1344 envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4);
1346 /* 6fire rear input init test */
1347 envy24_wrmt(sc, ENVY24_MT_RECORD, 0x00, 4);
1350 return 0;
1353 /* -------------------------------------------------------------------- */
1355 /* buffer copy routines */
1356 static void
1357 envy24_p32sl(struct sc_chinfo *ch)
1359 int length;
1360 sample32_t *dmabuf;
1361 u_int32_t *data;
1362 int src, dst, ssize, dsize, slot;
1363 int i;
1365 length = sndbuf_getready(ch->buffer) / 8;
1366 dmabuf = ch->parent->pbuf;
1367 data = (u_int32_t *)ch->data;
1368 src = sndbuf_getreadyptr(ch->buffer) / 4;
1369 dst = src / 2 + ch->offset;
1370 ssize = ch->size / 4;
1371 dsize = ch->size / 8;
1372 slot = ch->num * 2;
1374 for (i = 0; i < length; i++) {
1375 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src];
1376 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1377 dst++;
1378 dst %= dsize;
1379 src += 2;
1380 src %= ssize;
1383 return;
1386 static void
1387 envy24_p16sl(struct sc_chinfo *ch)
1389 int length;
1390 sample32_t *dmabuf;
1391 u_int16_t *data;
1392 int src, dst, ssize, dsize, slot;
1393 int i;
1395 #if(0)
1396 device_printf(ch->parent->dev, "envy24_p16sl()\n");
1397 #endif
1398 length = sndbuf_getready(ch->buffer) / 4;
1399 dmabuf = ch->parent->pbuf;
1400 data = (u_int16_t *)ch->data;
1401 src = sndbuf_getreadyptr(ch->buffer) / 2;
1402 dst = src / 2 + ch->offset;
1403 ssize = ch->size / 2;
1404 dsize = ch->size / 4;
1405 slot = ch->num * 2;
1406 #if(0)
1407 device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1408 #endif
1410 for (i = 0; i < length; i++) {
1411 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1412 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1413 #if(0)
1414 if (i < 16) {
1415 printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]);
1416 printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]);
1418 #endif
1419 dst++;
1420 dst %= dsize;
1421 src += 2;
1422 src %= ssize;
1424 #if(0)
1425 printf("\n");
1426 #endif
1428 return;
1431 static void
1432 envy24_p8u(struct sc_chinfo *ch)
1434 int length;
1435 sample32_t *dmabuf;
1436 u_int8_t *data;
1437 int src, dst, ssize, dsize, slot;
1438 int i;
1440 length = sndbuf_getready(ch->buffer) / 2;
1441 dmabuf = ch->parent->pbuf;
1442 data = (u_int8_t *)ch->data;
1443 src = sndbuf_getreadyptr(ch->buffer);
1444 dst = src / 2 + ch->offset;
1445 ssize = ch->size;
1446 dsize = ch->size / 4;
1447 slot = ch->num * 2;
1449 for (i = 0; i < length; i++) {
1450 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1451 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1452 dst++;
1453 dst %= dsize;
1454 src += 2;
1455 src %= ssize;
1458 return;
1461 static void
1462 envy24_r32sl(struct sc_chinfo *ch)
1464 int length;
1465 sample32_t *dmabuf;
1466 u_int32_t *data;
1467 int src, dst, ssize, dsize, slot;
1468 int i;
1470 length = sndbuf_getfree(ch->buffer) / 8;
1471 dmabuf = ch->parent->rbuf;
1472 data = (u_int32_t *)ch->data;
1473 dst = sndbuf_getfreeptr(ch->buffer) / 4;
1474 src = dst / 2 + ch->offset;
1475 dsize = ch->size / 4;
1476 ssize = ch->size / 8;
1477 slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1479 for (i = 0; i < length; i++) {
1480 data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1481 data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1482 dst += 2;
1483 dst %= dsize;
1484 src++;
1485 src %= ssize;
1488 return;
1491 static void
1492 envy24_r16sl(struct sc_chinfo *ch)
1494 int length;
1495 sample32_t *dmabuf;
1496 u_int16_t *data;
1497 int src, dst, ssize, dsize, slot;
1498 int i;
1500 length = sndbuf_getfree(ch->buffer) / 4;
1501 dmabuf = ch->parent->rbuf;
1502 data = (u_int16_t *)ch->data;
1503 dst = sndbuf_getfreeptr(ch->buffer) / 2;
1504 src = dst / 2 + ch->offset;
1505 dsize = ch->size / 2;
1506 ssize = ch->size / 8;
1507 slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1509 for (i = 0; i < length; i++) {
1510 data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1511 data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1512 dst += 2;
1513 dst %= dsize;
1514 src++;
1515 src %= ssize;
1518 return;
1521 /* -------------------------------------------------------------------- */
1523 /* channel interface */
1524 static void *
1525 envy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1527 struct sc_info *sc = (struct sc_info *)devinfo;
1528 struct sc_chinfo *ch;
1529 unsigned num;
1531 #if(0)
1532 device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir);
1533 #endif
1534 snd_mtxlock(sc->lock);
1535 if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1536 (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1537 snd_mtxunlock(sc->lock);
1538 return NULL;
1540 num = sc->chnum;
1542 ch = &sc->chan[num];
1543 ch->size = 8 * ENVY24_SAMPLE_NUM;
1544 ch->data = kmalloc(ch->size, M_ENVY24, M_NOWAIT);
1545 if (ch->data == NULL) {
1546 ch->size = 0;
1547 ch = NULL;
1549 else {
1550 ch->buffer = b;
1551 ch->channel = c;
1552 ch->parent = sc;
1553 ch->dir = dir;
1554 /* set channel map */
1555 ch->num = envy24_chanmap[num];
1556 snd_mtxunlock(sc->lock);
1557 sndbuf_setup(ch->buffer, ch->data, ch->size);
1558 snd_mtxlock(sc->lock);
1559 /* these 2 values are dummy */
1560 ch->unit = 4;
1561 ch->blk = 10240;
1563 snd_mtxunlock(sc->lock);
1565 return ch;
1568 static int
1569 envy24chan_free(kobj_t obj, void *data)
1571 struct sc_chinfo *ch = data;
1572 struct sc_info *sc = ch->parent;
1574 #if(0)
1575 device_printf(sc->dev, "envy24chan_free()\n");
1576 #endif
1577 snd_mtxlock(sc->lock);
1578 if (ch->data != NULL) {
1579 kfree(ch->data, M_ENVY24);
1580 ch->data = NULL;
1582 snd_mtxunlock(sc->lock);
1584 return 0;
1587 static int
1588 envy24chan_setformat(kobj_t obj, void *data, u_int32_t format)
1590 struct sc_chinfo *ch = data;
1591 struct sc_info *sc = ch->parent;
1592 struct envy24_emldma *emltab;
1593 /* unsigned int bcnt, bsize; */
1594 int i;
1596 #if(0)
1597 device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format);
1598 #endif
1599 snd_mtxlock(sc->lock);
1600 /* check and get format related information */
1601 if (ch->dir == PCMDIR_PLAY)
1602 emltab = envy24_pemltab;
1603 else
1604 emltab = envy24_remltab;
1605 if (emltab == NULL) {
1606 snd_mtxunlock(sc->lock);
1607 return -1;
1609 for (i = 0; emltab[i].format != 0; i++)
1610 if (emltab[i].format == format)
1611 break;
1612 if (emltab[i].format == 0) {
1613 snd_mtxunlock(sc->lock);
1614 return -1;
1617 /* set format information */
1618 ch->format = format;
1619 ch->emldma = emltab[i].emldma;
1620 if (ch->unit > emltab[i].unit)
1621 ch->blk *= ch->unit / emltab[i].unit;
1622 else
1623 ch->blk /= emltab[i].unit / ch->unit;
1624 ch->unit = emltab[i].unit;
1626 /* set channel buffer information */
1627 ch->size = ch->unit * ENVY24_SAMPLE_NUM;
1628 #if 0
1629 if (ch->dir == PCMDIR_PLAY)
1630 bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1631 else
1632 bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1633 bsize *= ch->unit;
1634 bcnt = ch->size / bsize;
1635 sndbuf_resize(ch->buffer, bcnt, bsize);
1636 #endif
1637 snd_mtxunlock(sc->lock);
1639 #if(0)
1640 device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0);
1641 #endif
1642 return 0;
1646 IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1647 of speed information value. And real hardware speed setting is done
1648 at start triggered(see envy24chan_trigger()). So, at this function
1649 is called, any value that ENVY24 can use is able to set. But, at
1650 start triggerd, some other channel is running, and that channel's
1651 speed isn't same with, then trigger function will fail.
1653 static int
1654 envy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1656 struct sc_chinfo *ch = data;
1657 u_int32_t val, prev;
1658 int i;
1660 #if(0)
1661 device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed);
1662 #endif
1663 prev = 0x7fffffff;
1664 for (i = 0; (val = envy24_speed[i]) != 0; i++) {
1665 if (abs(val - speed) < abs(prev - speed))
1666 prev = val;
1667 else
1668 break;
1670 ch->speed = prev;
1672 #if(0)
1673 device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed);
1674 #endif
1675 return ch->speed;
1678 static int
1679 envy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1681 struct sc_chinfo *ch = data;
1682 /* struct sc_info *sc = ch->parent; */
1683 u_int32_t size, prev;
1684 unsigned int bcnt, bsize;
1686 #if(0)
1687 device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize);
1688 #endif
1689 prev = 0x7fffffff;
1690 /* snd_mtxlock(sc->lock); */
1691 for (size = ch->size / 2; size > 0; size /= 2) {
1692 if (abs(size - blocksize) < abs(prev - blocksize))
1693 prev = size;
1694 else
1695 break;
1698 ch->blk = prev / ch->unit;
1699 if (ch->dir == PCMDIR_PLAY)
1700 ch->blk *= ENVY24_PLAY_BUFUNIT / 4;
1701 else
1702 ch->blk *= ENVY24_REC_BUFUNIT / 4;
1703 /* set channel buffer information */
1704 /* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */
1705 if (ch->dir == PCMDIR_PLAY)
1706 bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1707 else
1708 bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1709 bsize *= ch->unit;
1710 bcnt = ch->size / bsize;
1711 sndbuf_resize(ch->buffer, bcnt, bsize);
1712 /* snd_mtxunlock(sc->lock); */
1714 #if(0)
1715 device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev);
1716 #endif
1717 return prev;
1720 /* semantic note: must start at beginning of buffer */
1721 static int
1722 envy24chan_trigger(kobj_t obj, void *data, int go)
1724 struct sc_chinfo *ch = data;
1725 struct sc_info *sc = ch->parent;
1726 u_int32_t ptr;
1727 int slot;
1728 #if 0
1729 int i;
1731 device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go);
1732 #endif
1733 snd_mtxlock(sc->lock);
1734 if (ch->dir == PCMDIR_PLAY)
1735 slot = 0;
1736 else
1737 slot = 1;
1738 switch (go) {
1739 case PCMTRIG_START:
1740 #if(0)
1741 device_printf(sc->dev, "envy24chan_trigger(): start\n");
1742 #endif
1743 /* check or set channel speed */
1744 if (sc->run[0] == 0 && sc->run[1] == 0) {
1745 sc->speed = envy24_setspeed(sc, ch->speed);
1746 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1747 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1749 else if (ch->speed != 0 && ch->speed != sc->speed)
1750 return -1;
1751 if (ch->speed == 0)
1752 ch->channel->speed = sc->speed;
1753 /* start or enable channel */
1754 sc->run[slot]++;
1755 if (sc->run[slot] == 1) {
1756 /* first channel */
1757 ch->offset = 0;
1758 sc->blk[slot] = ch->blk;
1760 else {
1761 ptr = envy24_gethwptr(sc, ch->dir);
1762 ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1763 (ch->size / 4)) * 4 / ch->unit;
1764 if (ch->blk < sc->blk[slot])
1765 sc->blk[slot] = ch->blk;
1767 if (ch->dir == PCMDIR_PLAY) {
1768 ch->emldma(ch);
1769 envy24_setvolume(sc, ch->num);
1771 envy24_updintr(sc, ch->dir);
1772 if (sc->run[slot] == 1)
1773 envy24_start(sc, ch->dir);
1774 ch->run = 1;
1775 break;
1776 case PCMTRIG_EMLDMAWR:
1777 #if(0)
1778 device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n");
1779 #endif
1780 if (ch->run != 1)
1781 return -1;
1782 ch->emldma(ch);
1783 break;
1784 case PCMTRIG_EMLDMARD:
1785 #if(0)
1786 device_printf(sc->dev, "envy24chan_trigger(): emldmard\n");
1787 #endif
1788 if (ch->run != 1)
1789 return -1;
1790 ch->emldma(ch);
1791 break;
1792 case PCMTRIG_ABORT:
1793 if (ch->run) {
1794 #if(0)
1795 device_printf(sc->dev, "envy24chan_trigger(): abort\n");
1796 #endif
1797 ch->run = 0;
1798 sc->run[slot]--;
1799 if (ch->dir == PCMDIR_PLAY)
1800 envy24_mutevolume(sc, ch->num);
1801 if (sc->run[slot] == 0) {
1802 envy24_stop(sc, ch->dir);
1803 sc->intr[slot] = 0;
1805 #if 0
1806 else if (ch->blk == sc->blk[slot]) {
1807 sc->blk[slot] = ENVY24_SAMPLE_NUM / 2;
1808 for (i = 0; i < ENVY24_CHAN_NUM; i++) {
1809 if (sc->chan[i].dir == ch->dir &&
1810 sc->chan[i].run == 1 &&
1811 sc->chan[i].blk < sc->blk[slot])
1812 sc->blk[slot] = sc->chan[i].blk;
1814 if (ch->blk != sc->blk[slot])
1815 envy24_updintr(sc, ch->dir);
1817 #endif
1819 break;
1821 snd_mtxunlock(sc->lock);
1823 return 0;
1826 static int
1827 envy24chan_getptr(kobj_t obj, void *data)
1829 struct sc_chinfo *ch = data;
1830 struct sc_info *sc = ch->parent;
1831 u_int32_t ptr;
1832 int rtn;
1834 #if(0)
1835 device_printf(sc->dev, "envy24chan_getptr()\n");
1836 #endif
1837 snd_mtxlock(sc->lock);
1838 ptr = envy24_gethwptr(sc, ch->dir);
1839 rtn = ptr * ch->unit;
1840 snd_mtxunlock(sc->lock);
1842 #if(0)
1843 device_printf(sc->dev, "envy24chan_getptr(): return %d\n",
1844 rtn);
1845 #endif
1846 return rtn;
1849 static struct pcmchan_caps *
1850 envy24chan_getcaps(kobj_t obj, void *data)
1852 struct sc_chinfo *ch = data;
1853 struct sc_info *sc = ch->parent;
1854 struct pcmchan_caps *rtn;
1856 #if(0)
1857 device_printf(sc->dev, "envy24chan_getcaps()\n");
1858 #endif
1859 snd_mtxlock(sc->lock);
1860 if (ch->dir == PCMDIR_PLAY) {
1861 if (sc->run[0] == 0)
1862 rtn = &envy24_playcaps;
1863 else
1864 rtn = &sc->caps[0];
1866 else {
1867 if (sc->run[1] == 0)
1868 rtn = &envy24_reccaps;
1869 else
1870 rtn = &sc->caps[1];
1872 snd_mtxunlock(sc->lock);
1874 return rtn;
1877 static kobj_method_t envy24chan_methods[] = {
1878 KOBJMETHOD(channel_init, envy24chan_init),
1879 KOBJMETHOD(channel_free, envy24chan_free),
1880 KOBJMETHOD(channel_setformat, envy24chan_setformat),
1881 KOBJMETHOD(channel_setspeed, envy24chan_setspeed),
1882 KOBJMETHOD(channel_setblocksize, envy24chan_setblocksize),
1883 KOBJMETHOD(channel_trigger, envy24chan_trigger),
1884 KOBJMETHOD(channel_getptr, envy24chan_getptr),
1885 KOBJMETHOD(channel_getcaps, envy24chan_getcaps),
1886 { 0, 0 }
1888 CHANNEL_DECLARE(envy24chan);
1890 /* -------------------------------------------------------------------- */
1892 /* mixer interface */
1894 static int
1895 envy24mixer_init(struct snd_mixer *m)
1897 struct sc_info *sc = mix_getdevinfo(m);
1899 #if(0)
1900 device_printf(sc->dev, "envy24mixer_init()\n");
1901 #endif
1902 if (sc == NULL)
1903 return -1;
1905 /* set volume control rate */
1906 snd_mtxlock(sc->lock);
1907 envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1909 mix_setdevs(m, ENVY24_MIX_MASK);
1910 mix_setrecdevs(m, ENVY24_MIX_REC_MASK);
1911 snd_mtxunlock(sc->lock);
1913 return 0;
1916 static int
1917 envy24mixer_reinit(struct snd_mixer *m)
1919 struct sc_info *sc = mix_getdevinfo(m);
1921 if (sc == NULL)
1922 return -1;
1923 #if(0)
1924 device_printf(sc->dev, "envy24mixer_reinit()\n");
1925 #endif
1927 return 0;
1930 static int
1931 envy24mixer_uninit(struct snd_mixer *m)
1933 struct sc_info *sc = mix_getdevinfo(m);
1935 if (sc == NULL)
1936 return -1;
1937 #if(0)
1938 device_printf(sc->dev, "envy24mixer_uninit()\n");
1939 #endif
1941 return 0;
1944 static int
1945 envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1947 struct sc_info *sc = mix_getdevinfo(m);
1948 int ch = envy24_mixmap[dev];
1949 int hwch;
1950 int i;
1952 if (sc == NULL)
1953 return -1;
1954 if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1955 return -1;
1956 if (dev != 0 && ch == -1)
1957 return -1;
1958 hwch = envy24_chanmap[ch];
1959 #if(0)
1960 device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n",
1961 dev, left, right);
1962 #endif
1964 snd_mtxlock(sc->lock);
1965 if (dev == 0) {
1966 for (i = 0; i < sc->dacn; i++) {
1967 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1970 else {
1971 /* set volume value for hardware */
1972 if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN)
1973 sc->left[hwch] = ENVY24_VOL_MUTE;
1974 if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN)
1975 sc->right[hwch] = ENVY24_VOL_MUTE;
1977 /* set volume for record channel and running play channel */
1978 if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1979 envy24_setvolume(sc, hwch);
1981 snd_mtxunlock(sc->lock);
1983 return right << 8 | left;
1986 static u_int32_t
1987 envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1989 struct sc_info *sc = mix_getdevinfo(m);
1990 int ch = envy24_mixmap[src];
1991 #if(0)
1992 device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src);
1993 #endif
1995 if (ch > ENVY24_CHAN_PLAY_SPDIF)
1996 sc->src = ch;
1997 return src;
2000 static kobj_method_t envy24mixer_methods[] = {
2001 KOBJMETHOD(mixer_init, envy24mixer_init),
2002 KOBJMETHOD(mixer_reinit, envy24mixer_reinit),
2003 KOBJMETHOD(mixer_uninit, envy24mixer_uninit),
2004 KOBJMETHOD(mixer_set, envy24mixer_set),
2005 KOBJMETHOD(mixer_setrecsrc, envy24mixer_setrecsrc),
2006 { 0, 0 }
2008 MIXER_DECLARE(envy24mixer);
2010 /* -------------------------------------------------------------------- */
2012 /* The interrupt handler */
2013 static void
2014 envy24_intr(void *p)
2016 struct sc_info *sc = (struct sc_info *)p;
2017 struct sc_chinfo *ch;
2018 u_int32_t ptr, dsize, feed;
2019 int i;
2021 #if(0)
2022 device_printf(sc->dev, "envy24_intr()\n");
2023 #endif
2024 snd_mtxlock(sc->lock);
2025 if (envy24_checkintr(sc, PCMDIR_PLAY)) {
2026 #if(0)
2027 device_printf(sc->dev, "envy24_intr(): play\n");
2028 #endif
2029 dsize = sc->psize / 4;
2030 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1;
2031 #if(0)
2032 device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr);
2033 #endif
2034 ptr -= ptr % sc->blk[0];
2035 feed = (ptr + dsize - sc->intr[0]) % dsize;
2036 #if(0)
2037 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2038 #endif
2039 for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) {
2040 ch = &sc->chan[i];
2041 #if(0)
2042 if (ch->run)
2043 device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk);
2044 #endif
2045 if (ch->run && ch->blk <= feed) {
2046 snd_mtxunlock(sc->lock);
2047 chn_intr(ch->channel);
2048 snd_mtxlock(sc->lock);
2051 sc->intr[0] = ptr;
2052 envy24_updintr(sc, PCMDIR_PLAY);
2054 if (envy24_checkintr(sc, PCMDIR_REC)) {
2055 #if(0)
2056 device_printf(sc->dev, "envy24_intr(): rec\n");
2057 #endif
2058 dsize = sc->rsize / 4;
2059 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1;
2060 ptr -= ptr % sc->blk[1];
2061 feed = (ptr + dsize - sc->intr[1]) % dsize;
2062 for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) {
2063 ch = &sc->chan[i];
2064 if (ch->run && ch->blk <= feed) {
2065 snd_mtxunlock(sc->lock);
2066 chn_intr(ch->channel);
2067 snd_mtxlock(sc->lock);
2070 sc->intr[1] = ptr;
2071 envy24_updintr(sc, PCMDIR_REC);
2073 snd_mtxunlock(sc->lock);
2075 return;
2079 * Probe and attach the card
2082 static int
2083 envy24_pci_probe(device_t dev)
2085 u_int16_t sv, sd;
2086 int i;
2088 #if(0)
2089 printf("envy24_pci_probe()\n");
2090 #endif
2091 if (pci_get_device(dev) == PCID_ENVY24 &&
2092 pci_get_vendor(dev) == PCIV_ENVY24) {
2093 sv = pci_get_subvendor(dev);
2094 sd = pci_get_subdevice(dev);
2095 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2096 if (cfg_table[i].subvendor == sv &&
2097 cfg_table[i].subdevice == sd) {
2098 break;
2101 device_set_desc(dev, cfg_table[i].name);
2102 #if(0)
2103 printf("envy24_pci_probe(): return 0\n");
2104 #endif
2105 return 0;
2107 else {
2108 #if(0)
2109 printf("envy24_pci_probe(): return ENXIO\n");
2110 #endif
2111 return ENXIO;
2115 static void
2116 envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2118 /* struct sc_info *sc = (struct sc_info *)arg; */
2120 #if(0)
2121 device_printf(sc->dev, "envy24_dmapsetmap()\n");
2122 if (bootverbose) {
2123 printf("envy24(play): setmap %lx, %lx; ",
2124 (unsigned long)segs->ds_addr,
2125 (unsigned long)segs->ds_len);
2126 printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2128 #endif
2131 static void
2132 envy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2134 /* struct sc_info *sc = (struct sc_info *)arg; */
2136 #if(0)
2137 device_printf(sc->dev, "envy24_dmarsetmap()\n");
2138 if (bootverbose) {
2139 printf("envy24(record): setmap %lx, %lx; ",
2140 (unsigned long)segs->ds_addr,
2141 (unsigned long)segs->ds_len);
2142 printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2144 #endif
2147 static void
2148 envy24_dmafree(struct sc_info *sc)
2150 #if(0)
2151 device_printf(sc->dev, "envy24_dmafree():");
2152 if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2153 else printf(" sc->rmap(null)");
2154 if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2155 else printf(" sc->pmap(null)");
2156 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2157 else printf(" sc->rbuf(null)");
2158 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2159 else printf(" sc->pbuf(null)\n");
2160 #endif
2161 #if(0)
2162 if (sc->rmap)
2163 bus_dmamap_unload(sc->dmat, sc->rmap);
2164 if (sc->pmap)
2165 bus_dmamap_unload(sc->dmat, sc->pmap);
2166 if (sc->rbuf)
2167 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2168 if (sc->pbuf)
2169 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2170 #else
2171 bus_dmamap_unload(sc->dmat, sc->rmap);
2172 bus_dmamap_unload(sc->dmat, sc->pmap);
2173 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2174 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2175 #endif
2177 sc->rmap = sc->pmap = NULL;
2178 sc->pbuf = NULL;
2179 sc->rbuf = NULL;
2181 return;
2184 static int
2185 envy24_dmainit(struct sc_info *sc)
2187 u_int32_t addr;
2189 #if(0)
2190 device_printf(sc->dev, "envy24_dmainit()\n");
2191 #endif
2192 /* init values */
2193 sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM;
2194 sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM;
2195 sc->pbuf = NULL;
2196 sc->rbuf = NULL;
2197 sc->pmap = sc->rmap = NULL;
2198 sc->blk[0] = sc->blk[1] = 0;
2200 /* allocate DMA buffer */
2201 #if(0)
2202 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2203 #endif
2204 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2205 goto bad;
2206 #if(0)
2207 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2208 #endif
2209 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2210 goto bad;
2211 #if(0)
2212 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2213 #endif
2214 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0))
2215 goto bad;
2216 #if(0)
2217 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2218 #endif
2219 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0))
2220 goto bad;
2221 bzero(sc->pbuf, sc->psize);
2222 bzero(sc->rbuf, sc->rsize);
2224 /* set values to register */
2225 addr = vtophys(sc->pbuf);
2226 #if(0)
2227 device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2228 #endif
2229 envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4);
2230 #if(0)
2231 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
2232 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2233 #endif
2234 envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2);
2235 #if(0)
2236 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
2237 #endif
2238 addr = vtophys(sc->rbuf);
2239 envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4);
2240 envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2);
2242 return 0;
2243 bad:
2244 envy24_dmafree(sc);
2245 return ENOSPC;
2248 static void
2249 envy24_putcfg(struct sc_info *sc)
2251 device_printf(sc->dev, "system configuration\n");
2252 kprintf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2253 sc->cfg->subvendor, sc->cfg->subdevice);
2254 kprintf(" XIN2 Clock Source: ");
2255 switch (sc->cfg->scfg & PCIM_SCFG_XIN2) {
2256 case 0x00:
2257 kprintf("22.5792MHz(44.1kHz*512)\n");
2258 break;
2259 case 0x40:
2260 kprintf("16.9344MHz(44.1kHz*384)\n");
2261 break;
2262 case 0x80:
2263 kprintf("from external clock synthesizer chip\n");
2264 break;
2265 default:
2266 kprintf("illeagal system setting\n");
2268 kprintf(" MPU-401 UART(s) #: ");
2269 if (sc->cfg->scfg & PCIM_SCFG_MPU)
2270 kprintf("2\n");
2271 else
2272 kprintf("1\n");
2273 kprintf(" AC'97 codec: ");
2274 if (sc->cfg->scfg & PCIM_SCFG_AC97)
2275 kprintf("not exist\n");
2276 else
2277 kprintf("exist\n");
2278 kprintf(" ADC #: ");
2279 kprintf("%d\n", sc->adcn);
2280 kprintf(" DAC #: ");
2281 kprintf("%d\n", sc->dacn);
2282 kprintf(" Multi-track converter type: ");
2283 if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) {
2284 kprintf("AC'97(SDATA_OUT:");
2285 if (sc->cfg->acl & PCIM_ACL_OMODE)
2286 kprintf("packed");
2287 else
2288 kprintf("split");
2289 kprintf("|SDATA_IN:");
2290 if (sc->cfg->acl & PCIM_ACL_IMODE)
2291 kprintf("packed");
2292 else
2293 kprintf("split");
2294 kprintf(")\n");
2296 else {
2297 kprintf("I2S(");
2298 if (sc->cfg->i2s & PCIM_I2S_VOL)
2299 kprintf("with volume, ");
2300 if (sc->cfg->i2s & PCIM_I2S_96KHZ)
2301 kprintf("96KHz support, ");
2302 switch (sc->cfg->i2s & PCIM_I2S_RES) {
2303 case PCIM_I2S_16BIT:
2304 kprintf("16bit resolution, ");
2305 break;
2306 case PCIM_I2S_18BIT:
2307 kprintf("18bit resolution, ");
2308 break;
2309 case PCIM_I2S_20BIT:
2310 kprintf("20bit resolution, ");
2311 break;
2312 case PCIM_I2S_24BIT:
2313 kprintf("24bit resolution, ");
2314 break;
2316 kprintf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID);
2318 kprintf(" S/PDIF(IN/OUT): ");
2319 if (sc->cfg->spdif & PCIM_SPDIF_IN)
2320 kprintf("1/");
2321 else
2322 kprintf("0/");
2323 if (sc->cfg->spdif & PCIM_SPDIF_OUT)
2324 kprintf("1 ");
2325 else
2326 kprintf("0 ");
2327 if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT))
2328 kprintf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2);
2329 kprintf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2330 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2333 static int
2334 envy24_init(struct sc_info *sc)
2336 u_int32_t data;
2337 #if(0)
2338 int rtn;
2339 #endif
2340 int i;
2341 u_int32_t sv, sd;
2344 #if(0)
2345 device_printf(sc->dev, "envy24_init()\n");
2346 #endif
2348 /* reset chip */
2349 envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1);
2350 DELAY(200);
2351 envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1);
2352 DELAY(200);
2354 /* legacy hardware disable */
2355 data = pci_read_config(sc->dev, PCIR_LAC, 2);
2356 data |= PCIM_LAC_DISABLE;
2357 pci_write_config(sc->dev, PCIR_LAC, data, 2);
2359 /* check system configuration */
2360 sc->cfg = NULL;
2361 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2362 /* 1st: search configuration from table */
2363 sv = pci_get_subvendor(sc->dev);
2364 sd = pci_get_subdevice(sc->dev);
2365 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2366 #if(0)
2367 device_printf(sc->dev, "Set configuration from table\n");
2368 #endif
2369 sc->cfg = &cfg_table[i];
2370 break;
2373 if (sc->cfg == NULL) {
2374 /* 2nd: read configuration from table */
2375 sc->cfg = envy24_rom2cfg(sc);
2377 sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1;
2378 sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1;
2380 if (1 /* bootverbose */) {
2381 envy24_putcfg(sc);
2384 /* set system configuration */
2385 pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1);
2386 pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1);
2387 pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1);
2388 pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1);
2389 envy24_gpiosetmask(sc, sc->cfg->gpiomask);
2390 envy24_gpiosetdir(sc, sc->cfg->gpiodir);
2391 envy24_gpiowr(sc, sc->cfg->gpiostate);
2392 for (i = 0; i < sc->adcn; i++) {
2393 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2394 sc->cfg->codec->init(sc->adc[i]);
2396 for (i = 0; i < sc->dacn; i++) {
2397 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2398 sc->cfg->codec->init(sc->dac[i]);
2401 /* initialize DMA buffer */
2402 #if(0)
2403 device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n");
2404 #endif
2405 if (envy24_dmainit(sc))
2406 return ENOSPC;
2408 /* initialize status */
2409 sc->run[0] = sc->run[1] = 0;
2410 sc->intr[0] = sc->intr[1] = 0;
2411 sc->speed = 0;
2412 sc->caps[0].fmtlist = envy24_playfmt;
2413 sc->caps[1].fmtlist = envy24_recfmt;
2415 /* set channel router */
2416 envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0);
2417 envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0);
2418 /* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2420 /* set macro interrupt mask */
2421 data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2422 envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1);
2423 data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2424 #if(0)
2425 device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data);
2426 #endif
2428 return 0;
2431 static int
2432 envy24_alloc_resource(struct sc_info *sc)
2434 /* allocate I/O port resource */
2435 sc->csid = PCIR_CCS;
2436 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2437 &sc->csid, 0, ~0, 1, RF_ACTIVE);
2438 sc->ddmaid = PCIR_DDMA;
2439 sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2440 &sc->ddmaid, 0, ~0, 1, RF_ACTIVE);
2441 sc->dsid = PCIR_DS;
2442 sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2443 &sc->dsid, 0, ~0, 1, RF_ACTIVE);
2444 sc->mtid = PCIR_MT;
2445 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2446 &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2447 if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) {
2448 device_printf(sc->dev, "unable to map IO port space\n");
2449 return ENXIO;
2451 sc->cst = rman_get_bustag(sc->cs);
2452 sc->csh = rman_get_bushandle(sc->cs);
2453 sc->ddmat = rman_get_bustag(sc->ddma);
2454 sc->ddmah = rman_get_bushandle(sc->ddma);
2455 sc->dst = rman_get_bustag(sc->ds);
2456 sc->dsh = rman_get_bushandle(sc->ds);
2457 sc->mtt = rman_get_bustag(sc->mt);
2458 sc->mth = rman_get_bushandle(sc->mt);
2459 #if(0)
2460 device_printf(sc->dev,
2461 "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2462 pci_read_config(sc->dev, PCIR_CCS, 4),
2463 pci_read_config(sc->dev, PCIR_DDMA, 4),
2464 pci_read_config(sc->dev, PCIR_DS, 4),
2465 pci_read_config(sc->dev, PCIR_MT, 4));
2466 #endif
2468 /* allocate interupt resource */
2469 sc->irqid = 0;
2470 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2471 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2472 if (!sc->irq ||
2473 snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) {
2474 device_printf(sc->dev, "unable to map interrupt\n");
2475 return ENXIO;
2478 /* allocate DMA resource */
2479 if (bus_dma_tag_create(/*parent*/NULL,
2480 /*alignment*/4,
2481 /*boundary*/0,
2482 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2483 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2484 /*filter*/NULL, /*filterarg*/NULL,
2485 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2486 /*nsegments*/1, /*maxsegsz*/0x3ffff,
2487 /*flags*/0, &sc->dmat) != 0) {
2488 device_printf(sc->dev, "unable to create dma tag\n");
2489 return ENXIO;
2492 return 0;
2495 static int
2496 envy24_pci_attach(device_t dev)
2498 u_int32_t data;
2499 struct sc_info *sc;
2500 char status[SND_STATUSLEN];
2501 int err = 0;
2502 int i;
2504 #if(0)
2505 device_printf(dev, "envy24_pci_attach()\n");
2506 #endif
2507 /* get sc_info data area */
2508 if ((sc = kmalloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) {
2509 device_printf(dev, "cannot allocate softc\n");
2510 return ENXIO;
2513 bzero(sc, sizeof(*sc));
2514 sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_envy24 softc");
2515 sc->dev = dev;
2517 /* initialize PCI interface */
2518 data = pci_read_config(dev, PCIR_COMMAND, 2);
2519 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2520 pci_write_config(dev, PCIR_COMMAND, data, 2);
2521 data = pci_read_config(dev, PCIR_COMMAND, 2);
2523 /* allocate resources */
2524 err = envy24_alloc_resource(sc);
2525 if (err) {
2526 device_printf(dev, "unable to allocate system resources\n");
2527 goto bad;
2530 /* initialize card */
2531 err = envy24_init(sc);
2532 if (err) {
2533 device_printf(dev, "unable to initialize the card\n");
2534 goto bad;
2537 /* set multi track mixer */
2538 mixer_init(dev, &envy24mixer_class, sc);
2540 /* set channel information */
2541 err = pcm_register(dev, sc, 5, 2 + sc->adcn);
2542 if (err)
2543 goto bad;
2544 sc->chnum = 0;
2545 for (i = 0; i < 5; i++) {
2546 pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
2547 sc->chnum++;
2549 for (i = 0; i < 2 + sc->adcn; i++) {
2550 pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc);
2551 sc->chnum++;
2554 /* set status iformation */
2555 ksnprintf(status, SND_STATUSLEN,
2556 "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
2557 rman_get_start(sc->cs),
2558 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2559 rman_get_start(sc->ddma),
2560 rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1,
2561 rman_get_start(sc->ds),
2562 rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1,
2563 rman_get_start(sc->mt),
2564 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2565 rman_get_start(sc->irq));
2566 pcm_setstatus(dev, status);
2568 return 0;
2570 bad:
2571 if (sc->ih)
2572 bus_teardown_intr(dev, sc->irq, sc->ih);
2573 if (sc->irq)
2574 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2575 envy24_dmafree(sc);
2576 if (sc->dmat)
2577 bus_dma_tag_destroy(sc->dmat);
2578 if (sc->cfg->codec->destroy != NULL) {
2579 for (i = 0; i < sc->adcn; i++)
2580 sc->cfg->codec->destroy(sc->adc[i]);
2581 for (i = 0; i < sc->dacn; i++)
2582 sc->cfg->codec->destroy(sc->dac[i]);
2584 envy24_cfgfree(sc->cfg);
2585 if (sc->cs)
2586 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2587 if (sc->ddma)
2588 bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2589 if (sc->ds)
2590 bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2591 if (sc->mt)
2592 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2593 if (sc->lock)
2594 snd_mtxfree(sc->lock);
2595 kfree(sc, M_ENVY24);
2596 return err;
2599 static int
2600 envy24_pci_detach(device_t dev)
2602 struct sc_info *sc;
2603 int r;
2604 int i;
2606 #if(0)
2607 device_printf(dev, "envy24_pci_detach()\n");
2608 #endif
2609 sc = pcm_getdevinfo(dev);
2610 if (sc == NULL)
2611 return 0;
2612 r = pcm_unregister(dev);
2613 if (r)
2614 return r;
2616 envy24_dmafree(sc);
2617 if (sc->cfg->codec->destroy != NULL) {
2618 for (i = 0; i < sc->adcn; i++)
2619 sc->cfg->codec->destroy(sc->adc[i]);
2620 for (i = 0; i < sc->dacn; i++)
2621 sc->cfg->codec->destroy(sc->dac[i]);
2623 envy24_cfgfree(sc->cfg);
2624 bus_dma_tag_destroy(sc->dmat);
2625 bus_teardown_intr(dev, sc->irq, sc->ih);
2626 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2627 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2628 bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2629 bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2630 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2631 snd_mtxfree(sc->lock);
2632 kfree(sc, M_ENVY24);
2633 return 0;
2636 static device_method_t envy24_methods[] = {
2637 /* Device interface */
2638 DEVMETHOD(device_probe, envy24_pci_probe),
2639 DEVMETHOD(device_attach, envy24_pci_attach),
2640 DEVMETHOD(device_detach, envy24_pci_detach),
2641 { 0, 0 }
2644 static driver_t envy24_driver = {
2645 "pcm",
2646 envy24_methods,
2647 #if __FreeBSD_version > 500000
2648 PCM_SOFTC_SIZE,
2649 #else
2650 sizeof(struct snddev_info),
2651 #endif
2654 DRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0);
2655 MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2656 MODULE_DEPEND(snd_envy24, snd_spicds, 1, 1, 1);
2657 MODULE_VERSION(snd_envy24, 1);